Overhaul UI (mostly broken) ; add deep-sleep ; further improvements
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 24 KiB |
|
@ -155,7 +155,7 @@ void loop()
|
|||
while (display.nextPage());
|
||||
|
||||
// Hibernate the display to save power
|
||||
display.hibernate();
|
||||
//display.hibernate();
|
||||
|
||||
// Delay looping (deep sleep goes here in the future)
|
||||
delay(10*60*SECOND);
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
# Gitignore settings for ESPHome
|
||||
# This is an example and may include too much for your use-case.
|
||||
# You can modify this file to suit your needs.
|
||||
/.esphome/
|
||||
**/.pioenvs/
|
||||
**/.piolibdeps/
|
||||
**/lib/
|
||||
**/src/
|
||||
**/platformio.ini
|
||||
/secrets.yaml
|
|
@ -13,29 +13,18 @@ esphome.io based plant monitoring.
|
|||
| 8 | SparkFun Qwiic Adapter | https://www.sparkfun.com/products/14495 |
|
||||
| 1 | Qwiic Cable - 50mm | https://www.sparkfun.com/products/14426 |
|
||||
| 8 | Qwiic Cable - 500mm | https://www.sparkfun.com/products/14429 |
|
||||
| 1 | Waveshare 2.9" tri-color e-ink display | https://www.waveshare.com/product/modules/oleds-lcds/e-paper/2.9inch-e-paper-module-b.htm |
|
||||
| 1 | Waveshare 2.9" e-ink display | https://www.waveshare.com/product/modules/oleds-lcds/e-paper/2.9inch-e-paper-module.htm |
|
||||
| 1 | 18650 Battery Holder | https://www.sparkfun.com/products/12899 |
|
||||
| 15 | 4 pin 2.54mm pitch screw terminals | N/A |
|
||||
|
||||
## Software
|
||||
|
||||
- [https://github.com/esphome/esphome/blob/dev/esphome/components/bmp280/bmp280.h](https://github.com/esphome/esphome/blob/dev/esphome/components/bmp280/bmp280.h)
|
||||
- [https://learn.sparkfun.com/tutorials/esp32-thing-plus-hookup-guide](https://learn.sparkfun.com/tutorials/esp32-thing-plus-hookup-guide)
|
||||
- [https://learn.sparkfun.com/tutorials/qwiic-mux-hookup-guide](https://learn.sparkfun.com/tutorials/qwiic-mux-hookup-guide)
|
||||
- [http://docs.platformio.org/en/latest/boards/espressif32/esp32thing.html](http://docs.platformio.org/en/latest/boards/espressif32/esp32thing.html)
|
||||
- [https://esphome.io/components/esphome.html](https://esphome.io/components/esphome.html)
|
||||
- [https://esphome.io/components/time.html](https://esphome.io/components/time.html)
|
||||
- [https://esphome.io/devices/esp32.html](https://esphome.io/devices/esp32.html)
|
||||
- [https://esphome.io/components/wifi.html](https://esphome.io/components/wifi.html)
|
||||
- [https://esphome.io/components/ota.html](https://esphome.io/components/ota.html)
|
||||
- [https://esphome.io/components/deep_sleep.html](https://esphome.io/components/deep_sleep.html)
|
||||
- [https://esphome.io/components/sensor/wifi_signal.html](https://esphome.io/components/sensor/wifi_signal.html)
|
||||
- [https://esphome.io/components/sensor/uptime.html](https://esphome.io/components/sensor/uptime.html)
|
||||
- [https://esphome.io/components/display/waveshare_epaper.html](https://esphome.io/components/display/waveshare_epaper.html)
|
||||
- [https://esphome.io/components/sensor/dallas.html](https://esphome.io/components/sensor/dallas.html)
|
||||
- [https://esphome.io/components/sensor/custom.html](https://esphome.io/components/sensor/custom.html)
|
||||
- [https://esphome.io/components/i2c.html](https://esphome.io/components/i2c.html)
|
||||
- [https://esphome.io/components/sensor/index.html](https://esphome.io/components/sensor/index.html)
|
||||
- See deep sleep docs for a way to publish via mqtt to keep alive for updates
|
||||
- [https://community.home-assistant.io/t/hadashboard-publishing-an-mqtt-message/58614](https://community.home-assistant.io/t/hadashboard-publishing-an-mqtt-message/58614)
|
||||
- [https://community.home-assistant.io/t/mqtt-publish-in-scripts-yaml/29776](https://community.home-assistant.io/t/mqtt-publish-in-scripts-yaml/29776)
|
||||
- [https://thenounproject.com/term/update/452099/](https://thenounproject.com/term/update/452099/)
|
||||
- [https://thenounproject.com/term/download/356100/](https://thenounproject.com/term/download/356100/)
|
||||
- [https://github.com/ageir/chirp-rpi](https://github.com/ageir/chirp-rpi)
|
||||
- [https://github.com/Miceuz/i2c-moisture-sensor/blob/master/README.md](https://github.com/Miceuz/i2c-moisture-sensor/blob/master/README.md)
|
||||
- [https://github.com/Apollon77/I2CSoilMoistureSensor](https://github.com/Apollon77/I2CSoilMoistureSensor)
|
||||
|
@ -43,9 +32,14 @@ esphome.io based plant monitoring.
|
|||
## Future Hardware
|
||||
|
||||
- [https://www.adafruit.com/product/3931](https://www.adafruit.com/product/3931)
|
||||
- [https://www.adafruit.com/product/3258](https://www.adafruit.com/product/3258)
|
||||
- [https://www.adafruit.com/product/2142](https://www.adafruit.com/product/2142)
|
||||
- [https://www.adafruit.com/product/2135](https://www.adafruit.com/product/2135)
|
||||
- [https://www.adafruit.com/product/3931](https://www.adafruit.com/product/3931)
|
||||
- [https://www.adafruit.com/product/3258](https://www.adafruit.com/product/3258)
|
||||
- [https://www.tindie.com/products/miceuz/i2c-soil-moisture-sensor/](https://www.tindie.com/products/miceuz/i2c-soil-moisture-sensor/)
|
||||
|
||||
## Future Mini Build
|
||||
|
||||
- [https://www.adafruit.com/product/4172](https://www.adafruit.com/product/4172)
|
||||
- [https://www.adafruit.com/product/4026](https://www.adafruit.com/product/4026)
|
||||
- [https://www.sparkfun.com/products/11050](https://www.sparkfun.com/products/11050)
|
||||
- [https://www.adafruit.com/product/381](https://www.adafruit.com/product/381)
|
||||
- [https://www.sparkfun.com/products/10617](https://www.sparkfun.com/products/10617)
|
||||
- [https://www.sparkfun.com/products/12899](https://www.sparkfun.com/products/12899)
|
||||
- [https://smile.amazon.com/Polydoh-moldable-plastic-polymorph-plastimake/dp/B01N6QAFO5](https://smile.amazon.com/Polydoh-moldable-plastic-polymorph-plastimake/dp/B01N6QAFO5)
|
After Width: | Height: | Size: 9.3 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 5.3 KiB |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 8.7 KiB |
|
@ -0,0 +1,39 @@
|
|||
#include "esphome.h"
|
||||
#include <MAX1704X.h>
|
||||
|
||||
class MAX1704xSensor : public PollingComponent, public sensor::Sensor {
|
||||
private:
|
||||
MAX1704X _fuelGauge1 = MAX1704X(5);
|
||||
|
||||
public:
|
||||
sensor::Sensor *voltageSensor = new sensor::Sensor();
|
||||
sensor::Sensor *percentSensor = new sensor::Sensor();
|
||||
sensor::Sensor *isSleepingSensor = new sensor::Sensor();
|
||||
sensor::Sensor *alertIsActiveSensor = new sensor::Sensor();
|
||||
sensor::Sensor *getThresholdSensor = new sensor::Sensor();
|
||||
|
||||
MAX1704xSensor() : PollingComponent(5*60*1000) { }
|
||||
|
||||
void setup() override {
|
||||
_fuelGauge1.begin();
|
||||
_fuelGauge1.reset();
|
||||
_fuelGauge1.quickstart();
|
||||
}
|
||||
|
||||
void update() override {
|
||||
_fuelGauge1.wake();
|
||||
sleep(10);
|
||||
float voltage = _fuelGauge1.voltage();
|
||||
float percent = _fuelGauge1.percent();
|
||||
bool isSleeping = _fuelGauge1.isSleeping();
|
||||
bool alertIsActive = _fuelGauge1.alertIsActive();
|
||||
uint8_t getThreshold = _fuelGauge1.getThreshold();
|
||||
|
||||
voltageSensor->publish_state(voltage);
|
||||
percentSensor->publish_state(percent);
|
||||
isSleepingSensor->publish_state(isSleeping);
|
||||
alertIsActiveSensor->publish_state(alertIsActive);
|
||||
getThresholdSensor->publish_state(getThreshold);
|
||||
_fuelGauge1.sleep();
|
||||
}
|
||||
};
|
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 7.1 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 6.9 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 6.5 KiB |
After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 16 KiB |
|
@ -0,0 +1,259 @@
|
|||
# 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/
|
||||
|
||||
# Node Config
|
||||
esphome:
|
||||
#esphome_core_version:
|
||||
# local: "C:\\Users\\mcros\\src\\esphome\\esphome-core"
|
||||
name: !secret node_name
|
||||
platform: ESP32
|
||||
board: featheresp32
|
||||
platformio_options:
|
||||
upload_speed: 115200
|
||||
includes:
|
||||
- sht1x.h
|
||||
- max1704xsensor.h
|
||||
libraries:
|
||||
- SPI
|
||||
- Wire
|
||||
- "346"
|
||||
- "13"
|
||||
- "86"
|
||||
- "5812"
|
||||
|
||||
# WiFi config
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
domain: !secret node_domain
|
||||
|
||||
# Enable I2C (Qwiic and others)
|
||||
i2c:
|
||||
|
||||
# Enable SPI
|
||||
# CLK: D5
|
||||
# MOSI: D18
|
||||
spi:
|
||||
clk_pin: 5
|
||||
mosi_pin: 18
|
||||
|
||||
deep_sleep:
|
||||
run_duration: 12min
|
||||
sleep_duration: 48min
|
||||
wakeup_pin: 32
|
||||
|
||||
# Enable logging
|
||||
logger:
|
||||
|
||||
# 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: 'hass/status'
|
||||
payload: 'online'
|
||||
will_message:
|
||||
topic: 'hass/status'
|
||||
payload: 'offline'
|
||||
|
||||
# 2.9" Waveshare 3-color (red) 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
|
||||
cs_pin: 27
|
||||
dc_pin: 15
|
||||
busy_pin: 21
|
||||
reset_pin: 14
|
||||
model: 2.90in
|
||||
rotation: 90
|
||||
update_interval: 30s
|
||||
lambda: |-
|
||||
// Setup / Clear
|
||||
it.powerOn();
|
||||
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));
|
||||
}
|
||||
if (id(Battery_Level).state > 50) {
|
||||
it.image(0, 0, id(battery_50));
|
||||
}
|
||||
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(37,0, id(alert_filled));
|
||||
}
|
||||
else {
|
||||
it.printf(37, 0, id(deja_vu_mono_bold_8), "%.1f%%", id(Battery_Level).state);
|
||||
}
|
||||
// WiFi
|
||||
it.image(148, 0, id(wifi_icon));
|
||||
it.printf(185, 0, id(deja_vu_mono_bold_8), "%.1fdB", id(sensor_wifi_signal).state);
|
||||
// Temperature
|
||||
it.image(37, 0, id(thermometer));
|
||||
it.printf(37,37, id(deja_vu_mono_bold_8), "%.1f°F", id(Temperature_F).state);
|
||||
// Humidity
|
||||
it.image(148,37, id(humidity));
|
||||
it.printf(185,37, id(deja_vu_mono_bold_8), "%.1f%%", id(Humidity).state);
|
||||
// Plants
|
||||
it.image(0, 96, id(cat_grass));
|
||||
it.image(37, 96, id(tarragon));
|
||||
it.image(74, 96, id(cat_nip));
|
||||
it.image(111, 96, id(christmas_cactus));
|
||||
it.image(148, 96, id(inverted_cat_grass));
|
||||
it.image(185, 96, id(inverted_tarragon));
|
||||
it.image(222, 96, id(inverted_catnip));
|
||||
it.image(259, 96, id(inverted_christmas_cactus));
|
||||
// Sleep to conserve power
|
||||
//it.powerOff();
|
||||
|
||||
|
||||
font:
|
||||
- file: "DejaVuSansMono-Bold.ttf"
|
||||
id: deja_vu_mono_bold_8
|
||||
size: 8
|
||||
|
||||
image:
|
||||
- file: noun_Alert_2145614.png # empty
|
||||
id: alert_empty
|
||||
resize: 32x32
|
||||
- file: noun_Alert_2490416.png # filled
|
||||
id: alert_filled
|
||||
resize: 32x32
|
||||
- file: noun_battery indicator_1601217.png # battery 75%
|
||||
id: battery_75
|
||||
resize: 32x32
|
||||
- file: noun_battery level_1601219.png # battery 50%
|
||||
id: battery_50
|
||||
resize: 32x32
|
||||
- file: noun_Cactus_1197535.png # christmas cactus
|
||||
id: christmas_cactus
|
||||
resize: 32x32
|
||||
- file: noun_empty battery_1601215.png # battery 25%
|
||||
id: battery_25
|
||||
resize: 32x32
|
||||
- file: noun_empty battery_1601218.png # battery 0%
|
||||
id: battery_0
|
||||
resize: 32x32
|
||||
- file: noun_Full Battery_1601214.png # battery 100%
|
||||
id: battery_100
|
||||
resize: 32x32
|
||||
- file: noun_grass_355100.png # cat grass
|
||||
id: cat_grass
|
||||
resize: 32x32
|
||||
- file: noun_humidity_1762738.png # temp + humidity
|
||||
id: temp_humidity
|
||||
resize: 32x32
|
||||
- file: noun_humidity_2280622.png # humidity
|
||||
id: humidity
|
||||
resize: 32x32
|
||||
- file: noun_leaf_1153077.png # catnip
|
||||
id: cat_nip
|
||||
resize: 32x32
|
||||
- file: noun_Tarragon_499800.png # tarragon
|
||||
id: tarragon
|
||||
resize: 32x32
|
||||
- file: noun_Thermometer_217722.png # thermometer
|
||||
id: thermometer
|
||||
resize: 32x32
|
||||
- file: noun_wifi_2201334.png # wifi
|
||||
id: wifi_icon
|
||||
resize: 32x32
|
||||
- file: inverted_noun_Tarragon_499800.png # inverted tarragon
|
||||
id: inverted_tarragon
|
||||
resize: 32x32
|
||||
- file: inverted_noun_leaf_1153077.png # inverted catnip
|
||||
id: inverted_catnip
|
||||
resize: 32x32
|
||||
- file: inverted_noun_grass_355100.png # inverted cat grass
|
||||
id: inverted_cat_grass
|
||||
resize: 32x32
|
||||
- file: inverted_noun_empty battery_1601218.png # inverted battery_0
|
||||
id: inverted_battery_0
|
||||
resize: 32x32
|
||||
- file: inverted_noun_empty battery_1601215.png # inverted battery_25
|
||||
id: inverted_battery_25
|
||||
resize: 32x32
|
||||
- file: inverted_noun_Cactus_1197535.png # inverted christmas cactus
|
||||
id: inverted_christmas_cactus
|
||||
resize: 32x32
|
||||
|
||||
binary_sensor:
|
||||
- platform: status
|
||||
name: "Status"
|
||||
|
||||
sensor:
|
||||
- platform: wifi_signal
|
||||
id: sensor_wifi_signal
|
||||
name: "WiFi_Signal"
|
||||
update_interval: 60s
|
||||
unit_of_measurement: "dB"
|
||||
accuracy_decimals: 1
|
||||
- platform: uptime
|
||||
name: Uptime
|
||||
- platform: custom
|
||||
lambda: |-
|
||||
auto sht1x = new SHT1xSensor();
|
||||
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
|
||||
- name: "Temperature_F"
|
||||
id: Temperature_F
|
||||
unit_of_measurement: "°F"
|
||||
accuracy_decimals: 1
|
||||
- name: "Humidity"
|
||||
id: Humidity
|
||||
unit_of_measurement: "%"
|
||||
accuracy_decimals: 1
|
||||
- platform: custom
|
||||
lambda: |-
|
||||
auto max1704x = new MAX1704xSensor();
|
||||
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
|
||||
- name: "Battery_Level"
|
||||
id: Battery_Level
|
||||
unit_of_measurement: "%"
|
||||
accuracy_decimals: 1
|
||||
- name: "Battery_Sleeping"
|
||||
id: Battery_Sleeping
|
||||
- name: "Battery_Alert"
|
||||
id: Battery_Alert
|
||||
- name: "Battery_Threshold"
|
||||
id: Battery_Threshold
|
||||
accuracy_decimals: 0
|
|
@ -0,0 +1,6 @@
|
|||
nvs, data, nvs, 0x009000, 0x005000,
|
||||
otadata, data, ota, 0x00e000, 0x002000,
|
||||
app0, app, ota_0, 0x010000, 0x190000,
|
||||
app1, app, ota_1, 0x200000, 0x190000,
|
||||
eeprom, data, 0x99, 0x390000, 0x001000,
|
||||
spiffs, data, spiffs, 0x391000, 0x00F000
|
|
|
@ -0,0 +1,3 @@
|
|||
src/
|
||||
.pioenvs/
|
||||
partitions.csv
|
|
@ -0,0 +1,18 @@
|
|||
# Node
|
||||
node_name: node_name
|
||||
node_domain: .domain.tld
|
||||
|
||||
# WiFi
|
||||
wifi_ssid: "essid"
|
||||
wifi_password: "psk"
|
||||
|
||||
# Home Assistant API
|
||||
api_password: 'abadpassword'
|
||||
|
||||
# OTA
|
||||
ota_password: 'abadpassword'
|
||||
|
||||
# MQTT CLIENT
|
||||
mqtt_client_broker: 10.0.0.2
|
||||
mqtt_client_username: livingroom
|
||||
mqtt_client_password: MyMQTTPassword
|
|
@ -0,0 +1,34 @@
|
|||
// Adafruit temp/humidity sensor
|
||||
// We are using the SHT10
|
||||
// Humid accuracy +/- 5%
|
||||
// Steady accuracy between 10-80
|
||||
// example at 10/90 +/- 6%, 0/100 +/- 7.5%
|
||||
|
||||
#include "esphome.h"
|
||||
#include <SHT1x.h>
|
||||
|
||||
//sht1xDataPin A5 / 4
|
||||
//sht1xClockPin A1 / 25
|
||||
SHT1x sht1x(4, 25);
|
||||
|
||||
class SHT1xSensor : public PollingComponent, public sensor::Sensor {
|
||||
public:
|
||||
sensor::Sensor *temp_c_sensor = new sensor::Sensor();
|
||||
sensor::Sensor *temp_f_sensor = new sensor::Sensor();
|
||||
sensor::Sensor *humidity_sensor = new sensor::Sensor();
|
||||
|
||||
SHT1xSensor() : PollingComponent(5*60*1000) { }
|
||||
|
||||
void setup() override {
|
||||
}
|
||||
|
||||
void update() override {
|
||||
float temp_c = sht1x.readTemperatureC();
|
||||
float temp_f = sht1x.readTemperatureF();
|
||||
float humidity = sht1x.readHumidity();
|
||||
|
||||
temp_c_sensor->publish_state(temp_c);
|
||||
temp_f_sensor->publish_state(temp_f);
|
||||
humidity_sensor->publish_state(humidity);
|
||||
}
|
||||
};
|