├── images └── background.png ├── fonts ├── GothamRnd-Bold.ttf ├── GothamRnd-Book.ttf └── materialdesigniconswebfont.ttf ├── eink_dashboard_sensor.yaml ├── README_zh-tw.md ├── README.md └── eink-weather-board.yaml /images/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xangin/eink-weather-board/HEAD/images/background.png -------------------------------------------------------------------------------- /fonts/GothamRnd-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xangin/eink-weather-board/HEAD/fonts/GothamRnd-Bold.ttf -------------------------------------------------------------------------------- /fonts/GothamRnd-Book.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xangin/eink-weather-board/HEAD/fonts/GothamRnd-Book.ttf -------------------------------------------------------------------------------- /fonts/materialdesigniconswebfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xangin/eink-weather-board/HEAD/fonts/materialdesigniconswebfont.ttf -------------------------------------------------------------------------------- /eink_dashboard_sensor.yaml: -------------------------------------------------------------------------------- 1 | ########################################################### 2 | ## 3 | ## Weather Forecast Sensors 4 | ## !!Only for HA 2023.12.0 or later 5 | ## 6 | ########################################################### 7 | template: 8 | - trigger: 9 | # update interval for the forecast 10 | # every hour at 1 min will get forecast 11 | # ex: 10:01, 11:01, 12:01 ... 12 | - platform: time_pattern 13 | hours: "/1" 14 | minutes: 1 15 | action: 16 | - service: weather.get_forecasts 17 | target: 18 | entity_id: weather.myhome #replace with your weather forecast entity id 19 | data: 20 | type: hourly #make sure your weather entity support hourly forecast 21 | response_variable: hourly 22 | sensor: 23 | - name: "eink_sensors" 24 | unique_id: eink_sensors 25 | # use forecast[0] as this hour's weather condition 26 | # replace below 'weather.myhome' with your weather forecast entity id 27 | # The today_precipitation field should be populated based on the attribute name provided by the weather forecast service. 28 | state: > 29 | {{ hourly['weather.myhome'].forecast[0].condition }} 30 | attributes: 31 | today_temperature: > 32 | {{ hourly['weather.myhome'].forecast[0].temperature | round }}°C 33 | today_humidity: > 34 | {{ hourly['weather.myhome'].forecast[0].humidity | round }}% 35 | today_precipitation: > 36 | {{ hourly['weather.myhome'].forecast[0].precipitation_probability | round }}% 37 | 38 | forecast_weekday_1: > 39 | {{ as_timestamp(hourly['weather.myhome'].forecast[1].datetime) | timestamp_custom('%I') | int }}{{ as_timestamp(hourly['weather.myhome'].forecast[1].datetime) | timestamp_custom('%p') }} 40 | forecast_condition_1: > 41 | {{ hourly['weather.myhome'].forecast[1].condition }} 42 | forecast_temperature_1: > 43 | {{ hourly['weather.myhome'].forecast[1].temperature | round }}° 44 | 45 | forecast_weekday_2: > 46 | {{ as_timestamp(hourly['weather.myhome'].forecast[2].datetime) | timestamp_custom('%I') | int }}{{ as_timestamp(hourly['weather.myhome'].forecast[2].datetime) | timestamp_custom('%p') }} 47 | forecast_condition_2: > 48 | {{ hourly['weather.myhome'].forecast[2].condition }} 49 | forecast_temperature_2: > 50 | {{ hourly['weather.myhome'].forecast[2].temperature | round }}° 51 | 52 | forecast_weekday_3: > 53 | {{ as_timestamp(hourly['weather.myhome'].forecast[3].datetime) | timestamp_custom('%I') | int }}{{ as_timestamp(hourly['weather.myhome'].forecast[3].datetime) | timestamp_custom('%p') }} 54 | forecast_condition_3: > 55 | {{ hourly['weather.myhome'].forecast[3].condition }} 56 | forecast_temperature_3: > 57 | {{ hourly['weather.myhome'].forecast[3].temperature | round }}° 58 | 59 | forecast_weekday_4: > 60 | {{ as_timestamp(hourly['weather.myhome'].forecast[4].datetime) | timestamp_custom('%I') | int }}{{ as_timestamp(hourly['weather.myhome'].forecast[4].datetime) | timestamp_custom('%p') }} 61 | forecast_condition_4: > 62 | {{ hourly['weather.myhome'].forecast[4].condition }} 63 | forecast_temperature_4: > 64 | {{ hourly['weather.myhome'].forecast[4].temperature | round }}° 65 | 66 | -------------------------------------------------------------------------------- /README_zh-tw.md: -------------------------------------------------------------------------------- 1 | # ESPHome E-ink Weather board 2 | 3 | Buy Me A Coffee 4 | 5 | [English](https://github.com/xangin/eink-weather-board/blob/main/README.md) | 正體中文 6 | 7 | 感謝[Madelena](https://github.com/Madelena/esphome-weatherman-dashboard/)提供本專案硬體架構與程式碼的發想 8 | 9 | Thanks [Madelena](https://github.com/Madelena/esphome-weatherman-dashboard/) for inspired this project ideas and source code of weather data 10 | 11 | 本專案為直式的E-ink天氣預報資訊板放在玄關處,在指定的時段內每格固定,會自動更新顯示內容 12 | 13 | 另有橫式除了天氣資訊外,還能將個房間的溫濕度等資訊顯示在E-ink上: [E-ink Dashboard](https://github.com/xangin/esphome-eink-dashboard) 14 | 15 | 16 | 17 | 直式天氣資訊板顯示內容包括: 18 | - 今天日期 19 | - 當下天氣預報 20 | - 未來四小時天氣預報 21 | 22 | 23 | 24 | 以下將說明硬體架構、ESPHome yaml code與Home assistant yaml code 25 | 26 | ## Hardware 硬體架構 27 | 28 | - [微雪 7.5吋黑白墨水屏裸屏](https://detail.tmall.com/item.htm?id=606005913066) - 不帶外殼 29 | - [微雪 墨水屏裸屏 SPI驅動板 ESP32](https://detail.tmall.com/item.htm?id=605757128869) - wifi+藍牙版本(ESP32) 30 | - [IKEA RÖDALM 相框 13x18公分](https://www.ikea.com.tw/zh/products/wall-decoration/frames/rodalm-art-50550033) - 外框有木黑白三色,**注意裱框紙開孔較小,需要挖大** 31 | 32 | ## Installation 安裝方式 33 | 34 | 1. 將`/fonts`資料夾內的檔案及`e-ink-weather-board.yaml`放到HA/config/esphome的資料夾內 35 | 2. 將`eink_dashboard_sensor.yaml`放到HA/config/packages內 36 | 3. 將`/images`內的`background.png`放到HA/config/esphome/images的資料夾內 37 | 4. 將`e-ink-weather-board.yaml`及`eink_dashboard_sensor.yaml`的內容修改成自己HA裡的實體ID,**解說在下方** 38 | 5. HA檢查YAML code有無錯誤 39 | 1. 開發工具>YAML>檢查設定內容,確認左下角通知沒有出現錯誤 40 | 2. YAML 設定新載入中>模板實體 41 | 3. 開發工具>狀態>檢查`sensor.eink_sensors`有確實出現,以及內容是自己想要的 42 | 6. 在ESPhome將`e-ink-weather-board.yaml`燒錄至ESP32模組 43 | 7. 完成! 44 | 45 | ## ESPHome yaml 說明 46 | 47 | ### 在HA內手動更新面板 48 | 49 | ```YAML 50 | button: 51 | - platform: template 52 | name: '${devicename} Refresh' 53 | icon: 'mdi:update' 54 | on_press: 55 | then: 56 | - component.update: 'my_display' 57 | internal: false 58 | ``` 59 | 60 | 61 | ### 將HA的時間帶進ESPHome 62 | 63 | ```YAML 64 | time: 65 | - platform: homeassistant 66 | id: ha_time 67 | ``` 68 | 69 | 70 | ### 面板更新時機 71 | 72 | 請注意,此面板長時間通電會導致越刷越模糊,黑底會變成不是純黑,建議只有刷新時才將ESP32通電,或是刷新完進入Deep sleep以避免此情形發生 73 | 74 | 因為預設螢幕不會自動更新`update_interval: never`,是由HA內建自動化根據想要的間隔時間來按下更新面板按鈕 75 | 76 | 自動化流程如下: 77 | 78 | #### 1. 每隔多久時間觸發一次自動化: 79 | 80 | ```YAML 81 | trigger: 82 | - platform: time_pattern 83 | # /2 表示每2個小時,要每小時就寫 /1 84 | hours: "/2" 85 | # 1 表示在該小時的1分時執行,如06:01、08:01、10:01 86 | minutes: 1 87 | ``` 88 | 89 | #### 2. 條件: 90 | 91 | 在HA設定>裝置與服務>助手>新增助手>"每日定時感測器">設定想要更新的時段,名稱填`eink_refresh_time` 92 | 93 | ```YAML 94 | condition: 95 | #在可更新的時段內才更新 96 | - condition: state 97 | entity_id: binary_sensor.eink_refresh_time 98 | state: 'on' 99 | ``` 100 | 101 | #### 3. 動作: 102 | 103 | ```YAML 104 | action: 105 | #按下更新螢幕的按鈕,記得更換為自己的實體ID 106 | - service: button.press 107 | data: 108 | entity_id: button.eink_weather_board_screen_refresh 109 | ``` 110 | 111 | 自動化設定完記得至開發工具>YAML>檢查設定 112 | 113 | 確定都對後在`YAML 設定新載入中`按下`自動化`重新載入自動化才會生效 114 | 115 | ## HA template sensor 說明 116 | 117 | **要先確認在已經將以下程式碼寫在`configuration.yaml`內,這樣`eink_dashboard_sensor_new.yaml`檔案放進去才會生效** 118 | 119 | ![](https://user-images.githubusercontent.com/56766371/184566430-d2dff49b-38cd-4ddd-a775-eaadf7099fc1.png) 120 | 121 | 在HA 2023.12之後,天氣預報改由呼叫service來取得未來的資訊,所以利用此template sensor將想要的資料格式化後再丟給天氣板顯示 122 | 123 | 由於預設是顯示取得每小時的預報,**請先確認目前用的天氣整合有支援小時預報 (內建的met.no有)** 124 | 125 | 以下YAML表示每小時的1分將會呼叫取得"每小時"的天氣預報服務,同時更新內容在sensor.eink_sensors裡面 126 | 127 | 要注意更新面板的時機要在更新天氣預報之後,不然都會看到前一個小時的預報 128 | 129 | ```YAML 130 | 131 | - trigger: 132 | - platform: time_pattern 133 | hours: "/1" 134 | minutes: 1 135 | action: 136 | - service: weather.get_forecasts 137 | target: 138 | entity_id: weather.myhome #replace with your weather forecast entity id 139 | data: 140 | type: hourly 141 | response_variable: hourly 142 | 143 | ``` 144 | 145 | 會使用天氣預報回傳結果的第1組當作這小時的預報,並顯示第2~5組做未來每小時的預報 146 | 147 | `attributes`是將要使用的資訊從天氣預報拆分成出來,分別是: 148 | - 這小時的氣溫: `today_temperature` 149 | - 這小時的濕度: `today_humidity` 150 | - 這小時的降雨機率: `today_precipitation` 151 | - 未來四小時的時間: `forecast_weekday_1`, `forecast_weekday_2`, `forecast_weekday_3`, `forecast_weekday_4` 152 | - 未來四小時的天氣圖示: `forecast_condition_1`, `forecast_condition_2`, `forecast_condition_3`, `forecast_condition_4` 153 | - 未來四小時的氣溫: `forecast_temperature_1`, `forecast_temperature_2`, `forecast_temperature_3`, `forecast_temperature_4` 154 | 155 | 156 | ## References 157 | - https://github.com/Madelena/esphome-weatherman-dashboard/ 158 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESPHome E-ink Weather board 2 | 3 | Buy Me A Coffee 4 | 5 | English | [正體中文](https://github.com/xangin/eink-weather-board/blob/main/README_zh-tw.md) 6 | 7 | Thanks to [Madelena](https://github.com/Madelena/esphome-weatherman-dashboard/) for inspiring this project and providing the source code for weather data. 8 | 9 | This project is a vertical E-ink weather forecast board placed at the entrance, automatically updating and displaying content at specified intervals. 10 | 11 | There is also a horizontal version that can display temperature and humidity information for individual rooms on the E-ink: [E-ink Dashboard](https://github.com/xangin/esphome-eink-dashboard) 12 | 13 | 14 | 15 | The vertical weather board displays: 16 | - Today's date 17 | - Current weather forecast 18 | - Weather forecast for the next four hours 19 | 20 | 21 | 22 | Below are the hardware structure, ESPHome yaml code, and Home assistant yaml code. 23 | 24 | ## Hardware 25 | 26 | - [Waveshare 7.5-inch black and white E-ink screen](https://detail.tmall.com/item.htm?id=606005913066) - bare screen without casing 27 | - [Waveshare E-ink screen SPI driver board ESP32](https://detail.tmall.com/item.htm?id=605757128869) - WiFi + Bluetooth version (ESP32) 28 | - [IKEA RÖDALM Frame 13x18 cm](https://www.ikea.com.tw/zh/products/wall-decoration/frames/rodalm-art-50550033) - available in black, white, and wooden color. Note: The mat opening is small and needs to be enlarged 29 | 30 | ## Installation 31 | 32 | 1. Place the files in the `/fonts` folder and `e-ink-weather-board.yaml`in the HA/config/esphome folder. 33 | 2. Place `eink_dashboard_sensor.yaml` in the HA/config/packages folder. 34 | 3. Place `background.png` from the `/images` folder in the HA/config/esphome/images folder. 35 | 4. Modify `e-ink-weather-board.yaml` and `eink_dashboard_sensor.yaml` to match your HA entity IDs. **Instructions are below** 36 | 5. Check for YAML code errors in HA. 37 | 1. Developer Tools > YAML > Check Configuration, ensure no errors in the bottom left notification. 38 | 2. YAML Configuration Reloading > Template Entities 39 | 3. Developer Tools > States > Check `sensor.eink_sensors` to ensure it appears and contains the desired content. 40 | 6. Flash e-ink-weather-board.yaml to the ESP32 module in ESPHome. 41 | 7. Done! 42 | 43 | ## ESPHome yaml Explanation 44 | 45 | ### Manually update the panel in HA 46 | 47 | ```YAML 48 | button: 49 | - platform: template 50 | name: '${devicename} Refresh' 51 | icon: 'mdi:update' 52 | on_press: 53 | then: 54 | - component.update: 'my_display' 55 | internal: false 56 | ``` 57 | 58 | 59 | ### Pass HA time to ESPHome 60 | 61 | ```YAML 62 | time: 63 | - platform: homeassistant 64 | id: ha_time 65 | ``` 66 | 67 | 68 | ### Panel update timing 69 | 70 | Note: Long-term power to this panel may cause increasing blurriness. It is recommended to power the ESP32 only when refreshing or enter Deep Sleep to avoid this issue. 71 | 72 | The default screen does not automatically update `update_interval: never`. It is updated by HA automation based on the desired interval. 73 | 74 | Automation process: 75 | 76 | #### 1. Trigger automation at intervals: 77 | 78 | ```YAML 79 | trigger: 80 | - platform: time_pattern 81 | # /2 means every 2 hours, use /1 for every hour 82 | hours: "/2" 83 | # 1 means it runs at the 1st minute of the hour, like 06:01, 08:01, 10:01 84 | minutes: 1 85 | ``` 86 | 87 | #### 2. Condition: 88 | 89 | Set the update period in HA > Settings > Devices & Services > Helpers > Add Helper > "Daily Timer" > Set the desired update period, name it `eink_refresh_time`. 90 | 91 | ```YAML 92 | condition: 93 | #Update only during allowed periods 94 | - condition: state 95 | entity_id: binary_sensor.eink_refresh_time 96 | state: 'on' 97 | ``` 98 | 99 | #### 3. Action: 100 | 101 | ```YAML 102 | action: 103 | #Press the update button, replace with your entity ID 104 | - service: button.press 105 | data: 106 | entity_id: button.eink_weather_board_screen_refresh 107 | ``` 108 | 109 | Remember to check the configuration in Developer Tools > YAML > Check Configuration. 110 | 111 | Once everything is correct, reload the automation in YAML Configuration Reloading > Automation. 112 | 113 | ## HA template sensor Explanation 114 | 115 | **Ensure the following code is written in`configuration.yaml` for `eink_dashboard_sensor_new.yaml`to take effect** 116 | 117 | ![](https://user-images.githubusercontent.com/56766371/184566430-d2dff49b-38cd-4ddd-a775-eaadf7099fc1.png) 118 | 119 | Ensure the weather integration supports hourly forecasts (built-in met.no does). 120 | 121 | The following YAML calls the "hourly" weather forecast service at 1 minute past every hour and updates sensor.eink_sensors with the content. 122 | 123 | Update the panel after updating the weather forecast to avoid seeing the previous hour's forecast. 124 | 125 | ```YAML 126 | 127 | - trigger: 128 | - platform: time_pattern 129 | hours: "/1" 130 | minutes: 1 131 | action: 132 | - service: weather.get_forecasts 133 | target: 134 | entity_id: weather.myhome #replace with your weather forecast entity id 135 | data: 136 | type: hourly 137 | response_variable: hourly 138 | 139 | ``` 140 | 141 | Use the first set of the weather forecast as this hour's forecast and display the 2nd to 5th sets for the next four hours. 142 | 143 | `attributes`separates the information from the weather forecast as: 144 | - Temperature for this hour: `today_temperature` 145 | - Humidity for this hour: `today_humidity` 146 | - Precipitation probability for this hour: `today_precipitation` 147 | - Time for the next four hours: `forecast_weekday_1`, `forecast_weekday_2`, `forecast_weekday_3`, `forecast_weekday_4` 148 | - Weather icons for the next four hours: `forecast_condition_1`, `forecast_condition_2`, `forecast_condition_3`, `forecast_condition_4` 149 | - Temperature for the next four hours: `forecast_temperature_1`, `forecast_temperature_2`, `forecast_temperature_3`, `forecast_temperature_4` 150 | 151 | ## References 152 | - https://github.com/Madelena/esphome-weatherman-dashboard/ 153 | -------------------------------------------------------------------------------- /eink-weather-board.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | device_name: eink-weather-board 3 | 4 | esp32: 5 | board: esp32dev 6 | 7 | esphome: 8 | name: eink-weather-board 9 | 10 | # Enable logging 11 | logger: 12 | 13 | # Enable Home Assistant API 14 | api: 15 | 16 | ota: 17 | - platform: esphome 18 | password: !secret ota_password #remeber add ota_password in your secret.yaml 19 | 20 | wifi: 21 | networks: 22 | - ssid: !secret my_ap_ssid 23 | password: !secret my_ap_password 24 | 25 | # Enable fallback hotspot (captive portal) in case wifi connection fails 26 | ap: 27 | ssid: ${device_name} 28 | password: "12345678" 29 | 30 | # Include custom fonts 31 | font: 32 | 33 | - file: 'fonts/GothamRnd-Book.ttf' 34 | id: font_year 35 | size: 60 36 | glyphs: 37 | ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] 38 | 39 | - file: 'fonts/GothamRnd-Book.ttf' 40 | id: font_month 41 | size: 80 42 | glyphs: 43 | ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 44 | 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 45 | 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 46 | 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 47 | 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'] 48 | 49 | - file: 'fonts/GothamRnd-Bold.ttf' 50 | id: font_day 51 | size: 100 52 | glyphs: 53 | ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] 54 | 55 | - file: 'fonts/GothamRnd-Bold.ttf' 56 | id: font_weekday 57 | size: 70 58 | glyphs: 59 | ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 60 | 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 61 | 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 62 | 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 63 | 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ' '] 64 | 65 | - file: 'fonts/materialdesigniconswebfont.ttf' 66 | id: icon_today 67 | size: 220 68 | glyphs: &mdi-weather-glyphs 69 | - "\U000F0590" # mdi-weather-cloudy 70 | - "\U000F0F2F" # mdi-weather-cloudy-alert 71 | - "\U000F0E6E" # mdi-weather-cloudy-arrow-right 72 | - "\U000F0593" # mdi-weather-lightning 73 | - "\U000F067E" # mdi-weather-lightning-rainy 74 | - "\U000F0594" # mdi-weather-night 75 | - "\U000F0F31" # mdi-weather-night-partly-cloudy 76 | - "\U000F0595" # mdi-weather-partly-cloudy 77 | - "\U000F0F32" # mdi-weather-partly-lightning 78 | - "\U000F0F33" # mdi-weather-partly-rainy 79 | - "\U000F0596" # mdi-weather-pouring 80 | - "\U000F0597" # mdi-weather-rainy 81 | - "\U000F0599" # mdi-weather-sunny 82 | - "\U000F0F37" # mdi-weather-sunny-alert 83 | - "\U000F14E4" # mdi-weather-sunny-off 84 | - "\U000F059A" # mdi-weather-sunset 85 | - "\U000F059B" # mdi-weather-sunset-down 86 | - "\U000F059C" # mdi-weather-sunset-up 87 | - "\U000F059D" # mdi-weather-windy 88 | - "\U000F059E" # mdi-weather-windy-variant 89 | - "\U000F0591" # mdi-weather-fog 90 | - "\U000F0592" # mdi-weather-hail 91 | - "\U000F0F30" # mdi-weather-hazy 92 | 93 | #today temp 94 | - file: 'fonts/GothamRnd-Bold.ttf' 95 | id: font_today_temp 96 | size: 70 97 | glyphs: 98 | ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '°', 'C', '%'] 99 | 100 | #forecast time & temp 101 | - file: 'fonts/GothamRnd-Bold.ttf' 102 | id: font_medium_bold 103 | size: 40 104 | glyphs: 105 | ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '°', 'A', 'M', 'P'] 106 | 107 | #forecast icon 108 | - file: 'fonts/materialdesigniconswebfont.ttf' 109 | id: icon_forecast 110 | size: 70 111 | glyphs: *mdi-weather-glyphs 112 | 113 | #update time 114 | - file: 'fonts/GothamRnd-Book.ttf' 115 | id: font_smallest 116 | size: 12 117 | glyphs: 118 | ['/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' ', ':'] 119 | 120 | # Include Background 121 | image: 122 | - file: "images/background.png" 123 | id: eink_pannel 124 | type: BINARY 125 | 126 | 127 | time: 128 | - platform: homeassistant 129 | id: ha_time 130 | 131 | text_sensor: 132 | 133 | - platform: homeassistant 134 | entity_id: sensor.eink_sensors 135 | id: today_weather 136 | 137 | - platform: homeassistant 138 | entity_id: sensor.eink_sensors 139 | attribute: today_temperature 140 | id: today_temperature 141 | 142 | - platform: homeassistant 143 | entity_id: sensor.eink_sensors 144 | attribute: today_humidity 145 | id: today_humidity 146 | 147 | - platform: homeassistant 148 | entity_id: sensor.eink_sensors 149 | attribute: today_precipitation 150 | id: today_precipitation 151 | 152 | - platform: homeassistant 153 | entity_id: sensor.eink_sensors 154 | attribute: forecast_weekday_1 155 | id: forecast_weekday_1 156 | 157 | - platform: homeassistant 158 | entity_id: sensor.eink_sensors 159 | attribute: forecast_condition_1 160 | id: forecast_weather_1 161 | 162 | - platform: homeassistant 163 | entity_id: sensor.eink_sensors 164 | attribute: forecast_temperature_1 165 | id: forecast_temperature_1 166 | 167 | - platform: homeassistant 168 | entity_id: sensor.eink_sensors 169 | attribute: forecast_weekday_2 170 | id: forecast_weekday_2 171 | 172 | - platform: homeassistant 173 | entity_id: sensor.eink_sensors 174 | attribute: forecast_condition_2 175 | id: forecast_weather_2 176 | 177 | - platform: homeassistant 178 | entity_id: sensor.eink_sensors 179 | attribute: forecast_temperature_2 180 | id: forecast_temperature_2 181 | 182 | - platform: homeassistant 183 | entity_id: sensor.eink_sensors 184 | attribute: forecast_weekday_3 185 | id: forecast_weekday_3 186 | 187 | - platform: homeassistant 188 | entity_id: sensor.eink_sensors 189 | attribute: forecast_condition_3 190 | id: forecast_weather_3 191 | 192 | - platform: homeassistant 193 | entity_id: sensor.eink_sensors 194 | attribute: forecast_temperature_3 195 | id: forecast_temperature_3 196 | 197 | - platform: homeassistant 198 | entity_id: sensor.eink_sensors 199 | attribute: forecast_weekday_4 200 | id: forecast_weekday_4 201 | 202 | - platform: homeassistant 203 | entity_id: sensor.eink_sensors 204 | attribute: forecast_condition_4 205 | id: forecast_weather_4 206 | 207 | - platform: homeassistant 208 | entity_id: sensor.eink_sensors 209 | attribute: forecast_temperature_4 210 | id: forecast_temperature_4 211 | 212 | button: 213 | - platform: template 214 | name: '${device_name} Screen Refresh' 215 | icon: 'mdi:update' 216 | on_press: 217 | then: 218 | - component.update: 'my_display' 219 | internal: false 220 | 221 | binary_sensor: 222 | - platform: status 223 | name: "${device_name} WiFi Status" 224 | 225 | color: 226 | - id: color_black 227 | red: 0% 228 | green: 0% 229 | blue: 0% 230 | white: 50% 231 | - id: color_white 232 | red: 0% 233 | green: 0% 234 | blue: 0% 235 | white: 0% 236 | 237 | 238 | # Pins for Waveshare ePaper ESP Board 239 | spi: 240 | clk_pin: GPIO13 241 | mosi_pin: GPIO14 242 | 243 | # Now render everything on the ePaper screen. 244 | display: 245 | - platform: waveshare_epaper 246 | cs_pin: GPIO15 247 | dc_pin: GPIO27 248 | busy_pin: 249 | number: GPIO25 250 | inverted: true 251 | reset_pin: GPIO26 252 | model: 7.50inV2 253 | update_interval: never 254 | id: my_display 255 | rotation: 270° 256 | lambda: |- 257 | // Map weather states to MDI characters. 258 | std::map weather_icon_map 259 | { 260 | {"cloudy", "\U000F0590"}, 261 | {"cloudy-alert", "\U000F0F2F"}, 262 | {"fog", "\U000F0591"}, 263 | {"hail", "\U000F0592"}, 264 | {"hazy", "\U000F0F30"}, 265 | {"lightning", "\U000F0593"}, 266 | {"lightning-rainy", "\U000F067E"}, 267 | {"clear-night", "\U000F0594"}, 268 | {"night", "\U000F0594"}, 269 | {"night-partly-cloudy", "\U000F0F31"}, 270 | {"partlycloudy", "\U000F0595"}, 271 | {"partly-lightning", "\U000F0F32"}, 272 | {"partly-rainy", "\U000F0F33"}, 273 | {"pouring", "\U000F0596"}, 274 | {"rainy", "\U000F0597"}, 275 | {"sunny", "\U000F0599"}, 276 | {"sunny-alert", "\U000F0F37"}, 277 | {"sunny-off", "\U000F14E4"}, 278 | {"sunset", "\U000F059A"}, 279 | {"sunset-down", "\U000F059B"}, 280 | {"sunset-up", "\U000F059C"}, 281 | {"windy", "\U000F059D"}, 282 | {"windy-variant", "\U000F059E"}, 283 | }; 284 | //background 285 | it.image(0, 0, id(eink_pannel)); 286 | 287 | //************************ TODAY ************************ 288 | 289 | //month 290 | it.strftime(20, 75, id(font_month),id(color_black), TextAlign::TOP_LEFT, "%b", id(ha_time).now()); 291 | 292 | //day 293 | it.strftime(245, 62, id(font_day),id(color_black), TextAlign::TOP_CENTER, "%d", id(ha_time).now()); 294 | 295 | //year 296 | it.strftime(390, 93, id(font_year),id(color_black), TextAlign::TOP_CENTER, "%Y", id(ha_time).now()); 297 | 298 | //weekday 299 | it.strftime(240, 170, id(font_weekday),id(color_black), TextAlign::TOP_CENTER, "%A", id(ha_time).now()); 300 | 301 | //************************ TODAY WEATHER ************************ 302 | int today_temp_y=305; 303 | //icon 304 | it.printf(105, 310, id(icon_today),id(color_black), TextAlign::TOP_CENTER, "%s", weather_icon_map[id(today_weather).state.c_str()].c_str()); 305 | 306 | //temperature 307 | it.printf(285, today_temp_y, id(font_today_temp),id(color_black), TextAlign::TOP_LEFT, "%s", id(today_temperature).state.c_str()); 308 | 309 | //humidity 310 | it.printf(285, today_temp_y+80, id(font_today_temp),id(color_black), TextAlign::TOP_LEFT, "%s", id(today_humidity).state.c_str()); 311 | 312 | //precipitation 313 | it.printf(285, today_temp_y+160, id(font_today_temp),id(color_black), TextAlign::TOP_LEFT, "%s", id(today_precipitation).state.c_str()); 314 | 315 | //************************ FORECAST ************************ 316 | int forecast_y=610; 317 | int forecast_icon_gap=45; 318 | int forecast_data_gap=130; 319 | 320 | //HOUR1 321 | //weekday 322 | it.printf(60, forecast_y, id(font_medium_bold),id(color_black), TextAlign::TOP_CENTER, "%s", id(forecast_weekday_1).state.c_str()); 323 | //icon 324 | it.printf(60, forecast_y+forecast_icon_gap, id(icon_forecast),id(color_black), TextAlign::TOP_CENTER, "%s", weather_icon_map[id(forecast_weather_1).state.c_str()].c_str()); 325 | //temperature 326 | it.printf(60, forecast_y+forecast_data_gap, id(font_medium_bold),id(color_black), TextAlign::TOP_CENTER, "%s", id(forecast_temperature_1).state.c_str()); 327 | 328 | 329 | //HOUR2 330 | //weekday 331 | it.printf(180, forecast_y, id(font_medium_bold),id(color_black), TextAlign::TOP_CENTER, "%s", id(forecast_weekday_2).state.c_str()); 332 | //icon 333 | it.printf(180, forecast_y+forecast_icon_gap, id(icon_forecast),id(color_black), TextAlign::TOP_CENTER, "%s", weather_icon_map[id(forecast_weather_2).state.c_str()].c_str()); 334 | //temperature 335 | it.printf(183, forecast_y+forecast_data_gap, id(font_medium_bold),id(color_black), TextAlign::TOP_CENTER, "%s", id(forecast_temperature_2).state.c_str()); 336 | 337 | //HOUR3 338 | //weekday 339 | it.printf(300, forecast_y, id(font_medium_bold),id(color_black), TextAlign::TOP_CENTER, "%s", id(forecast_weekday_3).state.c_str()); 340 | //icon 341 | it.printf(300, forecast_y+forecast_icon_gap, id(icon_forecast),id(color_black), TextAlign::TOP_CENTER, "%s", weather_icon_map[id(forecast_weather_3).state.c_str()].c_str()); 342 | //temperature 343 | it.printf(303, forecast_y+forecast_data_gap, id(font_medium_bold),id(color_black), TextAlign::TOP_CENTER, "%s", id(forecast_temperature_3).state.c_str()); 344 | 345 | 346 | //HOUR4 347 | //weekday 348 | it.printf(425, forecast_y, id(font_medium_bold),id(color_black), TextAlign::TOP_CENTER, "%s", id(forecast_weekday_4).state.c_str()); 349 | //icon 350 | it.printf(425, forecast_y+forecast_icon_gap, id(icon_forecast),id(color_black), TextAlign::TOP_CENTER, "%s", weather_icon_map[id(forecast_weather_4).state.c_str()].c_str()); 351 | //temperature 352 | it.printf(425, forecast_y+forecast_data_gap, id(font_medium_bold),id(color_black), TextAlign::TOP_CENTER, "%s", id(forecast_temperature_4).state.c_str()); 353 | 354 | //last update time 355 | it.strftime(2, 786, id(font_smallest),id(color_black), TextAlign::TOP_LEFT, "%m/%d %H:%M", id(ha_time).now()); 356 | --------------------------------------------------------------------------------