Hi,
I do want to have an ePaper in front of a meeting room, that shows, when the room is busy. The addon is, that there are two physical buttons, one where the user can update the ePaper and one where he can boot the room for a fixed length. Until know it is all running “perfectly” but I noticed, that the battery is drained pretty “quick”, so I wanted to use deep sleep mode as often as I can.
To be most flexible, I want to be able to put the ESP in deepSleep by HomeAssistant (Deep sleep would be e.g. between 7pm and 8am on workdays, all weekend, and whenever I want it.)
I use GPIO17 refreshing the display and GPIO16 for booking a fixed timeslot.
If the ESP is in DeepSleep, I want to print this on the epaper and let the user notice, that it might take some time, until he can use the “Booking” switch, and before he has to use the ePaper rerefresh button to wake the ESP up.
Here is the esphome start file:
substitutions:
# !!! ALL LOWER CASE, NO dashes (-) because prohibited by ESPHome IDs and no underscores (_) because prohibited in DNS Host Names
rmgr_device_name: "framery1"
# --------------
# DO NOT CHANGE BELOW THIS LINE - must be the same for all framerys.
# --------------
packages:
base: !include
file: common/calendar_free_busy_display.yaml
vars:
rmgr_device_name: "${rmgr_device_name}"
# Core Configuration Section: https://esphome.io/components/esphome.html
esphome:
# https://esphome.io/components/esphome.html#changing-esphome-node-name
name: "${rmgr_device_name}"
and here the file that is for all rooms the same:
# Calendar / Free Busy DASHBOARD
# For Home Assistant and ESPHome
# Inspired by WEATHERMAN by Madelena Mak 2022 - https://mmak.es
#
#######################
# VARIABLES passed into the system:
# - rmgr_device_name: the common prefix for sensors etc (still a bad name)
#
# Core Configuration Section: https://esphome.io/components/esphome.html
esphome:
# name is defined in specific instance config (e.g. framery1.yaml etc)
# https://esphome.io/components/esphome.html#on-boot
# on_boot is an *Automation* (https://esphome.io/automations/#automation)
on_boot: # == "Trigger"
priority: 200.0
then: # == "Actions"
- component.update: epaper_screen_print
- delay: 5s
#- logger.log: "Initial sensor data received: Refreshing display..."
#- lambda: 'id(initial_data_received) = true;'
#- script.execute: epaper_screen_update
# this triggers a reload in Home Assistant (which pushes the data down to the device)
- homeassistant.event:
event: "esphome.${rmgr_device_name}.booted"
# https://esphome.io/components/esp32.html
esp32:
# "if unsure choose a generic board from Espressif such as esp32dev."
board: esp32dev
framework:
type: arduino
# Enable logging
# https://esphome.io/components/logger.html
logger:
# level: NONE
# level: ERROR
# level: WARN
# level: INFO
level: DEBUG
# level: VERBOSE
# level: VERY_VERBOSE
# Global variables for detecting if the display needs to be refreshed. (Thanks @paviro!)
# https://esphome.io/components/globals.html
globals:
- id: initial_data_received
type: bool
restore_value: no
initial_value: 'false'
- id: headline_text
type: std::string
restore_value: no
- id: subheadline_text
type: std::string
restore_value: no
- id: timeslots
type: std::vector<std::string>
restore_value: no
- id: is_occupied
type: std::vector<bool>
restore_value: no
- id: rmgr_booking_slot_length_minutes
type: std::string
restore_value: no
- id: last_display_refresh
type: std::string
restore_value: no
# Enable Home Assistant API
# https://esphome.io/components/api.html
api:
services:
- service: "draw_schedule"
variables:
param_headline_text: string
param_subheadline_text: string
# !!! you need the same number of entries in param_timeslots and param_is_occupied
param_timeslots: string[]
param_is_occupied: bool[]
param_rmgr_booking_slot_length_minutes: string
param_last_display_refresh: string
then:
- lambda: 'id(initial_data_received) = true;'
- lambda: 'id(headline_text) = param_headline_text;'
- lambda: 'id(subheadline_text) = param_subheadline_text;'
- lambda: 'id(timeslots) = param_timeslots;'
- lambda: 'id(is_occupied) = param_is_occupied;'
- lambda: 'id(rmgr_booking_slot_length_minutes) = param_rmgr_booking_slot_length_minutes;'
- lambda: 'id(last_display_refresh) = param_last_display_refresh;'
- logger.log: ".-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. calfreebusy_draw_schedule Data"
- logger.log:
format: "param_headline_text has value >%s<"
args: [ 'id(headline_text).c_str()' ]
- logger.log:
format: "param_subheadline_text has value >%s<"
args: [ 'id(subheadline_text).c_str()' ]
- logger.log:
format: "param_timeslots has value >%i<"
args: [ 'id(timeslots)' ]
- component.update: epaper_screen_print
# https://esphome.io/components/ota/esphome
ota:
- platform: esphome
# Wifi information
wifi:
# Optional manual IP
networks:
# channel: 11
ssid: !secret wifi_ssid
password: !secret wifi_password
# manual_ip:
# static_ip: 192.168.90.182
# gateway: 192.168.90.1
# subnet: 255.255.255.0
# Enable fallback hotspot (captive portal) in case wifi connection fails
# ausgeshcaltet, da es
# ap:
# ssid: !secret wifi_ssid
# password: !secret wifi_password
# Include custom fonts
font:
- file: 'fonts/GothamRnd-Book.ttf'
id: font_small_book
size: 18
glyphs: ['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', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', '-', ' ', '°', '.', '%', 'ä', 'ö', 'ü', 'ß', '(', ')']
- file: 'fonts/GothamRnd-Bold.ttf'
id: font_large_bold
size: 108
glyphs: ['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', 'Ä', 'Ö', 'Ü', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', '-', ' ', '°', '.','m', '%']
- file: 'fonts/GothamRnd-Bold.ttf'
id: font_title
size: 54
glyphs: ['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', 'Ä', 'Ö', 'Ü', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', '-', ' ', '°', '.','m', 'u', 'p', 'd', 't', '%']
- file: 'fonts/GothamRnd-Bold.ttf'
id: font_medium_bold
size: 30
glyphs: ['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', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', '-', ' ', '°', '.', '%', 'ä', 'ö', 'ü', 'ß', '(', ')']
- file: 'fonts/GothamRnd-Bold.ttf'
id: font_small_bold
size: 18
glyphs: ['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', 'Ä', 'Ö', 'Ü', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', '-', ' ', '°', '.','m', '%']
# Include Material Design Icons font
# Thanks to https://community.home-assistant.io/t/display-materialdesign-icons-on-esphome-attached-to-screen/199790/16
- file: 'fonts/materialdesignicons-webfont.ttf'
id: font_mdi_medlarge
size: 18
glyphs:
- "\U000F05A9" # mdi-wifi
- "\U000F0928" # mdi-wifi-strength-4
- "\U000F0925" # mdi-wifi-strength-3
- "\U000F0922" # mdi-wifi-strength-2
- "\U000F091F" # mdi-wifi-strength-1
- "\U000F092B" # mdi-wifi-strength-alert-outline
# Check if epaper should be refreshed
sensor:
- platform: wifi_signal
name: "${rmgr_device_name} - WiFi Signal Strength"
id: "${rmgr_device_name}_wifisignal"
unit_of_measurement: "dBm"
entity_category: "diagnostic"
update_interval: 600s
#binary_sensor:
## refresh epaper display
# - platform: homeassistant
# entity_id: input_boolean.update_epaper_display
# id: update_epaper_display
binary_sensor:
- platform: gpio
name: "${rmgr_device_name}_book_now"
pin:
number: GPIO16
inverted: true
mode:
input: true
pullup: true
filters:
- delayed_on: 10ms
on_multi_click:
- timing:
- ON for at most 1s
- OFF for at most 1s
- ON for at most 1s
- OFF for at least 0.2s
then:
- logger.log: "Double Clicked"
- homeassistant.event:
event: esphome.${rmgr_device_name}_booknow_doubleclicked
- timing: # INFO: this is currently not used functionally.
- ON for 1s to 2s
- OFF for at least 0.5s
then:
- logger.log: "Single Long Clicked"
- homeassistant.event:
event: esphome.${rmgr_device_name}_booknow_longclicked
- timing:
- ON for at most 1s
- OFF for at least 0.5s
then:
- logger.log: "Single Short Clicked"
- homeassistant.event:
event: esphome.${rmgr_device_name}_booknow_clicked
- platform: gpio
name: "${rmgr_device_name}_refresh"
pin:
number: GPIO17
inverted: true
mode:
input: true
pullup: true
filters:
- delayed_on: 10ms
on_multi_click:
- timing:
- ON for at most 1s
- OFF for at most 1s
- ON for at most 1s
- OFF for at least 0.2s
then:
- logger.log: "Double Clicked"
- homeassistant.event:
event: esphome.${rmgr_device_name}_refresh_doubleclicked
- timing: # INFO: this is currently not used functionally.
- ON for 1s to 2s
- OFF for at least 0.5s
then:
- logger.log: "Single Long Clicked"
- homeassistant.event:
event: esphome.${rmgr_device_name}_refresh_longclicked
- timing:
- ON for at most 1s
- OFF for at least 0.5s
then:
- logger.log: "Single Short Clicked"
- homeassistant.event:
event: esphome.${rmgr_device_name}_refresh_clicked
# Pins for Waveshare ePaper ESP Board
spi:
clk_pin: GPIO13 # SCLK P13 SPI CLK pin, clock signal input
mosi_pin: GPIO14 # DIN P14 SPI MOSI pin, data input
# Now render everything on the ePaper screen.
display:
- platform: waveshare_epaper
# models from https://esphome.io/components/display/waveshare_epaper
# model: 7.50inV2 # s/w board evtl. älterer Treiber ???
# model: 7.50in-nV2 # s/w board
model: 7.50in-bV3 # r/s/w board
id: epaper_screen_print
cs_pin: GPIO15 # CS P15 Chip selection, low active
dc_pin: GPIO27 # DC P27 Data/command, low for commands, high for data
busy_pin:
number: GPIO25 # BUSY P25 Busy status output pin (means busy)
inverted: true
reset_pin: GPIO26 # RST P26 Reset, low active
reset_duration: 2ms
update_interval: never
rotation: 90°
lambda: |-
int offsetY = 40;
int offsetX = 0;
//# Print loading screen before data is received.
if (id(initial_data_received) == false) {
it.printf(240, 390, id(font_small_bold), TextAlign::TOP_CENTER, "WARTE AUF DATEN");
} else {
// headline
int lineHeight = 35;
it.printf(50, offsetY, id(font_medium_bold), TextAlign::TOP_LEFT, "%s", id(headline_text).c_str());
offsetY += lineHeight;
// subheadline
lineHeight = 22;
it.printf(150, offsetY, id(font_small_book), TextAlign::TOP_LEFT, "%s", id(subheadline_text).c_str());
offsetY += lineHeight;
lineHeight = 22;
for (size_t i = 0; i < id(timeslots).size(); ++i) {
offsetY += lineHeight;
it.printf(50, offsetY, id(font_small_book), TextAlign::TOP_LEFT, "%s", id(timeslots)[i].c_str());
if (id(is_occupied)[i]) {
it.filled_rectangle(120, offsetY, 100, lineHeight);
}
}
}
//# decide for the WiFi-signal Symbol
//# is printed printed below
std::string wifiSymbol = "";
offsetX = it.get_width() - 50;
offsetY = it.get_height() - 150;
if(id(${rmgr_device_name}_wifisignal).has_state ()) {
if (id(${rmgr_device_name}_wifisignal).state >= -50) {
// Excellent
wifiSymbol = "\U000F0928";
} else if (id(${rmgr_device_name}_wifisignal).state >= -60) {
//Good
wifiSymbol = "\U000F0925";
} else if (id(${rmgr_device_name}_wifisignal).state >= -67) {
//Fair
wifiSymbol = "\U000F0922";
} else if (id(${rmgr_device_name}_wifisignal).state >= -70) {
//Weak
wifiSymbol = "\U000F091F";
} else {
//Unlikely working signal
wifiSymbol = "\U000F092B";
}
}
// Print booking slot length + Last refresh + Wifi
// we write from bottom to top
offsetX = it.get_width() - 50;
offsetY = it.get_height() - 130;
int lineHeight = 22;
// Print DBI and Wifi Signal
it.printf(offsetX - 25, offsetY, id(font_small_book), TextAlign::TOP_RIGHT, "%.0f dB", id(${rmgr_device_name}_wifisignal).state);
it.printf(offsetX, offsetY, id(font_mdi_medlarge), TextAlign::TOP_RIGHT, "%s", wifiSymbol.c_str());
//
it.printf(offsetX - 150, offsetY, id(font_small_book), TextAlign::TOP_RIGHT, "%s", id(rmgr_booking_slot_length_minutes).c_str());
offsetY -= lineHeight;
it.printf(offsetX, offsetY, id(font_small_book), TextAlign::TOP_RIGHT, "%s", id(last_display_refresh).c_str());
captive_portal:
Before I start, I do want to know if this is
a.) doable and useful
b.) what drawback I might get.
There is still the way to have a bigger battery or use power in some roome, but I do like the idea, that I can hang it on the wall everywhere for about 14 days.
thank you for all suggestions
Juergen