Open jlongman opened 2 years ago
It is "supported" by ESPhome, yes.... depending on what you want to do with it...?!
You can use the ePaper screen (with partial refresh), and the 5-way switch. Accessing the onboard (ESP8266) as a status light seemed to cause issues, so I don't include that.
The ADC can also be included to measure the voltage level of the battery. But be aware the voltage divider used isn't right for a lipo battery.
There's a lot of pins used on the ESP8266 which tend to interfere with the OTA process by some line going low (I think?!), so I also include the "Safe mode reboot" switch, which seems allows for 100% guarantee upload (weeks of troubleshooting and testing!).
Do you have a specific example you'd like to set the Badgy up with, I can post an example YAML config?
Here's two examples I have using Badgy and Home Assistant using ESPHome. The buttons aren't really used, but they could be to move between pages of content as an example.
@chunkysteveo you tagged a post with
esphome
here
Yeah, that example was also another version I had - before I updated it to the hourly/daily forecast one seen above. Those "weather" examples use a custom sensor within Home Assistant to format a bunch of other sensors into a simple text sensor that the Badgy can process and display.
Amazing! I’m interested in both of those, yes, and I also have a co2 monitor that I might do on its own in as- large-as-possible text. Getting the switches going might be interesting to flip between them, later, but as I have two of them I can start without it.
Let me put a 'hello world' config yaml file up here for you to start on, which should give you some good pointers and a good base... how OK are you with ESPHome and HA?
A ‘hello world’ would help a lot, thanks!
Okay with esphome, I’ve put some basic sonoff switches, a co2 meter together; and competent with HA, I’ve wrestled and won with templates, etc.
Not had any time to gather all my scripts and info together, but below is a quick and dirty "hello world" which should get you working as a proof of concept:
In HA, you will need weather.home (Met.no weather service), binary_sensor.door_sensor_back_door_contact (a binary sensor such as a door sensor), sensor.multisensor_garage_temperature (a temperature sensor of some sort), binary_sensor.multisensor_garage_motion (a motion sensor binary sensor such as a PIR sensor. This is to blank the screen if no one is present to save on the epaper life, comment out the if else statement if you want it to always be on), and you will need to download and add some fonts to the ESPHome directory (fonts/materialdesignicons-webfont.ttf, fonts/materialdesignicons-webfont-6.9.96.ttf (I need to combine these two MDI calls into one (lazy!), feel free to fix!), fonts/Roboto-Bold.ttf, fonts/Roboto-Regular.ttf)
Hopefully the below will give you some ideas and paths to explore. The end result will be a vertical Badgy with two temperature readings, a weather cloud/sun icon from Met.no service, and a CLOSED/OPEN and door icon at the bottom, along with the update time, battery icon, and wifi range icon. This is a mis-match of a bunch of versions I have running, so it's cut back from what I run, but has a lot of things in there that I have learned..... Use the Safe Restart button if you are having issues OTA updates to Badgy.
substitutions:
display_name: 'EPaper Display Badgy 01'
device_description: 'EPaper Display Badgy 01. The White one!'
friendly_name: 'EPaper Display Badgy 01'
device_name: epaper-display-01
node_name: epaper_display_01
globals:
- id: data_updated
type: bool
restore_value: no
initial_value: 'false'
- id: initial_data_received
type: bool
restore_value: no
initial_value: 'false'
esphome:
name: ${device_name}
comment: ${device_description}
on_boot:
- priority: 200.0
then:
- component.update: epaper
- priority: 800.0
then:
- component.update: ${node_name}_uptime_raw
- component.update: wifisignal
esp8266:
board: nodemcuv2
# Enable logging
logger:
# level: debug
# Enable Home Assistant API
api:
ota:
password: !secret ota_password
num_attempts: 5
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Epaper-Display-01"
password: "PdfmXwsyIhdgEjsxnf"
captive_portal:
time:
- platform: homeassistant
id: homeassistant_time
#light:
# - platform: status_led
# name: ${display_name} Onboard LED
# pin:
# number: GPIO2
# inverted: true
text_sensor:
- platform: wifi_info
ip_address:
name: ${display_name} IP Address
ssid:
name: ${display_name} Connected SSID
bssid:
name: ${display_name} Connected BSSID
- platform: template
name: ${friendly_name} Uptime
id: ${node_name}_uptime
icon: mdi:clock-start
- platform: homeassistant
name: forecast
id: weather_forecast_today
entity_id: weather.home
internal: true
binary_sensor:
- platform: status
name: ${display_name} Status
- platform: gpio
pin:
number: GPIO3
mode: INPUT_PULLUP
inverted: true
name: ${display_name} SW LEFT
filters:
- delayed_on: 10ms
- platform: gpio
pin:
number: GPIO1
mode: INPUT_PULLUP
inverted: true
name: ${display_name} SW DOWN
filters:
- delayed_on: 10ms
- platform: gpio
pin:
number: GPIO10
mode: INPUT_PULLUP
inverted: true
name: ${display_name} SW UP
filters:
- delayed_on: 10ms
- platform: gpio
pin:
number: GPIO12
mode: INPUT_PULLUP
inverted: true
name: ${display_name} SW RIGHT
filters:
- delayed_on: 10ms
- platform: gpio
pin:
number: GPIO5
mode: INPUT_PULLUP
inverted: true
name: ${display_name} SW CENTRE
filters:
- delayed_on: 10ms
- platform: homeassistant
id: door_backdoor
entity_id: binary_sensor.door_sensor_back_door_contact
internal: true
on_state:
then:
- component.update: epaper
- platform: homeassistant
id: multisensor_garage_motion_sensor
entity_id: binary_sensor.multisensor_garage_motion
internal: true
on_state:
then:
- component.update: epaper
sensor:
- platform: adc
pin: A0
#attenuation: auto
name: ${display_name} ADC Voltage RAW
id: li_ion_voltage_raw
update_interval: 10s
entity_category: diagnostic
unit_of_measurement: "V"
state_class: measurement
device_class: voltage
on_raw_value:
then:
- sensor.template.publish:
id: li_ion_voltage
state: !lambda |-
return ((id(li_ion_voltage_raw).state*(314000+100000)) / 100000);
- platform: template
name: ${display_name} Battery Voltage
id: li_ion_voltage
#update_interval: 60s
accuracy_decimals: 2
entity_category: diagnostic
unit_of_measurement: "V"
device_class: voltage
state_class: measurement
- platform: template
name: ${display_name} Battery Percentage
id: li_ion_voltage_percentage
unit_of_measurement: '%'
update_interval: 12s
entity_category: diagnostic
accuracy_decimals: 0
device_class: battery
state_class: measurement
lambda: |-
return (((id(li_ion_voltage).state - 3) /1.14) * 100.00);
- platform: wifi_signal
name: ${display_name} WiFi Singal Strength
id: wifisignal
update_interval: 120s
- platform: uptime
name: "${friendly_name} Uptime Sensor"
id: ${node_name}_uptime_raw
update_interval: 60s
on_raw_value:
then:
- logger.log:
format: "Raw Value of Uptime sensor: %f, %f"
args: ['id(${node_name}_uptime_raw).raw_state', 'id(${node_name}_uptime_raw).state']
level: INFO
- text_sensor.template.publish:
id: ${node_name}_uptime
state: !lambda |-
int seconds = round(id(${node_name}_uptime_raw).raw_state);
int days = seconds / (24 * 3600);
seconds = seconds % (24 * 3600);
int hours = seconds / 3600;
seconds = seconds % 3600;
int minutes = seconds / 60;
seconds = seconds % 60;
return (
(days ? String(days) + "d " : "") +
(hours ? String(hours) + "h " : "") +
(minutes ? String(minutes) + "m " : "") +
(String(seconds) + "s")
).c_str();
- platform: homeassistant
id: temp_garage
entity_id: sensor.multisensor_garage_temperature
internal: true
on_value:
then:
- component.update: epaper
- platform: homeassistant
id: temp_solar_weather
#entity_id: sensor.solar_weather_station_temperature
entity_id: sensor.weather_home_temperature
internal: true
on_value:
then:
- component.update: epaper
button:
- platform: restart
name: ${display_name} restart
- platform: safe_mode
name: "${display_name} Restart (Safe Mode)"
font:
- file: 'fonts/materialdesignicons-webfont.ttf'
# https://github.com/Templarian/MaterialDesign-Webfont/tree/v5.8.55
id: icon_font_new
size: 32
glyphs: [
"\U000F0F54", # mdi-home-thermometer
"\U000F0F55", # mdi-home-thermometer-outline
"\U000F18D6", # mdi-sun-thermometer
"\U000F054A", # mdi-umbrella
"\U000F081B", # mdi-door-closed
"\U000F081C", # mdi-door-open
"\U000F0438", # mdi-radiator
"\U000F0AD7", # mdi-radiator-disabled
"\U000F0AD8", # mdi-radiator-off
"\U000F0828", # mdi-hot-tub
"\U000F1903", # home-lightning-bolt
"\U000F0238", # mdi-fire"
"\U000F07D0", # mdi-home-assistant
"\U000F0F61", # mdi-moon-first-quarter
"\U000F0F62", # mdi-moon-full
"\U000F0F63", # mdi-moon-last-quarter
"\U000F0F64", # mdi-moon-new
"\U000F0F65", # mdi-moon-waning-crescent
"\U000F0F66", # mdi-moon-waning-gibbous
"\U000F0F67", # mdi-moon-waxing-crescent
"\U000F0F68" # mdi-moon-waxing-gibbous
]
- file: 'fonts/materialdesignicons-webfont-6.9.96.ttf'
# https://github.com/Templarian/MaterialDesign-Webfont/tree/v6.9.96
id: icon_font_small
size: 14
glyphs: [
# Wifi
"\U000F092B", # mdi-wifi-strength-alert-outline
"\U000F091F", # mdi-wifi-strength-1
"\U000F0922", # mdi-wifi-strength-2
"\U000F0925", # mdi-wifi-strength-3
"\U000F0928", # mdi-wifi-strength-4
"\U000F0438", #mdi-radiator
"\U000F0AD7", #mdi-radiator-disabled
"\U000F0AD8", #mdi-radiator-off
"\U000F1903", #home-lightning-bolt
"\U000F12A3", #mdi-battery-high
"\U000F12A2", #mdi-battery-medium
"\U000F12A1", #mdi-battery-low
"\U000F008E", #mdi-battery-outline
]
- file: 'fonts/Roboto-Bold.ttf'
id: temp_font
size: 32
glyphs:
['&', '@', '!', ',', '.', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0',
'1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z','å', 'ä', 'ö', '/']
- file: 'fonts/Roboto-Regular.ttf'
id: footer_font
size: 12
glyphs:
['&', '@', '!', ',', '.', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0',
'1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z','å', 'ä', 'ö', '/','º','µ','³']
- file: 'fonts/materialdesignicons-webfont.ttf'
id: weather_font
size: 32
glyphs:
# Weather
- "\U000F0590" # weather-cloudy
- "\U000F0F2F" # weather-cloudy-alert
- "\U000F0E6E" # weather-cloudy-arrow-right
- "\U000F0591" # weather-fog
- "\U000F0592" # weather-hail
- "\U000F0F30" # weather-hazy
- "\U000F0898" # weather-hurricane
- "\U000F0593" # weather-lightning
- "\U000F067E" # weather-lightning-rainy
- "\U000F0594" # weather-night
- "\U000F0F31" # weather-night-partly-cloudy
- "\U000F0595" # weather-partly-cloudy
- "\U000F0F32" # weather-partly-lightning
- "\U000F0F33" # weather-partly-rainy
- "\U000F0F34" # weather-partly-snowy
- "\U000F0F35" # weather-partly-snowy-rainy
- "\U000F0596" # weather-pouring
- "\U000F0597" # weather-rainy
- "\U000F0598" # weather-snowy
- "\U000F0F36" # weather-snowy-heavy
- "\U000F067F" # weather-snowy-rainy
- "\U000F0599" # weather-sunny
- "\U000F0F37" # weather-sunny-alert
- "\U000F14E4" # weather-sunny-off
- "\U000F059A" # weather-sunset
- "\U000F059B" # weather-sunset-down
- "\U000F059C" # weather-sunset-up
- "\U000F0F38" # weather-tornado
- "\U000F059D" # weather-windy
- "\U000F059E" # weather-windy-variant
- file: 'fonts/Roboto-Bold.ttf'
id: status_font
size: 18
glyphs:
['&', '@', '!', ',', '.', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0',
'1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z', 'å', 'ä', 'ö', '/']
spi:
clk_pin: GPIO14
mosi_pin: GPIO13 #DIN
display:
- platform: waveshare_epaper
id: epaper
cs_pin: GPIO15
dc_pin: GPIO0
busy_pin: GPIO4
reset_pin: GPIO2
model: 2.90in
#model: 2.90in-b
rotation: 180°
# full_update_every: 30
update_interval: 3600s
lambda: |-
if(id(multisensor_garage_motion_sensor).state){
// Map weather states to MDI characters.
std::map<std::string, std::string> weather_icon_map
{
{"cloudy", "\U000F0590"},
{"cloudy-alert", "\U000F0F2F"},
{"cloudy-arrow-right", "\U000F0E6E"},
{"fog", "\U000F0591"},
{"hail", "\U000F0592"},
{"hazy", "\U000F0F30"},
{"hurricane", "\U000F0898"},
{"lightning", "\U000F0593"},
{"lightning-rainy", "\U000F067E"},
{"night", "\U000F0594"},
{"night-partly-cloudy", "\U000F0F31"},
{"partlycloudy", "\U000F0595"},
{"partly-lightning", "\U000F0F32"},
{"partly-rainy", "\U000F0F33"},
{"partly-snowy", "\U000F0F34"},
{"partly-snowy-rainy", "\U000F0F35"},
{"pouring", "\U000F0596"},
{"rainy", "\U000F0597"},
{"snowy", "\U000F0598"},
{"snowy-heavy", "\U000F0F36"},
{"snowy-rainy", "\U000F067F"},
{"sunny", "\U000F0599"},
{"sunny-alert", "\U000F0F37"},
{"sunny-off", "\U000F14E4"},
{"sunset", "\U000F059A"},
{"sunset-down", "\U000F059B"},
{"sunset-up", "\U000F059C"},
{"tornado", "\U000F0F38"},
{"windy", "\U000F059D"},
{"windy-variant", "\U000F059E"},
{"first_quarter", "\U000F0F61"},
{"full_moon", "\U000F0F62"},
{"last_quarter", "\U000F0F63"},
{"new_moon", "\U000F0F64"},
{"waning_crescent", "\U000F0F65"},
{"waning_gibbous", "\U000F0F66"},
{"waxing_crescent", "\U000F0F67"},
{"waxing_gibbous", "\U000F0F68"}
};
int x, y, c, x_top, y_top;
ESP_LOGI("display", "Updating..");
/* Print time in HH:MM format */
/*if(id(homeassistant_time).now().is_valid()) {
it.strftime(64, 0, id(temp_font), TextAlign::TOP_CENTER, "%H:%M", id(homeassistant_time).now());
}*/
/* FOOTER */
if(id(homeassistant_time).now().is_valid()) {
it.strftime(128 - 16, 296 - 3 , id(footer_font), TextAlign::BASELINE_RIGHT , "%d/%m/%Y %H:%M", id(homeassistant_time).now());
/* Battery Strength */
if(id(li_ion_voltage_percentage).has_state()) {
x = 12, y = 296 - 0;
if (id(li_ion_voltage_percentage).state >= 90) {
//Excellent
it.print(x, y, id(icon_font_small), TextAlign::BOTTOM_RIGHT, "\U000F12A3");
ESP_LOGI("Battery", "Exellent");
} else if (id(li_ion_voltage_percentage).state >= 60) {
//Good
it.print(x, y, id(icon_font_small), TextAlign::BOTTOM_RIGHT, "\U000F12A2");
ESP_LOGI("Battery", "Good");
} else if (id(li_ion_voltage_percentage).state >= 30) {
//Fair
it.print(x, y, id(icon_font_small), TextAlign::BOTTOM_RIGHT, "\U000F12A1");
ESP_LOGI("Battery", "Fair");
} else {
//Unlikely working signal
it.print(x, y, id(icon_font_small), TextAlign::BOTTOM_RIGHT, "\U000F008E");
ESP_LOGI("Battery", "Unlikely");
}
}
/* WiFi Signal Strength */
if(id(wifisignal).has_state()) {
x = 128 - 0, y = 296 - 0;
if (id(wifisignal).state >= -50) {
//Excellent
it.print(x, y, id(icon_font_small), TextAlign::BOTTOM_RIGHT, "\U000F0928");
ESP_LOGI("WiFi", "Exellent");
} else if (id(wifisignal).state >= -60) {
//Good
it.print(x, y, id(icon_font_small), TextAlign::BOTTOM_RIGHT, "\U000F0925");
ESP_LOGI("WiFi", "Good");
} else if (id(wifisignal).state >= -67) {
//Fair
it.print(x, y, id(icon_font_small), TextAlign::BOTTOM_RIGHT, "\U000F0922");
ESP_LOGI("WiFi", "Fair");
} else if (id(wifisignal).state >= -70) {
//Weak
it.print(x, y, id(icon_font_small), TextAlign::BOTTOM_RIGHT, "\U000F091F");
ESP_LOGI("WiFi", "Weak");
} else {
//Unlikely working signal
it.print(x, y, id(icon_font_small), TextAlign::BOTTOM_RIGHT, "\U000F092B");
ESP_LOGI("WiFi", "Unlikely");
}
}
}
y = 100, x = 100;
x_top = 0, y_top = 32+4;
// Print garage temperature (from homeassistant sensor)
y = 100, x = 100;
if (id(temp_garage).has_state()) {
it.print(32, y_top+32-3, id(icon_font_new), TextAlign::BOTTOM_RIGHT, "\U000F0F55");
it.printf(28+100, y_top+32, id(temp_font), TextAlign::BOTTOM_RIGHT , "%5.1f°C", id(temp_garage).state);
}
// Print Solar Weather Station temperature (from homeassistant sensor)
if (id(temp_solar_weather).has_state()) {
it.printf(34, y_top+32+32-3, id(weather_font), TextAlign::BOTTOM_RIGHT, "%s", weather_icon_map[id(weather_forecast_today).state.c_str()].c_str());
//it.print(34, y_top+32+32-3, id(icon_font_new), TextAlign::BOTTOM_RIGHT, "\U000F18D6");
it.printf(28+100, y_top+32+32, id(temp_font), TextAlign::BOTTOM_RIGHT , "%5.1f°C", id(temp_solar_weather).state);
}
//DOOR
if (id(door_backdoor).has_state()) {
it.printf(64, 220, id(temp_font), TextAlign::TOP_CENTER, "%s", id(door_backdoor).state ? "OPEN" : "CLOSED");
if (id(door_backdoor).state) {
it.print(2, 250, id(icon_font_new), "\U000F081C");
} else {
it.print(2, 250, id(icon_font_new), "\U000F081B");
}
}
}
else{
it.fill(COLOR_OFF);
}
Finally some time to get back to this, and preliminary results are good!
First attempts I was seeing nothing but either I watching the logs wirelessly prevents it from displaying or maybe I had update_interval
too low or wasn't patient enough.
Now that I've got the basics I'll look at getting my CO2 levels in, thanks muchly!
Ahhh - i wondered when you'd look at this. Good to hear it's working. I have similar results with blank screens, reboots etc. Not sure if it's the device wiring or the code, but it's not the most stable ePaper screen for HA.
Enjoy tinkering with the YAML! Check out https://github.com/Madelena/esphome-weatherman-dashboard for some good inspiration too. And there are a bunch of epaper esphome projects to borrow ideas from!
BTW, I'd given up on it for a while and checked in again and its working brilliantly now! I think something in esphome improved more than any change I did. Now I have to find the other one I've misplaced!
Showing:
BTW, I'd given up on it for a while and checked in again and its working brilliantly now! I think something in esphome improved more than any change I did. Now I have to find the other one I've misplaced!
Showing:
- time
- indoor temp
- outdoor temp
- co2
- status of front and back doors
- back door on right, front door on left
- last update time and wifi strength.
Haha! Looking awesome!!! Glad it is working for you. Mine has lived on my wall ever since with all sorts of temps and door icons!
Is badgy supported by esphome? Does anyone have config files if so?
@chunkysteveo you tagged a post with
esphome
hereThe waveshare eink displays seem similar and closest, but different enough it seemed worth asking.
(Rev 2A if it matters)