├── display.jpg ├── display2.jpg ├── images └── weather1 │ ├── fog.png │ ├── hail.png │ ├── cloudy.png │ ├── rainy.png │ ├── snowy.png │ ├── sunny.png │ ├── windy.png │ ├── lightning.png │ ├── pouring.png │ ├── clear-night.png │ ├── exceptional.png │ ├── snowy-rainy.png │ ├── partly-cloudy.png │ ├── partly-cloudyN.png │ ├── windy-variant.png │ └── lightning-rainy.png ├── includes ├── iTouch.yaml └── iTouch2.yaml ├── README.md ├── sensor_ha ├── forecast_8hours.yaml └── forecast_5days.yaml ├── wt32sc01b.yaml └── wt32sc01a.yaml /display.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krunkel/wt32sc01-with-esphome/HEAD/display.jpg -------------------------------------------------------------------------------- /display2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krunkel/wt32sc01-with-esphome/HEAD/display2.jpg -------------------------------------------------------------------------------- /images/weather1/fog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krunkel/wt32sc01-with-esphome/HEAD/images/weather1/fog.png -------------------------------------------------------------------------------- /images/weather1/hail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krunkel/wt32sc01-with-esphome/HEAD/images/weather1/hail.png -------------------------------------------------------------------------------- /images/weather1/cloudy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krunkel/wt32sc01-with-esphome/HEAD/images/weather1/cloudy.png -------------------------------------------------------------------------------- /images/weather1/rainy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krunkel/wt32sc01-with-esphome/HEAD/images/weather1/rainy.png -------------------------------------------------------------------------------- /images/weather1/snowy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krunkel/wt32sc01-with-esphome/HEAD/images/weather1/snowy.png -------------------------------------------------------------------------------- /images/weather1/sunny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krunkel/wt32sc01-with-esphome/HEAD/images/weather1/sunny.png -------------------------------------------------------------------------------- /images/weather1/windy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krunkel/wt32sc01-with-esphome/HEAD/images/weather1/windy.png -------------------------------------------------------------------------------- /images/weather1/lightning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krunkel/wt32sc01-with-esphome/HEAD/images/weather1/lightning.png -------------------------------------------------------------------------------- /images/weather1/pouring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krunkel/wt32sc01-with-esphome/HEAD/images/weather1/pouring.png -------------------------------------------------------------------------------- /images/weather1/clear-night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krunkel/wt32sc01-with-esphome/HEAD/images/weather1/clear-night.png -------------------------------------------------------------------------------- /images/weather1/exceptional.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krunkel/wt32sc01-with-esphome/HEAD/images/weather1/exceptional.png -------------------------------------------------------------------------------- /images/weather1/snowy-rainy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krunkel/wt32sc01-with-esphome/HEAD/images/weather1/snowy-rainy.png -------------------------------------------------------------------------------- /images/weather1/partly-cloudy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krunkel/wt32sc01-with-esphome/HEAD/images/weather1/partly-cloudy.png -------------------------------------------------------------------------------- /images/weather1/partly-cloudyN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krunkel/wt32sc01-with-esphome/HEAD/images/weather1/partly-cloudyN.png -------------------------------------------------------------------------------- /images/weather1/windy-variant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krunkel/wt32sc01-with-esphome/HEAD/images/weather1/windy-variant.png -------------------------------------------------------------------------------- /images/weather1/lightning-rainy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krunkel/wt32sc01-with-esphome/HEAD/images/weather1/lightning-rainy.png -------------------------------------------------------------------------------- /includes/iTouch.yaml: -------------------------------------------------------------------------------- 1 | platform: touchscreen 2 | id: ${iId} 3 | internal: True 4 | page_id: ${iPg} 5 | filters: 6 | - delayed_on: ${delayedOn} 7 | x_min: ${iX1} 8 | x_max: ${iX2} 9 | y_min: ${iY1} 10 | y_max: ${iY2} -------------------------------------------------------------------------------- /includes/iTouch2.yaml: -------------------------------------------------------------------------------- 1 | platform: touchscreen 2 | id: ${iId} 3 | internal: True 4 | page_id: ${iPg} 5 | x_min: ${iY1} 6 | x_max: ${iY2} 7 | y_min: ${iX1} 8 | y_max: ${iX2} 9 | on_press: 10 | - script.execute: ${iSc} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | WT32SC01 display with Esphome and Home-Assistant 2 | ================================================ 3 | Example config for a WT32SC01 ( WT32-SC01 with ESP32 WRover module ) display using Esphome, controlling Home Assistant entities and using Home Assistant sensors to display Meteo forecast, temperatures,.... 4 | 5 | The meteo forecaste part is depending on a template sensor in Home Assistant. See ./sensor_ha/forecast_8hours.yaml. 6 | The images in ./images/weather1 should be places in the home assistant config/esphome/images/weather1 folder 7 | 8 | In the latest version I added a RCWL-0516 radar sensor behind the display to undim the screen... Also stopped using the 'delayed_on' and 'delayed_off' filters of the binary sensor to 'debounce' the touchscreen. Was not working for me.... Now using script with delay... 9 | 10 | The code in this project is based on contributions of many others on https://community.home-assistant.io/! 11 | 12 | ![display.jpg](./display.jpg) 13 | 14 | ![display2.jpg](./display2.jpg) 15 | 16 | -------------------------------------------------------------------------------- /sensor_ha/forecast_8hours.yaml: -------------------------------------------------------------------------------- 1 | # part of my home assistant templates.yaml file 2 | # creates a text sensor with compact forecast info for my esphome devices 3 | # exp: "15u;0;19.1;0.0;partlycloudy;7;D#16u;0;19.3;0.0;partlycloudy;7;D#17u;0;19.5;0.0;sunny;12;D#18u...." 4 | - trigger: 5 | - platform: time_pattern 6 | minutes: "/30" 7 | action: 8 | - service: weather.get_forecasts 9 | data: 10 | type: hourly 11 | target: 12 | entity_id: weather.home 13 | response_variable: fc_hourly 14 | sensor: 15 | - name: "forecast_8hours" 16 | unique_id: "forecast_8hours" 17 | state: >- 18 | {% set CondCode = { 19 | "clear-night": 1, 20 | "cloudy": 2, 21 | "fog": 3, 22 | "hail": 4, 23 | "lightning": 5, 24 | "lightning-rainy": 6, 25 | "partlycloudy": 7, 26 | "pouring": 8, 27 | "rainy": 9, 28 | "snowy": 10, 29 | "snowy-rainy": 11, 30 | "sunny": 12, 31 | "windy": 13, 32 | "windy-variant": 14, 33 | "exceptional": 15 34 | } %} 35 | {% if (fc_hourly['weather.home']) %} 36 | {% set tsunrise = as_datetime(states.sun.sun.attributes.next_rising).astimezone().hour %} 37 | {% set tsunset = as_datetime(states.sun.sun.attributes.next_setting).astimezone().hour %} 38 | {% for fc in fc_hourly['weather.home'].forecast[0:8] 39 | %}{% set fc_hour = as_datetime(fc.datetime).astimezone().hour %}{{fc_hour}}u;0;{{fc.temperature}};{{fc.precipitation}};{{fc.condition}};{{CondCode[fc.condition]}};{% 40 | if ((fc_hour > tsunrise) and (fc_hour < tsunset)) %}D{% else %}N{% endif %}#{% 41 | endfor %} 42 | {% else %} 43 | Null 44 | {% endif %} -------------------------------------------------------------------------------- /sensor_ha/forecast_5days.yaml: -------------------------------------------------------------------------------- 1 | # part of my home assistant templates.yaml file 2 | # creates a text sensor with compact forecast info for my esphome devices 3 | # exp: "Wo;14.0;19.5;0.0;cloudy;2;D#Do;11.0;19.4;2.0;rainy;9;D#Vr;9.7;18.8;7.6;cloudy;2;D#Za;13.3;15.1;35.9;rainy;9;D#Zo;12.4;20.2;2.7;rainy;9;D#" 4 | - trigger: 5 | - platform: time_pattern 6 | hours: "/2" 7 | action: 8 | - service: weather.get_forecasts 9 | data: 10 | type: daily 11 | target: 12 | entity_id: weather.home 13 | response_variable: fc_daily 14 | sensor: 15 | - name: "forecast_5days" 16 | unique_id: "forecast_5days" 17 | state: >- 18 | {% set WDay = { 19 | "0": "Zo", 20 | "1": "Ma", 21 | "2": "Di", 22 | "3": "Wo", 23 | "4": "Do", 24 | "5": "Vr", 25 | "6": "Za" 26 | } %} 27 | {% set CondCode = { 28 | "clear-night": 1, 29 | "cloudy": 2, 30 | "fog": 3, 31 | "hail": 4, 32 | "lightning": 5, 33 | "lightning-rainy": 6, 34 | "partlycloudy": 7, 35 | "pouring": 8, 36 | "rainy": 9, 37 | "snowy": 10, 38 | "snowy-rainy": 11, 39 | "sunny": 12, 40 | "windy": 13, 41 | "windy-variant": 14, 42 | "exceptional": 15 43 | } %} 44 | {% if (fc_daily['weather.home']) %} 45 | {% for fc in fc_daily['weather.home'].forecast[0:5] 46 | %}{% set dt = strptime(fc.datetime.split("T")[0],'%Y-%m-%d') 47 | %}{{WDay[dt.strftime('%w')]}};{{fc.templow}};{{fc.temperature}};{{fc.precipitation}};{{fc.condition}};{{CondCode[fc.condition]}};D#{% 48 | endfor %} 49 | {% else %} 50 | Null 51 | {% endif %} 52 | -------------------------------------------------------------------------------- /wt32sc01b.yaml: -------------------------------------------------------------------------------- 1 | # Inspired by 2 | # Meconiotech on https://community.home-assistant.io/t/lookig-for-importing-forecast/345520/3 3 | # Delorean https://community.home-assistant.io/t/wt32-sc01-with-esphome/473531/13 4 | # and many more.... 5 | substitutions: 6 | name: "wt32sc01b" 7 | friendly_name: "WT32 SC01 B" 8 | id_prefix: "wt32sc01b" 9 | # for ha entity "light.licht_overloop" typeX = "light" - buttonX = "licht_overloop" 10 | # textX = caption on screen, actionX = action to perform in ha entity, imgX = image used on button 11 | button1: "all_garage" 12 | text1: "garage" 13 | type1: "light" 14 | action1: "toggle" 15 | img1: "imgLampgroup" 16 | #----------------- 17 | button2: "all_boven" 18 | text2: "boven" 19 | type2: "light" 20 | action2: "turn_off" 21 | img2: "imgLampgroup" 22 | #----------------- 23 | button3: "licht_berging" 24 | text3: "berging" 25 | type3: "light" 26 | action3: "toggle" 27 | img3: "imgLamp" 28 | #----------------- 29 | button4: "licht_kelder" 30 | text4: "kelder" 31 | type4: "light" 32 | action4: "turn_off" 33 | img4: "imgLamp" 34 | #----------------- 35 | button5: "licht_keuken" 36 | text5: "keuken" 37 | type5: "light" 38 | action5: "turn_off" 39 | img5: "imgLampgroup" 40 | #----------------- 41 | button6: "all_woonkamer" 42 | text6: "woonk." 43 | type6: "light" 44 | action6: "turn_off" 45 | img6: "imgLampgroup" 46 | #----------------- 47 | button7: "all_beneden" 48 | text7: "beneden" 49 | type7: "light" 50 | action7: "turn_off" 51 | img7: "imgLampgroup" 52 | #----------------- 53 | delay1: "100ms" 54 | delay2: "300ms" 55 | 56 | esphome: 57 | name: ${name} 58 | friendly_name: ${friendly_name} 59 | on_boot: 60 | then: 61 | - light.turn_on: 62 | id: ${id_prefix}_backlight 63 | brightness: 50% 64 | - display.page.show: klok5 65 | 66 | esp32: 67 | board: esp-wrover-kit 68 | framework: 69 | type: arduino 70 | psram: 71 | mode: octal 72 | speed: 80MHz 73 | 74 | preferences: 75 | flash_write_interval: 15min 76 | 77 | logger: 78 | level: Error 79 | # level: DEBUG 80 | 81 | api: 82 | encryption: 83 | key: !secret ha_defaultkey 84 | 85 | ota: 86 | - platform: esphome 87 | password: !secret esphome_ota_pw 88 | 89 | wifi: 90 | ssid: !secret wifi_ssid_iot 91 | password: !secret wifi_pw_iot 92 | manual_ip: 93 | static_ip: !secret ip_wt32sc01b 94 | gateway: !secret ip_iot_gateway 95 | subnet: !secret ip_iot_subnet 96 | dns1: !secret ip_iot_dns 97 | ap: 98 | ssid: "${name} Fallback Hotspot" 99 | password: !secret esphome_fb_pw 100 | 101 | globals: 102 | - id: global_forecast 103 | type: int 104 | restore_value: no 105 | initial_value: '0' 106 | 107 | script: 108 | - id: undim_script 109 | mode: restart 110 | then: 111 | - light.turn_on: 112 | id: ${id_prefix}_backlight 113 | brightness: 70% 114 | - delay: 15 sec 115 | - light.turn_on: 116 | id: ${id_prefix}_backlight 117 | brightness: 15% 118 | - id: but1_script 119 | mode: single 120 | then: 121 | - homeassistant.service: 122 | service: ${type1}.${action1} 123 | data_template: 124 | entity_id: ${type1}.${button1} 125 | - delay: ${delay1} 126 | - component.update: ${id_prefix}_display 127 | - delay: ${delay2} 128 | - id: but2_script 129 | mode: single 130 | then: 131 | - homeassistant.service: 132 | service: ${type2}.${action2} 133 | data_template: 134 | entity_id: ${type2}.${button2} 135 | - delay: ${delay1} 136 | - component.update: ${id_prefix}_display 137 | - delay: ${delay2} 138 | - id: but3_script 139 | mode: single 140 | then: 141 | - homeassistant.service: 142 | service: ${type3}.${action3} 143 | data_template: 144 | entity_id: ${type3}.${button3} 145 | - delay: ${delay1} 146 | - component.update: ${id_prefix}_display 147 | - delay: ${delay2} 148 | - id: but4_script 149 | mode: single 150 | then: 151 | - homeassistant.service: 152 | service: ${type4}.${action4} 153 | data_template: 154 | entity_id: ${type4}.${button4} 155 | - delay: ${delay1} 156 | - component.update: ${id_prefix}_display 157 | - delay: ${delay2} 158 | - id: but5_script 159 | mode: single 160 | then: 161 | - homeassistant.service: 162 | service: ${type5}.${action5} 163 | data_template: 164 | entity_id: ${type5}.${button5} 165 | - delay: ${delay1} 166 | - component.update: ${id_prefix}_display 167 | - delay: ${delay2} 168 | - id: but6_script 169 | mode: single 170 | then: 171 | - homeassistant.service: 172 | service: ${type6}.${action6} 173 | data_template: 174 | entity_id: ${type6}.${button6} 175 | - delay: ${delay1} 176 | - component.update: ${id_prefix}_display 177 | - delay: ${delay2} 178 | - id: but7_script 179 | mode: single 180 | then: 181 | - homeassistant.service: 182 | service: ${type7}.${action7} 183 | data_template: 184 | entity_id: ${type7}.${button7} 185 | - delay: ${delay1} 186 | - component.update: ${id_prefix}_display 187 | - delay: ${delay2} 188 | - id: but_forecast 189 | mode: single 190 | then: 191 | - globals.set: 192 | id: global_forecast 193 | value: !lambda |- 194 | if (id(global_forecast) == 1) { 195 | return 0; 196 | } else { 197 | return 1; 198 | } 199 | - component.update: ${id_prefix}_display 200 | - delay: ${delay2} 201 | - id: but_time 202 | mode: single 203 | then: 204 | - script.execute: undim_script 205 | - delay: ${delay2} 206 | 207 | time: 208 | - platform: homeassistant 209 | id: homeassistant_time 210 | 211 | output: 212 | - platform: ledc 213 | pin: GPIO23 214 | id: gpio_23_backlight_pwm 215 | 216 | light: 217 | - platform: monochromatic 218 | output: gpio_23_backlight_pwm 219 | name: "${friendly_name} backlight" 220 | id: ${id_prefix}_backlight 221 | restore_mode: RESTORE_DEFAULT_OFF 222 | 223 | i2c: 224 | id: i2c_bus_intern 225 | sda: 18 226 | scl: 19 227 | scan: false 228 | 229 | touchscreen: 230 | - platform: ft63x6 231 | id: ${id_prefix}_touch 232 | i2c_id: i2c_bus_intern 233 | interrupt_pin: GPIO39 234 | transform: 235 | swap_xy: true 236 | mirror_y: true 237 | on_touch: 238 | - script.execute: undim_script 239 | # - lambda: |- 240 | # ESP_LOGI("cal", "x=%d, y=%d, x_raw=%d, y_raw=%0d", 241 | # touch.x, 242 | # touch.y, 243 | # touch.x_raw, 244 | # touch.y_raw 245 | # ); 246 | 247 | spi: 248 | clk_pin: GPIO14 249 | mosi_pin: GPIO13 250 | miso_pin: GPIO12 251 | 252 | display: 253 | - platform: ili9xxx 254 | id: ${id_prefix}_display 255 | model: ST7796 256 | cs_pin: GPIO15 257 | dc_pin: GPIO21 258 | reset_pin: GPIO22 259 | invert_colors: false 260 | transform: 261 | swap_xy: true 262 | dimensions: 263 | width: 480 264 | height: 320 265 | # rotation: 90 266 | pages: 267 | - id: klok5 268 | lambda: |- 269 | auto time = id(homeassistant_time).now(); 270 | uint16_t v1 = 96; uint16_t v2 = 192; uint16_t v3 = 288; uint16_t v4 = 384; 271 | uint16_t m1 = 48; uint16_t m2 = 144; uint16_t m3 = 240; uint16_t m4 = 336; uint16_t m5 = 432; 272 | it.line(0, 96, 479, 96, my_blue); 273 | it.line(0, 208, 479, 208, my_blue); 274 | // select hourly or daily forecast depending on 'global_forecast' 275 | std::string sForecasts = ""; 276 | if (id(global_forecast) == 0) { 277 | if (id(ha_forecast).has_state()) { 278 | sForecasts = id(ha_forecast).state; 279 | } 280 | } else { 281 | if (id(ha_forecast5days).has_state()) { 282 | sForecasts = id(ha_forecast5days).state; 283 | } 284 | } 285 | if ((sForecasts > "") & (sForecasts != "Null")) { 286 | uint8_t count = 0; 287 | uint16_t wx = 0; 288 | uint16_t imglft; 289 | uint16_t imgtop = 15; 290 | char *outerloop = NULL; 291 | char *innerloop = NULL; 292 | char *Ftime; 293 | char *FtempL; 294 | char *FtempH; 295 | char *Fmm; 296 | char *Fcondition; 297 | uint8_t FCondCode; 298 | char *Fdaynight; 299 | 300 | // loop through first 5 forecasts 301 | // ============================== 302 | char *sHourly = strtok_r (&sForecasts[0],"#",&outerloop); 303 | while ((sHourly != NULL) && (count < 5 )) { 304 | Ftime = strtok_r (sHourly, ";",&innerloop); 305 | FtempL = strtok_r (NULL, ";",&innerloop); 306 | FtempH = strtok_r (NULL, ";",&innerloop); 307 | Fmm = strtok_r (NULL, ";",&innerloop); 308 | Fcondition = strtok_r (NULL, ";",&innerloop); 309 | char *sCond = strtok_r (NULL, ";",&innerloop); 310 | FCondCode = atoi(sCond); 311 | Fdaynight = strtok_r (NULL, ";",&innerloop); 312 | 313 | // display image based on condition code an daynight code 314 | // ====================================================== 315 | imglft = wx + 13; 316 | switch(FCondCode) { 317 | case 1: 318 | it.image(imglft, imgtop, id(ImgCnd1)); 319 | break; 320 | case 2: 321 | it.image(imglft, imgtop, id(ImgCnd2)); 322 | break; 323 | case 3: 324 | it.image(imglft, imgtop, id(ImgCnd3)); 325 | break; 326 | case 4: 327 | it.image(imglft, imgtop, id(ImgCnd4)); 328 | break; 329 | case 5: 330 | it.image(imglft, imgtop, id(ImgCnd5)); 331 | break; 332 | case 6: 333 | it.image(imglft, imgtop, id(ImgCnd6)); 334 | break; 335 | case 7: 336 | if (strcmp(Fdaynight,"D") == 0) { 337 | it.image(imglft, imgtop, id(ImgCnd7D)); 338 | } else { 339 | it.image(imglft, imgtop, id(ImgCnd7N)); 340 | } 341 | break; 342 | case 8: 343 | it.image(imglft, imgtop, id(ImgCnd8)); 344 | break; 345 | case 9: 346 | it.image(imglft, imgtop, id(ImgCnd9)); 347 | break; 348 | case 10: 349 | it.image(imglft, imgtop, id(ImgCnd10)); 350 | break; 351 | case 11: 352 | it.image(imglft, imgtop, id(ImgCnd11)); 353 | break; 354 | case 12: 355 | if (strcmp(Fdaynight,"D") == 0) { 356 | it.image(imglft, imgtop, id(ImgCnd12)); 357 | } else { 358 | it.image(imglft, imgtop, id(ImgCnd1)); 359 | } 360 | 361 | break; 362 | default: 363 | it.printf(wx+48, 60, id(fntSml), my_blue, TextAlign::BOTTOM_CENTER, "%s", Fcondition); 364 | } 365 | int tgaugemax; int tgaugemin; int tzero; 366 | switch(time.month) { 367 | case 11: 368 | case 12: 369 | case 1: 370 | case 2: // winter: -12°>0>20° 371 | tgaugemax = 40; tgaugemin = -24; tzero = 65; // (25=max/ 89=min /65=0) 372 | break; 373 | case 5: 374 | case 6: 375 | case 7: 376 | case 8: 377 | case 9: // summer: 0>32° 378 | tgaugemax = 64; tgaugemin = 0; tzero = 89; // (25=max/ 89=min /89=0) 379 | break; 380 | default: // -8°>0>24° 381 | tgaugemax = 48; tgaugemin = -16; tzero = 73; // (25=max/ 89=min /73=0) 382 | } 383 | 384 | // display hour temperature 385 | // ======================== 386 | it.printf(wx+6, 0, id(fntSml), my_blue, TextAlign::TOP_LEFT, "%s", Ftime); 387 | it.printf(wx+89, 0, id(fntSml), my_blue, TextAlign::TOP_RIGHT, "%s°", FtempH); 388 | 389 | // display temp gauge 390 | // ================== 391 | it.rectangle(wx+8, 24, 8, 66, my_grey); 392 | int templow = int((atof(FtempL) * 2) + 0.5); 393 | int temphigh = int((atof(FtempH) * 2) + 0.5); 394 | if (templow < -tgaugemin) {templow = -tgaugemin;} 395 | if (temphigh < -tgaugemin) {temphigh = -tgaugemin;} 396 | if (templow > tgaugemax) {templow = tgaugemax;} 397 | if (temphigh > tgaugemax) {temphigh = tgaugemax;} 398 | if (templow == temphigh) {templow = 0;} // for hourly 399 | if (templow > 0) { 400 | it.filled_rectangle(wx+9, (tzero-temphigh) , 6, (temphigh - templow + 1), my_yellow); 401 | } else if (temphigh < 0) { 402 | it.filled_rectangle(wx+9, (tzero+temphigh) , 6, (temphigh - templow + 1), my_red); 403 | } else { 404 | it.filled_rectangle(wx+9, tzero-temphigh , 6, temphigh, my_yellow); 405 | it.filled_rectangle(wx+9, tzero , 6, (templow * -1), my_red); 406 | } 407 | it.line(wx+8, tzero, wx+18, tzero, my_grey); 408 | it.line(wx+16, tzero-20, wx+18, tzero-20, my_grey); 409 | it.line(wx+16, tzero-40, wx+18, tzero-40, my_grey); 410 | it.line(wx+16, tzero-10, wx+17, tzero-10, my_grey); 411 | it.line(wx+16, tzero-30, wx+17, tzero-30, my_grey); 412 | if (tgaugemax > 60) { 413 | it.line(wx+16, tzero-60, wx+18, tzero-60, my_grey); 414 | it.line(wx+16, tzero-50, wx+17, tzero-50, my_grey); 415 | } 416 | it.print(wx+20, tzero-5, id(fntXS), my_grey, TextAlign::TOP_LEFT, "0");; 417 | it.printf(wx+20, 20, id(fntXS), my_grey, TextAlign::TOP_LEFT, "%i",(tgaugemax/2)); 418 | 419 | // display precipitation gauge 420 | // =========================== 421 | uint16_t scaleprecip; 422 | uint16_t scalemax; 423 | float precip = atof(Fmm); 424 | bool preciphigh = false; 425 | if (id(global_forecast) == 0) { 426 | if (precip > 2) { 427 | scaleprecip = (uint16_t) (precip * 16); 428 | scalemax = 4; 429 | preciphigh = true; 430 | } else { 431 | scaleprecip = (uint16_t) (precip * 32); 432 | scalemax = 2; 433 | } 434 | } else { 435 | if (precip > 10) { 436 | scaleprecip = (uint16_t) (precip * 3.2); 437 | scalemax = 20; 438 | preciphigh = true; 439 | } else { 440 | scaleprecip = (uint16_t) (precip * 6.4); 441 | scalemax = 10; 442 | } 443 | } 444 | if (scaleprecip > 64) {scaleprecip = 64;} 445 | FCondCode = atoi(sCond); 446 | imglft = wx + 12; 447 | it.rectangle(wx+80, 24, 8, 66, my_grey); 448 | if (preciphigh) { 449 | it.filled_rectangle(wx+81, 89 - scaleprecip, 6, scaleprecip, my_purple); 450 | } else { 451 | it.filled_rectangle(wx+81, 89 - scaleprecip, 6, scaleprecip, my_blue); 452 | } 453 | it.line(wx+78, 24, wx+80, 24, my_grey); 454 | it.line(wx+78, 56, wx+80, 56, my_grey); 455 | it.line(wx+78, 89, wx+80, 89, my_grey); 456 | it.print(wx+78, 84, id(fntXS), my_grey, TextAlign::TOP_RIGHT, "0mm"); 457 | it.printf(wx+78, 20, id(fntXS), my_grey, TextAlign::TOP_RIGHT, "%imm", scalemax); 458 | wx+=96; 459 | count++; 460 | sHourly = strtok_r (NULL,"#",&outerloop); 461 | } 462 | } 463 | it.line(v1, 96, v1, 319, my_blue); 464 | it.line(v2, 208, v2, 319, my_blue); 465 | it.line(v3, 208, v3, 319, my_blue); 466 | it.line(v4, 96, v4, 319, my_blue); 467 | // ================================ 468 | // Display Time, Date, Temperatures 469 | // ================================ 470 | it.strftime(m3, 175, id(fntBig), my_white, TextAlign::BOTTOM_CENTER, "%H:%M", time); 471 | it.strftime(m3, 200, id(fntMid), my_white, TextAlign::BOTTOM_CENTER, "%d:%m:%Y", time); 472 | it.image(102, 130, id(ImgTempin), my_yellow); 473 | it.printf(102, 100, id(fntMid), my_yellow, TextAlign::TOP_LEFT, "%.1f°", id(ha_tempbinnen).state); 474 | it.image(346, 130, id(ImgTempout), my_yellow); 475 | it.printf(380, 100, id(fntMid), my_yellow, TextAlign::TOP_RIGHT, "%.1f°", id(ha_tempbuiten).state); 476 | // ==================== 477 | // Display WifiStrenght 478 | // ==================== 479 | uint16_t wfx = 105; 480 | uint16_t wfy = 176; 481 | if (id(${id_prefix}_wifi).has_state()) { 482 | if (id(${id_prefix}_wifi).state < -70) { 483 | it.image(wfx, wfy, id(wifi1),my_yellow); 484 | } else if (id(${id_prefix}_wifi).state < -60) { 485 | it.image(wfx, wfy, id(wifi2),my_green); 486 | } else if (id(${id_prefix}_wifi).state < -50) { 487 | it.image(wfx, wfy, id(wifi3),my_green); 488 | } else { 489 | it.image(wfx, wfy, id(wifi4),my_green); 490 | } 491 | it.printf(128, 206, id(fntSml), my_green, TextAlign::BOTTOM_LEFT, "%.0f",id(${id_prefix}_wifi).state); 492 | } else { 493 | it.image(wfx, wfy, id(wifi0),my_red); 494 | } 495 | // ============== 496 | // Display Motion 497 | // ============== 498 | if (id(prox_move).state) { 499 | it.image(346, wfy, id(ImgMotion),my_yellow); 500 | } else { 501 | it.image(346, wfy, id(ImgMotion),my_grey); 502 | } 503 | // =============== 504 | // Display Buttons 505 | // =============== 506 | uint16_t imgy1 = 104; uint16_t txty1 = 200; 507 | uint16_t imgy2 = 216; uint16_t txty2 = 312; 508 | it.print(m1, txty1, id(fntSml), my_blue, TextAlign::BOTTOM_CENTER, "${text1}"); 509 | if (id(ha_${button1}).state == "on") { 510 | it.image(10, imgy1, id(${img1}),my_yellow); 511 | } else { 512 | it.image(10, imgy1, id(${img1}),my_grey); 513 | } 514 | it.print(m5, txty1, id(fntSml), my_blue, TextAlign::BOTTOM_CENTER, "${text2}"); 515 | if (id(ha_${button2}).state == "on") { 516 | it.image(v4+10, imgy1, id(${img2}),my_yellow); 517 | } else { 518 | it.image(v4+10, imgy1, id(${img2}),my_grey); 519 | } 520 | it.print(m1, txty2, id(fntSml), my_blue, TextAlign::BOTTOM_CENTER, "${text3}"); 521 | if (id(ha_${button3}).state == "on") { 522 | it.image(10, imgy2, id(${img3}),my_yellow); 523 | } else { 524 | it.image(10, imgy2, id(${img3}),my_grey); 525 | } 526 | it.print(m2, txty2, id(fntSml), my_blue, TextAlign::BOTTOM_CENTER, "${text4}");; 527 | if (id(ha_${button4}).state == "on") { 528 | it.image(v1+10, imgy2, id(${img4}),my_yellow); 529 | } else { 530 | it.image(v1+10, imgy2, id(${img4}),my_grey); 531 | } 532 | it.print(m3, txty2, id(fntSml), my_blue, TextAlign::BOTTOM_CENTER, "${text5}"); 533 | if (id(ha_${button5}).state == "on") { 534 | it.image(v2+10, imgy2, id(${img5}),my_yellow); 535 | } else { 536 | it.image(v2+10, imgy2, id(${img5}),my_grey); 537 | } 538 | it.print(m4, txty2, id(fntSml), my_blue, TextAlign::BOTTOM_CENTER, "${text6}"); 539 | if (id(ha_${button6}).state == "on") { 540 | it.image(v3+10, imgy2, id(${img6}),my_yellow); 541 | } else { 542 | it.image(v3+10, imgy2, id(${img6}),my_grey); 543 | } 544 | it.print(m5, txty2, id(fntSml), my_blue, TextAlign::BOTTOM_CENTER, "${text7}"); 545 | if (id(ha_${button7}).state == "on") { 546 | it.image(v4+10, imgy2, id(${img7}),my_yellow); 547 | } else { 548 | it.image(v4+10, imgy2, id(${img7}),my_grey); 549 | } 550 | 551 | font: 552 | - file: 553 | type: gfonts 554 | family: "Roboto" 555 | id: fntXS 556 | size: 8 557 | glyphs: 0123456789:. °m 558 | - file: 559 | type: gfonts 560 | family: "Roboto" 561 | id: fntSml 562 | size: 18 563 | - file: 564 | type: gfonts 565 | family: "Roboto" 566 | id: fntMid 567 | size: 28 568 | - file: 569 | type: gfonts 570 | family: "Roboto Condensed" 571 | weight: bold 572 | id: fntTemp 573 | size: 48 574 | glyphs: 0123456789:. ° 575 | - file: 576 | type: gfonts 577 | family: "Roboto Condensed" 578 | weight: bold 579 | id: fntBig 580 | size: 64 581 | glyphs: 0123456789:. 582 | 583 | color: 584 | - id: my_white 585 | red: 100% 586 | green: 100% 587 | blue: 100% 588 | - id: my_grey 589 | red: 50% 590 | green: 50% 591 | blue: 50% 592 | - id: my_red 593 | red: 100% 594 | green: 25% 595 | blue: 25% 596 | - id: my_green 597 | red: 0% 598 | green: 80% 599 | blue: 0% 600 | - id: my_blue 601 | red: 20% 602 | green: 60% 603 | blue: 100% 604 | - id: my_purple 605 | red: 100% 606 | green: 0% 607 | blue: 100% 608 | - id: my_yellow 609 | red: 75% 610 | green: 75% 611 | blue: 0% 612 | 613 | 614 | image: 615 | - file: mdi:air-conditioner 616 | id: imgAirco 617 | resize: 76x70 618 | dither: FLOYDSTEINBERG 619 | type: GRAYSCALE 620 | - file: mdi:lightbulb 621 | id: imgLamp 622 | resize: 76x76 623 | dither: FLOYDSTEINBERG 624 | type: GRAYSCALE 625 | - file: mdi:lightbulb-group 626 | id: imgLampgroup 627 | resize: 76x76 628 | dither: FLOYDSTEINBERG 629 | type: GRAYSCALE 630 | - file: mdi:wifi-strength-alert-outline 631 | id: wifi0 632 | resize: 24x24 633 | dither: FLOYDSTEINBERG 634 | type: GRAYSCALE 635 | - file: mdi:wifi-strength-1 636 | id: wifi1 637 | resize: 24x24 638 | dither: FLOYDSTEINBERG 639 | type: GRAYSCALE 640 | - file: mdi:wifi-strength-2 641 | id: wifi2 642 | resize: 24x24 643 | dither: FLOYDSTEINBERG 644 | type: GRAYSCALE 645 | - file: mdi:wifi-strength-3 646 | id: wifi3 647 | resize: 24x24 648 | dither: FLOYDSTEINBERG 649 | type: GRAYSCALE 650 | - file: mdi:wifi-strength-4 651 | id: wifi4 652 | resize: 24x24 653 | dither: FLOYDSTEINBERG 654 | type: GRAYSCALE 655 | - file: mdi:sun-thermometer-outline 656 | id: ImgTempout 657 | resize: 32x32 658 | dither: FLOYDSTEINBERG 659 | type: GRAYSCALE 660 | - file: mdi:home-thermometer-outline 661 | id: ImgTempin 662 | resize: 32x32 663 | dither: FLOYDSTEINBERG 664 | type: GRAYSCALE 665 | - file: mdi:motion-sensor 666 | id: ImgMotion 667 | resize: 24x24 668 | dither: FLOYDSTEINBERG 669 | type: GRAYSCALE 670 | - file: ./images/weather1/clear-night.png 671 | id: ImgCnd1 672 | type: RGB 673 | transparency: chroma_key 674 | # transparency: 675 | resize: 72x72 676 | - file: ./images/weather1/cloudy.png 677 | id: ImgCnd2 678 | type: RGB 679 | transparency: chroma_key 680 | resize: 72x72 681 | - file: ./images/weather1/fog.png 682 | id: ImgCnd3 683 | type: RGB 684 | transparency: chroma_key 685 | resize: 72x72 686 | - file: ./images/weather1/hail.png 687 | id: ImgCnd4 688 | type: RGB 689 | transparency: chroma_key 690 | resize: 72x72 691 | - file: ./images/weather1/lightning.png 692 | id: ImgCnd5 693 | type: RGB 694 | transparency: chroma_key 695 | resize: 72x72 696 | - file: ./images/weather1/lightning-rainy.png 697 | id: ImgCnd6 698 | type: RGB 699 | transparency: chroma_key 700 | resize: 72x72 701 | - file: ./images/weather1/partly-cloudy.png 702 | id: ImgCnd7D 703 | type: RGB 704 | transparency: chroma_key 705 | resize: 72x72 706 | - file: ./images/weather1/partly-cloudyN.png 707 | id: ImgCnd7N 708 | type: RGB 709 | transparency: chroma_key 710 | resize: 72x72 711 | - file: ./images/weather1/rainy.png 712 | id: ImgCnd8 713 | type: RGB 714 | transparency: chroma_key 715 | resize: 72x72 716 | - file: ./images/weather1/rainy.png 717 | id: ImgCnd9 718 | type: RGB 719 | transparency: chroma_key 720 | resize: 72x72 721 | - file: ./images/weather1/snowy.png 722 | id: ImgCnd10 723 | type: RGB 724 | transparency: chroma_key 725 | resize: 72x72 726 | - file: ./images/weather1/snowy-rainy.png 727 | id: ImgCnd11 728 | type: RGB 729 | transparency: chroma_key 730 | resize: 72x72 731 | - file: ./images/weather1/sunny.png 732 | id: ImgCnd12 733 | type: RGB 734 | transparency: chroma_key 735 | resize: 72x72 736 | - file: ./images/weather1/windy.png 737 | id: ImgCnd13 738 | type: RGB 739 | transparency: chroma_key 740 | resize: 72x72 741 | - file: ./images/weather1/windy-variant.png 742 | id: ImgCnd14 743 | type: RGB 744 | transparency: chroma_key 745 | resize: 72x72 746 | - file: ./images/weather1/exceptional.png 747 | id: ImgCnd15 748 | type: RGB 749 | transparency: chroma_key 750 | resize: 72x72 751 | 752 | sensor: 753 | - platform: wifi_signal 754 | name: "${id_prefix}_wifi" 755 | id: "${id_prefix}_wifi" 756 | internal: True 757 | update_interval: 10s 758 | - platform: homeassistant 759 | entity_id: sensor.temp_buiten 760 | id: ha_tempbuiten 761 | internal: True 762 | - platform: homeassistant 763 | entity_id: sensor.atag_binnentemperatuur 764 | id: ha_tempbinnen 765 | internal: True 766 | 767 | 768 | binary_sensor: 769 | # touch sensors page 'klok5' 770 | # 3 regions top to bottom: lines on 96 and 208 771 | # Y=0>94=top=forecast 772 | # Y=98>206=middle=button top1/clock/top2 773 | # Y=210>318=bottom=buttons bot1/.../bop5 774 | # 5 regions left to right: 775 | # X= (0) 1>93 (95) 97>190 (192) 194>286 (288) 290>382 (384) 386>478 (480) 776 | - <<: !include {file: includes/iTouch2.yaml, vars: {iId: "k5top1", iPg: "klok5", iX1: "1", iX2: "93", iY1: "98", iY2: "206", iSc: "but1_script"}} 777 | - <<: !include {file: includes/iTouch2.yaml, vars: {iId: "k5top2", iPg: "klok5", iX1: "386", iX2: "478", iY1: "98", iY2: "206", iSc: "but2_script"}} 778 | - <<: !include {file: includes/iTouch2.yaml, vars: {iId: "k5bot1", iPg: "klok5", iX1: "1", iX2: "93", iY1: "210", iY2: "318", iSc: "but3_script"}} 779 | - <<: !include {file: includes/iTouch2.yaml, vars: {iId: "k5bot2", iPg: "klok5", iX1: "97", iX2: "190", iY1: "210", iY2: "318", iSc: "but4_script"}} 780 | - <<: !include {file: includes/iTouch2.yaml, vars: {iId: "k5bot3", iPg: "klok5", iX1: "194", iX2: "286", iY1: "210", iY2: "318", iSc: "but5_script"}} 781 | - <<: !include {file: includes/iTouch2.yaml, vars: {iId: "k5bot4", iPg: "klok5", iX1: "290", iX2: "382", iY1: "210", iY2: "318", iSc: "but6_script"}} 782 | - <<: !include {file: includes/iTouch2.yaml, vars: {iId: "k5bot5", iPg: "klok5", iX1: "386", iX2: "478", iY1: "210", iY2: "318", iSc: "but7_script"}} 783 | - <<: !include {file: includes/iTouch2.yaml, vars: {iId: "k5changeforecast", iPg: "klok5", iX1: "10", iX2: "470", iY1: "0", iY2: "94", iSc: "but_forecast"}} 784 | - <<: !include {file: includes/iTouch2.yaml, vars: {iId: "k5touchklok", iPg: "klok5", iX1: "97", iX2: "382", iY1: "98", iY2: "206", iSc: "but_time"}} 785 | - platform: gpio 786 | pin: 33 787 | name: "prox_move" 788 | id: "prox_move" 789 | device_class: motion 790 | on_state: 791 | - script.execute: undim_script 792 | 793 | text_sensor: 794 | - platform: homeassistant 795 | entity_id: ${type1}.${button1} 796 | id: ha_${button1} 797 | internal: True 798 | - platform: homeassistant 799 | entity_id: ${type2}.${button2} 800 | id: ha_${button2} 801 | internal: True 802 | - platform: homeassistant 803 | entity_id: ${type3}.${button3} 804 | id: ha_${button3} 805 | internal: True 806 | - platform: homeassistant 807 | entity_id: ${type4}.${button4} 808 | id: ha_${button4} 809 | internal: True 810 | - platform: homeassistant 811 | entity_id: ${type5}.${button5} 812 | id: ha_${button5} 813 | internal: True 814 | - platform: homeassistant 815 | entity_id: ${type6}.${button6} 816 | id: ha_${button6} 817 | internal: True 818 | - platform: homeassistant 819 | entity_id: ${type7}.${button7} 820 | id: ha_${button7} 821 | internal: True 822 | - platform: homeassistant 823 | entity_id: sensor.forecast_8hours 824 | id: ha_forecast 825 | internal: True 826 | - platform: homeassistant 827 | entity_id: sensor.forecast_5days 828 | id: ha_forecast5days 829 | internal: True 830 | -------------------------------------------------------------------------------- /wt32sc01a.yaml: -------------------------------------------------------------------------------- 1 | # Inspired by 2 | # Meconiotech on https://community.home-assistant.io/t/lookig-for-importing-forecast/345520/3 3 | # Delorean https://community.home-assistant.io/t/wt32-sc01-with-esphome/473531/13 4 | # and many more.... 5 | substitutions: 6 | name: "wt32sc01a" 7 | friendly_name: "WT32 SC01 A" 8 | id_prefix: "wt32sc01a" 9 | # for ha entity "light.licht_overloop" typeX = "light" - buttonX = "licht_overloop" 10 | # textX = caption on screen, actionX = action to perform in ha entity, imgX = image used on button 11 | button1: "power_airco" 12 | text1: "airco" 13 | type1: "switch" 14 | action1: "turn_on" 15 | img1: "imgAirco" 16 | #----------------- 17 | button2: "all_boven" 18 | text2: "boven" 19 | type2: "light" 20 | action2: "turn_off" 21 | img2: "imgLampgroup" 22 | #----------------- 23 | button3: "licht_overloop" 24 | text3: "overloop" 25 | type3: "light" 26 | action3: "toggle" 27 | img3: "imgLamp" 28 | #----------------- 29 | button4: "licht_trap" 30 | text4: "trap" 31 | type4: "light" 32 | action4: "toggle" 33 | img4: "imgLamp" 34 | #----------------- 35 | button5: "licht_inkom" 36 | text5: "inkom" 37 | type5: "light" 38 | action5: "toggle" 39 | img5: "imgLamp" 40 | #----------------- 41 | button6: "all_woonkamer" 42 | text6: "woonk." 43 | type6: "light" 44 | action6: "turn_off" 45 | img6: "imgLampgroup" 46 | #----------------- 47 | button7: "all_beneden" 48 | text7: "beneden" 49 | type7: "light" 50 | action7: "turn_off" 51 | img7: "imgLampgroup" 52 | #----------------- 53 | delay1: "100ms" 54 | delay2: "300ms" 55 | 56 | esphome: 57 | name: ${name} 58 | friendly_name: ${friendly_name} 59 | on_boot: 60 | then: 61 | - light.turn_on: 62 | id: ${id_prefix}_backlight 63 | brightness: 50% 64 | - display.page.show: klok5 65 | 66 | esp32: 67 | board: esp-wrover-kit 68 | framework: 69 | type: arduino 70 | psram: 71 | mode: octal 72 | speed: 80MHz 73 | 74 | preferences: 75 | flash_write_interval: 15min 76 | 77 | logger: 78 | level: Error 79 | 80 | api: 81 | encryption: 82 | key: !secret ha_defaultkey 83 | 84 | ota: 85 | - platform: esphome 86 | password: !secret esphome_ota_pw 87 | 88 | wifi: 89 | ssid: !secret wifi_ssid_iot 90 | password: !secret wifi_pw_iot 91 | manual_ip: 92 | static_ip: !secret ip_wt32sc01a 93 | gateway: !secret ip_iot_gateway 94 | subnet: !secret ip_iot_subnet 95 | dns1: !secret ip_iot_dns 96 | ap: 97 | ssid: "${name} Fallback Hotspot" 98 | password: !secret esphome_fb_pw 99 | 100 | globals: 101 | - id: global_forecast 102 | type: int 103 | restore_value: no 104 | initial_value: '0' 105 | 106 | script: 107 | - id: undim_script 108 | mode: restart 109 | then: 110 | - light.turn_on: 111 | id: ${id_prefix}_backlight 112 | brightness: 70% 113 | - delay: 15 sec 114 | - light.turn_on: 115 | id: ${id_prefix}_backlight 116 | brightness: 15% 117 | - id: but1_script 118 | mode: single 119 | then: 120 | - homeassistant.service: 121 | service: ${type1}.${action1} 122 | data_template: 123 | entity_id: ${type1}.${button1} 124 | - delay: ${delay1} 125 | - component.update: ${id_prefix}_display 126 | - delay: ${delay2} 127 | - lambda: |- 128 | ESP_LOGI("cal","knop"); 129 | 130 | - id: but2_script 131 | mode: single 132 | then: 133 | - homeassistant.service: 134 | service: ${type2}.${action2} 135 | data_template: 136 | entity_id: ${type2}.${button2} 137 | - delay: ${delay1} 138 | - component.update: ${id_prefix}_display 139 | - delay: ${delay2} 140 | - id: but3_script 141 | mode: single 142 | then: 143 | - homeassistant.service: 144 | service: ${type3}.${action3} 145 | data_template: 146 | entity_id: ${type3}.${button3} 147 | - delay: ${delay1} 148 | - component.update: ${id_prefix}_display 149 | - delay: ${delay2} 150 | - id: but4_script 151 | mode: single 152 | then: 153 | - homeassistant.service: 154 | service: ${type4}.${action4} 155 | data_template: 156 | entity_id: ${type4}.${button4} 157 | - delay: ${delay1} 158 | - component.update: ${id_prefix}_display 159 | - delay: ${delay2} 160 | - id: but5_script 161 | mode: single 162 | then: 163 | - homeassistant.service: 164 | service: ${type5}.${action5} 165 | data_template: 166 | entity_id: ${type5}.${button5} 167 | - delay: ${delay1} 168 | - component.update: ${id_prefix}_display 169 | - delay: ${delay2} 170 | - id: but6_script 171 | mode: single 172 | then: 173 | - homeassistant.service: 174 | service: ${type6}.${action6} 175 | data_template: 176 | entity_id: ${type6}.${button6} 177 | - delay: ${delay1} 178 | - component.update: ${id_prefix}_display 179 | - delay: ${delay2} 180 | - id: but7_script 181 | mode: single 182 | then: 183 | - homeassistant.service: 184 | service: ${type7}.${action7} 185 | data_template: 186 | entity_id: ${type7}.${button7} 187 | - delay: ${delay1} 188 | - component.update: ${id_prefix}_display 189 | - delay: ${delay2} 190 | - id: but_forecast 191 | mode: single 192 | then: 193 | - globals.set: 194 | id: global_forecast 195 | value: !lambda |- 196 | if (id(global_forecast) == 1) { 197 | return 0; 198 | } else { 199 | return 1; 200 | } 201 | - component.update: ${id_prefix}_display 202 | - delay: ${delay2} 203 | - id: but_time 204 | mode: single 205 | then: 206 | - script.execute: undim_script 207 | - delay: ${delay2} 208 | 209 | time: 210 | - platform: homeassistant 211 | id: homeassistant_time 212 | 213 | output: 214 | - platform: ledc 215 | pin: GPIO23 216 | id: gpio_23_backlight_pwm 217 | 218 | light: 219 | - platform: monochromatic 220 | output: gpio_23_backlight_pwm 221 | name: "${friendly_name} backlight" 222 | id: ${id_prefix}_backlight 223 | restore_mode: RESTORE_DEFAULT_OFF 224 | 225 | i2c: 226 | id: i2c_bus_intern 227 | sda: 18 228 | scl: 19 229 | scan: false 230 | 231 | touchscreen: 232 | - platform: ft63x6 233 | id: ${id_prefix}_touch 234 | i2c_id: i2c_bus_intern 235 | interrupt_pin: GPIO39 236 | transform: 237 | swap_xy: true 238 | mirror_y: true 239 | on_touch: 240 | - script.execute: undim_script 241 | # - lambda: |- 242 | # ESP_LOGI("cal", "x=%d, y=%d, x_raw=%d, y_raw=%0d", 243 | # touch.x, 244 | # touch.y, 245 | # touch.x_raw, 246 | # touch.y_raw 247 | # ); 248 | 249 | spi: 250 | clk_pin: GPIO14 251 | mosi_pin: GPIO13 252 | miso_pin: GPIO12 253 | 254 | display: 255 | - platform: ili9xxx 256 | id: ${id_prefix}_display 257 | model: ST7796 258 | cs_pin: GPIO15 259 | dc_pin: GPIO21 260 | reset_pin: GPIO22 261 | invert_colors: false 262 | transform: 263 | swap_xy: true 264 | dimensions: 265 | width: 480 266 | height: 320 267 | # rotation: 90 268 | pages: 269 | - id: klok5 270 | lambda: |- 271 | auto time = id(homeassistant_time).now(); 272 | uint16_t v1 = 96; uint16_t v2 = 192; uint16_t v3 = 288; uint16_t v4 = 384; 273 | uint16_t m1 = 48; uint16_t m2 = 144; uint16_t m3 = 240; uint16_t m4 = 336; uint16_t m5 = 432; 274 | it.line(0, 96, 479, 96, my_blue); 275 | it.line(0, 208, 479, 208, my_blue); 276 | // select hourly or daily forecast depending on 'global_forecast' 277 | std::string sForecasts = ""; 278 | if (id(global_forecast) == 0) { 279 | if (id(ha_forecast).has_state()) { 280 | sForecasts = id(ha_forecast).state; 281 | } 282 | } else { 283 | if (id(ha_forecast5days).has_state()) { 284 | sForecasts = id(ha_forecast5days).state; 285 | } 286 | } 287 | if ((sForecasts > "") & (sForecasts != "Null")) { 288 | uint8_t count = 0; 289 | uint16_t wx = 0; 290 | uint16_t imglft; 291 | uint16_t imgtop = 15; 292 | char *outerloop = NULL; 293 | char *innerloop = NULL; 294 | char *Ftime; 295 | char *FtempL; 296 | char *FtempH; 297 | char *Fmm; 298 | char *Fcondition; 299 | uint8_t FCondCode; 300 | char *Fdaynight; 301 | 302 | // loop through first 5 forecasts 303 | // ============================== 304 | char *sHourly = strtok_r (&sForecasts[0],"#",&outerloop); 305 | while ((sHourly != NULL) && (count < 5 )) { 306 | Ftime = strtok_r (sHourly, ";",&innerloop); 307 | FtempL = strtok_r (NULL, ";",&innerloop); 308 | FtempH = strtok_r (NULL, ";",&innerloop); 309 | Fmm = strtok_r (NULL, ";",&innerloop); 310 | Fcondition = strtok_r (NULL, ";",&innerloop); 311 | char *sCond = strtok_r (NULL, ";",&innerloop); 312 | FCondCode = atoi(sCond); 313 | Fdaynight = strtok_r (NULL, ";",&innerloop); 314 | 315 | // display image based on condition code an daynight code 316 | // ====================================================== 317 | imglft = wx + 13; 318 | switch(FCondCode) { 319 | case 1: 320 | it.image(imglft, imgtop, id(ImgCnd1)); 321 | break; 322 | case 2: 323 | it.image(imglft, imgtop, id(ImgCnd2)); 324 | break; 325 | case 3: 326 | it.image(imglft, imgtop, id(ImgCnd3)); 327 | break; 328 | case 4: 329 | it.image(imglft, imgtop, id(ImgCnd4)); 330 | break; 331 | case 5: 332 | it.image(imglft, imgtop, id(ImgCnd5)); 333 | break; 334 | case 6: 335 | it.image(imglft, imgtop, id(ImgCnd6)); 336 | break; 337 | case 7: 338 | if (strcmp(Fdaynight,"D") == 0) { 339 | it.image(imglft, imgtop, id(ImgCnd7D)); 340 | } else { 341 | it.image(imglft, imgtop, id(ImgCnd7N)); 342 | } 343 | break; 344 | case 8: 345 | it.image(imglft, imgtop, id(ImgCnd8)); 346 | break; 347 | case 9: 348 | it.image(imglft, imgtop, id(ImgCnd9)); 349 | break; 350 | case 10: 351 | it.image(imglft, imgtop, id(ImgCnd10)); 352 | break; 353 | case 11: 354 | it.image(imglft, imgtop, id(ImgCnd11)); 355 | break; 356 | case 12: 357 | if (strcmp(Fdaynight,"D") == 0) { 358 | it.image(imglft, imgtop, id(ImgCnd12)); 359 | } else { 360 | it.image(imglft, imgtop, id(ImgCnd1)); 361 | } 362 | 363 | break; 364 | default: 365 | it.printf(wx+48, 60, id(fntSml), my_blue, TextAlign::BOTTOM_CENTER, "%s", Fcondition); 366 | } 367 | int tgaugemax; int tgaugemin; int tzero; 368 | switch(time.month) { 369 | case 11: 370 | case 12: 371 | case 1: 372 | case 2: // winter: -12°>0>20° 373 | tgaugemax = 40; tgaugemin = -24; tzero = 65; // (25=max/ 89=min /65=0) 374 | break; 375 | case 5: 376 | case 6: 377 | case 7: 378 | case 8: 379 | case 9: // summer: 0>32° 380 | tgaugemax = 64; tgaugemin = 0; tzero = 89; // (25=max/ 89=min /89=0) 381 | break; 382 | default: // -8°>0>24° 383 | tgaugemax = 48; tgaugemin = -16; tzero = 73; // (25=max/ 89=min /73=0) 384 | } 385 | 386 | // display hour temperature 387 | // ======================== 388 | it.printf(wx+6, 0, id(fntSml), my_blue, TextAlign::TOP_LEFT, "%s", Ftime); 389 | it.printf(wx+89, 0, id(fntSml), my_blue, TextAlign::TOP_RIGHT, "%s°", FtempH); 390 | 391 | // display temp gauge 392 | // ================== 393 | it.rectangle(wx+8, 24, 8, 66, my_grey); 394 | int templow = int((atof(FtempL) * 2) + 0.5); 395 | int temphigh = int((atof(FtempH) * 2) + 0.5); 396 | if (templow < -tgaugemin) {templow = -tgaugemin;} 397 | if (temphigh < -tgaugemin) {temphigh = -tgaugemin;} 398 | if (templow > tgaugemax) {templow = tgaugemax;} 399 | if (temphigh > tgaugemax) {temphigh = tgaugemax;} 400 | if (templow == temphigh) {templow = 0;} // for hourly 401 | if (templow > 0) { 402 | it.filled_rectangle(wx+9, (tzero-temphigh) , 6, (temphigh - templow + 1), my_yellow); 403 | } else if (temphigh < 0) { 404 | it.filled_rectangle(wx+9, (tzero+temphigh) , 6, (temphigh - templow + 1), my_red); 405 | } else { 406 | it.filled_rectangle(wx+9, tzero-temphigh , 6, temphigh, my_yellow); 407 | it.filled_rectangle(wx+9, tzero , 6, (templow * -1), my_red); 408 | } 409 | it.line(wx+8, tzero, wx+18, tzero, my_grey); 410 | it.line(wx+16, tzero-20, wx+18, tzero-20, my_grey); 411 | it.line(wx+16, tzero-40, wx+18, tzero-40, my_grey); 412 | it.line(wx+16, tzero-10, wx+17, tzero-10, my_grey); 413 | it.line(wx+16, tzero-30, wx+17, tzero-30, my_grey); 414 | if (tgaugemax > 60) { 415 | it.line(wx+16, tzero-60, wx+18, tzero-60, my_grey); 416 | it.line(wx+16, tzero-50, wx+17, tzero-50, my_grey); 417 | } 418 | it.print(wx+20, tzero-5, id(fntXS), my_grey, TextAlign::TOP_LEFT, "0");; 419 | it.printf(wx+20, 20, id(fntXS), my_grey, TextAlign::TOP_LEFT, "%i",(tgaugemax/2)); 420 | 421 | // display precipitation gauge 422 | // =========================== 423 | uint16_t scaleprecip; 424 | uint16_t scalemax; 425 | float precip = atof(Fmm); 426 | bool preciphigh = false; 427 | if (id(global_forecast) == 0) { 428 | if (precip > 2) { 429 | scaleprecip = (uint16_t) (precip * 16); 430 | scalemax = 4; 431 | preciphigh = true; 432 | } else { 433 | scaleprecip = (uint16_t) (precip * 32); 434 | scalemax = 2; 435 | } 436 | } else { 437 | if (precip > 10) { 438 | scaleprecip = (uint16_t) (precip * 3.2); 439 | scalemax = 20; 440 | preciphigh = true; 441 | } else { 442 | scaleprecip = (uint16_t) (precip * 6.4); 443 | scalemax = 10; 444 | } 445 | } 446 | if (scaleprecip > 64) {scaleprecip = 64;} 447 | FCondCode = atoi(sCond); 448 | imglft = wx + 12; 449 | it.rectangle(wx+80, 24, 8, 66, my_grey); 450 | if (preciphigh) { 451 | it.filled_rectangle(wx+81, 89 - scaleprecip, 6, scaleprecip, my_purple); 452 | } else { 453 | it.filled_rectangle(wx+81, 89 - scaleprecip, 6, scaleprecip, my_blue); 454 | } 455 | it.line(wx+78, 24, wx+80, 24, my_grey); 456 | it.line(wx+78, 56, wx+80, 56, my_grey); 457 | it.line(wx+78, 89, wx+80, 89, my_grey); 458 | it.print(wx+78, 84, id(fntXS), my_grey, TextAlign::TOP_RIGHT, "0mm"); 459 | it.printf(wx+78, 20, id(fntXS), my_grey, TextAlign::TOP_RIGHT, "%imm", scalemax); 460 | wx+=96; 461 | count++; 462 | sHourly = strtok_r (NULL,"#",&outerloop); 463 | } 464 | } 465 | it.line(v1, 96, v1, 319, my_blue); 466 | it.line(v2, 208, v2, 319, my_blue); 467 | it.line(v3, 208, v3, 319, my_blue); 468 | it.line(v4, 96, v4, 319, my_blue); 469 | // ================================ 470 | // Display Time, Date, Temperatures 471 | // ================================ 472 | it.strftime(m3, 175, id(fntBig), my_white, TextAlign::BOTTOM_CENTER, "%H:%M", time); 473 | it.strftime(m3, 200, id(fntMid), my_white, TextAlign::BOTTOM_CENTER, "%d:%m:%Y", time); 474 | it.image(102, 130, id(ImgTempin), my_yellow); 475 | it.printf(102, 100, id(fntMid), my_yellow, TextAlign::TOP_LEFT, "%.1f°", id(ha_tempbinnen).state); 476 | it.image(346, 130, id(ImgTempout), my_yellow); 477 | it.printf(380, 100, id(fntMid), my_yellow, TextAlign::TOP_RIGHT, "%.1f°", id(ha_tempbuiten).state); 478 | // ==================== 479 | // Display WifiStrenght 480 | // ==================== 481 | uint16_t wfx = 105; 482 | uint16_t wfy = 176; 483 | if (id(${id_prefix}_wifi).has_state()) { 484 | if (id(${id_prefix}_wifi).state < -70) { 485 | it.image(wfx, wfy, id(wifi1),my_yellow); 486 | } else if (id(${id_prefix}_wifi).state < -60) { 487 | it.image(wfx, wfy, id(wifi2),my_green); 488 | } else if (id(${id_prefix}_wifi).state < -50) { 489 | it.image(wfx, wfy, id(wifi3),my_green); 490 | } else { 491 | it.image(wfx, wfy, id(wifi4),my_green); 492 | } 493 | it.printf(128, 206, id(fntSml), my_green, TextAlign::BOTTOM_LEFT, "%.0f",id(${id_prefix}_wifi).state); 494 | } else { 495 | it.image(wfx, wfy, id(wifi0),my_red); 496 | } 497 | // ============== 498 | // Display Motion 499 | // ============== 500 | if (id(prox_move).state) { 501 | it.image(346, wfy, id(ImgMotion),my_yellow); 502 | } else { 503 | it.image(346, wfy, id(ImgMotion),my_grey); 504 | } 505 | // =============== 506 | // Display Buttons 507 | // =============== 508 | uint16_t imgy1 = 104; uint16_t txty1 = 200; 509 | uint16_t imgy2 = 216; uint16_t txty2 = 312; 510 | it.print(m1, txty1, id(fntSml), my_blue, TextAlign::BOTTOM_CENTER, "${text1}"); 511 | if (id(ha_${button1}).state == "on") { 512 | it.image(10, imgy1, id(${img1}),my_yellow); 513 | } else { 514 | it.image(10, imgy1, id(${img1}),my_grey); 515 | } 516 | it.print(m5, txty1, id(fntSml), my_blue, TextAlign::BOTTOM_CENTER, "${text2}"); 517 | if (id(ha_${button2}).state == "on") { 518 | it.image(v4+10, imgy1, id(${img2}),my_yellow); 519 | } else { 520 | it.image(v4+10, imgy1, id(${img2}),my_grey); 521 | } 522 | it.print(m1, txty2, id(fntSml), my_blue, TextAlign::BOTTOM_CENTER, "${text3}"); 523 | if (id(ha_${button3}).state == "on") { 524 | it.image(10, imgy2, id(${img3}),my_yellow); 525 | } else { 526 | it.image(10, imgy2, id(${img3}),my_grey); 527 | } 528 | it.print(m2, txty2, id(fntSml), my_blue, TextAlign::BOTTOM_CENTER, "${text4}");; 529 | if (id(ha_${button4}).state == "on") { 530 | it.image(v1+10, imgy2, id(${img4}),my_yellow); 531 | } else { 532 | it.image(v1+10, imgy2, id(${img4}),my_grey); 533 | } 534 | it.print(m3, txty2, id(fntSml), my_blue, TextAlign::BOTTOM_CENTER, "${text5}"); 535 | if (id(ha_${button5}).state == "on") { 536 | it.image(v2+10, imgy2, id(${img5}),my_yellow); 537 | } else { 538 | it.image(v2+10, imgy2, id(${img5}),my_grey); 539 | } 540 | it.print(m4, txty2, id(fntSml), my_blue, TextAlign::BOTTOM_CENTER, "${text6}"); 541 | if (id(ha_${button6}).state == "on") { 542 | it.image(v3+10, imgy2, id(${img6}),my_yellow); 543 | } else { 544 | it.image(v3+10, imgy2, id(${img6}),my_grey); 545 | } 546 | it.print(m5, txty2, id(fntSml), my_blue, TextAlign::BOTTOM_CENTER, "${text7}"); 547 | if (id(ha_${button7}).state == "on") { 548 | it.image(v4+10, imgy2, id(${img7}),my_yellow); 549 | } else { 550 | it.image(v4+10, imgy2, id(${img7}),my_grey); 551 | } 552 | 553 | font: 554 | - file: 555 | type: gfonts 556 | family: "Roboto" 557 | id: fntXS 558 | size: 8 559 | glyphs: 0123456789:. °m 560 | - file: 561 | type: gfonts 562 | family: "Roboto" 563 | id: fntSml 564 | size: 18 565 | - file: 566 | type: gfonts 567 | family: "Roboto" 568 | id: fntMid 569 | size: 28 570 | - file: 571 | type: gfonts 572 | family: "Roboto Condensed" 573 | weight: bold 574 | id: fntTemp 575 | size: 48 576 | glyphs: 0123456789:. ° 577 | - file: 578 | type: gfonts 579 | family: "Roboto Condensed" 580 | weight: bold 581 | id: fntBig 582 | size: 64 583 | glyphs: 0123456789:. 584 | 585 | color: 586 | - id: my_white 587 | red: 100% 588 | green: 100% 589 | blue: 100% 590 | - id: my_grey 591 | red: 50% 592 | green: 50% 593 | blue: 50% 594 | - id: my_red 595 | red: 100% 596 | green: 25% 597 | blue: 25% 598 | - id: my_green 599 | red: 0% 600 | green: 80% 601 | blue: 0% 602 | - id: my_blue 603 | red: 20% 604 | green: 60% 605 | blue: 100% 606 | - id: my_purple 607 | red: 100% 608 | green: 0% 609 | blue: 100% 610 | - id: my_yellow 611 | red: 75% 612 | green: 75% 613 | blue: 0% 614 | 615 | 616 | image: 617 | - file: mdi:air-conditioner 618 | id: imgAirco 619 | resize: 76x70 620 | dither: FLOYDSTEINBERG 621 | type: grayscale 622 | - file: mdi:lightbulb 623 | id: imgLamp 624 | resize: 76x76 625 | dither: FLOYDSTEINBERG 626 | type: grayscale 627 | - file: mdi:lightbulb-group 628 | id: imgLampgroup 629 | resize: 76x76 630 | dither: FLOYDSTEINBERG 631 | type: grayscale 632 | - file: mdi:wifi-strength-alert-outline 633 | id: wifi0 634 | resize: 24x24 635 | dither: FLOYDSTEINBERG 636 | type: grayscale 637 | - file: mdi:wifi-strength-1 638 | id: wifi1 639 | resize: 24x24 640 | dither: FLOYDSTEINBERG 641 | type: grayscale 642 | - file: mdi:wifi-strength-2 643 | id: wifi2 644 | resize: 24x24 645 | dither: FLOYDSTEINBERG 646 | type: grayscale 647 | - file: mdi:wifi-strength-3 648 | id: wifi3 649 | resize: 24x24 650 | dither: FLOYDSTEINBERG 651 | type: grayscale 652 | - file: mdi:wifi-strength-4 653 | id: wifi4 654 | resize: 24x24 655 | dither: FLOYDSTEINBERG 656 | type: grayscale 657 | - file: mdi:sun-thermometer-outline 658 | id: ImgTempout 659 | resize: 32x32 660 | dither: FLOYDSTEINBERG 661 | type: grayscale 662 | - file: mdi:home-thermometer-outline 663 | id: ImgTempin 664 | resize: 32x32 665 | dither: FLOYDSTEINBERG 666 | type: grayscale 667 | - file: mdi:motion-sensor 668 | id: ImgMotion 669 | resize: 24x24 670 | dither: FLOYDSTEINBERG 671 | type: grayscale 672 | - file: ./images/weather1/clear-night.png 673 | id: ImgCnd1 674 | type: RGB 675 | transparency: chroma_key 676 | resize: 72x72 677 | - file: ./images/weather1/cloudy.png 678 | id: ImgCnd2 679 | type: RGB 680 | transparency: chroma_key 681 | resize: 72x72 682 | - file: ./images/weather1/fog.png 683 | id: ImgCnd3 684 | type: RGB 685 | transparency: chroma_key 686 | resize: 72x72 687 | - file: ./images/weather1/hail.png 688 | id: ImgCnd4 689 | type: RGB 690 | transparency: chroma_key 691 | resize: 72x72 692 | - file: ./images/weather1/lightning.png 693 | id: ImgCnd5 694 | type: RGB 695 | transparency: chroma_key 696 | resize: 72x72 697 | - file: ./images/weather1/lightning-rainy.png 698 | id: ImgCnd6 699 | type: RGB 700 | transparency: chroma_key 701 | resize: 72x72 702 | - file: ./images/weather1/partly-cloudy.png 703 | id: ImgCnd7D 704 | type: RGB 705 | transparency: chroma_key 706 | resize: 72x72 707 | - file: ./images/weather1/partly-cloudyN.png 708 | id: ImgCnd7N 709 | type: RGB 710 | transparency: chroma_key 711 | resize: 72x72 712 | - file: ./images/weather1/rainy.png 713 | id: ImgCnd8 714 | type: RGB 715 | transparency: chroma_key 716 | resize: 72x72 717 | - file: ./images/weather1/rainy.png 718 | id: ImgCnd9 719 | type: RGB 720 | transparency: chroma_key 721 | resize: 72x72 722 | - file: ./images/weather1/snowy.png 723 | id: ImgCnd10 724 | type: RGB 725 | transparency: chroma_key 726 | resize: 72x72 727 | - file: ./images/weather1/snowy-rainy.png 728 | id: ImgCnd11 729 | type: RGB 730 | transparency: chroma_key 731 | resize: 72x72 732 | - file: ./images/weather1/sunny.png 733 | id: ImgCnd12 734 | type: RGB 735 | transparency: chroma_key 736 | resize: 72x72 737 | - file: ./images/weather1/windy.png 738 | id: ImgCnd13 739 | type: RGB 740 | transparency: chroma_key 741 | resize: 72x72 742 | - file: ./images/weather1/windy-variant.png 743 | id: ImgCnd14 744 | type: RGB 745 | transparency: chroma_key 746 | resize: 72x72 747 | - file: ./images/weather1/exceptional.png 748 | id: ImgCnd15 749 | type: RGB 750 | transparency: chroma_key 751 | resize: 72x72 752 | 753 | sensor: 754 | - platform: wifi_signal 755 | name: "${id_prefix}_wifi" 756 | id: "${id_prefix}_wifi" 757 | internal: True 758 | update_interval: 10s 759 | - platform: homeassistant 760 | entity_id: sensor.temp_buiten 761 | id: ha_tempbuiten 762 | internal: True 763 | - platform: homeassistant 764 | entity_id: sensor.atag_binnentemperatuur 765 | id: ha_tempbinnen 766 | internal: True 767 | 768 | binary_sensor: 769 | # touch sensors page 'klok5' 770 | # 3 regions top to bottom: lines on 96 and 208 771 | # Y=0>94=top=forecast 772 | # Y=98>206=middle=button top1/clock/top2 773 | # Y=210>318=bottom=buttons bot1/.../bop5 774 | # 5 regions left to right: 775 | # X= (0) 1>93 (95) 97>190 (192) 194>286 (288) 290>382 (384) 386>478 (480) 776 | - <<: !include {file: includes/iTouch2.yaml, vars: {iId: "k5top1", iPg: "klok5", iX1: "1", iX2: "93", iY1: "98", iY2: "206", iSc: "but1_script"}} 777 | - <<: !include {file: includes/iTouch2.yaml, vars: {iId: "k5top2", iPg: "klok5", iX1: "386", iX2: "478", iY1: "98", iY2: "206", iSc: "but2_script"}} 778 | - <<: !include {file: includes/iTouch2.yaml, vars: {iId: "k5bot1", iPg: "klok5", iX1: "1", iX2: "93", iY1: "210", iY2: "318", iSc: "but3_script"}} 779 | - <<: !include {file: includes/iTouch2.yaml, vars: {iId: "k5bot2", iPg: "klok5", iX1: "97", iX2: "190", iY1: "210", iY2: "318", iSc: "but4_script"}} 780 | - <<: !include {file: includes/iTouch2.yaml, vars: {iId: "k5bot3", iPg: "klok5", iX1: "194", iX2: "286", iY1: "210", iY2: "318", iSc: "but5_script"}} 781 | - <<: !include {file: includes/iTouch2.yaml, vars: {iId: "k5bot4", iPg: "klok5", iX1: "290", iX2: "382", iY1: "210", iY2: "318", iSc: "but6_script"}} 782 | - <<: !include {file: includes/iTouch2.yaml, vars: {iId: "k5bot5", iPg: "klok5", iX1: "386", iX2: "478", iY1: "210", iY2: "318", iSc: "but7_script"}} 783 | - <<: !include {file: includes/iTouch2.yaml, vars: {iId: "k5changeforecast", iPg: "klok5", iX1: "10", iX2: "470", iY1: "0", iY2: "94", iSc: "but_forecast"}} 784 | - <<: !include {file: includes/iTouch2.yaml, vars: {iId: "k5touchklok", iPg: "klok5", iX1: "97", iX2: "382", iY1: "98", iY2: "206", iSc: "but_time"}} 785 | - platform: gpio 786 | pin: 33 787 | name: "prox_move" 788 | id: "prox_move" 789 | device_class: motion 790 | on_state: 791 | - script.execute: undim_script 792 | 793 | text_sensor: 794 | - platform: homeassistant 795 | entity_id: ${type1}.${button1} 796 | id: ha_${button1} 797 | internal: True 798 | - platform: homeassistant 799 | entity_id: ${type2}.${button2} 800 | id: ha_${button2} 801 | internal: True 802 | - platform: homeassistant 803 | entity_id: ${type3}.${button3} 804 | id: ha_${button3} 805 | internal: True 806 | - platform: homeassistant 807 | entity_id: ${type4}.${button4} 808 | id: ha_${button4} 809 | internal: True 810 | - platform: homeassistant 811 | entity_id: ${type5}.${button5} 812 | id: ha_${button5} 813 | internal: True 814 | - platform: homeassistant 815 | entity_id: ${type6}.${button6} 816 | id: ha_${button6} 817 | internal: True 818 | - platform: homeassistant 819 | entity_id: ${type7}.${button7} 820 | id: ha_${button7} 821 | internal: True 822 | - platform: homeassistant 823 | entity_id: sensor.forecast_8hours 824 | id: ha_forecast 825 | internal: True 826 | - platform: homeassistant 827 | entity_id: sensor.forecast_5days 828 | id: ha_forecast5days 829 | internal: True 830 | --------------------------------------------------------------------------------