# Further reference # https://platformio.org/lib # SHT1x - 86 - https://platformio.org/lib/show/86/SHT1x # MAX1704X - 5812 - https://platformio.org/lib/show/5812/MAX1704X/ # GxEPD2 - 5869 - https://platformio.org/lib/show/5869/GxEPD2 # AsyncMqttClient - 346 - https://platformio.org/lib/show/346/AsyncMqttClient/ # Adafruit GFX Library - 13 - https://platformio.org/lib/show/13/Adafruit GFX Library/ # SparkFun VEML6075 Library - 5452 - https://platformio.org/lib/show/5452/SparkFun%20VEML6075%20Arduino%20Library # Adafruit Seesaw - 1890 - https://platformio.org/lib/show/1890/Adafruit%20seesaw%20Library # Node Config esphome: name: !secret node_name platform: ESP32 board: featheresp32 platformio_options: upload_speed: 115200 includes: - sht1x.h - max1704xsensor.h - veml6075.h - plants.h libraries: - SPI - Wire - "346" - "86" - "5812" - "5452" - "1890" on_boot: - priority: 90.0 # 100 is highest where early init happens, 50.0 is where sensors come up then: - lambda: |- id(early_boot) = true; pinMode(13, OUTPUT); digitalWrite(13, HIGH); delay(100); - priority: -100 then: - lambda: |- id(early_boot) = false; ESP_LOGD("on_boot: -10:", "Starting sensor updates"); ////////////////////////////////////////////////// ESP_LOGD("on_boot: -10:", "WiFi"); id(sensor_wifi_signal)->update(); ESP_LOGD("on_boot: -10:", "END WiFi"); ////////////////////////////////////////////////// //ESP_LOGD("on_boot: -10:", "UV"); //id(ptr_component_veml6075)->update(); //ESP_LOGD("on_boot: -10:", "END UV"); ////////////////////////////////////////////////// //ESP_LOGD("on_boot: -10:", "delay(500)"); delay(500); ESP_LOGD("on_boot: -10:", "END delay(500)"); ////////////////////////////////////////////////// ESP_LOGD("on_boot: -10:", "shtx1"); ((SHT1xSensor*)id(ptr_component_shtx1))->update(); ESP_LOGD("on_boot: -10:", "END shtx1"); ////////////////////////////////////////////////// ESP_LOGD("on_boot: -10:", "delay(500)"); delay(500); ESP_LOGD("on_boot: -10:", "END delay(500)"); ////////////////////////////////////////////////// ESP_LOGD("on_boot: -10:", "max1704x"); id(ptr_component_max1704x)->update(); ESP_LOGD("on_boot: -10:", "END max1704x"); ////////////////////////////////////////////////// ESP_LOGD("on_boot: -10:", "delay(500)"); delay(500); ESP_LOGD("on_boot: -10:", "END delay(500)"); ////////////////////////////////////////////////// ESP_LOGD("on_boot: -10:", "Plants"); id(ptr_component_plants)->update(); ESP_LOGD("on_boot: -10:", "END plants"); ////////////////////////////////////////////////// ESP_LOGD("on_boot: -10:", "delay(500)"); delay(500); ESP_LOGD("on_boot: -10:", "END delay(500)"); ////////////////////////////////////////////////// ESP_LOGD("on_boot: -10:", "Value sensor_wifi_signal: %.1f", id(sensor_wifi_signal).state); ESP_LOGD("on_boot: -10:", "Value Temperature_C: %.1f", id(Temperature_C).state); ESP_LOGD("on_boot: -10:", "Value Temperature_F: %.1f", id(Temperature_F).state); ESP_LOGD("on_boot: -10:", "Value Humidity: %.1f", id(Humidity).state); ESP_LOGD("on_boot: -10:", "Value uva: %.1f", id(uva).state); ESP_LOGD("on_boot: -10:", "Value uvb: %.1f", id(uvb).state); ESP_LOGD("on_boot: -10:", "Value uv_index: %.1f", id(uv_index).state); ESP_LOGD("on_boot: -10:", "Value Plant_1_Enabled: %f", id(Plant_1_Enabled).state); ESP_LOGD("on_boot: -10:", "Value Plant_2_Enabled: %f", id(Plant_2_Enabled).state); ESP_LOGD("on_boot: -10:", "Value Plant_3_Enabled: %f", id(Plant_3_Enabled).state); ESP_LOGD("on_boot: -10:", "Value Plant_4_Enabled: %f", id(Plant_4_Enabled).state); ESP_LOGD("on_boot: -10:", "Value Plant_5_Enabled: %f", id(Plant_5_Enabled).state); ESP_LOGD("on_boot: -10:", "Value Plant_6_Enabled: %f", id(Plant_6_Enabled).state); ESP_LOGD("on_boot: -10:", "Value Plant_7_Enabled: %f", id(Plant_7_Enabled).state); ESP_LOGD("on_boot: -10:", "Value Plant_8_Enabled: %f", id(Plant_8_Enabled).state); ESP_LOGD("on_boot: -10:", "Value Plant_1: %.1f", id(Plant_1).state); ESP_LOGD("on_boot: -10:", "Value Plant_2: %.1f", id(Plant_2).state); ESP_LOGD("on_boot: -10:", "Value Plant_3: %.1f", id(Plant_3).state); ESP_LOGD("on_boot: -10:", "Value Plant_4: %.1f", id(Plant_4).state); ESP_LOGD("on_boot: -10:", "Value Plant_5: %.1f", id(Plant_5).state); ESP_LOGD("on_boot: -10:", "Value Plant_6: %.1f", id(Plant_6).state); ESP_LOGD("on_boot: -10:", "Value Plant_7: %.1f", id(Plant_7).state); ESP_LOGD("on_boot: -10:", "Value Plant_8: %.1f", id(Plant_8).state); ESP_LOGD("on_boot: -10:", "Value Plant_1_Remote_Enabled: %f", id(Plant_1_Remote_Enabled).state); ESP_LOGD("on_boot: -10:", "Value Plant_2_Remote_Enabled: %f", id(Plant_2_Remote_Enabled).state); ESP_LOGD("on_boot: -10:", "Value Plant_3_Remote_Enabled: %f", id(Plant_3_Remote_Enabled).state); ESP_LOGD("on_boot: -10:", "Value Plant_4_Remote_Enabled: %f", id(Plant_4_Remote_Enabled).state); ESP_LOGD("on_boot: -10:", "Value Plant_5_Remote_Enabled: %f", id(Plant_5_Remote_Enabled).state); ESP_LOGD("on_boot: -10:", "Value Plant_6_Remote_Enabled: %f", id(Plant_6_Remote_Enabled).state); ESP_LOGD("on_boot: -10:", "Value Plant_7_Remote_Enabled: %f", id(Plant_7_Remote_Enabled).state); ESP_LOGD("on_boot: -10:", "Value Plant_8_Remote_Enabled: %f", id(Plant_8_Remote_Enabled).state); ESP_LOGD("on_boot: -10:", "Value Battery_Voltage: %.1f", id(Battery_Voltage).state); ESP_LOGD("on_boot: -10:", "Value Battery_Level: %.1f", id(Battery_Level).state); ESP_LOGD("on_boot: -10:", "Value Battery_Sleeping: %.1f", id(Battery_Sleeping).state); ESP_LOGD("on_boot: -10:", "Value Battery_Alert: %.1f", id(Battery_Alert).state); ESP_LOGD("on_boot: -10:", "Value Battery_Threshold: %.1f", id(Battery_Threshold).state); ////////////////////////////////////////////////// ESP_LOGD("on_boot: -10:", "Display"); id(display_main).clear(); id(display_main).update(); ESP_LOGD("on_boot: -10:", "END Display"); ////////////////////////////////////////////////// ESP_LOGD("on_boot: -10:", "END custom"); delay(500); // Go to deep sleep if NOT in OTA mode if (! id(ota_mode)) { id(deep_sleep_main)->begin_sleep(); } on_shutdown: then: - lambda: |- digitalWrite(13, LOW); # Basic status infos via blinky LED # https://esphome.io/components/status_led.html status_led: pin: number: 32 inverted: True # WiFi config wifi: ssid: !secret wifi_ssid password: !secret wifi_password domain: !secret node_domain power_save_mode: light # Enable I2C (Qwiic and others) i2c: # Enable SPI # CLK: D5 # MOSI: D18 spi: clk_pin: 5 mosi_pin: 18 deep_sleep: id: deep_sleep_main run_duration: 15min sleep_duration: 6h wakeup_pin_mode: INVERT_WAKEUP # stop caring and be judicious about tolerance of goofy pin modes # Enable logging logger: level: DEBUG # Flip to ERROR for production deployments baud_rate: 115200 # Disable UART logging # Enable Home Assistant API #api: # password: !secret api_password # OTA Config ota: password: !secret ota_password safe_mode: true # Web Server (DISABLE outside of testing) #web_server: # port: 80 # MQTT CLIENT mqtt: broker: !secret mqtt_client_broker port: 8883 username: !secret mqtt_client_username password: !secret mqtt_client_password birth_message: topic: 'ha/status' payload: 'online' will_message: topic: 'ha/status' payload: 'offline' globals: - id: ptr_component_shtx1 type: "SHT1xSensor*" restore_value: no - id: ptr_component_veml6075 type: "VEML6075Sensor*" restore_value: no - id: ptr_component_max1704x type: "MAX1704xSensor*" restore_value: no - id: ptr_component_plants type: "PlantsSensor*" restore_value: no - id: early_boot type: bool restore_value: no - id: ota_mode type: bool restore_value: no initial_value: "false" time: - platform: sntp id: sntp_time servers: 10.5.5.2 binary_sensor: - platform: status name: "Status" - platform: gpio name: "OTA Button" id: button_ota internal: true pin: number: A3 mode: INPUT_PULLDOWN on_release: then: - lambda: |- id(ota_mode) = true; - deep_sleep.prevent: deep_sleep_main sensor: - platform: wifi_signal id: sensor_wifi_signal name: "WiFi_Signal" update_interval: 3min unit_of_measurement: "dB" accuracy_decimals: 1 expire_after: 12h - platform: custom lambda: |- SHT1xSensor* sht1x = new SHT1xSensor(); id(ptr_component_shtx1) = sht1x; App.register_component(sht1x); return {sht1x->temp_c_sensor, sht1x->temp_f_sensor, sht1x->humidity_sensor}; sensors: - name: "Temperature_C" id: Temperature_C unit_of_measurement: "°C" accuracy_decimals: 1 expire_after: 12h - name: "Temperature_F" id: Temperature_F unit_of_measurement: "°F" accuracy_decimals: 1 expire_after: 12h - name: "Humidity" id: Humidity unit_of_measurement: "%" accuracy_decimals: 1 expire_after: 12h - platform: custom lambda: |- VEML6075Sensor* veml6075 = new VEML6075Sensor(); id(ptr_component_veml6075) = veml6075; App.register_component(veml6075); return {veml6075->uva_sensor, veml6075->uvb_sensor, veml6075->uv_index_sensor}; sensors: - name: "UVA" id: uva accuracy_decimals: 2 expire_after: 12h - name: "UVB" id: uvb accuracy_decimals: 2 expire_after: 12h - name: "UV Index" id: uv_index accuracy_decimals: 2 expire_after: 12h - platform: custom lambda: |- PlantsSensor* plants = new PlantsSensor(); id(ptr_component_plants) = plants; App.register_component(plants); return {plants->plant_1_enabled, plants->plant_2_enabled, plants->plant_3_enabled, plants->plant_4_enabled, plants->plant_5_enabled, plants->plant_6_enabled, plants->plant_7_enabled, plants->plant_7_enabled, plants->plant_1_sensor, plants->plant_2_sensor, plants->plant_3_sensor, plants->plant_4_sensor, plants->plant_5_sensor, plants->plant_6_sensor, plants->plant_7_sensor, plants->plant_8_sensor, plants->plant_1_remote_enabled, plants->plant_2_remote_enabled, plants->plant_3_remote_enabled, plants->plant_4_remote_enabled, plants->plant_5_remote_enabled, plants->plant_6_remote_enabled, plants->plant_7_remote_enabled, plants->plant_8_remote_enabled }; sensors: - name: "Plant 1 - Enabled" id: Plant_1_Enabled expire_after: 12h - name: "Plant 2 - Enabled" id: Plant_2_Enabled expire_after: 12h - name: "Plant 3 - Enabled" id: Plant_3_Enabled expire_after: 12h - name: "Plant 4 - Enabled" id: Plant_4_Enabled expire_after: 12h - name: "Plant 5 - Enabled" id: Plant_5_Enabled expire_after: 12h - name: "Plant 6 - Enabled" id: Plant_6_Enabled expire_after: 12h - name: "Plant 7 - Enabled" id: Plant_7_Enabled expire_after: 12h - name: "Plant 8 - Enabled" id: Plant_8_Enabled expire_after: 12h - name: "Plant 1" id: Plant_1 accuracy_decimals: 2 expire_after: 12h - name: "Plant 2" id: Plant_2 accuracy_decimals: 2 expire_after: 12h - name: "Plant 3" id: Plant_3 accuracy_decimals: 2 expire_after: 12h - name: "Plant 4" id: Plant_4 accuracy_decimals: 2 expire_after: 12h - name: "Plant 5" id: Plant_5 accuracy_decimals: 2 expire_after: 12h - name: "Plant 6" id: Plant_6 accuracy_decimals: 2 expire_after: 12h - name: "Plant 7" id: Plant_7 accuracy_decimals: 2 expire_after: 12h - name: "Plant 8" id: Plant_8 accuracy_decimals: 2 expire_after: 12h - name: "Plant 1 - Remote - Enabled" id: Plant_1_Remote_Enabled expire_after: 12h - name: "Plant 2 - Remote - Enabled" id: Plant_2_Remote_Enabled expire_after: 12h - name: "Plant 3 - Remote - Enabled" id: Plant_3_Remote_Enabled expire_after: 12h - name: "Plant 4 - Remote - Enabled" id: Plant_4_Remote_Enabled expire_after: 12h - name: "Plant 5 - Remote - Enabled" id: Plant_5_Remote_Enabled expire_after: 12h - name: "Plant 6 - Remote - Enabled" id: Plant_6_Remote_Enabled expire_after: 12h - name: "Plant 7 - Remote - Enabled" id: Plant_7_Remote_Enabled expire_after: 12h - name: "Plant 8 - Remote - Enabled" id: Plant_8_Remote_Enabled expire_after: 12h - platform: custom lambda: |- MAX1704xSensor* max1704x = new MAX1704xSensor(); id(ptr_component_max1704x) = max1704x; App.register_component(max1704x); return {max1704x->voltageSensor, max1704x->percentSensor, max1704x->isSleepingSensor, max1704x->alertIsActiveSensor, max1704x->getThresholdSensor}; sensors: - name: "Battery_Voltage" id: Battery_Voltage unit_of_measurement: "V" accuracy_decimals: 2 expire_after: 12h - name: "Battery_Level" id: Battery_Level unit_of_measurement: "%" accuracy_decimals: 1 expire_after: 12h - name: "Battery_Sleeping" id: Battery_Sleeping expire_after: 12h - name: "Battery_Alert" id: Battery_Alert expire_after: 12h - name: "Battery_Threshold" id: Battery_Threshold accuracy_decimals: 0 expire_after: 12h # 2.9" Waveshare e-ink setup # BUSY -> 21, RST -> 14, DC -> 15, CS -> 27, CLK -> SCK(5), DIN -> MOSI(18), GND -> GND, 3.3V -> 3.3V display: - platform: waveshare_epaper id: display_main cs_pin: 27 dc_pin: 15 busy_pin: 21 reset_pin: 14 model: 2.90in rotation: 90 update_interval: 1h lambda: |- if (id(early_boot)) { it.clear(); it.image(84, 0, id(rocket_ship)); } else { delay(60*1000); // Clear it.clear(); // Battery if (id(Battery_Level).state > 90) { it.image(0, 0, id(battery_100)); } else if (id(Battery_Level).state > 75) { it.image(0, 0, id(battery_75)); } else if (id(Battery_Level).state > 50) { it.image(0, 0, id(battery_50)); } else if (id(Battery_Level).state > 25) { it.image(0, 0, id(inverted_battery_25)); } else { it.image(0, 0, id(inverted_battery_0)); } if (id(Battery_Alert).state != 0) { it.image(32, 0, id(alert_filled)); } else { it.printf(32, 16, id(deja_vu_mono), "%.1f%%", id(Battery_Level).state); } // Temperature it.image(116, 0, id(thermometer)); // 148, 0 it.printf(153, 16, id(deja_vu_mono), "%.1f°F", id(Temperature_F).state); // OTA Mode if (id(ota_mode)) { it.image(259, 0, id(ota_mode_enabled)); } // Last update it.image(0, 32, id(last_sync_icon)); it.strftime(32, 39, id(deja_vu_mono), "%Y-%m-%d %H:%M", id(sntp_time).now()); // Plants //if (id(Plant_1_Remote_Enabled).state) { // it.image(0, 64, id(vase)); //} //else { // it.image(0, 64, id(disabled_vase)); //} if (id(Plant_2_Remote_Enabled).state) { it.image(37, 64, id(vase)); } else { it.image(37, 64, id(disabled_vase)); } if (id(Plant_3_Remote_Enabled).state) { it.image(74, 64, id(vase)); } else { it.image(74, 64, id(disabled_vase)); } if (id(Plant_4_Remote_Enabled).state) { it.image(111, 64, id(vase)); } else { it.image(111, 64, id(disabled_vase)); } if (id(Plant_5_Remote_Enabled).state) { it.image(148, 64, id(vase)); } else { it.image(148, 64, id(disabled_vase)); } if (id(Plant_6_Remote_Enabled).state) { it.image(185, 64, id(vase)); } else { it.image(185, 64, id(disabled_vase)); } if (id(Plant_7_Remote_Enabled).state) { it.image(222, 64, id(vase)); } else { it.image(222, 64, id(disabled_vase)); } if (id(Plant_8_Remote_Enabled).state) { it.image(259, 64, id(vase)); } else { it.image(259, 64, id(disabled_vase)); } if (id(Plant_1_Enabled).state) { if (id(Plant_1).state < 1.0) { it.image(0, 96, id(inverted_bamboo)); } else { it.image(0, 96, id(bamboo)); } } else { it.image(0, 96, id(disabled_tulip)); } if (id(Plant_2_Enabled).state) { if (id(Plant_2).state < 500.0) { it.image(37, 96, id(inverted_cat_nip)); } else { it.image(37, 96, id(cat_nip)); } } else { it.image(37, 96, id(disabled_tulip)); } if (id(Plant_3_Enabled).state) { it.image(74, 96, id(tulip)); } else { it.image(74, 96, id(disabled_tulip)); } if (id(Plant_4_Enabled).state) { it.image(111, 96, id(tulip)); } else { it.image(111, 96, id(disabled_tulip)); } if (id(Plant_5_Enabled).state) { it.image(148, 96, id(tulip)); } else { it.image(148, 96, id(disabled_tulip)); } if (id(Plant_6_Enabled).state) { it.image(185, 96, id(tulip)); } else { it.image(185, 96, id(disabled_tulip)); } if (id(Plant_7_Enabled).state) { it.image(222, 96, id(tulip)); } else { it.image(222, 96, id(disabled_tulip)); } if (id(Plant_8_Enabled).state) { it.image(259, 96, id(tulip)); } else { it.image(259, 96, id(disabled_tulip)); } } font: - file: "fonts/DejaVuSansMono.ttf" id: deja_vu_mono size: 18 image: - file: graphics/noun_Alert_2145614.png # empty id: alert_empty resize: 32x32 - file: graphics/noun_Alert_2490416.png # filled id: alert_filled resize: 32x32 - file: graphics/noun_battery indicator_1601217.png # battery 75% id: battery_75 resize: 32x32 - file: graphics/noun_battery level_1601219.png # battery 50% id: battery_50 resize: 32x32 - file: graphics/noun_Cactus_1197535.png # christmas cactus id: christmas_cactus resize: 32x32 - file: graphics/noun_empty battery_1601215.png # battery 25% id: battery_25 resize: 32x32 - file: graphics/noun_empty battery_1601218.png # battery 0% id: battery_0 resize: 32x32 - file: graphics/noun_Full Battery_1601214.png # battery 100% id: battery_100 resize: 32x32 - file: graphics/noun_grass_355100.png # cat grass id: cat_grass resize: 32x32 - file: graphics/noun_humidity_1762738.png # temp + humidity id: temp_humidity resize: 32x32 - file: graphics/noun_leaf_1153077.png # catnip id: cat_nip resize: 32x32 - file: graphics/noun_Tarragon_499800.png # tarragon id: tarragon resize: 32x32 - file: graphics/noun_Thermometer_217722.png # thermometer id: thermometer resize: 32x32 - file: graphics/noun_update_2346502.png # last sync id: last_sync_icon resize: 32x32 - file: graphics/inverted_noun_Tarragon_499800.png # inverted tarragon id: inverted_tarragon resize: 32x32 - file: graphics/inverted_noun_leaf_1153077.png # inverted catnip id: inverted_cat_nip resize: 32x32 - file: graphics/inverted_noun_grass_355100.png # inverted cat grass id: inverted_cat_grass resize: 32x32 - file: graphics/inverted_noun_empty battery_1601218.png # inverted battery_0 id: inverted_battery_0 resize: 32x32 - file: graphics/inverted_noun_empty battery_1601215.png # inverted battery_25 id: inverted_battery_25 resize: 32x32 - file: graphics/inverted_noun_Cactus_1197535.png # inverted christmas cactus id: inverted_christmas_cactus resize: 32x32 - file: graphics/noun_Tulip_2510353.png # tulip id: tulip resize: 32x32 - file: graphics/inverted_noun_Tulip_2510353.png # inverted tulip id: inverted_tulip resize: 32x32 - file: graphics/noun_poinsettia_1007994.png # poinsettia id: poinsettia resize: 32x32 - file: graphics/inverted_noun_poinsettia_1007994.png # inverted poinsettia id: inverted_poinsettia resize: 32x32 - file: graphics/inverted_noun_vase_206668.png # inverted vase id: inverted_vase resize: 32x32 - file: graphics/inverted_noun_Bamboo_254221.png # inverted bamboo id: inverted_bamboo resize: 32x32 - file: graphics/noun_Bamboo_254221.png # bamboo id: bamboo resize: 32x32 - file: graphics/noun_vase_206668.png # vase id: vase resize: 32x32 - file: graphics/disabled_noun_vase_206668.png # disabled vase id: disabled_vase resize: 32x32 - file: graphics/disabled_noun_Tulip_2510353.png # disabled tulip id: disabled_tulip resize: 32x32 - file: graphics/noun_Settings Download_1854756.png # ota mode enabled id: ota_mode_enabled resize: 32x32 - file: graphics/noun_startup_1946229.png # rocket ship / startup id: rocket_ship resize: 128x128