pipish/.screen_base.yaml
2024-03-10 01:23:40 +01:00

643 lines
21 KiB
YAML

esphome:
name: ${device_id}
name_add_mac_suffix: true
on_boot:
- priority: 220.0
then:
- it8951e.clear
- delay: 100ms
- component.update: m5paper_display
- priority: -100.0
then:
- delay: 10s
- component.update: m5paper_display
esp32:
board: m5stack-grey
framework:
type: arduino
external_components:
- source: github://Passific/m5paper_esphome
# Enable logging
logger:
level: DEBUG
# Enable psram
psram:
# Enable Home Assistant API
api:
ota:
globals:
- id: material_icons_map
type: std::map<std::string, std::string>
restore_value: no
initial_value: |
{
{"mdi-weather-night", "󰖔"},
{"mdi-weather-cloudy", "󰖐"},
{"mdi-weather-cloudy-alert", "󰼯"},
{"mdi-weather-fog", "󰖑"},
{"mdi-weather-hail", "󰖒"},
{"mdi-weather-lightning-rainy", "󰙾"},
{"mdi-weather-lightning", "󰖓"},
{"mdi-weather-partly-cloudy", "󰖕"},
{"mdi-weather-night-partly-cloudy", "󰼱"},
{"mdi-weather-pouring", "󰖖"},
{"mdi-weather-rainy", "󰖗"},
{"mdi-weather-snowy-rainy", "󰙿"},
{"mdi-weather-snowy", "󰖘"},
{"mdi-weather-sunny", "󰖙"},
{"mdi-weather-windy-variant", "󰖞"},
{"mdi-weather-windy", "󰖝"},
{"mdi-cloud-question", "󰨹"},
{"mdi-thermometer", "󰔏"},
{"mdi-water-percent", "󰖎"},
{"mdi-molecule-co2", "󰟤"},
{"mdi-wind-power-outline", "󱪉"},
{"mdi-home-outline", "󰚡"},
{"mdi-tree-outline", "󰹩"},
{"mdi-gauge", "󰊚"},
{"mdi-battery-high", "󱊣"},
{"mdi-battery-medium", "󱊢"},
{"mdi-battery-low", "󱊡"},
{"mdi-battery-alert-variant-outline", "󱃍"},
{"mdi-battery-charging-high", "󱊦"},
{"mdi-battery-unknown", "󰂑"},
{"mdi-shield-outline", "󰒙"},
{"mdi-shield-home-outline", "󰳋"},
{"mdi-shield-lock-outline", "󰳌"},
{"mdi-shield-moon-outline", "󱠩"},
{"mdi-shield-alert-outline", "󰻍"},
{"mdi-molecule-co2", "󰟤"},
{"mdi-radioactive", "󰐼"},
{"mdi-numeric-0-circle-outline", "󰲟"},
{"mdi-numeric-1-circle-outline", "󰲡"},
{"mdi-numeric-2-circle-outline", "󰲣"},
{"mdi-numeric-3-circle-outline", "󰲥"},
{"mdi-numeric-4-circle-outline", "󰲧"},
{"mdi-numeric-5-circle-outline", "󰲩"},
{"mdi-numeric-6-circle-outline", "󰲫"},
{"mdi-numeric-7-circle-outline", "󰲭"},
{"mdi-numeric-8-circle-outline", "󰲯"},
{"mdi-numeric-9-plus-circle-outline", "󰲳"},
}
font:
- file: 'gfonts://Roboto'
id: normal_font
size: 40
- file: 'gfonts://Roboto@medium'
id: condition_font
size: 80
- file: "gfonts://Orbitron"
id: clock_font
size: 80
- file: "fonts/materialdesignicons-webfont.ttf"
id: small_icons_font
size: 50
glyphs: [
'󰖖', #mdi-weather-pouring
'󰔏', #mdi-thermometer
'󰖎', #mdi-water-percent
'󰟤', #mdi-molecule-co2
'󱪉', #mdi-wind-power-outline
'󰚡', #mdi-home-outline
'󰹩', #mdi-tree-outline
'󰊚', #mdi-gauge
]
- file: "fonts/materialdesignicons-webfont.ttf"
id: weather_font
size: 256
glyphs: [
'󰖔', #mdi-weather-night
'󰖐', #mdi-weather-cloudy
'󰼯', #mdi-weather-cloudy-alert
'󰖑', #mdi-weather-fog
'󰖒', #mdi-weather-hail
'󰙾', #mdi-weather-lightning-rainy
'󰖓', #mdi-weather-lightning
'󰖕', #mdi-weather-partly-cloudy
'󰼱', #mdi-weather-night-partly-cloudy
'󰖖', #mdi-weather-pouring
'󰖗', #mdi-weather-rainy
'󰙿', #mdi-weather-snowy-rainy
'󰖘', #mdi-weather-snowy
'󰖙', #mdi-weather-sunny
'󰖞', #mdi-weather-windy-variant
'󰖝', #mdi-weather-windy
'󰨹', #mdi-cloud-question
]
- file: "fonts/materialdesignicons-webfont.ttf"
id: battery_font
size: 40
glyphs: [
'󱊣', #mdi-battery-high
'󱊢', #mdi-battery-medium
'󱊡', #mdi-battery-low
'󱃍', #mdi-battery-alert-variant-outline
'󱊦', #mdi-battery-charging-high
'󰂑', #mdi-battery-unknown
]
- file: "fonts/materialdesignicons-webfont.ttf"
id: alarms_font
size: 80
glyphs: [
'󰒙', #mdi-shield-outline
'󰳋', #mdi-shield-home-outline
'󰳌', #mdi-shield-lock-outline
'󱠩', #mdi-shield-moon-outline
'󰻍', #mdi-shield-alert-outline
'󰟤', #mdi-molecule-co2
'󰐼', #mdi-radioactive
'󰲟', #mdi-numeric-0-circle-outline
'󰲡', #mdi-numeric-1-circle-outline
'󰲣', #mdi-numeric-2-circle-outline
'󰲥', #mdi-numeric-3-circle-outline
'󰲧', #mdi-numeric-4-circle-outline
'󰲩', #mdi-numeric-5-circle-outline
'󰲫', #mdi-numeric-6-circle-outline
'󰲭', #mdi-numeric-7-circle-outline
'󰲯', #mdi-numeric-8-circle-outline
'󰲳', #mdi-numeric-9-plus-circle-outline
]
spi:
clk_pin: GPIO14
mosi_pin: GPIO12
miso_pin: GPIO13
i2c:
sda: GPIO21
scl: GPIO22
display:
- platform: it8951e
id: m5paper_display
cs_pin: GPIO15
reset_pin: GPIO23
reset_duration: 100ms
busy_pin: GPIO27
rotation: 0
reversed: False
update_interval: never
lambda: |-
// Clock
it.strftime(25, 420, id(clock_font), "%H:%M", id(rtc_time).now());
// Weather icon
Color weather_icon_color;
weather_icon_color.raw_32 = 0x0D;
#if 0 // Use for testing
std::string _conditions[] {
"clear-night",
"cloudy",
"exceptional",
"fog",
"hail",
"lightning-rainy",
"lightning",
"partlycloudy",
"pouring",
"rainy",
"snowy-rainy",
"snowy",
"sunny",
"windy",
"windy-variant",
};
static int _cond_index = 0;
std::string conditions = _conditions[_cond_index];
_cond_index = (_cond_index + 1) % 15;
#else
std::string conditions = id(weather_conditions).state;
#endif
std::string img = id(material_icons_map)["mdi-cloud-question"];
if (conditions == "clear-night")
{
conditions = "clear";
img = id(material_icons_map)["mdi-weather-night"];
}
else if (conditions == "cloudy")
img = id(material_icons_map)["mdi-weather-cloudy"];
else if (conditions == "exceptional")
img = id(material_icons_map)["mdi-weather-cloudy-alert"];
else if (conditions == "fog")
img = id(material_icons_map)["mdi-weather-fog"];
else if (conditions == "hail")
img = id(material_icons_map)["mdi-weather-hail"];
else if (conditions == "lightning-rainy")
{
conditions = "thunderstorm";
img = id(material_icons_map)["mdi-weather-lightning-rainy"];
}
else if (conditions == "lightning")
img = id(material_icons_map)["mdi-weather-lightning"];
else if (conditions == "partlycloudy")
{
bool is_night = id(sun_position).state == "below_horizon";
if (is_night)
img = id(material_icons_map)["mdi-weather-night-partly-cloudy"];
else
img = id(material_icons_map)["mdi-weather-partly-cloudy"];
conditions = "partly cloudy";
}
else if (conditions == "pouring")
{
img = id(material_icons_map)["mdi-weather-pouring"];
conditions = "shower";
}
else if (conditions == "rainy")
img = id(material_icons_map)["mdi-weather-rainy"];
else if (conditions == "snowy-rainy")
{
img = id(material_icons_map)["mdi-weather-snowy-rainy"];
conditions = "sleet";
}
else if (conditions == "snowy")
img = id(material_icons_map)["mdi-weather-snowy"];
else if (conditions == "sunny")
img = id(material_icons_map)["mdi-weather-sunny"];
else if (conditions == "windy")
img = id(material_icons_map)["mdi-weather-windy"];
else if (conditions == "windy-variant")
{
img = id(material_icons_map)["mdi-weather-windy-variant"];
conditions = "windy";
}
it.print(25, 55, id(weather_font), weather_icon_color, img.c_str());
uint base_y = 25;
if (!conditions.empty())
{
conditions[0] = toupper(conditions[0]);
it.printf(295, base_y, id(condition_font), conditions.c_str());
}
#define NOT_NAN(x) ((x) == (x))
// Outdoor
it.print(295, base_y + 100, id(small_icons_font), weather_icon_color, id(material_icons_map)["mdi-tree-outline"].c_str());
it.print(355, base_y + 100, id(normal_font), "Outdoor:");
// Temperature
it.print(295, base_y + 150, id(small_icons_font), weather_icon_color, id(material_icons_map)["mdi-thermometer"].c_str());
float temp = id(outdoor_temperature).state;
if (NOT_NAN(temp))
it.printf(355, base_y + 150, id(normal_font), "%.1f°C", temp);
else
it.print(355, base_y + 150, id(normal_font), "---");
// Humidity
it.print(295, base_y + 200, id(small_icons_font), weather_icon_color, id(material_icons_map)["mdi-water-percent"].c_str());
float humidity = id(outdoor_humidity).state;
if (NOT_NAN(humidity))
it.printf(355, base_y + 200, id(normal_font), "%.1f%%", humidity);
else
it.print(355, base_y + 200, id(normal_font), "---");
// Rainfall
it.print(295, base_y + 250, id(small_icons_font), weather_icon_color, id(material_icons_map)["mdi-weather-pouring"].c_str());
float rainfall = id(outdoor_rainfall).state;
if (NOT_NAN(rainfall))
it.printf(355, base_y + 250, id(normal_font), "%.1f mm", rainfall);
else
it.print(355, base_y + 250, id(normal_font), "---");
// Wind strength
it.print(295, base_y + 300, id(small_icons_font), weather_icon_color, id(material_icons_map)["mdi-wind-power-outline"].c_str());
float wind_strength = id(outdoor_wind_strength).state;
if (NOT_NAN(wind_strength))
it.printf(355, base_y + 300, id(normal_font), "%d km/h", (int)wind_strength);
else
it.print(355, base_y + 300, id(normal_font), "---");
// Indoor
it.print(560, base_y + 100, id(small_icons_font), weather_icon_color, id(material_icons_map)["mdi-home-outline"].c_str());
it.print(620, base_y + 100, id(normal_font), "Indoor:");
// Temperature
it.print(560, base_y + 150, id(small_icons_font), weather_icon_color, id(material_icons_map)["mdi-thermometer"].c_str());
temp = id(indoor_temperature).state;
if (NOT_NAN(temp))
it.printf(620, base_y + 150, id(normal_font), "%.1f°C", temp);
else
it.print(620, base_y + 150, id(normal_font), "---");
// Humidity
it.print(560, base_y + 200, id(small_icons_font), weather_icon_color, id(material_icons_map)["mdi-water-percent"].c_str());
humidity = id(indoor_humidity).state;
if (NOT_NAN(humidity))
it.printf(620, base_y + 200, id(normal_font), "%.1f%%", humidity);
else
it.print(620, base_y + 200, id(normal_font), "---");
// Pressure
it.print(560, base_y + 250, id(small_icons_font), weather_icon_color, id(material_icons_map)["mdi-gauge"].c_str());
float pressure = id(indoor_pressure).state;
if (NOT_NAN(pressure))
it.printf(620, base_y + 250, id(normal_font), "%d mbar", (int)pressure);
else
it.print(620, base_y + 250, id(normal_font), "---");
// CO2
it.print(560, base_y + 300, id(small_icons_font), weather_icon_color, id(material_icons_map)["mdi-molecule-co2"].c_str());
float co2 = id(indoor_co2).state;
if (NOT_NAN(co2))
it.printf(620, base_y + 300, id(normal_font), "%d ppm", (int)co2);
else
it.print(620, base_y + 300, id(normal_font), "---");
// Battery
std::string battery_icon = id(material_icons_map)["mdi-battery-unknown"];
float voltage = id(m5paper_battery_voltage).state;
if (voltage > 4.10)
battery_icon = id(material_icons_map)["mdi-battery-charging-high"];
else
{
float battery_level = id(m5paper_battery_level).state;
if (NOT_NAN(battery_level))
{
if (battery_level < 10)
battery_icon = id(material_icons_map)["mdi-battery-alert-variant-outline"];
else if (battery_level < 40)
battery_icon = id(material_icons_map)["mdi-battery-low"];
else if (battery_level < 70)
battery_icon = id(material_icons_map)["mdi-battery-medium"];
else
battery_icon = id(material_icons_map)["mdi-battery-high"];
}
}
it.print(910, 10, id(battery_font), battery_icon.c_str());
// Alarms
Color alarm_enabled;
alarm_enabled.raw_32 = 0x0E;
Color alarm_disabled;
alarm_disabled.raw_32 = 0x03;
// Alarmo
bool alarmo_enabled = false;
std::string al_icon = id(material_icons_map)["mdi-shield-outline"];
std::string al_status = id(alarmo_status).state;
if (al_status == "triggered")
{
al_icon = id(material_icons_map)["mdi-shield-alert-outline"];
alarmo_enabled = true;
}
else
{
std::string al_arm = id(alarmo_mode).state;
if (al_arm == "armed_home")
{
al_icon = id(material_icons_map)["mdi-shield-home-outline"];
alarmo_enabled = true;
}
else if (al_arm == "armed_home")
{
al_icon = id(material_icons_map)["mdi-shield-home-outline"];
alarmo_enabled = true;
}
else if (al_arm == "armed_night")
{
al_icon = id(material_icons_map)["mdi-shield-moon-outline"];
alarmo_enabled = true;
}
else if (al_arm.rfind("armed_", 0) == 0)
{
al_icon = id(material_icons_map)["mdi-shield-lock-outline"];
alarmo_enabled = true;
}
}
it.print(870, 100, id(alarms_font), alarmo_enabled ? alarm_enabled : alarm_disabled, al_icon.c_str());
// Radiation
it.print(870, 190, id(alarms_font), id(radiation_alarm).state ? alarm_enabled : alarm_disabled, id(material_icons_map)["mdi-radioactive"].c_str());
// Lights
std::string lights_icon_id;
float _lights = id(lights_counter).state;
if ((!NOT_NAN(_lights)) || (_lights < 0))
_lights = 0;
int lights = (int)_lights;
if (lights >= 9)
lights_icon_id = "mdi-numeric-9-plus-circle-outline";
else
{
lights_icon_id = "mdi-numeric-0-circle-outline";
lights_icon_id[12] += lights;
}
it.print(870, 280, id(alarms_font), (lights > 0) ? alarm_enabled : alarm_disabled, id(material_icons_map)[lights_icon_id].c_str());
// Rain
unsigned int g_left = 325;
unsigned int g_top = 395;
unsigned int g_width = 600;
unsigned int g_height = 120;
unsigned int max_items = 12;
float max_value = 4.0;
unsigned int item_width = g_width / max_items;
it.rectangle(g_left, g_top, g_width, g_height);
for (int i = 1; i < max_items; i++)
it.line(g_left + item_width * i, g_top, g_left + item_width * i, g_top + g_height);
unsigned int unit_height = (unsigned int) ((float) g_height / max_value);
for (int i = 1; i < max_value; i++)
it.line(g_left, g_top + g_height - i * unit_height, g_left + g_width, g_top + g_height - i * unit_height);
std::string forecast_str = id(precipitation_forecast).state;
size_t pos = 0;
size_t counter = 0;
bool last_item = false;
Color graph_color;
graph_color.raw_32 = 0x0F;
while (!last_item)
{
size_t found = forecast_str.find(",", pos+1);
std::string value_str = "";
if (found != std::string::npos)
{
value_str = forecast_str.substr(pos, found - pos);
pos = found + 1;
}
else
{
value_str = forecast_str.substr(pos);
last_item = true;
}
char *pEnd = NULL;
float value = strtof(value_str.c_str(), &pEnd);
//if (pEnd == NULL)
{
if (value > max_value)
value = max_value;
if (value > 0)
{
unsigned int h = ((max_value - value) / max_value) * g_height;
it.filled_rectangle(g_left + item_width * counter, g_top + h, item_width, g_height - h, graph_color);
}
}
counter++;
if (counter >= max_items)
break;
}
graph:
- id: co2_graph
sensor: indoor_co2
duration: 6h
min_value: 400
max_value: 2400
width: 600
height: 120
x_grid: 1h
y_grid: 500
border: true
touchscreen:
- platform: gt911
display: m5paper_display
id: gt911_touchscreen
interrupt_pin: GPIO36
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
power_save_mode: "HIGH"
switch:
- platform: restart
id: restart_switch
name: ${device_name} Restart
time:
- platform: homeassistant
id: homeassistant_time
timezone: Europe/Paris
on_time_sync:
- bm8563.write_time
- platform: bm8563
id: rtc_time
sleep_duration: 60000ms
on_time:
- seconds: 0
then:
- component.update: m5paper_display
m5paper:
battery_power_pin: GPIO5
main_power_pin: GPIO2
sensor:
- platform: adc
disabled_by_default: true
pin: GPIO35
name: ${device_name} battery voltage
id: m5paper_battery_voltage
update_interval: 10s
attenuation: 11db
filters:
- multiply: 2 #1,27272727
- platform: sht3xd
temperature:
name: ${device_name} temperature
id: m5paper_temperature
device_class: "temperature"
state_class: "measurement"
icon: mdi:thermometer
humidity:
name: ${device_name} humidity
id: m5paper_humidity
device_class: "humidity"
state_class: "measurement"
icon: mdi:water-percent
address: 0x44
update_interval: 10s
- platform: template
name: ${device_name} battery level
id: m5paper_battery_level
unit_of_measurement: '%'
device_class: "battery"
state_class: "measurement"
icon: mdi:battery-high
update_interval: 20s
lambda: |-
constexpr float min_level = 3.52;
constexpr float max_level = 4.15;
return ((id(m5paper_battery_voltage).state - min_level) / (max_level - min_level)) * 100.00;
filters:
- clamp:
min_value: 0
max_value: 100
- platform: homeassistant
name: Outdoor temperature
id: outdoor_temperature
entity_id: ${outdoor_temperature}
- platform: homeassistant
name: Outdoor humidity
id: outdoor_humidity
entity_id: ${outdoor_humidity}
- platform: homeassistant
name: Rainfall last hour
id: outdoor_rainfall
entity_id: ${outdoor_rainfall}
- platform: homeassistant
name: Wind strength
id: outdoor_wind_strength
entity_id: ${outdoor_wind_strength}
- platform: homeassistant
name: Indoor temperature
id: indoor_temperature
entity_id: ${indoor_temperature}
- platform: homeassistant
name: Indoor humidity
id: indoor_humidity
entity_id: ${indoor_humidity}
- platform: homeassistant
name: Indoor pressure
id: indoor_pressure
entity_id: ${indoor_pressure}
- platform: homeassistant
name: Indoor CO2
id: indoor_co2
entity_id: ${indoor_co2}
- platform: homeassistant
name: Lights counter
id: lights_counter
entity_id: ${lights_counter}
text_sensor:
- platform: homeassistant
name: Weather
id: weather_conditions
entity_id: ${weather_conditions}
- platform: homeassistant
name: Sun
id: sun_position
entity_id: sun.sun
- platform: homeassistant
name: Alarmo status
id: alarmo_status
entity_id: ${alarmo_status}
- platform: homeassistant
name: Alarmo mode
id: alarmo_mode
entity_id: ${alarmo_status}
attribute: arm_mode
- platform: homeassistant
name: Forecast
id: precipitation_forecast
entity_id: sensor.precipitation_forecast
attribute: hourly
binary_sensor:
- platform: gpio
name: ${device_name} right button
id: right_button
icon: mdi:gesture-tap-button
pin:
number: GPIO37
inverted: true
on_release:
- component.update: m5paper_display
- platform: gpio
name: ${device_name} BTN/PWR button
icon: mdi:gesture-tap-button
pin:
number: GPIO38
inverted: true
- platform: gpio
name: ${device_name} left button
icon: mdi:gesture-tap-button
pin:
number: GPIO39
inverted: true
- platform: homeassistant
name: Radiation alarm
id: radiation_alarm
entity_id: ${radiation_alarm}