Tu kod ESP, jeszcze nie do końca posprzątany, nazwa projektu myląca bo początkowo miałem to stawiać na ESP8266 ale przy dużej ilości sensorów przestawał działać więc wziąłem esp32 z innego projektu i tak nazwa została.
W planach jeszcze zasilanie bateryjne + usypianie ale to trzeba potestować ile podziała dlatego wskaźnik bateryjki jest.
Do dopracowania jeszcze odświeżanie ekranu bo component.update nie odświeża mojego einka stąd refresh co 10 minut.
Ogólnie jestem totalnym amatorem a w HA “bawię się” jakieś 3-4 miesiące więc z góry przepraszam za mój poziom.
esphome:
name: sony
friendly_name: SONY
on_boot:
priority: 200.0
then:
- component.update: my_display
- wait_until:
condition:
lambda: 'return id(data_updated) == true;'
# Poczekaj trochę dłużej, aby wszystkie elementy zostały odebrane
- delay: 5s
- logger.log: "Odebrano wstępne dane czujnika: Odświeżanie ekranu..."
- lambda: 'id(initial_data_received) = true;'
- script.execute: update_screen
esp32:
board: esp32dev
framework:
type: arduino
external_components:
- source: github://pr#6209
components: [ waveshare_epaper ]
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "###############################"
ota:
password: "#############################"
script:
- id: update_screen
then:
- lambda: 'id(data_updated) = false;'
- component.update: my_display
- lambda: 'id(recorded_display_refresh) += 1;'
- lambda: 'id(display_last_update).publish_state(id(homeassistant_time).now().timestamp);'
time:
- platform: homeassistant
id: homeassistant_time
on_time:
- seconds: 0
minutes: /30
then:
- if:
condition:
lambda: 'return id(data_updated) == true;'
then:
- if:
condition:
binary_sensor.is_on: motion_detected
then:
- logger.log: "Zaktualizowano dane czujnika i wykryto aktywność w domu: odświeżanie wyświetlacza..."
- script.execute: update_screen
else:
- logger.log: "Dane czujnika zostały zaktualizowane, ale w domu brak aktywności – pominięto odświeżanie wyświetlacza."
else:
- logger.log: "Brak aktualizacji czujników – pominięto odświeżanie wyświetlacza."
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
binary_sensor:
- platform: homeassistant
entity_id: binary_sensor.czujnik_ruchu_ias_zone
id: motion_detected
globals:
- id: data_updated
type: bool
restore_value: no
initial_value: 'false'
- id: initial_data_received
type: bool
restore_value: no
initial_value: 'false'
- id: recorded_display_refresh
type: int
restore_value: yes
initial_value: '0'
sensor:
- platform: wifi_signal
name: "WiFi Signal Sensor"
update_interval: 60s
id: sign
- platform: homeassistant
id: humout
entity_id: sensor.tz3000_xr3htd96_ts0201_wilgotnosc
internal: true
- platform: homeassistant
id: tempout
entity_id: sensor.tz3000_xr3htd96_ts0201_sensor_zewnetrzny
internal: true
- platform: homeassistant
id: humsal
entity_id: sensor.sensor_salon_wilgotnosc
internal: true
- platform: homeassistant
id: tempsal
entity_id: sensor.sensor_salon_temperatura
internal: true
- platform: homeassistant
id: tempszym
entity_id: sensor.sensor_szymon_temperatura
internal: true
- platform: homeassistant
id: humszym
entity_id: sensor.sensor_szymon_wilgotnosc_2
internal: true
- platform: homeassistant
id: tempsyp
entity_id: sensor.sensor_sypialnia_temperatura
internal: true
- platform: bmp280
address: 0x77
update_interval: 60s
temperature:
name: "temperatura"
id: temp
oversampling: 2x
accuracy_decimals: 1
internal: true
pressure:
name: "ciśnienie"
id: pres
accuracy_decimals: 0
internal: true
- platform: aht10
variant: aht20
address: 0x38
update_interval: 60s
temperature:
name: "temperatura 2"
id: temp2
accuracy_decimals: 1
internal: true
humidity:
name: "wilgotność"
id: hum
accuracy_decimals: 1
internal: true
- platform: homeassistant
id: templaz
entity_id: sensor.sensor_lazienka_temperatura_2
- platform: homeassistant
id: humlaz
entity_id: sensor.sensor_lazienka_wilgotnosc_2
- platform: template
name: "eink - Czas aktualizacji wyświetlacza"
device_class: timestamp
entity_category: "diagnostic"
id: display_last_update
- platform: template
name: "eink - Zarejestrowane Oswieżanie wyświetlacza"
accuracy_decimals: 0
unit_of_measurement: "Odświeżenia"
state_class: "total_increasing"
entity_category: "diagnostic"
lambda: 'return id(recorded_display_refresh);'
# Weatherman encje
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_temperature_0
id: weather_temperature_0
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_temperature_1
id: weather_temperature_1
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_temperature_2
id: weather_temperature_2
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_temperature_3
id: weather_temperature_3
on_value:
then:
- lambda: 'id(data_updated) = true;'
text_sensor:
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_condition_now
id: weather_condition_now
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_condition_0
id: weather_condition_0
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_timestamp_0
id: weather_timestamp_0
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_condition_1
id: weather_condition_1
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_timestamp_1
id: weather_timestamp_1
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_datestamp_1
id: weather_datestamp_1
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_condition_2
id: weather_condition_2
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_timestamp_2
id: weather_timestamp_2
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_datestamp_2
id: weather_datestamp_2
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_condition_3
id: weather_condition_3
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_timestamp_3
id: weather_timestamp_3
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_datestamp_3
id: weather_datestamp_3
on_value:
then:
- lambda: 'id(data_updated) = true;'
color:
- id: wh20
white: 20%
- id: wh40
white: 40%
- id: wh60
white: 100%
- id: wh0
white: 0%
font:
- file: "arial.ttf"
id: font1
size: 28
- file: "arialbd.ttf"
id: font1b
size: 28
- file: "ariali.ttf"
id: font1i
size: 24
- file: "arial.ttf"
id: font2
size: 20
- file: "arialbd.ttf"
id: font2b
size: 20
- file: "arialbd.ttf"
id: font3b
size: 56
- file: "arial.ttf"
id: font3
size: 56
- file: "arialbd.ttf"
id: font4
size: 16
- file: 'fonts/materialdesignicons-webfont.ttf'
id: font_mdi_large
size: 110
glyphs: &mdi-weather-glyphs
- "\U000F0590" # mdi-weather-cloudy
- "\U000F0F2F" # mdi-weather-cloudy-alert
- "\U000F0E6E" # mdi-weather-cloudy-arrow-right
- "\U000F0591" # mdi-weather-fog
- "\U000F0592" # mdi-weather-hail
- "\U000F0F30" # mdi-weather-hazy
- "\U000F0898" # mdi-weather-hurricane
- "\U000F0593" # mdi-weather-lightning
- "\U000F067E" # mdi-weather-lightning-rainy
- "\U000F0594" # mdi-weather-clear-night
- "\U000F0F31" # mdi-weather-night-partly-cloudy
- "\U000F0595" # mdi-weather-partly-cloudy
- "\U000F0F32" # mdi-weather-partly-lightning
- "\U000F0F33" # mdi-weather-partly-rainy
- "\U000F0F34" # mdi-weather-partly-snowy
- "\U000F0F35" # mdi-weather-partly-snowy-rainy
- "\U000F0596" # mdi-weather-pouring
- "\U000F0597" # mdi-weather-rainy
- "\U000F0598" # mdi-weather-snowy
- "\U000F0F36" # mdi-weather-snowy-heavy
- "\U000F067F" # mdi-weather-snowy-rainy
- "\U000F0599" # mdi-weather-sunny
- "\U000F0F37" # mdi-weather-sunny-alert
- "\U000F14E4" # mdi-weather-sunny-off
- "\U000F059A" # mdi-weather-sunset
- "\U000F059B" # mdi-weather-sunset-down
- "\U000F059C" # mdi-weather-sunset-up
- "\U000F0F38" # mdi-weather-tornado
- "\U000F059D" # mdi-weather-windy
- "\U000F059E" # mdi-weather-windy-variant
- "\U000F058E" # mdi-water-percent
- "\U000F04C5" # mdi-spedometer
- "\U000F0F29" # mdi-snowflake-alert
- "\U000F15FA" # mdi-windsock
- file: 'fonts/materialdesignicons-webfont.ttf'
id: font_mdi_mid
size: 60
glyphs: *mdi-weather-glyphs
spi:
clk_pin: 33
mosi_pin: 25
i2c:
sda: 17
scl: 16
scan: True
frequency: 50kHz
image:
- file: "icons/dbed32.bmp"
id: dbed
- file: "icons/living32.bmp"
id: living
- file: "icons/bed32.bmp"
id: bed
- file: "icons/bath32.bmp"
id: laz
display:
- platform: waveshare_epaper
id: my_display
cs_pin: 27
dc_pin: 32
busy_pin: 12
reset_pin: 14
model: 4.20in-v2
rotation: 90
reset_duration: 2ms
update_interval: 10min
lambda: |-
// 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"},
{"clear-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"},
};
//zmiana numeru miesiąca na skrotowa nazwe
std::map<std::string, std::string> mies_map
{
{"1", "sty"},
{"2", "lut"},
{"3", "mar"},
{"4", "kwi"},
{"5", "maj"},
{"6", "cze"},
{"7", "lip"},
{"8", "sie"},
{"9", "wrz"},
{"10", "paz"},
{"11", "lis"},
{"12", "gru"},
};
// Wskaźnik WIFI
int x=(int)id(sign).state;
if ((x>-90) && (x<0)) it.filled_rectangle( 278,394,4,4, id(wh60)); else it.rectangle( 278,394,4,4, id(wh60));
if ((x>-70) && (x<0)) it.filled_rectangle( 283,392,4,6, id(wh60)); else it.rectangle( 283,392,4,6, id(wh60));
if ((x>-55) && (x<0)) it.filled_rectangle( 288,389,4,9, id(wh60)); else it.rectangle(288,389,4,9, id(wh60));
if ((x>-40) && (x<0)) it.filled_rectangle( 293,386,4,12, id(wh60)); else it.rectangle(293,386,4,12, id(wh60));
// duża ikona pogody
it.printf(299, 10, id(font_mdi_large), TextAlign::TOP_RIGHT, "%s", weather_icon_map[id(weather_condition_now).state.c_str()].c_str());
// ikonki prognozy
if(id(weather_temperature_1).has_state ()) {
it.printf(64, 159, id(font_mdi_mid), TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_1).state.c_str()].c_str());
it.printf(64, 145, id(font2b), TextAlign::TOP_CENTER, "%2.0f°C", id(weather_temperature_1).state);
it.printf(58, 215, id(font4), TextAlign::TOP_RIGHT, "%s", id(weather_timestamp_1).state.c_str());
it.printf(60, 215, id(font4), TextAlign::TOP_LEFT, "%s", mies_map[id(weather_datestamp_1).state.c_str()].c_str());
}
if(id(weather_temperature_2).has_state ()) {
it.printf(149, 159, id(font_mdi_mid), TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_2).state.c_str()].c_str());
it.printf(149, 145, id(font2b), TextAlign::TOP_CENTER, "%2.0f°C", id(weather_temperature_2).state);
it.printf(143, 215, id(font4), TextAlign::TOP_RIGHT, "%s", id(weather_timestamp_2).state.c_str());
it.printf(145, 215, id(font4), TextAlign::TOP_LEFT, "%s", mies_map[id(weather_datestamp_2).state.c_str()].c_str());
}
if(id(weather_temperature_3).has_state ()) {
it.printf(234, 159, id(font_mdi_mid), TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_3).state.c_str()].c_str());
it.printf(234, 145, id(font2b), TextAlign::TOP_CENTER, "%2.0f°C", id(weather_temperature_3).state);
it.printf(228, 215, id(font4), TextAlign::TOP_RIGHT, "%s", id(weather_timestamp_3).state.c_str());
it.printf(230, 215, id(font4), TextAlign::TOP_LEFT, "%s", mies_map[id(weather_datestamp_3).state.c_str()].c_str());
}
// BATERYJKA
it.line(0,383,299, 383, COLOR_ON);
it.rectangle(3,387,20, 12, COLOR_ON);
it.rectangle(22,389,4, 8, COLOR_ON);
// Temperatura czujnik zewnętrzny
if (id(tempout).has_state()) {
it.printf(130, -5, id(font3b), TextAlign::TOP_RIGHT, "%.1f", id(tempout).state);
}
// znaczek C maly
it.printf(130,0, id(font1b), TextAlign::TOP_LEFT, "°C");
// wilgotnosc czujnik zewnetrzny
if (id(humout).has_state()) {
it.printf(130, 45, id(font3), TextAlign::TOP_RIGHT, "%.1f", id(humout).state);
}
//znaczek % maly
it.printf(134,50, id(font1b), TextAlign::TOP_LEFT, "%%");
// cisnienie czujnik w stacji
if (id(pres).has_state()) {
it.printf(130, 100, id(font2), TextAlign::TOP_RIGHT, "%.0f hPa", id(pres).state);
}
// ikona pokoj Szymona
it.image(133,316,id(bed));
// temperatura pok Szymona
if (id(tempszym).has_state()) {
it.printf(122, 318, id(font1i), TextAlign::TOP_RIGHT, "%.1f°C", id(tempszym).state);
}
// wilgotnosc pok Szymona
if (id(humszym).has_state()) {
it.printf(177, 318, id(font1i), TextAlign::TOP_LEFT, "%.1f%%", id(humszym).state);
}
// ikonka salon
it.image(133,248,id(living));
// temperatura czujnik w stacji
if (id(temp2).has_state()) {
it.printf(122, 250, id(font1i), TextAlign::TOP_RIGHT, "%.1f°C", id(temp2).state);
}
// wilgotnosc czujnik salon
if (id(humsal).has_state()) {
it.printf(177, 250, id(font1i), TextAlign::TOP_LEFT, "%.1f%%", id(humsal).state);
}
// ikonka sypialnia
it.image(133,282,id(dbed));
// temperatura czujnik sypialnia
if (id(tempsyp).has_state()) {
it.printf(122, 284, id(font1i), TextAlign::TOP_RIGHT, "%.1f°C", id(tempsyp).state);
}
// wilgotnosc czujnik w stacji
if (id(hum).has_state()) {
it.printf(177, 284, id(font1i), TextAlign::TOP_LEFT, "%.1f%%", id(hum).state);
}
// ikonka lazienka
it.image(133,350,id(laz));
// temperatura czujnik lazienka
if (id(templaz).has_state()) {
it.printf(122, 352, id(font1i), TextAlign::TOP_RIGHT, "%.1f°C", id(templaz).state);
}
// wilgotnosc czujnik w lazienka
if (id(humlaz).has_state()) {
it.printf(177, 352, id(font1i), TextAlign::TOP_LEFT, "%.1f%%", id(humlaz).state);
}
Config HA:
template:
- binary_sensor:
- name: Weatherman Motion Detected
unique_id: "dfa78de7-d761-425f-9731-86f1af332eac"
device_class: "occupancy"
delay_off: 1min
state: >-
{%- if states('input_boolean.eink_czujnik_ruchu') == 'on' %}
on
{%- else -%}
off
{%- endif -%}
- trigger:
platform: time_pattern
minutes: "/1"
action:
- service: weather.get_forecasts
data:
type: daily
target:
entity_id: weather.forecast_home
response_variable: daily
sensor:
- name: Weatherman Data
state: "OK"
attributes:
weather_condition_now: >
{% set cond_now = states('weather.forecast_home') %}
{% if states('sun.sun') == 'below_horizon' %}
{% if cond_now == 'sunny' %} clear-night {% elif cond_now == 'partlycloudy' %} night-partly-cloudy {% else %} {{ cond_now }} {% endif %}
{% else %}
{{ cond_now }}
{% endif %}
weather_condition_0: >
{% set cond0 = daily["weather.forecast_home"].forecast[0].condition %}
{% set next_setting = as_timestamp(state_attr('sun.sun', 'next_setting')) %}
{% set next_rising = as_timestamp(state_attr('sun.sun', 'next_rising')) %}
{% set cond0_time = as_timestamp(daily["weather.forecast_home"].forecast[0].datetime) %}
{% if cond0_time < next_rising and next_rising < next_setting %}
{% if cond0 == 'sunny' %} clear-night {% elif cond0 == 'partlycloudy' %} night-partly-cloudy {% else %} {{ cond0 }} {% endif %}
{% else %}
{{ cond0 }}
{% endif %}
weather_temperature_0: >
{{ daily["weather.forecast_home"].forecast[0].temperature | round }}
weather_timestamp_0: >
{{ as_timestamp(daily["weather.forecast_home"].forecast[0].datetime) | timestamp_custom('%d') | int }}
weather_condition_1: >
{% set cond1 = daily["weather.forecast_home"].forecast[1].condition %}
{% set next_setting = as_timestamp(state_attr('sun.sun', 'next_setting')) %}
{% set next_rising = as_timestamp(state_attr('sun.sun', 'next_rising')) %}
{% set cond1_time = as_timestamp(daily["weather.forecast_home"].forecast[1].datetime) %}
{% if cond1_time < next_rising and next_rising < next_setting %}
{% if cond1 == 'sunny' %} clear-night {% elif cond1 == 'partlycloudy' %} night-partly-cloudy {% else %} {{ cond1 }} {% endif %}
{% else %}
{{ cond1 }}
{% endif %}
weather_temperature_1: >
{{ daily["weather.forecast_home"].forecast[1].temperature | round }}
weather_timestamp_1: >
{{ as_timestamp(daily["weather.forecast_home"].forecast[1].datetime) | timestamp_custom('%d') | int }}
weather_datestamp_1: >
{{ as_timestamp(daily["weather.forecast_home"].forecast[1].datetime) | timestamp_custom('%m') | int }}
weather_condition_2: >
{% set cond2 = daily["weather.forecast_home"].forecast[2].condition %}
{% set next_setting = as_timestamp(state_attr('sun.sun', 'next_setting')) %}
{% set next_rising = as_timestamp(state_attr('sun.sun', 'next_rising')) %}
{% set cond2_time = as_timestamp(daily["weather.forecast_home"].forecast[2].datetime) %}
{% if cond2_time < next_rising and next_rising < next_setting %}
{% if cond2 == 'sunny' %} clear-night {% elif cond2 == 'partlycloudy' %} night-partly-cloudy {% else %} {{ cond2 }} {% endif %}
{% else %}
{{ cond2 }}
{% endif %}
weather_temperature_2: >
{{ daily["weather.forecast_home"].forecast[2].temperature | round }}
weather_timestamp_2: >
{{ as_timestamp(daily["weather.forecast_home"].forecast[2].datetime) | timestamp_custom('%d') | int }}
weather_datestamp_2: >
{{ as_timestamp(daily["weather.forecast_home"].forecast[2].datetime) | timestamp_custom('%m') | int }}
weather_condition_3: >
{% set cond3 = daily["weather.forecast_home"].forecast[3].condition %}
{% set next_setting = as_timestamp(state_attr('sun.sun', 'next_setting')) %}
{% set next_rising = as_timestamp(state_attr('sun.sun', 'next_rising')) %}
{% set cond3_time = as_timestamp(daily["weather.forecast_home"].forecast[3].datetime) %}
{% if cond3_time < next_rising and next_rising < next_setting %}
{% if cond3 == 'sunny' %} clear-night {% elif cond3 == 'partlycloudy' %} night-partly-cloudy {% else %} {{ cond3 }} {% endif %}
{% else %}
{{ cond3 }}
{% endif %}
weather_temperature_3: >
{{ daily["weather.forecast_home"].forecast[3].temperature | round }}
weather_timestamp_3: >
{{ as_timestamp(daily["weather.forecast_home"].forecast[3].datetime) | timestamp_custom('%d') | int }}
weather_datestamp_3: >
{{ as_timestamp(daily["weather.forecast_home"].forecast[3].datetime) | timestamp_custom('%m') | int }}