Abstract
I’ve already built a smart home system based on Home Assistant. The most important task is showing the states of both bathrooms‘ doors sensors because I don’t want to physically check them just like checking other dudes' excretion duration… And sometimes is just too lazy to take out the phone and check the next bus to the city center, or just too lazy to check the real feel temperature.
There is. An ESPHome-based desktop terminal, which shows all needed information.
Components
The terminal is built based on Wemos D1 Mini, which is using ESP8266 as the main controller. It is conntected with a BME 680 sensor, a ssd1306 OLED, two led for showing doors' states and a button.
OLED burn-in protection
If the normal blue OLED display keeps showing something similar, the pixel of it might be damaged. Therefore, we can let it display some sort of display protection animation or set some mechanism to shut the display down. The funniest thing is, that we have everything to make the display show animation. But the display is way too rubish…the refresh rate, the low resolution. It doesn’t deserve it. So in my third version, I’ve added a button to change the pages of the display and after 10 seconds, the display is shut down.
Pull-up resistor
As you might know, the input signal might be disturbed, although it is connected directly by wire. Therefore, we should use a pull-up resistor, which could keep the GPIO voltage always high level. It just simply connects the 3.3v to the input GPIO through a 10 KOhm resistor. If someone presses the button, and because the button resistance is way smaller than the 10KOhm resistor, so the input GPIO voltage is forced to become low level, just like shortcut the GPIO direct to the ground. As an alternative, Wemos D1 Mini provides a build-in pull-up resistor at pin D3 and D4 (D4 with onboard LED). We can also activate them with configs.
Some dumb things about the timer in ESPHome
Timer
Normally, once the program is interrupted by pressing the button, another program should run. In our case, ideally, should be either “turn on the display and show the first page, timer initialized” or “switch to the next page, timer refreshed 10 sec.”. However, ESPHome provides only an initializor for the timer. If we keep using - delay: 10 s
after button pressing, tones of the timer are created…So, save some hair for the future. Just set up a timer once the button is pressed…
binary_sensor:
- platform: gpio
pin: 14
id: display_button
name: "display button"
on_press:
then:
- if:
condition:
// use global var flag_dis to distinguish the presses
lambda: return id(flag_dis) == 0;
then:
- display.page.show: page1
- globals.set:
id: flag_dis
value: '1'
- logger.log: "10s timer is set"
- delay: 10 s
- display.page.show: page_off
- globals.set:
id: flag_dis
value: '0'
- logger.log: "time's up"
else :
display.page.show_next: terminal_display
Bugs of display contents?
I’ve seen an official example, which uses lambda function to determine the display content.
display:
- platform: ...
# ...
lambda: |-
if (id(my_binary_sensor).state) {
it.print(0, 0, id(my_font), "state: ON");
} else {
it.print(0, 0, id(my_font), "state: OFF");
}
// Shorthand:
it.printf(0, 0, id(my_font), "State: %s", id(my_binary_sensor).state ? "ON" : "OFF");
My suggestion is, don’t do that. Just in my case, it will crash your program in a couple of hours. You could just simply create a new page for shutting down the display
display:
- platform: ssd1306_i2c
model: "SSD1306 128x64"
id: terminal_display
pages:
// page to shut down the display
- id: page_off
lambda: |-
it.fill(COLOR_OFF);
- id: page1
lambda: |-
it.printf(0, 3, id(normal_font), "1. Bus: %.0f min", id(display_181_frist).state);
it.printf(0, 30, id(normal_font), "2. Bus: %.0f min", id(display_181_second).state);
- id: page2
lambda: |-
it.printf(0, 2, id(normal_font), "temp. %.01f°C", id(room_temperature).state);
it.printf(0, 30, id(normal_font), "humid. %.01f%%", id(room_humidity).state);
- id: page3
lambda: |-
it.printf(0, 2, id(normal_font), "%s", id(weather_display).state.c_str());
it.printf(0, 30, id(normal_font), "R.F. %.01f°C", id(display_real_feel).state);
Case
first version
This is some kind of over-engineered design.