diff --git a/growbox-fan.yaml b/growbox-fan.yaml new file mode 100644 index 0000000000000000000000000000000000000000..ce5ec5da24bee0817316cbe6ef4d0192103ee426 --- /dev/null +++ b/growbox-fan.yaml @@ -0,0 +1,8 @@ +substitutions: + devicename: "growbox-fan" + comment: "Growbox Fan Control" + +packages: + base: !include packages/base.yaml + time: !include packages/time.yaml + nous_a1t: !include packages/nous_a1t.yaml diff --git a/growbox-light.yaml b/growbox-light.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f8357c3efceb3c51a5e5f8943db8beae08fc7a92 --- /dev/null +++ b/growbox-light.yaml @@ -0,0 +1,8 @@ +substitutions: + devicename: "growbox-light" + comment: "Growbox Light Control" + +packages: + base: !include packages/base.yaml + time: !include packages/time.yaml + nous_a1t: !include packages/nous_a1t.yaml diff --git a/growbox.yaml b/growbox.yaml index 09ec990704fc6619ac199241668eafbd3885b3c3..cc3ba13a64ed21b1929139f12f360296ce535945 100644 --- a/growbox.yaml +++ b/growbox.yaml @@ -2,13 +2,25 @@ substitutions: devicename: "growbox" comment: "Grow Tent Monitor" + # Growbox Nodes + hostname_light: "${devicename}-light.${domain}" + hostname_fan: "${devicename}-fan.${domain}" + + # Overrides + #bme280_script: "fan_control_speed" + packages: - base: !include packages/base.yaml - esp32: !include packages/esp32.yaml - time: !include packages/time.yaml - bme280: !include packages/bme280.yaml - yieryi2178: !include packages/yieryi3178.yaml - scd40: !include packages/scd40.yaml - mlx90614: !include packages/mlx90614.yaml - gp8403: !include packages/gp8403.yaml - vpd: !include packages/vpd.yaml + base: !include packages/base.yaml + esp32: !include packages/esp32.yaml + time: !include packages/time.yaml + bme280: !include packages/bme280.yaml + yieryi2178: !include packages/yieryi3178.yaml + scd40: !include packages/scd40.yaml + mlx90614: !include packages/mlx90614.yaml + gp8403: !include packages/gp8403.yaml + vpd: !include packages/vpd.yaml + fan_settings: !include packages/fan_settings.yaml + fan_power: !include packages/fan_power.yaml + fan_script_power: !include packages/fan_script_power.yaml + light_power: !include packages/light_power.yaml + light_settings: !include packages/light_settings.yaml diff --git a/packages/base.yaml b/packages/base.yaml index c6129d522e3e50f3c21ece6c9e94783abbe27b4f..7f0d829e3bb2b8f5f4da0eb1e0b1672dee791bf2 100644 --- a/packages/base.yaml +++ b/packages/base.yaml @@ -9,6 +9,8 @@ esphome: then: - lambda: |- id(sntp_time).update(); + id(fan_power_state).execute(); + id(light_power_state).execute(); substitutions: domain: !secret domain diff --git a/packages/fan.yaml b/packages/fan.yaml deleted file mode 100644 index c1ac7705581a8dde74f9a513e761eaf2fbccbbe0..0000000000000000000000000000000000000000 --- a/packages/fan.yaml +++ /dev/null @@ -1,168 +0,0 @@ -output: - - platform: ledc - pin: GPIO13 - id: fan_dimmer - frequency: 223Hz - min_power: 0.36 - max_power: 0.78 - zero_means_zero: true - -fan: - - platform: speed - output: fan_dimmer - id: fan_extraction - name: "Fan" - -prometheus: - relabel: - fan_extraction: - id: fan - name: Fan - propbox_fan: - id: power_fan - name: "Power Fan" - -sensor: - - platform: template - name: "temperature_max" - lambda: return atoi(id(temperature_max).state.c_str()); - internal: true - - platform: template - name: "temperature_hysteresis" - lambda: return atoi(id(temperature_hysteresis).state.c_str()); - internal: true - - platform: template - name: "temperature_min" - lambda: return atoi(id(temperature_min).state.c_str()); - internal: true - - platform: template - name: "humidity_max" - lambda: return atoi(id(humidity_max).state.c_str()); - internal: true - - platform: template - name: "humidity_hysteresis" - lambda: return atoi(id(humidity_hysteresis).state.c_str()); - internal: true - - platform: template - name: "humidity_min" - lambda: return atoi(id(humidity_min).state.c_str()); - internal: true - -select: - - platform: template - id: temperature_max - name: "Fan: Temperature On" - options: ["21", "22", "23", "24", "25", "26", "27", "28", "29", "30"] - initial_option: "27" - optimistic: true - restore_value: true - - platform: template - id: temperature_hysteresis - name: "Fan: Temperature Hysteresis" - options: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"] - initial_option: "1" - optimistic: true - restore_value: true - - platform: template - id: temperature_min - name: "Fan: Temperature Off" - options: ["16", "17", "18", "19", "20", "21", "22", "23", "24", "25"] - initial_option: "21" - optimistic: true - restore_value: true - - platform: template - id: humidity_max - name: "Fan: Humidity On" - options: ["40", "45", "50", "55", "60", "65", "70", "75", "80", "85"] - initial_option: "70" - optimistic: true - restore_value: true - - platform: template - id: humidity_hysteresis - name: "Fan: Humidity Hysteresis" - options: ["1", "2", "3", "4", "5", "10", "15"] - initial_option: "5" - optimistic: true - restore_value: true - - platform: template - id: humidity_min - name: "Fan: Humidity Off" - options: ["30", "35", "40", "45", "50", "55", "60", "65", "70", "80"] - initial_option: "40" - optimistic: true - restore_value: true - - -switch: - - platform: template - id: propbox_fan - name: "Power: Fan" - optimistic: true - turn_on_action: - - http_request.post: http://${hostname_fan}/switch/power/turn_on - turn_off_action: - - http_request.post: http://${hostname_fan}/switch/power/turn_off - -interval: - - interval: 1min - then: - - script.execute: fan_state - -script: - - id: fan_control - then: - - lambda: |- - // Normal On: - // switch fan on when either temperature or humidity is above "max", unless humidity/temperature is below "min" - if ( - !id(fan_extraction).state && - ( - (id(bme280_temperature).state >= atoi(id(temperature_max).state.c_str()) && id(bme280_humidity).state >= atoi(id(humidity_min).state.c_str())) || - (id(bme280_humidity).state >= atoi(id(humidity_max).state.c_str()) && id(bme280_temperature).state >= atoi(id(temperature_min).state.c_str())) - ) - ) { - ESP_LOGI("fan", "Fan On"); - auto call = id(fan_extraction).turn_on(); - call.perform(); - } - - // Forced Off, ignoring Hysteresis: - // switch fan off when either temperature or humidity are below "min", unless humidity/temperature is above "max" - else if ( - id(fan_extraction).state && - ( - (id(bme280_temperature).state <= atoi(id(temperature_min).state.c_str()) && id(bme280_humidity).state <= atoi(id(humidity_max).state.c_str())) || - (id(bme280_humidity).state <= atoi(id(humidity_min).state.c_str()) && id(bme280_temperature).state <= atoi(id(temperature_max).state.c_str())) - ) - ) { - ESP_LOGI("fan", "Fan Off (forced)"); - auto call = id(fan_extraction).turn_off(); - call.perform(); - } - - // Normal Off, respecting Hysteresis: - // switch fan off when both temperature and humidity are below "max minus hysteresis" - else if ( - id(fan_extraction).state && - ( - id(bme280_temperature).state <= atoi(id(temperature_max).state.c_str()) - atoi(id(temperature_hysteresis).state.c_str()) && - id(bme280_humidity).state <= atoi(id(humidity_max).state.c_str()) - atoi(id(humidity_hysteresis).state.c_str()) - ) - ) { - ESP_LOGI("fan", "Fan Off"); - auto call = id(fan_extraction).turn_off(); - call.perform(); - } - - id: fan_state - then: - - lambda: |- - HTTPClient http; - bool state = false; - http.begin("http://${hostname_fan}/switch/power"); - if (http.GET() == 200) { - DynamicJsonDocument doc(200); - deserializeJson(doc, http.getString()); - state = (doc["state"] == "ON") ? true : false; - } - id(propbox_fan).publish_state(state); - http.end(); diff --git a/packages/fan_power.yaml b/packages/fan_power.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e1f657637970f727c0078d9ae56dbc87e3a29302 --- /dev/null +++ b/packages/fan_power.yaml @@ -0,0 +1,35 @@ +switch: + - platform: template + id: power_fan + name: "Fan: Power" + optimistic: true + turn_on_action: + - http_request.post: http://${hostname_fan}/switch/power/turn_on + turn_off_action: + - http_request.post: http://${hostname_fan}/switch/power/turn_off + +interval: + - interval: 1min + then: + - script.execute: fan_power_state + +script: + - id: fan_power_state + then: + - lambda: |- + HTTPClient http; + bool state = false; + http.begin("http://${hostname_fan}/switch/power"); + if (http.GET() == 200) { + DynamicJsonDocument doc(200); + deserializeJson(doc, http.getString()); + state = (doc["state"] == "ON") ? true : false; + } + id(power_fan).publish_state(state); + http.end(); + +prometheus: + relabel: + power_fan: + id: power_fan + name: "Power Fan" diff --git a/packages/fan_script_power.yaml b/packages/fan_script_power.yaml new file mode 100644 index 0000000000000000000000000000000000000000..536bd976125c831035e72d17bb89a2e7c7d5d486 --- /dev/null +++ b/packages/fan_script_power.yaml @@ -0,0 +1,45 @@ +script: + - id: fan_control_power + then: + - lambda: |- + // Normal On: + // switch fan on when either temperature or humidity is above "max", unless humidity/temperature is below "min" + if ( + !id(fan_speed).state && + ( + (id(bme280_temperature).state >= atoi(id(temperature_max).state.c_str()) && id(bme280_humidity).state >= atoi(id(humidity_min).state.c_str())) || + (id(bme280_humidity).state >= atoi(id(humidity_max).state.c_str()) && id(bme280_temperature).state >= atoi(id(temperature_min).state.c_str())) + ) + ) { + ESP_LOGI("fan", "Fan On"); + auto call = id(fan_speed).turn_on(); + call.perform(); + } + + // Forced Off, ignoring Hysteresis: + // switch fan off when either temperature or humidity are below "min", unless humidity/temperature is above "max" + else if ( + id(fan_speed).state && + ( + (id(bme280_temperature).state <= atoi(id(temperature_min).state.c_str()) && id(bme280_humidity).state <= atoi(id(humidity_max).state.c_str())) || + (id(bme280_humidity).state <= atoi(id(humidity_min).state.c_str()) && id(bme280_temperature).state <= atoi(id(temperature_max).state.c_str())) + ) + ) { + ESP_LOGI("fan", "Fan Off (forced)"); + auto call = id(fan_speed).turn_off(); + call.perform(); + } + + // Normal Off, respecting Hysteresis: + // switch fan off when both temperature and humidity are below "max minus hysteresis" + else if ( + id(fan_speed).state && + ( + id(bme280_temperature).state <= atoi(id(temperature_max).state.c_str()) - atoi(id(temperature_hysteresis).state.c_str()) && + id(bme280_humidity).state <= atoi(id(humidity_max).state.c_str()) - atoi(id(humidity_hysteresis).state.c_str()) + ) + ) { + ESP_LOGI("fan", "Fan Off"); + auto call = id(fan_speed).turn_off(); + call.perform(); + } diff --git a/packages/fan_settings.yaml b/packages/fan_settings.yaml new file mode 100644 index 0000000000000000000000000000000000000000..dae1a667352f19be091c17e26f6dee273b0c703c --- /dev/null +++ b/packages/fan_settings.yaml @@ -0,0 +1,69 @@ +sensor: + - platform: template + name: "temperature_max" + lambda: return atoi(id(temperature_max).state.c_str()); + internal: true + - platform: template + name: "temperature_hysteresis" + lambda: return atoi(id(temperature_hysteresis).state.c_str()); + internal: true + - platform: template + name: "temperature_min" + lambda: return atoi(id(temperature_min).state.c_str()); + internal: true + - platform: template + name: "humidity_max" + lambda: return atoi(id(humidity_max).state.c_str()); + internal: true + - platform: template + name: "humidity_hysteresis" + lambda: return atoi(id(humidity_hysteresis).state.c_str()); + internal: true + - platform: template + name: "humidity_min" + lambda: return atoi(id(humidity_min).state.c_str()); + internal: true + +select: + - platform: template + id: temperature_max + name: "Fan: Temperature On" + options: ["21", "22", "23", "24", "25", "26", "27", "28", "29", "30"] + initial_option: "27" + optimistic: true + restore_value: true + - platform: template + id: temperature_hysteresis + name: "Fan: Temperature Hysteresis" + options: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"] + initial_option: "1" + optimistic: true + restore_value: true + - platform: template + id: temperature_min + name: "Fan: Temperature Off" + options: ["16", "17", "18", "19", "20", "21", "22", "23", "24", "25"] + initial_option: "21" + optimistic: true + restore_value: true + - platform: template + id: humidity_max + name: "Fan: Humidity On" + options: ["40", "45", "50", "55", "60", "65", "70", "75", "80", "85"] + initial_option: "70" + optimistic: true + restore_value: true + - platform: template + id: humidity_hysteresis + name: "Fan: Humidity Hysteresis" + options: ["1", "2", "3", "4", "5", "10", "15"] + initial_option: "5" + optimistic: true + restore_value: true + - platform: template + id: humidity_min + name: "Fan: Humidity Off" + options: ["30", "35", "40", "45", "50", "55", "60", "65", "70", "80"] + initial_option: "40" + optimistic: true + restore_value: true diff --git a/packages/gp8403.yaml b/packages/gp8403.yaml index d901d308de947b0a9008ceb1f3d11aa13ab015be..effa8374b9621eaca9ed563ff980983951c61183 100644 --- a/packages/gp8403.yaml +++ b/packages/gp8403.yaml @@ -21,7 +21,7 @@ output: number: - platform: template id: dimmer_fan - name: "Dimmer: Fan" + name: "Fan: Speed" min_value: 0 max_value: 100 step: 1 @@ -33,7 +33,7 @@ number: - lambda: !lambda 'id(gp8403_ch0).set_level(x / 100);' - platform: template id: dimmer_light - name: "Dimmer: Light" + name: "Light: Level" min_value: 0 max_value: 100 step: 1 @@ -46,13 +46,15 @@ number: sensor: - platform: template - id: fan_level - name: "Fan Level" + internal: true + id: fan_speed + name: "Fan Speed" unit_of_measurement: '%' accuracy_decimals: 0 lambda: !lambda 'return id(dimmer_fan).state;' update_interval: 5s - platform: template + internal: true id: light_level name: "Light Level" unit_of_measurement: '%' diff --git a/packages/light.yaml b/packages/light_power.yaml similarity index 52% rename from packages/light.yaml rename to packages/light_power.yaml index 7f109e12b485d5dd783dc06c9bd02483f229c6e9..a76da53285debb0d8f915b996b646665dd9bda60 100644 --- a/packages/light.yaml +++ b/packages/light_power.yaml @@ -1,35 +1,7 @@ -substitutions: - # Schedules - schedule_grow_on: "0 0 3 * * *" - schedule_grow_off: "0 0 21 * * *" - schedule_bloom_on: "0 0 6 * * *" - schedule_bloom_off: "0 0 18 * * *" - -prometheus: - relabel: - propbox_light: - id: power_light - name: "Power Light" - -sensor: - - platform: template - name: "schedule" - lambda: return id(schedule).active_index(); - internal: true - -select: - - platform: template - id: schedule - name: "Light: Schedule" - options: ["Disabled", "Grow", "Bloom"] - initial_option: "Disabled" - optimistic: true - restore_value: true - switch: - platform: template - id: propbox_light - name: "Power: Light" + id: power_light + name: "Light: Power" optimistic: true turn_on_action: - http_request.post: http://${hostname_light}/switch/power/turn_on @@ -39,10 +11,10 @@ switch: interval: - interval: 1min then: - - script.execute: light_state + - script.execute: light_power_state script: - - id: light_state + - id: light_power_state then: - lambda: |- HTTPClient http; @@ -53,5 +25,11 @@ script: deserializeJson(doc, http.getString()); state = (doc["state"] == "ON") ? true : false; } - id(propbox_light).publish_state(state); + id(power_light).publish_state(state); http.end(); + +prometheus: + relabel: + power_light: + id: power_light + name: "Power Light" diff --git a/packages/light_settings.yaml b/packages/light_settings.yaml new file mode 100644 index 0000000000000000000000000000000000000000..80d593f6cf9281978ef51d8e898c97a91ebe391d --- /dev/null +++ b/packages/light_settings.yaml @@ -0,0 +1,21 @@ +substitutions: + # Schedules + schedule_grow_on: "0 0 3 * * *" + schedule_grow_off: "0 0 21 * * *" + schedule_bloom_on: "0 0 6 * * *" + schedule_bloom_off: "0 0 18 * * *" + +sensor: + - platform: template + name: "schedule" + lambda: return id(schedule).active_index(); + internal: true + +select: + - platform: template + id: schedule + name: "Light: Schedule" + options: ["Disabled", "Grow", "Bloom"] + initial_option: "Disabled" + optimistic: true + restore_value: true diff --git a/packages/time.yaml b/packages/time.yaml index a4f830e546884d7cd5adea5519ab96fb324f17d8..82d0a3d81fe955ec40ad8f8578e37f1e93eca16b 100644 --- a/packages/time.yaml +++ b/packages/time.yaml @@ -3,3 +3,29 @@ 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/yyac3s.yaml b/packages/yyac3s.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c9c1ab96debe80ac0e730d468063a4919e5c34fe --- /dev/null +++ b/packages/yyac3s.yaml @@ -0,0 +1,20 @@ +output: + - platform: ledc + pin: GPIO13 + id: fan_dimmer + frequency: 223Hz + min_power: 0.36 + max_power: 0.78 + zero_means_zero: true + +fan: + - platform: speed + output: fan_dimmer + id: fan_speed + name: "Fan Speed" + +prometheus: + relabel: + fan_speed: + id: fan_speed + name: Fan Speed diff --git a/propbox.yaml b/propbox.yaml index 2d844830bacabae22a1f7d3d9270f92d3e4bcb8f..359caf80ab23515dfb8c5ef1e31250fefb070d0a 100644 --- a/propbox.yaml +++ b/propbox.yaml @@ -3,56 +3,21 @@ substitutions: comment: "Propagator Controller" # Propbox Nodes - hostname_light: "propbox-light.${domain}" - hostname_fan: "propbox-fan.${domain}" + hostname_light: "${devicename}-light.${domain}" + hostname_fan: "${devicename}-fan.${domain}" # Overrides - bme280_script: "fan_control" - -esphome: - on_boot: - priority: -200 - then: - - lambda: |- - id(fan_state).execute(); - id(light_state).execute(); + bme280_script: "fan_control_power" packages: - base: !include packages/base.yaml - esp32: !include packages/esp32.yaml - bme280: !include packages/bme280.yaml - ds18b20: !include packages/ds18b20.yaml - fan: !include packages/fan.yaml - light: !include packages/light.yaml - -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(propbox_light).turn_on(); - } - - cron: ${schedule_grow_off} - then: - - lambda: |- - if (id(schedule).state == "Grow") { - id(propbox_light).turn_off(); - } - - cron: ${schedule_bloom_on} - then: - - lambda: |- - if (id(schedule).state == "Bloom") { - id(propbox_light).turn_on(); - } - - cron: ${schedule_bloom_off} - then: - - lambda: |- - if (id(schedule).state == "Bloom") { - id(propbox_light).turn_off(); - } - + base: !include packages/base.yaml + esp32: !include packages/esp32.yaml + time: !include packages/time.yaml + bme280: !include packages/bme280.yaml + ds18b20: !include packages/ds18b20.yaml + yyac32: !include packages/yyac3s.yaml + fan_settings: !include packages/fan_settings.yaml + fan_power: !include packages/fan_power.yaml + fan_script_power: !include packages/fan_script_power.yaml + light_power: !include packages/light_power.yaml + light_settings: !include packages/light_settings.yaml