diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 78333fd4763995583933059e3308e4d74a4dc02c..a17dcf07eca2c02e16a34fcbc2478048f5600704 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -25,3 +25,5 @@ deploy_configs:
     - cp -rv *.yaml packages /srv/esphome/growsmart/
   tags:
     - shell
+  rules:
+    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
diff --git a/growbox-screen.yaml b/growbox-screen.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..bb6fec4f6a007c54cd79b15e07223953d3066fb6
--- /dev/null
+++ b/growbox-screen.yaml
@@ -0,0 +1,11 @@
+substitutions:
+  devicename: "growbox-screen"
+  comment: "Grow Box Screen"
+
+packages:
+  base:           !include packages/base.yaml
+  esp32:          !include packages/esp32.yaml
+  time:           !include packages/time.yaml
+  mqtt:           !include packages/mqtt.yaml
+  display:        !include packages/display_cyd2usb.yaml
+  screen:         !include packages/screen.yaml
diff --git a/packages/display_cyd2usb.yaml b/packages/display_cyd2usb.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c59784393c3e5c30ee21706c3d4873dc4b7a2277
--- /dev/null
+++ b/packages/display_cyd2usb.yaml
@@ -0,0 +1,118 @@
+i2c:
+  sda: 27
+  scan: false
+
+spi:
+  - id: tft
+    clk_pin: GPIO14
+    mosi_pin: GPIO13
+    miso_pin: GPIO12
+  - id: touch
+    clk_pin: GPIO25
+    mosi_pin: GPIO32
+    miso_pin: GPIO39
+
+display:
+  - platform: ili9xxx
+    id: esp_display
+    model: ili9342
+    spi_id: tft
+    cs_pin: GPIO15
+    dc_pin: GPIO2
+    color_order: rgb
+    transform:
+      swap_xy: true
+      mirror_x: true
+      mirror_y: true
+    dimensions:
+      height: 320
+      width: 240
+    lambda: |-
+      it.fill(id(Color::BLACK));
+      it.line(0, 0, 50, 50);
+      it.filled_circle(60, 160, 30, id(green));
+      it.filled_circle(180, 160, 30, id(red));
+      it.print(60, 160, id(mdi_large), TextAlign::CENTER, "󰛨");
+      it.print(180, 160, id(mdi_large), TextAlign::CENTER, "󰛨");
+      it.print(216, 0, id(mdi_medium), id(wifi_iconstring).c_str());
+
+# Set up the xpt2046 touch platform
+touchscreen:
+  platform: xpt2046
+  spi_id: touch
+  cs_pin: GPIO33
+  interrupt_pin: GPIO36
+  update_interval: 50ms
+  threshold: 400
+  calibration:
+    x_min: 180
+    x_max: 3800
+    y_min: 240
+    y_max: 3860
+  transform:
+    mirror_x: true
+  # When the display is touched, turn on the backlight,
+  # store that we had a recent touch, and update the UI
+  on_touch:
+    then:
+      - light.turn_on:
+          id: backlight
+          brightness: 100%
+      - lambda: |-
+          id(recent_touch) = true;
+
+output:
+  - platform: ledc
+    pin: GPIO21
+    id: backlight_pwm
+  - platform: ledc
+    id: output_red
+    pin: GPIO4
+    inverted: true
+  - platform: ledc
+    id: output_green
+    pin: GPIO16
+    inverted: true
+  - platform: ledc
+    id: output_blue
+    pin: GPIO17
+    inverted: true
+
+light:
+  - platform: monochromatic
+    output: backlight_pwm
+    name: Display Backlight
+    id: backlight
+    restore_mode: ALWAYS_ON
+  - platform: rgb
+    name: LED
+    id: led
+    red: output_red
+    green: output_green
+    blue: output_blue
+    gamma_correct: 1.0
+    restore_mode: ALWAYS_ON
+    effects:
+      - pulse:
+          name: "Default"
+          transition_length: 3s
+          update_interval: 3s
+          min_brightness: 33%
+          max_brightness: 100%
+    on_turn_on:
+      - light.turn_on:
+          id: led
+          effect: "Default"
+
+interval:
+  - interval: 5s
+    then:
+      - if:
+          condition:
+            - lambda: "return !id(recent_touch);"
+          then:
+            - light.turn_on:
+                id: backlight
+                brightness: 25%
+          else:
+            - lambda: "id(recent_touch) = false;"
diff --git a/packages/esp32.yaml b/packages/esp32.yaml
index 7779c0d2124a158ddbd6d07974020b0d0565a39e..4f0ac5965480a209dcca33a5db36e1d954fdcd5d 100644
--- a/packages/esp32.yaml
+++ b/packages/esp32.yaml
@@ -3,5 +3,7 @@ esp32:
   framework:
     type: arduino
 
+i2c:
+
 wifi:
   power_save_mode: none
diff --git a/packages/fonts/Arimo-Regular.ttf b/packages/fonts/Arimo-Regular.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..7872b35ab5dc33e12e7ddaccdef089c0a34cc461
Binary files /dev/null and b/packages/fonts/Arimo-Regular.ttf differ
diff --git a/packages/fonts/materialdesignicons-webfont.ttf b/packages/fonts/materialdesignicons-webfont.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..edd6cb0752abb6d3856bd586475cbc81b3085f18
Binary files /dev/null and b/packages/fonts/materialdesignicons-webfont.ttf differ
diff --git a/packages/screen.yaml b/packages/screen.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..4afe3bf1a5f6471beca199301bf58742cbdbf4b7
--- /dev/null
+++ b/packages/screen.yaml
@@ -0,0 +1,111 @@
+
+# Set up some global variables for some values that we want to persist
+globals:
+  - id: wifi_iconstring
+    type: std::string
+    restore_value: no
+    initial_value: '"󰤮"'
+  - id: recent_touch
+    type: bool
+    restore_value: no
+    initial_value: "true"
+
+# ============================================================ 
+# ESPHome Display related setup
+#
+# Create a font to use, add and remove glyphs as needed
+# The Material Design Icon font is going to be used to display wifi
+# state as well as displaying the lightbulb icons
+font:
+  - file: 'packages/fonts/materialdesignicons-webfont.ttf'
+    id: mdi_large
+    size: 48
+    glyphs: [
+        "󰛨", # lightbulb-on
+        "󰹏", # lightbulb-off
+    ]
+  - file: "packages/fonts/materialdesignicons-webfont.ttf"
+    id: mdi_medium
+    size: 24
+    glyphs: [
+        "󰤮", # no-wifi
+        "󰤫", # low-wifi
+        "󰤟", # wifi-1
+        "󰤢", # wifi-2
+        "󰤥", # wifi-3
+        "󰤨", # wifi-4
+    ]
+
+# Create a Home Assistant blue color
+color:
+  - id: green
+    hex: 00FF00
+  - id: red
+    hex: FF0000
+
+# Setup two binary sensors for the two areas for touch
+binary_sensor:
+  - platform: touchscreen
+    name: Light Green
+    x_min: 0
+    x_max: 120
+    y_min: 0
+    y_max: 320
+    on_press:
+      then:
+        - light.turn_on:
+            id: led
+            red: 0.0
+            green: 1.0
+            blue: 0.0            
+
+  - platform: touchscreen
+    name: Light Red
+    x_min: 120
+    x_max: 240
+    y_min: 0
+    y_max: 320
+    on_press:
+      then:
+        - light.turn_on:
+            id: led
+            red: 1.0
+            green: 0.0
+            blue: 0.0
+
+
+# Setup a script that can update the UI values independent of the display lambda
+# so that we're not trying to pull the WiFi signal strength every single frame
+script:
+  - id: update_ui_values
+    then:
+    - lambda: |-
+        if (isnan(id(wifi_signal_pct).state))
+            id(wifi_iconstring) = "󰤮"; // No-wifi
+        else if (id(wifi_signal_pct).state < 10)
+            id(wifi_iconstring) = "󰤟";  // low-wifi
+        else if (id(wifi_signal_pct).state < 30)
+            id(wifi_iconstring) = "󰤟"; // wifi-1
+        else if (id(wifi_signal_pct).state < 50)
+            id(wifi_iconstring) = "󰤢"; // wifi-2
+        else if (id(wifi_signal_pct).state < 75)
+            id(wifi_iconstring) = "󰤥"; // wifi-3
+        else
+            id(wifi_iconstring) = "󰤨"; // wifi-4
+
+# Update the UI state every 10 seconds
+interval:
+  - interval: 1s
+    then:
+      - script.execute: update_ui_values
+
+# Wifi sensor that drives the UI signal strength icon
+sensor:
+  - platform: wifi_signal # Reports the WiFi signal strength in %
+    name: "WiFi Signal Percent"
+    filters:
+      - lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
+    unit_of_measurement: "Signal %"
+    id: wifi_signal_pct
+    update_interval: 60s
+    entity_category: "diagnostic"