diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e789f235853a2196e7f6f267d4c0f53590cf809d
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,25 @@
+stages:
+  - validate
+  - deploy
+
+image:
+  name: esphome/esphome:2022.11.3
+  entrypoint: [""]
+
+validate_configs:
+  stage: validate
+  before_script:
+    - cat "${SECRETS_YAML}" > "packages/secrets.yaml"
+  script:
+    - for yml in *.yaml; do esphome config ${yml}; done
+  tags:
+    - docker
+
+deploy_configs:
+  stage: deploy
+  before_script:
+    - cat "${SECRETS_YAML}" > "packages/secrets.yaml"
+  script:
+    - cp -r *.yaml packages include /srv/esphome/groovy-industries
+  tags:
+    - shell
diff --git a/growbox.yaml b/growbox.yaml
index e490a5de6b95c74563e748a79cb2d814c8faf000..6748c88b94cdd1eee77b322a4334d0ab790ab5bb 100644
--- a/growbox.yaml
+++ b/growbox.yaml
@@ -1,18 +1,18 @@
 substitutions:
   devicename: "growbox"
-  comment: "Grow Tent Monitor"
+  comment: "Grow Tent Controller"
 
   # Growbox Nodes
   hostname_light: "${devicename}-light.${domain}"
   hostname_fan: "${devicename}-fan.${domain}"
 
   # Overrides
-  bme280_script: "fan_control_power"
+  fan_script: "fan_control_power"
 
 packages:
   base:           !include packages/base.yaml
   esp32:          !include packages/esp32.yaml
-  time:           !include packages/time.yaml
+  time:           !include packages/time_schedule.yaml
   bme280:         !include packages/bme280.yaml
   yieryi2178:     !include packages/yieryi3178.yaml
   scd40:          !include packages/scd40.yaml
diff --git a/packages/base.yaml b/packages/base.yaml
index 7f0d829e3bb2b8f5f4da0eb1e0b1672dee791bf2..e10e0d1e58367880d16263bd7edcd66cf64561e2 100644
--- a/packages/base.yaml
+++ b/packages/base.yaml
@@ -9,16 +9,14 @@ esphome:
     then:
       - lambda: |-
           id(sntp_time).update();
-          id(fan_power_state).execute();
-          id(light_power_state).execute();
 
 substitutions:
   domain: !secret domain
   timezone: !secret timezone
-  bme280_script: "dummy"
+  fan_script: "dummy"
 
 preferences:
-  flash_write_interval: 0s
+  flash_write_interval: 5s
 
 logger:
   # level: INFO
diff --git a/packages/bme280.yaml b/packages/bme280.yaml
index c51fc6a88fd4543ded5ed41a7d1c0f80c07ee3a9..853a969c930c66989b318b42a502df75d522d6d2 100644
--- a/packages/bme280.yaml
+++ b/packages/bme280.yaml
@@ -10,7 +10,7 @@ sensor:
     on_value:
       then:
         - lambda: |-
-            id(${bme280_script}).execute();
+            id(${fan_script}).execute();
   humidity:
     id: bme280_humidity
     name: "Air: Humidity"
@@ -19,7 +19,7 @@ sensor:
     on_value:
       then:
         - lambda: |-
-            id(${bme280_script}).execute();
+            id(${fan_script}).execute();
   pressure:
     id: bme280_pressure
     name: "Air: Pressure"
diff --git a/packages/fan_power.yaml b/packages/fan_power.yaml
index e1f657637970f727c0078d9ae56dbc87e3a29302..83d0d84ca688b7a50009dbca9596bf963a910563 100644
--- a/packages/fan_power.yaml
+++ b/packages/fan_power.yaml
@@ -1,3 +1,10 @@
+esphome:
+  on_boot:
+    priority: -200
+    then:
+      - lambda: |-
+          id(fan_power_state).execute();
+
 switch:
   - platform: template
     id: power_fan
diff --git a/packages/fan_settings.yaml b/packages/fan_settings.yaml
index dae1a667352f19be091c17e26f6dee273b0c703c..052e11f6206bcf7af480895c28961e0004bf67f9 100644
--- a/packages/fan_settings.yaml
+++ b/packages/fan_settings.yaml
@@ -25,6 +25,13 @@ sensor:
     internal: true
 
 select:
+  - platform: template
+    id: fan_mode
+    name: "Fan: Mode"
+    options: ["Power", "Speed"]
+    initial_option: "Power"
+    optimistic: true
+    restore_value: true
   - platform: template
     id: temperature_max
     name: "Fan: Temperature On"
@@ -67,3 +74,23 @@ select:
     initial_option: "40"
     optimistic: true
     restore_value: true
+
+number:
+  - platform: template
+    id: fan_speed_default
+    name: "Fan: Speed Default"
+    min_value: 0
+    max_value: 100
+    step: 1
+    mode: slider
+    optimistic: true
+    restore_value: true
+  - platform: template
+    id: fan_speed_max
+    name: "Fan: Speed Fast"
+    min_value: 0
+    max_value: 100
+    step: 1
+    mode: slider
+    optimistic: true
+    restore_value: true
diff --git a/packages/gp8403.yaml b/packages/gp8403.yaml
index d3fef0d243996b486d86cf1ef9e6db8c18694235..ba46c84514ba9542a3ba3ae98c44aee190fc6c6b 100644
--- a/packages/gp8403.yaml
+++ b/packages/gp8403.yaml
@@ -32,7 +32,17 @@ fan:
 
 light:
   - platform: monochromatic
+    id: light_level
     name: "Light: Level"
     output: gp8403_ch1
     default_transition_length: 0s
     gamma_correct: 0
+
+prometheus:
+  relabel:
+    fan_speed:
+      id: fan_speed
+      name: "Fan Speed"
+    light_level:
+      id: light_level
+      name: "Light Level"
diff --git a/packages/light_power.yaml b/packages/light_power.yaml
index a76da53285debb0d8f915b996b646665dd9bda60..93066fa3bac0c673d809abf167fcc22d65725473 100644
--- a/packages/light_power.yaml
+++ b/packages/light_power.yaml
@@ -1,3 +1,10 @@
+esphome:
+  on_boot:
+    priority: -200
+    then:
+      - lambda: |-
+          id(light_power_state).execute();
+
 switch:
   - platform: template
     id: power_light
diff --git a/packages/light_settings.yaml b/packages/light_settings.yaml
index 80d593f6cf9281978ef51d8e898c97a91ebe391d..059dffb0799c23cfa430098a414349814407950b 100644
--- a/packages/light_settings.yaml
+++ b/packages/light_settings.yaml
@@ -7,7 +7,8 @@ substitutions:
 
 sensor:
   - platform: template
-    name: "schedule"
+    id: light_schedule
+    name: "Light Schedule"
     lambda: return id(schedule).active_index();
     internal: true
 
diff --git a/packages/time.yaml b/packages/time.yaml
index 82d0a3d81fe955ec40ad8f8578e37f1e93eca16b..a4f830e546884d7cd5adea5519ab96fb324f17d8 100644
--- a/packages/time.yaml
+++ b/packages/time.yaml
@@ -3,29 +3,3 @@ time:
     id: sntp_time
     timezone: ${timezone}
     update_interval: 1h
-    on_time:
-      - cron: ${schedule_grow_on}
-        then:
-          - lambda: |-
-              if (id(schedule).state == "Grow") {
-                id(power_light).turn_on();
-              }
-      - cron: ${schedule_grow_off}
-        then:
-          - lambda: |-
-              if (id(schedule).state == "Grow") {
-                id(power_light).turn_off();
-              }
-      - cron: ${schedule_bloom_on}
-        then:
-          - lambda: |-
-              if (id(schedule).state == "Bloom") {
-                id(power_light).turn_on();
-              }
-      - cron: ${schedule_bloom_off}
-        then:
-          - lambda: |-
-              if (id(schedule).state == "Bloom") {
-                id(power_light).turn_off();
-              }
-
diff --git a/packages/time_schedule.yaml b/packages/time_schedule.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..82d0a3d81fe955ec40ad8f8578e37f1e93eca16b
--- /dev/null
+++ b/packages/time_schedule.yaml
@@ -0,0 +1,31 @@
+time:
+  - platform: sntp
+    id: sntp_time
+    timezone: ${timezone}
+    update_interval: 1h
+    on_time:
+      - cron: ${schedule_grow_on}
+        then:
+          - lambda: |-
+              if (id(schedule).state == "Grow") {
+                id(power_light).turn_on();
+              }
+      - cron: ${schedule_grow_off}
+        then:
+          - lambda: |-
+              if (id(schedule).state == "Grow") {
+                id(power_light).turn_off();
+              }
+      - cron: ${schedule_bloom_on}
+        then:
+          - lambda: |-
+              if (id(schedule).state == "Bloom") {
+                id(power_light).turn_on();
+              }
+      - cron: ${schedule_bloom_off}
+        then:
+          - lambda: |-
+              if (id(schedule).state == "Bloom") {
+                id(power_light).turn_off();
+              }
+
diff --git a/packages/yyac3s.yaml b/packages/yyac3s.yaml
index c9c1ab96debe80ac0e730d468063a4919e5c34fe..f2580d0286784ee23a098b9fd12bab2d8b1c60cc 100644
--- a/packages/yyac3s.yaml
+++ b/packages/yyac3s.yaml
@@ -11,10 +11,10 @@ fan:
   - platform: speed
     output: fan_dimmer
     id: fan_speed
-    name: "Fan Speed"
+    name: "Fan: Speed"
 
 prometheus:
   relabel:
     fan_speed:
       id: fan_speed
-      name: Fan Speed
+      name: "Fan Speed"
diff --git a/propbox.yaml b/propbox.yaml
index a952ba641b65045d6949bcf208e658a812bd56e1..23da35a226bddc039d66b66ca921ebdd83ef50d1 100644
--- a/propbox.yaml
+++ b/propbox.yaml
@@ -7,12 +7,12 @@ substitutions:
   hostname_fan: "${devicename}-fan.${domain}"
 
   # Overrides
-  bme280_script: "fan_control_power"
+  fan_script: "fan_control_power"
 
 packages:
   base:           !include packages/base.yaml
   esp32:          !include packages/esp32.yaml
-  time:           !include packages/time.yaml
+  time:           !include packages/time_schedule.yaml
   bme280:         !include packages/bme280.yaml
   ds18b20:        !include packages/ds18b20.yaml
   yyac32:         !include packages/yyac3s.yaml