diff --git a/esphome/epaperframe.yaml b/esphome/epaperframe.yaml new file mode 100644 index 0000000..565eb01 --- /dev/null +++ b/esphome/epaperframe.yaml @@ -0,0 +1,388 @@ +esphome: + name: epaperframe + platform: ESP32 + board: nodemcu-32s + on_boot: + priority: -10 + then: + - delay: 10s + - component.update: epaper + +wifi: + ssid: "Voltage-legacy" + password: !secret voltage_legacy_psk + use_address: epaperframe.home + power_save_mode: high + fast_connect: on + + # Enable fallback hotspot (captive portal) in case wifi connection fails + ap: + ssid: "Epaperframe Fallback Hotspot" + password: !secret fallback_psk + +captive_portal: + +# Enable logging +logger: + +# Enable Home Assistant API +api: + password: !secret api + encryption: + key: !secret apikey + +ota: + password: !secret ota + +# Refresh screen on button click +binary_sensor: + - platform: gpio + pin: + number: GPIO18 + mode: INPUT_PULLUP + inverted: True + name: "Refresh screen" + internal: True + on_click: + then: + - logger.log: + level: INFO + format: 'Button pressed, refreshing screen!' + - component.update: epaper + +# DHT22 sensor +sensor: + - platform: dht + model: dht22 + pin: 22 + temperature: + name: "Temperatur" + humidity: + name: "Luftfeuchtigkeit" + update_interval: 60s + + # WiFi signal strength + - platform: wifi_signal + name: "WiFi Signalstärke" + id: wifisignal + update_interval: 60s + + - platform: homeassistant + entity_id: sensor.wohnzimmer_feinstaub_pm_2_5um + id: pm25_livingroom + + - platform: homeassistant + entity_id: sensor.wohnzimmer_temperatur + id: temp_livingroom + + - platform: homeassistant + entity_id: sensor.wohnzimmer_luftfeuchtigkeit + id: humid_livingroom + + - platform: homeassistant + entity_id: sensor.temperatur_aussen + id: temp_outdoor + + - platform: homeassistant + entity_id: sensor.luftfeuchtigkeit_aussen + id: humid_outdoor + + - platform: homeassistant + entity_id: sensor.schlafzimmer_luftdruck + id: airpressure + + - platform: homeassistant + entity_id: zone.home + attribute: latitude + id: home_lat + + - platform: homeassistant + entity_id: zone.home + attribute: longitude + id: home_long + +text_sensor: + - platform: homeassistant + entity_id: sun.sun + id: sun_state + internal: True + +# - platform: homeassistant +# entity_id: sun.sun +# id: sun_rise +# attribute: next_rising +# internal: True + +# - platform: homeassistant +# entity_id: sun.sun +# id: sun_set +# attribute: next_setting +# internal: True + + - platform: sun + name: "Nächster Sonnenaufgang" + id: sun_rise + type: sunrise + format: "%H:%M" + internal: True + + - platform: sun + name: "Nächster Sonnenuntergang" + id: sun_set + type: sunset + format: "%H:%M" + internal: True + +# Webserver configuration entry +web_server: + port: 80 +# css_include: "esphome-docs/_static/webserver-v1.min.css" +# css_url: "" +# js_include: "../../../esphome-docs/_static/webserver-v1.min.js" +# js_url: "" + auth: + username: admin + password: !secret web_server_password + +sun: + latitude: id(home_lat) + longitude: id(home_long) + id: sun_sun + +time: + - platform: homeassistant + id: homeassistant_time + +# Font definitions +font: + - file: 'fonts/Roboto-Medium.ttf' + id: roboto_med_30 + size: 30 + + - file: 'fonts/Roboto-Regular.ttf' + id: footer_font + size: 15 + 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: big_sensor_unit + size: 20 + 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-Medium.ttf' + id: sub_sensor_font + size: 30 + 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-Bold.ttf' + id: big_sensor_font + size: 80 + + - file: 'fonts/materialdesignicons-webfont.ttf' + id: mdi_small + size: 31 + glyphs: [ + '󰔏', # mdi-themometer + '󰖎', # mdi-water-percent + '󰂵', # mdi-blur (pm2.5) + '󰟤', # mdi-co2 + '󰊚', # mdi-gauge (air pressure) + '󰖙', # mdi-weather-sunny + '󰖛', # mdi-weather-sunset-down + '󰖜', # mdi-weather-sunset-up + '󰽡', # mdi-moon-first-quarter + '󰽢', # mdi-moon-full + '󰽣', # mdi-moon-last-quarter + '󰽤', # mdi-moon-new + '󰽥', # mdi-moon-waning-crescent + '󰽦', # mdi-moon-waning-gibbous + '󰽧', # mdi-moon-waxing-crescent + '󰽨', # mdi-moon-waxing-gibbous + ] + + - file: 'fonts/materialdesignicons-webfont.ttf' + id: mdi_wifi + size: 20 + glyphs: [ + # Wifi + '󰤫', # mdi-wifi-strength-alert-outline + '󰤟', # mdi-wifi-strength-1 + '󰤢', # mdi-wifi-strength-2 + '󰤥', # mdi-wifi-strength-3 + '󰤨' # mdi-wifi-strength-4 + ] + + - file: 'fonts/materialdesignicons-webfont.ttf' + id: mdi_med + size: 33 + glyphs: [ + '󰀦' # mdi-alert + ] + +spi: + clk_pin: 23 + mosi_pin: 32 + +display: + - platform: waveshare_epaper + id: epaper + cs_pin: 27 + dc_pin: 26 + busy_pin: 33 + reset_pin: 25 + model: 7.50in + # full_update_every: 30 # not supported on this display + update_interval: never + lambda: |- + + int pm25_danger_thres = 40; + + float outdoor_temp = id(temp_outdoor).state; + int outdoor_humid = int(id(humid_outdoor).state); + float air_pressure = id(airpressure).state; + float livingroom_temp = id(temp_livingroom).state; + int livingroom_humid = int(id(humid_livingroom).state); + int livingroom_pm25 = int(id(pm25_livingroom).state); + + // Format: 2021-10-08T05:40:47.467076+00:00 + //struct tm tm; + //strptime(id(sun_rise).state.c_str(), '%Y-%m-%dT%H:%M:%S.%f%z'); + //std::string sunrise = printf("%d:%d", tm.tm_hour, tm.tm_min); + + /* OUTSIDE */ + it.print(10, 10, id(big_sensor_unit), "Umwelt"); + // Draw the outline of a rectangle with the top left at [78,21], a width of 305 and a height of 3 + it.filled_rectangle(78, 21, 305, 3); + if(id(sun_state).has_state()) { + ESP_LOGI("Sun", "State of the sun: %s", id(sun_state).state.c_str()); + ESP_LOGD("Sun", "Sunset: %s", id(sun_set).state.c_str()); + ESP_LOGD("Sun", "Sunrise ESPHOME: %s", id(sun_rise).state.c_str()); + //ESP_LOGD("Sun", "Sunrise ESPHOME: %s, Sunrise HA: %s", id(sun_rise).state.c_str(), sunrise.c_str()); + //ESP_LOGD("Location", "Latitude: %f, Longitude: %f", id(home_lat).state, id(home_long).state); + + //if(id(sun_state).state == "above_horizon") { + it.print(10, 75, id(mdi_small), TextAlign::BASELINE_LEFT, "󰖜"); //sun-up + it.printf(50, 75, id(sub_sensor_font), TextAlign::BASELINE_LEFT, "%s", id(sun_rise).state.c_str()); + it.print(135, 75, id(mdi_small), TextAlign::BASELINE_LEFT, "󰖛"); //sun-down + it.printf(175, 75, id(sub_sensor_font), TextAlign::BASELINE_LEFT, "%s", id(sun_set).state.c_str()); + //it.strftime(50, 75, id(footer_font), TextAlign::BASELINE_LEFT, "Nächster Sonnenuntergang %d.%m.%Y %H:%M", id(sun_set).state.c_str()); + //} + //else { + //it.print(10, 75, id(mdi_small), TextAlign::BASELINE_LEFT, "󰖛"); //sun-down + //it.strftime(50, 75, id(footer_font), TextAlign::BASELINE_LEFT, "Nächster Sonnenaufgang %d.%m.%Y %H:%M", id(sun_rise)); + //} + } + it.print(10, 115, id(mdi_small), TextAlign::BASELINE_LEFT, "󰊚"); //air-pressure + it.print(375, 75, id(mdi_small), TextAlign::BASELINE_CENTER, "󰔏"); //thermometer + it.print(375, 115, id(mdi_small), TextAlign::BASELINE_CENTER, "󰖎"); //water-percent + + if(outdoor_temp > -100 && outdoor_temp < 100) { + it.printf(357, 75, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, "%2.1fºC", outdoor_temp); + } + else { + it.print(357, 75, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, " - ºC"); + } + + if(outdoor_humid >=0 && outdoor_humid <= 100) { + it.printf(357, 115, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, "%3d%%", outdoor_humid); + } + else { + it.print(357, 115, id(sub_sensor_font), TextAlign::BASELINE_RIGHT, " - %"); + } + + if(air_pressure < 1200 && air_pressure >=800) { //Has valid value + it.printf(50, 115, id(sub_sensor_font), TextAlign::BASELINE_LEFT, "%4.1fhPa", air_pressure); + } + else { //Invalid or error value + it.print(50, 115, id(sub_sensor_font), TextAlign::BASELINE_LEFT, "- hPa"); + } + + /* INSIDE */ + + int offsetY = 137; + it.print(10, 10 + offsetY, id(big_sensor_unit), "INSIDE"); + it.filled_rectangle(78, 21 + offsetY, 305, 3); + it.print(10, 114 + offsetY, id(big_sensor_unit), TextAlign::BASELINE_LEFT, "PM2.5"); + it.print(375, 75 + offsetY, id(mdi_small), TextAlign::BASELINE_CENTER, "󰔏"); //thermometer + it.print(375, 115 + offsetY, id(mdi_small), TextAlign::BASELINE_CENTER, "󰖎"); //water-percent + + if(livingroom_temp > -100 && livingroom_temp < 100){ + it.printf(357, 75 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT , "%2.1fºC", livingroom_temp); + }else{ + it.print(357, 75 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT , " - ºC"); + } + + if(livingroom_humid >=0 && livingroom_humid <= 100){ + it.printf(357, 115 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT , "%3d%%", livingroom_humid); + }else{ + it.print(357, 115 + offsetY, id(sub_sensor_font), TextAlign::BASELINE_RIGHT , " - %"); + } + + + if(livingroom_pm25 < 255 && livingroom_pm25 >=0){ + if (livingroom_pm25 > 99){ + it.printf(205, 114 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT , "%3d", livingroom_pm25); + it.print(210, 114 + offsetY, id(big_sensor_unit),TextAlign::BASELINE_LEFT, "µg/m³"); + }else{ + it.printf(175, 114 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT , "%2d", livingroom_pm25); + it.print(180, 114 + offsetY, id(big_sensor_unit),TextAlign::BASELINE_LEFT, "µg/m³"); + } + + if(livingroom_pm25 >= pm25_danger_thres){ + it.print(37, 87 + offsetY, id(mdi_med), TextAlign::BASELINE_CENTER, "󰀦"); //warning + } + + } + else{ + it.print(175, 114 + offsetY, id(big_sensor_font), TextAlign::BASELINE_RIGHT , "- "); + it.print(180, 114 + offsetY, id(big_sensor_unit),TextAlign::BASELINE_LEFT, "µg/m³"); + } + + + /* FOOTER */ + it.strftime(610, 374 , id(footer_font), TextAlign::BASELINE_RIGHT , "Letzte Aktualisierung %d.%m.%Y %H:%M", id(homeassistant_time).now()); + + /* WiFi Signal Strenght */ + if(id(wifisignal).has_state()) { + int x = 626; + int y = 376; + if (id(wifisignal).state >= -50) { + //Excellent + it.print(x, y, id(mdi_wifi), TextAlign::BASELINE_CENTER, "󰤨"); + ESP_LOGI("WiFi", "Excellent"); + } else if (id(wifisignal).state >= -60) { + //Good + it.print(x, y, id(mdi_wifi), TextAlign::BASELINE_CENTER, "󰤥"); + ESP_LOGI("WiFi", "Good"); + } else if (id(wifisignal).state >= -75) { + //Fair + it.print(x, y, id(mdi_wifi), TextAlign::BASELINE_CENTER, "󰤢"); + ESP_LOGI("WiFi", "Fair"); + } else if (id(wifisignal).state >= -100) { + //Weak + it.print(x, y, id(mdi_wifi), TextAlign::BASELINE_CENTER, "󰤟"); + ESP_LOGI("WiFi", "Weak"); + } else { + //Unlikely working signal + it.print(x, y, id(mdi_wifi), TextAlign::BASELINE_CENTER, "󰤫"); + ESP_LOGI("WiFi", "Unlikely"); + } + } diff --git a/esphome/fonts/Roboto-Black.ttf b/esphome/fonts/Roboto-Black.ttf new file mode 100644 index 0000000..2d45238 Binary files /dev/null and b/esphome/fonts/Roboto-Black.ttf differ diff --git a/esphome/fonts/Roboto-BlackItalic.ttf b/esphome/fonts/Roboto-BlackItalic.ttf new file mode 100644 index 0000000..29a4359 Binary files /dev/null and b/esphome/fonts/Roboto-BlackItalic.ttf differ diff --git a/esphome/fonts/Roboto-Bold.ttf b/esphome/fonts/Roboto-Bold.ttf new file mode 100644 index 0000000..d998cf5 Binary files /dev/null and b/esphome/fonts/Roboto-Bold.ttf differ diff --git a/esphome/fonts/Roboto-BoldItalic.ttf b/esphome/fonts/Roboto-BoldItalic.ttf new file mode 100644 index 0000000..b4e2210 Binary files /dev/null and b/esphome/fonts/Roboto-BoldItalic.ttf differ diff --git a/esphome/fonts/Roboto-Italic.ttf b/esphome/fonts/Roboto-Italic.ttf new file mode 100644 index 0000000..5b390ff Binary files /dev/null and b/esphome/fonts/Roboto-Italic.ttf differ diff --git a/esphome/fonts/Roboto-Light.ttf b/esphome/fonts/Roboto-Light.ttf new file mode 100644 index 0000000..3526798 Binary files /dev/null and b/esphome/fonts/Roboto-Light.ttf differ diff --git a/esphome/fonts/Roboto-LightItalic.ttf b/esphome/fonts/Roboto-LightItalic.ttf new file mode 100644 index 0000000..46e9bf7 Binary files /dev/null and b/esphome/fonts/Roboto-LightItalic.ttf differ diff --git a/esphome/fonts/Roboto-Medium.ttf b/esphome/fonts/Roboto-Medium.ttf new file mode 100644 index 0000000..f714a51 Binary files /dev/null and b/esphome/fonts/Roboto-Medium.ttf differ diff --git a/esphome/fonts/Roboto-MediumItalic.ttf b/esphome/fonts/Roboto-MediumItalic.ttf new file mode 100644 index 0000000..5dc6a2d Binary files /dev/null and b/esphome/fonts/Roboto-MediumItalic.ttf differ diff --git a/esphome/fonts/Roboto-Regular.ttf b/esphome/fonts/Roboto-Regular.ttf new file mode 100644 index 0000000..2b6392f Binary files /dev/null and b/esphome/fonts/Roboto-Regular.ttf differ diff --git a/esphome/fonts/Roboto-Thin.ttf b/esphome/fonts/Roboto-Thin.ttf new file mode 100644 index 0000000..4e797cf Binary files /dev/null and b/esphome/fonts/Roboto-Thin.ttf differ diff --git a/esphome/fonts/Roboto-ThinItalic.ttf b/esphome/fonts/Roboto-ThinItalic.ttf new file mode 100644 index 0000000..eea836f Binary files /dev/null and b/esphome/fonts/Roboto-ThinItalic.ttf differ diff --git a/esphome/fonts/materialdesignicons-webfont.ttf b/esphome/fonts/materialdesignicons-webfont.ttf new file mode 100644 index 0000000..5545629 Binary files /dev/null and b/esphome/fonts/materialdesignicons-webfont.ttf differ