diff --git a/.gitignore b/.gitignore index 4e4bfb3e21aab785c81430ccf1a28fec2392890b..a3f580867229530c26bdce4a9ac672b9ab249a9b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ /.esphome/ **/secrets.yaml /testbox.yaml +/*.code-workspace diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1053d71b5d9e238db648a337326b7e3baa7c275d..e1f69e964d0d9a585a75379d856f1ace8150d1c5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,25 +1,40 @@ stages: - validate + - build - deploy image: - name: esphome/esphome:2022.11.3 + name: esphome/esphome:2023.9.3 entrypoint: [""] validate_configs: stage: validate - before_script: - - cat "${SECRETS_YAML}" > "packages/secrets.yaml" script: + - cat ${SECRETS_YAML} > packages/secrets.yaml - for yml in *.yaml; do esphome config ${yml} >/dev/null; done + artifacts: + expire_in: 1 hour + paths: + - packages/secrets.yaml + tags: + - docker + +build_configs: + stage: build + before_script: + - mkdir build + script: + - for yml in *.yaml; do esphome config --show-secrets ${yml} > build/${yml}; done + artifacts: + expire_in: 1 hour + paths: + - build/*.yaml tags: - docker deploy_configs: stage: deploy - before_script: - - cat "${SECRETS_YAML}" > "packages/secrets.yaml" script: - - cp -r *.yaml packages include /srv/esphome/groovy-industries + - cp -rv build/*.yaml /srv/esphome/groovy-industries/ tags: - shell diff --git a/README.md b/README.md index 7f32052ab01d759c4a803be398770728f9fa0bb7..e326750db41533bfc8ee81221035d95109ee16cd 100644 --- a/README.md +++ b/README.md @@ -4,17 +4,25 @@ Home Grow(n) Monitoring ## Components -* propbox: ESP32 Propagator Controller - * BME280 Temperature and Humidity Sensor (3.3V, I2C) - * Dallas DS18B20 Temperature Sensor - * YYAC-3S Triac for Fan Control (5V, PWM) -* propbox-(light|fan): Nous A1T Smart Plug for Light & Fan Power Usage Monitoring -* growbox: ESP32 Grow Tent Monitor - * Yieryi 3178 EC/pH Monitor (RS485 via XY-485 board) +* growbox: ESP32-S3 Grow Tent Monitor + * 230V to 5V/2A Power Supply + * Adafruit LTC4311 I2C Extender (3,3V) * BME280 Temperature and Humidity Sensor (3.3V, I2C) * SCD40 CO2 Sensor (5V, I2C) * MLX90614-DCI IR Temperature Sensor (3.3V, I2C) * GP8403 0-10V DAC for Fan & LED Control (5V, I2C) + * DFR0553 ADS1115 ADC for EC & pH Sensors (5V, I2C) + * DFR0300 Analog Electrical Conductivity Sensor V2 (K=1) + * SEN0161-V2 Analog pH meter V2 + * DFR0504 Analog Signal Isolator (5V) [min.1 for EC, better 2 for EC and pH] + * STS35 Temperature Sensor (Waterproof Probe version, 3,3V, I2C) [seems to be not available anymore, try SHT35] + +* propbox: ESP32 Propagator Controller + * BME280 Temperature and Humidity Sensor (3.3V, I2C) + * Dallas DS18B20 Temperature Sensor + * YYAC-3S Triac for Fan Control (5V, PWM) + +* (growbox|propbox)-(light|fan): Nous A1T Smart Plug for Light & Fan Power Usage Monitoring ## Configuration Copy `packages/secrets.yaml.dist` to `packages/secrets.yaml` and adjust to your preferences. diff --git a/growbox.yaml b/growbox.yaml index fda0e21b156e9db932f3273c2166cc94b248630d..be6d0211961e5646bb4e4617209a1bcd1626720e 100644 --- a/growbox.yaml +++ b/growbox.yaml @@ -11,7 +11,7 @@ substitutions: packages: base: !include packages/base.yaml - esp32: !include packages/esp32.yaml + esp32: !include packages/esp32s3.yaml time: !include packages/time_schedule.yaml bme280: !include packages/bme280.yaml scd40: !include packages/scd40.yaml diff --git a/include/gp8403.h b/include/gp8403.h deleted file mode 100644 index 32a2e26f9b24294d779fb86cadd6c7e0438df078..0000000000000000000000000000000000000000 --- a/include/gp8403.h +++ /dev/null @@ -1,36 +0,0 @@ -#include "esphome.h" -#include "DFRobot_GP8403.h" - -class GP8403 : public Component, public FloatOutput { - public: - - DFRobot_GP8403 dac; - int channel; - float factor; - - GP8403(int c, float f = 1.0) { - channel = c; - factor = f; - } - - float get_setup_priority() const override { return esphome::setup_priority::BUS; } - - void setup() override { - while(dac.begin()!=0){ - ESP_LOGD("gp8403", "Initializing GP8403..."); - delay(1000); - } - ESP_LOGD("gp8403", "GP8403 Initialized!"); - dac.setDACOutRange(dac.eOutputRange10V); - } - - void write_state(float state) override { - ESP_LOGV("gp8403", "Received state %f", state); - // state is the percentage this output should be on, from 0.0 to 1.0 - // we need to convert it to millivolts (0-10000 for 0-10V) - int millivolts = (float)state * 10000; - dac.setDACOutVoltage(millivolts * factor, channel); - dac.store(); - ESP_LOGD("gp8403", "Channel %d set to %.2fV (%dmV, %g%%)", channel, millivolts/1000.0, millivolts, state*100.0); - } -}; diff --git a/include/mlx90614.h b/include/mlx90614.h deleted file mode 100644 index a1467dc11f5912c2da1342f3ebfb521122bebd46..0000000000000000000000000000000000000000 --- a/include/mlx90614.h +++ /dev/null @@ -1,28 +0,0 @@ -#include "esphome.h" -#include "Adafruit_MLX90614.h" - -class MLX90614 : public PollingComponent { - public: - - Adafruit_MLX90614 mlx90614 = Adafruit_MLX90614(); - Sensor *ambient_temperature = new Sensor(); - Sensor *object_temperature = new Sensor(); - - MLX90614( uint32_t update_interval ) : PollingComponent(update_interval) {} - - void setup() override { - mlx90614.begin(); - } - - void update() override { - float amb_temperature = 0.0; - amb_temperature = mlx90614.readAmbientTempC(); // reading twice seemed to eliminate intermittent invalid data reads (shows as 1037.5 C) - amb_temperature = mlx90614.readAmbientTempC(); - ambient_temperature->publish_state(amb_temperature); - - float obj_temperature = 0.0; - obj_temperature = mlx90614.readObjectTempC(); // only had invalid reads for ambient teperature but taking two readings of object temperature as well fwiw - obj_temperature = mlx90614.readObjectTempC(); - object_temperature->publish_state(obj_temperature); - } -}; diff --git a/include/yieryi_3178.h b/include/yieryi_3178.h deleted file mode 100644 index edf7d19065684f00fb19f2e1c8df1393358865e6..0000000000000000000000000000000000000000 --- a/include/yieryi_3178.h +++ /dev/null @@ -1,74 +0,0 @@ -#include "esphome.h" -#include "esphome/core/helpers.h" - -class Yieryi3178 : public UARTDevice, public PollingComponent { - public: - - Sensor *ec = new Sensor(); - Sensor *ph = new Sensor(); - Sensor *rh = new Sensor(); - Sensor *temp = new Sensor(); - Sensor *bat = new Sensor(); - - Yieryi3178(UARTComponent *parent, uint32_t update_interval) : UARTDevice(parent), PollingComponent(update_interval) {} - - std::vector<uint8_t> bytes; - byte request[8] = { 0x01, 0x03, 0x00, 0x00, 0x00, 0x04, 0x44, 0x09 }; - - typedef union { - unsigned char Byte[2]; - uint16_t UInt16; - } TwoByte; - - void update() override { - write_array(request, sizeof(request)); - flush(); - delay(10); - - while(available() > 0) { - bytes.push_back(read()); - - if(bytes.size() < 16) - continue; - - if(bytes.size() == 16) { - ESP_LOGVV("yieryi3178", "Bytes received: %s", format_hex_pretty(bytes).c_str()); - - TwoByte data_ec; - data_ec.Byte[0] = bytes[5]; - data_ec.Byte[1] = bytes[4]; - ec->publish_state(data_ec.UInt16 * 0.001); - ESP_LOGV("yieryi3178", "EC: %.3f", data_ec.UInt16 * 0.001); - - TwoByte data_ph; - data_ph.Byte[0] = bytes[7]; - data_ph.Byte[1] = bytes[6]; - ph->publish_state(data_ph.UInt16 * 0.01); - ESP_LOGV("yieryi3178", "pH: %.2f", data_ph.UInt16 * 0.01); - - TwoByte data_rh; - data_rh.Byte[0] = bytes[9]; - data_rh.Byte[1] = bytes[8]; - rh->publish_state(data_rh.UInt16); - ESP_LOGV("yieryi3178", "RH: %i", data_rh.UInt16); - - TwoByte data_temp; - data_temp.Byte[0] = bytes[11]; - data_temp.Byte[1] = bytes[10]; - temp->publish_state(data_temp.UInt16 * 0.1); - ESP_LOGV("yieryi3178", "Temp: %.1f", data_temp.UInt16 * 0.1); - - TwoByte data_bat; - data_bat.Byte[0] = bytes[13]; - data_bat.Byte[1] = bytes[12]; - bat->publish_state(data_bat.UInt16 / 100 / 1.5); - ESP_LOGV("yieryi3178", "Bat: %.1f", data_bat.UInt16 / 100 / 1.5); - - bytes.clear(); - - while(available() > 0) - read(); - } - } - } -}; \ No newline at end of file diff --git a/packages/base.yaml b/packages/base.yaml index 71172bcd393d8b7851411f41da88e18647b6b0e0..24a11024e5e7502a6f7263ffe6016fad2d39c4d4 100644 --- a/packages/base.yaml +++ b/packages/base.yaml @@ -3,7 +3,7 @@ esphome: comment: $comment project: name: "groovy.industries" - version: "1.0" + version: "2.0" on_boot: priority: -100 then: @@ -16,7 +16,7 @@ substitutions: fan_script: "dummy" preferences: - flash_write_interval: 5s + flash_write_interval: 15s logger: # level: INFO @@ -31,8 +31,9 @@ ota: wifi: ssid: !secret wifi_ssid password: !secret wifi_password - #fast_connect: on + fast_connect: on reboot_timeout: 1min + domain: .${domain} use_address: ${devicename}.${domain} web_server: diff --git a/packages/ec.yaml b/packages/ec.yaml index 6490c10cd615ccd35f733e1ed87fa5b94968696d..c5b740e69ec4c620d04ccc253de787f2b970faaf 100644 --- a/packages/ec.yaml +++ b/packages/ec.yaml @@ -26,7 +26,7 @@ sensor: # update_interval: 5s # lambda: !lambda return id(ec_k); - platform: template - name: "EC:" + name: "EC" id: ec unit_of_measurement: "mS" accuracy_decimals: 3 diff --git a/packages/esp32.yaml b/packages/esp32.yaml index c6c105d392fe787f275f4b0c9be17f102284cd4b..c0f6e298c818d03b5fc3806b31c21e8002e31b61 100644 --- a/packages/esp32.yaml +++ b/packages/esp32.yaml @@ -1,5 +1,9 @@ esp32: board: esp32dev + framework: + type: arduino + version: latest + platform_version: 6.4.0 i2c: sda: 21 diff --git a/packages/esp32s3.yaml b/packages/esp32s3.yaml new file mode 100644 index 0000000000000000000000000000000000000000..4923f99b0759136af5a003c36da77c11915b8b8b --- /dev/null +++ b/packages/esp32s3.yaml @@ -0,0 +1,28 @@ +esp32: + board: seeed_xiao_esp32s3 + variant: esp32s3 + framework: + type: arduino + version: latest + platform_version: 6.4.0 + +esphome: + platformio_options: + board_build.flash_mode: dio + +psram: + mode: octal + speed: 80MHz + +status_led: + pin: + number: GPIO21 + inverted: True + +i2c: + sda: 5 + scl: 6 + frequency: 10khz + +wifi: + power_save_mode: none diff --git a/packages/fan_power.yaml b/packages/fan_power.yaml index 83d0d84ca688b7a50009dbca9596bf963a910563..24d00f0e856f1d5c21ce16ec7d8999cabcf38bb6 100644 --- a/packages/fan_power.yaml +++ b/packages/fan_power.yaml @@ -2,6 +2,8 @@ esphome: on_boot: priority: -200 then: + - wait_until: + wifi.connected: - lambda: |- id(fan_power_state).execute(); @@ -15,25 +17,17 @@ switch: 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(); + then: + - http_request.get: + url: "http://${hostname_fan}/switch/power" + on_response: + then: + - lambda: |- + json::parse_json(id(http_request_data).get_string(), [](JsonObject root) { + id(power_fan).publish_state(root["value"]); + }); prometheus: relabel: diff --git a/packages/gp8403.yaml b/packages/gp8403.yaml index ba46c84514ba9542a3ba3ae98c44aee190fc6c6b..d6a5e0ca590716af88bf6f8c7bb23675404d058c 100644 --- a/packages/gp8403.yaml +++ b/packages/gp8403.yaml @@ -1,39 +1,33 @@ -esphome: - includes: - - include/gp8403.h - libraries: - - Wire - - dfrobot/DFRobot_GP8403@^1.0.0 +gp8403: + id: dac_10v + voltage: 10V output: -- platform: custom - type: float - lambda: |- - auto gp8403_ch0 = new GP8403(0, 0.919); - auto gp8403_ch1 = new GP8403(1, 0.919); - App.register_component(gp8403_ch0); - App.register_component(gp8403_ch1); - return {gp8403_ch0, gp8403_ch1}; - outputs: - - id: gp8403_ch0 - min_power: 0.10 - max_power: 1.0 - zero_means_zero: true - - id: gp8403_ch1 - min_power: 0.10 - max_power: 1.0 - zero_means_zero: true + - platform: gp8403 + id: gp8403_ch0 + gp8403_id: dac_10v + channel: 0 + min_power: 0.10 + max_power: 1.0 + zero_means_zero: true + - platform: gp8403 + id: gp8403_ch1 + gp8403_id: dac_10v + channel: 1 + min_power: 0.10 + max_power: 1.0 + zero_means_zero: true fan: - platform: speed output: gp8403_ch0 id: fan_speed - name: "Fan: Speed" + name: "Fan" light: - platform: monochromatic id: light_level - name: "Light: Level" + name: "Light" output: gp8403_ch1 default_transition_length: 0s gamma_correct: 0 diff --git a/packages/light_power.yaml b/packages/light_power.yaml index 93066fa3bac0c673d809abf167fcc22d65725473..62db1d456a1e213ab5b2389ebe9c8d270c04826b 100644 --- a/packages/light_power.yaml +++ b/packages/light_power.yaml @@ -2,6 +2,8 @@ esphome: on_boot: priority: -200 then: + - wait_until: + wifi.connected: - lambda: |- id(light_power_state).execute(); @@ -15,25 +17,17 @@ switch: turn_off_action: - http_request.post: http://${hostname_light}/switch/power/turn_off -interval: - - interval: 1min - then: - - script.execute: light_power_state - script: - id: light_power_state then: - - lambda: |- - HTTPClient http; - bool state = false; - http.begin("http://${hostname_light}/switch/power"); - if (http.GET() == 200) { - DynamicJsonDocument doc(200); - deserializeJson(doc, http.getString()); - state = (doc["state"] == "ON") ? true : false; - } - id(power_light).publish_state(state); - http.end(); + - http_request.get: + url: "http://${hostname_light}/switch/power" + on_response: + then: + - lambda: |- + json::parse_json(id(http_request_data).get_string(), [](JsonObject root) { + id(power_light).publish_state(root["value"]); + }); prometheus: relabel: diff --git a/packages/mlx90614.yaml b/packages/mlx90614.yaml index 8feccb9454850f963fc9d903a65045aa46d5dadb..dd008f6d06601452466374172d445ab15480c367 100644 --- a/packages/mlx90614.yaml +++ b/packages/mlx90614.yaml @@ -1,29 +1,18 @@ -esphome: - includes: - - include/mlx90614.h - libraries: - - Wire - - SPI - - https://github.com/adafruit/Adafruit_BusIO @ 1.14.1 - - https://github.com/adafruit/Adafruit-MLX90614-Library @ 2.1.3 - sensor: -- platform: custom - lambda: |- - auto mlx90614 = new MLX90614(5000); - App.register_component(mlx90614); - return {mlx90614->ambient_temperature, mlx90614->object_temperature}; - sensors: - - id: mlx90614_temperature_ambient - name: "IR: Ambient Temperature" - unit_of_measurement: °C - accuracy_decimals: 2 - <<: !include filter.yaml - - id: mlx90614_temperature_object - name: "IR: Object Temperature" - unit_of_measurement: °C - accuracy_decimals: 2 - <<: !include filter.yaml + - platform: mlx90614 + update_interval: 5s + ambient: + id: mlx90614_temperature_ambient + name: "IR: Ambient Temperature" + unit_of_measurement: °C + accuracy_decimals: 2 + <<: !include filter.yaml + object: + id: mlx90614_temperature_object + name: "IR: Object Temperature" + unit_of_measurement: °C + accuracy_decimals: 2 + <<: !include filter.yaml prometheus: relabel: diff --git a/packages/ph.yaml b/packages/ph.yaml index ffd1f3cc1fcb55fa849959d3b76d26a74c2f2200..84a982dbc2c6dbc95c7ca299ca27a9a0f0626819 100644 --- a/packages/ph.yaml +++ b/packages/ph.yaml @@ -56,7 +56,7 @@ sensor: # update_interval: 5s # lambda: !lambda return id(ph918_raw); - platform: template - name: "pH:" + name: "pH" id: ph unit_of_measurement: "pH" accuracy_decimals: 2 diff --git a/packages/time_schedule.yaml b/packages/time_schedule.yaml index 82d0a3d81fe955ec40ad8f8578e37f1e93eca16b..6f287d10fc0ffd9df21751a09079b2a3308e5644 100644 --- a/packages/time_schedule.yaml +++ b/packages/time_schedule.yaml @@ -28,4 +28,11 @@ time: if (id(schedule).state == "Bloom") { id(power_light).turn_off(); } - + - seconds: 0 + minutes: /1 + then: + - script.execute: light_power_state + - seconds: 0 + minutes: /1 + then: + - script.execute: fan_power_state diff --git a/packages/yieryi3178.yaml b/packages/yieryi3178.yaml deleted file mode 100644 index fb96446be1da4255103653d1a28ed49dddd23d35..0000000000000000000000000000000000000000 --- a/packages/yieryi3178.yaml +++ /dev/null @@ -1,55 +0,0 @@ -esphome: - includes: - - include/yieryi_3178.h - -uart: - id: uart_rs485 - tx_pin: 19 # TXD - rx_pin: 18 # RXD - baud_rate: 9600 - -sensor: -- platform: custom - lambda: |- - auto yieryi3178 = new Yieryi3178(id(uart_rs485), 5000); - App.register_component(yieryi3178); - return {yieryi3178->ec, yieryi3178->ph, yieryi3178->rh, yieryi3178->temp, yieryi3178->bat}; - sensors: - - id: yieryi3178_ec - name: "Water: EC" - unit_of_measurement: "mS" - accuracy_decimals: 3 - - id: yieryi3178_ph - name: "Water: pH" - unit_of_measurement: "pH" - accuracy_decimals: 2 - - id: yieryi3178_humidity - name: "Water: Humidity" - unit_of_measurement: "%" - accuracy_decimals: 0 - - id: yieryi3178_temperature - name: "Water: Temperature" - unit_of_measurement: "°C" - accuracy_decimals: 1 - - id: yieryi3178_battery - name: "Water: Battery Level" - unit_of_measurement: "%" - accuracy_decimals: 1 - -prometheus: - relabel: - yieryi3178_ec: - id: ec - name: "EC" - yieryi3178_ph: - id: ph - name: "pH" - yieryi3178_humidity: - id: humidity_water - name: "Humidity (EC/pH Monitor)" - yieryi3178_temperature: - id: temperature_water - name: "Water Temperature" - yieryi3178_battery: - id: battery_water - name: "Battery Level"