├── esphome ├── readme.md └── nspanel-mf.yaml ├── photo-lights.png ├── hmi-compiled ├── hmi.tft └── readme.md ├── hmi-project ├── hmi0.HMI └── readme.md ├── screenshot-alarm.png ├── screenshot-boot.png ├── screenshot-home.png ├── screenshot-music.png ├── screenshot-ha-sensors.png └── README.md /esphome/readme.md: -------------------------------------------------------------------------------- 1 | ## ESPHome configuration file 2 | -------------------------------------------------------------------------------- /photo-lights.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcfager/nspanel-mf/HEAD/photo-lights.png -------------------------------------------------------------------------------- /hmi-compiled/hmi.tft: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcfager/nspanel-mf/HEAD/hmi-compiled/hmi.tft -------------------------------------------------------------------------------- /hmi-project/hmi0.HMI: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcfager/nspanel-mf/HEAD/hmi-project/hmi0.HMI -------------------------------------------------------------------------------- /screenshot-alarm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcfager/nspanel-mf/HEAD/screenshot-alarm.png -------------------------------------------------------------------------------- /screenshot-boot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcfager/nspanel-mf/HEAD/screenshot-boot.png -------------------------------------------------------------------------------- /screenshot-home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcfager/nspanel-mf/HEAD/screenshot-home.png -------------------------------------------------------------------------------- /screenshot-music.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcfager/nspanel-mf/HEAD/screenshot-music.png -------------------------------------------------------------------------------- /screenshot-ha-sensors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcfager/nspanel-mf/HEAD/screenshot-ha-sensors.png -------------------------------------------------------------------------------- /hmi-compiled/readme.md: -------------------------------------------------------------------------------- 1 | ## Compiled HMI 2 | The file in this directory is the compiled HMI file ready to be uploaded to the NSPanel. 3 | -------------------------------------------------------------------------------- /hmi-project/readme.md: -------------------------------------------------------------------------------- 1 | ## HMI Project 2 | This file can be edited with [Nextion Editor](https://nextion.tech/nextion-editor/) to alter the HMI. 3 | 4 | Once you have done changes, click "Compile" to verify the code compiles. Click "File" and "TFT file output" to create the tft file for the NSPanel. 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NSPanel-MF 2 | Current version: 2022-01-19. _Changelog further down_ 3 | 4 | Custom HMI controlled by ESPHome for the Sonoff NSPanel. Includes home screen with weather data and clock, media player card, control of 8 lights per card with 4 available cards (can be enabled/disabled from ESPHome/HA), bootup screen and disable screen for alarm. Audible notifications can be sent from Home Assistant that remain visible on the screen for a set period of time. The screen dims down and turns off similarly to a iPhone (dim down + screensaver) and is woken up by tapping the display. More to come. 5 | 6 | Navigation is done by swipe gestures. 7 | 8 | All content on the screen can be controlled from ESPHome and is very easily integrated to Home Assistant. 9 | 10 | [Youtube video](https://www.youtube.com/watch?v=2e5-53lGF94) 11 | 12 | [Youtube video of notification function](https://youtu.be/fmObpwFJT7o) 13 | 14 | ## Credits 15 | I created this based on information shared in the following forum threads: 16 | [Home assistant thread](https://community.home-assistant.io/t/sonoff-nspanel-smart-scene-wall-switch-by-itead-coming-soon-on-kickstarter/332962/), 17 | [ESPHome thread](https://github.com/esphome/feature-requests/issues/1469) 18 | 19 | Significant parts of the ESPHome config and ideas in the HMI are from [Masto](https://github.com/masto/NSPanel-Demo-Files/). 20 | 21 | The HMI theme is based on the [Lovelace iOS dark mode theme](https://github.com/basnijholt/lovelace-ios-dark-mode-theme) 22 | 23 | Weather icons are from [simple weather card](https://github.com/kalkih/simple-weather-card) 24 | 25 | Light icons on the Lights-page are from [Hass BHA Icons](https://github.com/hulkhaugen/hass-bha-icons) 26 | 27 | Other icons are from [Material Design Icons](https://materialdesignicons.com/) 28 | 29 | The font is the Ubuntu font. 30 | 31 | Touch swipe navigation inspired by [blakadder](https://community.home-assistant.io/t/sonoff-nspanel-smart-scene-wall-switch-by-itead-coming-soon-on-kickstarter/332962/120) 32 | 33 | The ESPHome config yaml is based on [Masto's example config](https://github.com/masto/NSPanel-Demo-Files) 34 | 35 | ## HMI Screenshots 36 | ![Home screen](screenshot-home.png) 37 | 38 | ![Music screen](screenshot-music.png) 39 | 40 | ![Lights screen](photo-lights.png) 41 | 42 | ![Bootup screen](screenshot-boot.png) 43 | 44 | ![Alarm screen](screenshot-alarm.png) 45 | 46 | ![Notification screen](screenshot-notification.png) 47 | 48 | ![HA Sensors](screenshot-ha-sensors.png) 49 | 50 | 51 | 52 | _Not all exposed entities are visible on the screenshot._ 53 | _The items look slightly poorly centered. This is to cope with the issue that the physical screen is larger than the visible area._ 54 | 55 | ## Usage 56 | The weather entities, media entities, lights etc. are selected in the ESPHome config. You can navigate between screens by using a swipe gesture on the screen (left or right). The code is prepared for swipe up and down as well. The media player is on the left side, and the lights on the right side. 57 | The config that is not done in ESPHome is done in Home Assistant. 58 | 59 | In the example config a big part of the config is done in the ESPHome YAML file. If you prefer to set-and-forget it, you can replace the media entities, weather entities, light entities etc. with HA templates or input_text fields. That way you can re-configure everything directly from Home Assistant. 60 | 61 | Any information and/or code found here is used on your own risk. 62 | 63 | ## Installation 64 | 1. Install and configure ESPHome. 65 | 2. Prepare the NSPanel for flashing (see instructions in the forum pages linked above). 66 | 3. Download the ESPHome sketch and adjust to your needs. Flash it to the NSPanel. Pay special attention to the _tft_url_ parameter and ensure it is accessible by the NSPanel. 67 | 4. Download the HMI file and save it to the _tft_url_ location. 68 | 5. Add the unit to Home Assistant through the ESPHome integration. 69 | 6. Run the _esphome.nspanel_upload_tft_ service from Home Assistant. This will download the HMI to the NSPanel. Please note that this will block the ESPHome connection during the update. Follow the progress on the HMI screen. When the HMI is installed, reboot the unit. 70 | 7. Configure the unit in Home Assistant to add actions to the buttons etc. it exposes. 71 | 8. Enjoy! 72 | 73 | ## Changelog (latest revision 2022-01-19) 74 | - Swipe support! Navigation between pages is now done by swiping the screen left or right. Code prepared for up and down as well. Based on blakadder's method. A page "Swipe", id 12, is available to adjust the threshold values and to make the code easily transferable to your custom design. The actual threshold values are stored as global variables in the Program.s-tab in the Nextion Editor. 75 | - The screen will automatically naviagte back to the Home screen if left untouched for a set period of time. Can be disabled from HA, but that also disables dimdown and screensaver. 76 | - Dimdown and screen saver. The screen will dim down after a set period of time if left untouched (30 s). After 30 more seconds (1 min in total), the "screensaver" will go on. This makes the screen all black and turns off the backlight. The function was inspired by masto's setup, but slightly modified to make GUI development easier and to better work with multiple pages. 77 | - Multiple Lights pages that can be enabled and disabled from ESPHome - even dynamically during runtime if needed. 78 | - QR page added to display QR codes. The page works, but the service is broken. Need to figure out a way to pass the actual data to it. What already works is to manually go to the QR page and to manually set the QR data. The corresponding QR image is then generated. 79 | - Fixed so that the weather symbol for sunny after sunset is clear-night 80 | - Added Home.text1 and Home.text2 with a small font to the lower right corner of the Home page. I use them to display the fuel/charging state and ranges of our cars. 81 | 82 | ## Breaking changes (latest revision 2022-01-19) 83 | Component numbering changed as the old navigation hotspots have been removed. Affects Music and Light page. 84 | 85 | 86 | ## TODO 87 | Somewhat in a priority order: 88 | - Add equipment page for vacuum robot, lawn mower robot, AC. 89 | - Add electrical power monitoring page 90 | - Fix QR page (my idea is to use it to share Wifi-access without passwords) 91 | - Add support for RGBW lights (change color etc). 92 | -------------------------------------------------------------------------------- /esphome/nspanel-mf.yaml: -------------------------------------------------------------------------------- 1 | # NSPanel YAML by marcfager. Please check github for credits: https://github.com/marcfager/nspanel-mf 2 | # Version 2022-01-19 3 | 4 | substitutions: 5 | # Name the device and it's entities 6 | device_name: nspanel-dev 7 | 8 | # Example config.yaml 9 | esphome: 10 | name: nspanel 11 | comment: $device_name 12 | 13 | esp32: 14 | board: esp32dev 15 | 16 | # Wifi settings. Add these to your secrets.yaml. fast_connect must be true for a hidden ssid. 17 | wifi: 18 | ssid: !secret ssid 19 | password: !secret wifi_pwd 20 | fast_connect: !secret wifi_fast_connect 21 | 22 | # API. Add api_pwd to your secrets.yaml. 23 | api: 24 | password: !secret api_pwd 25 | services: 26 | # Service to play a rtttl tone 27 | - service: play_rtttl 28 | variables: 29 | song_str: string 30 | then: 31 | - rtttl.play: 32 | rtttl: !lambda 'return song_str;' 33 | # Service to update the HMI file 34 | - service: upload_tft 35 | then: 36 | - lambda: 'id(disp1)->upload_tft();' 37 | # Service to control the visible page from Home Assistant 38 | - service: set_page 39 | variables: 40 | page: int 41 | then: 42 | - lambda: id(disp1).send_command_printf("page %i", page); 43 | # Service to show a notification on the screen for 15 s. Tap or wait to close 44 | - service: notification 45 | variables: 46 | header: string 47 | message: string 48 | then: 49 | - lambda: |- 50 | id(disp1).set_component_text_printf("Notifications.head", "%s", header.c_str()); 51 | id(disp1).set_component_text_printf("Notifications.body", "%s", message.c_str()); 52 | id(disp1).send_command_printf("page 6"); 53 | - rtttl.play: "twobits:d=4,o=5,b=220:c6,8g,8g,a,g,p,b,c6" 54 | - delay: 15s 55 | - lambda: |- 56 | id(disp1).send_command_printf("page 0"); 57 | id(disp1).set_component_text_printf("Notifications.head", " "); 58 | id(disp1).set_component_text_printf("Notifications.body", " "); 59 | id(disp1).send_command_printf("page 0"); 60 | # Service to send a command directly to the display. Useful for testing 61 | - service: send_command 62 | variables: 63 | cmd: string 64 | then: 65 | - lambda: 'id(disp1).send_command_printf("%s", cmd.c_str());' 66 | # Service to show a QR code on the display (ex. for WiFi password) 67 | - service: display_qr 68 | variables: 69 | qrdata: string 70 | then: 71 | - lambda: |- 72 | id(disp1).set_component_text_printf("QR.qr0", "%s", qrdata.c_str()); 73 | id(disp1).send_command_printf("page 7"); 74 | - delay: 15s 75 | - lambda: |- 76 | id(disp1).send_command_printf("page 0"); 77 | id(disp1).send_command_printf("QR.qr0.txt="); 78 | id(disp1).send_command_printf("page 0"); 79 | # Service to wake up screen 80 | - service: wakeup_screen 81 | then: 82 | - lambda: |- 83 | id(disp1).send_command_printf("page 0"); 84 | 85 | 86 | # Time component that fetches time from Home Assistant and updates the display once a minute and when the display is ready at bootup (and time is available). 87 | time: 88 | - platform: homeassistant 89 | id: homeassistant_time 90 | on_time: 91 | - seconds: 0 92 | minutes: /1 93 | then: 94 | - lambda: id(disp1).set_component_text_printf("Home.time", "%02i:%02i", id(homeassistant_time).now().hour, id(homeassistant_time).now().minute); 95 | - lambda: id(disp1).set_component_text_printf("Home.date", "%i-%02i-%02i", id(homeassistant_time).now().year, id(homeassistant_time).now().month, id(homeassistant_time).now().day_of_month); 96 | on_time_sync: 97 | then: 98 | - wait_until: 99 | switch.is_on: nextion_init 100 | - lambda: id(disp1).set_component_text_printf("Home.time", "%02i:%02i", id(homeassistant_time).now().hour, id(homeassistant_time).now().minute); 101 | - lambda: id(disp1).set_component_text_printf("Home.date", "%i-%02i-%02i", id(homeassistant_time).now().year, id(homeassistant_time).now().month, id(homeassistant_time).now().day_of_month); 102 | 103 | 104 | # Logger. Disable the temperature sensor etc. to focus on the HMI development 105 | logger: 106 | baud_rate: 0 107 | level: DEBUG 108 | logs: 109 | sensor: WARN 110 | resistance: WARN 111 | text_sensor: WARN 112 | ntc: WARN 113 | 114 | # OTA (Over the air updates) password. Add to your secrets.yaml 115 | ota: 116 | password: !secret ota_pwd 117 | 118 | # Uart for the Nextion display 119 | uart: 120 | tx_pin: 16 121 | rx_pin: 17 122 | baud_rate: 115200 123 | id: tf_uart 124 | 125 | # Functionality for the Nextion display 126 | external_components: 127 | - source: github://pr#2956 128 | components: [nextion] 129 | refresh: 1h 130 | 131 | # A reboot button is always useful 132 | button: 133 | - platform: restart 134 | name: $device_name Restart 135 | 136 | # Binary sensors 137 | binary_sensor: 138 | # Left button below the display 139 | - platform: gpio 140 | name: $device_name Left Button 141 | pin: 142 | number: 14 143 | inverted: true 144 | on_click: 145 | - switch.toggle: relay_1 146 | 147 | # Right button below the display 148 | - platform: gpio 149 | name: $device_name Right Button 150 | pin: 151 | number: 27 152 | inverted: true 153 | on_click: 154 | - switch.toggle: relay_2 155 | 156 | 157 | # Buttons on the Music page 158 | - platform: nextion 159 | name: $device_name Music previous 160 | page_id: 1 161 | component_id: 1 162 | 163 | - platform: nextion 164 | name: $device_name Music play pause 165 | page_id: 1 166 | component_id: 2 167 | 168 | - platform: nextion 169 | name: $device_name Music next 170 | page_id: 1 171 | component_id: 3 172 | 173 | - platform: nextion 174 | name: $device_name Music cast 175 | page_id: 1 176 | component_id: 4 177 | 178 | - platform: nextion 179 | name: $device_name Music voldown 180 | page_id: 1 181 | component_id: 7 182 | 183 | - platform: nextion 184 | name: $device_name Music volup 185 | page_id: 1 186 | component_id: 8 187 | 188 | - platform: nextion 189 | name: $device_name Playlist cocktail 190 | page_id: 1 191 | component_id: 9 192 | 193 | - platform: nextion 194 | name: $device_name Playlist food 195 | page_id: 1 196 | component_id: 10 197 | 198 | - platform: nextion 199 | name: $device_name Playlist dance 200 | page_id: 1 201 | component_id: 11 202 | 203 | - platform: nextion 204 | name: $device_name Playlist note 205 | page_id: 1 206 | component_id: 12 207 | 208 | # Buttons on the Lights page 209 | - platform: nextion 210 | name: $device_name Light 0 button 211 | page_id: 2 212 | component_id: 17 213 | on_click: 214 | - homeassistant.service: 215 | service: light.toggle 216 | data: 217 | entity_id: light.secto 218 | 219 | - platform: nextion 220 | name: $device_name Light 1 button 221 | page_id: 2 222 | component_id: 18 223 | on_click: 224 | - homeassistant.service: 225 | service: light.toggle 226 | data: 227 | entity_id: light.sarfatti 228 | 229 | - platform: nextion 230 | name: $device_name Light 2 button 231 | page_id: 2 232 | component_id: 19 233 | on_click: 234 | - homeassistant.service: 235 | service: light.toggle 236 | data: 237 | entity_id: light.kok_lillabanken 238 | 239 | - platform: nextion 240 | name: $device_name Light 3 button 241 | page_id: 2 242 | component_id: 20 243 | on_click: 244 | - homeassistant.service: 245 | service: switch.toggle 246 | data: 247 | entity_id: switch.tamburslampan 248 | 249 | - platform: nextion 250 | name: $device_name Light 4 button 251 | page_id: 2 252 | component_id: 21 253 | on_click: 254 | - homeassistant.service: 255 | service: light.toggle 256 | data: 257 | entity_id: light.pentiklampa 258 | 259 | - platform: nextion 260 | name: $device_name Light 5 button 261 | page_id: 2 262 | component_id: 22 263 | on_click: 264 | - homeassistant.service: 265 | service: switch.toggle 266 | data: 267 | entity_id: switch.kontorsfonster 268 | 269 | - platform: nextion 270 | name: $device_name Light 6 button 271 | page_id: 2 272 | component_id: 23 273 | on_click: 274 | - homeassistant.service: 275 | service: light.toggle 276 | data: 277 | entity_id: light.kontorspentik 278 | 279 | - platform: nextion 280 | name: $device_name Light 7 button 281 | page_id: 2 282 | component_id: 24 283 | on_click: 284 | - homeassistant.service: 285 | service: switch.toggle 286 | data: 287 | entity_id: switch.oscars 288 | 289 | 290 | output: 291 | # Buzzer for playing tones 292 | - platform: ledc 293 | id: buzzer_out 294 | pin: 295 | number: 21 296 | 297 | switch: 298 | # Physical relay 1 299 | - platform: gpio 300 | name: $device_name Relay 1 301 | id: relay_1 302 | pin: 303 | number: 22 304 | 305 | # Physical relay 2 306 | - platform: gpio 307 | name: $device_name Relay 2 308 | id: relay_2 309 | pin: 310 | number: 19 311 | 312 | # Turn screen power on/off. Easy way to configure the screen power control, but this should not be used from HA, as all components must be re-initialized afterwards. For lights, names of lights etc. this practically means that the state must change once to happen. 313 | - platform: gpio 314 | name: $device_name Screen Power 315 | id: screen_power 316 | entity_category: config 317 | pin: 318 | number: 4 319 | inverted: true 320 | restore_mode: ALWAYS_ON 321 | 322 | # Basically a global variable to keep track on whether the Nextion display is ready or not. Delays initial info from HA to the display. 323 | - platform: template 324 | name: $device_name Nextion inited 325 | id: nextion_init 326 | entity_category: config 327 | restore_state: false 328 | assumed_state: off 329 | optimistic: true 330 | 331 | # Show alarm screen on the display and disable it (except for physical buttons). 332 | - platform: template 333 | name: $device_name Alarm screen 334 | id: alarm_activated 335 | restore_state: false 336 | assumed_state: off 337 | optimistic: true 338 | on_turn_on: 339 | - lambda: id(disp1).send_command_printf("page 5"); 340 | on_turn_off: 341 | - lambda: id(disp1).send_command_printf("page 0"); 342 | 343 | # Disable Dim-down-function on screen 344 | - platform: template 345 | name: $device_name Disable dim-down 346 | id: disp1_disdim 347 | restore_state: true 348 | assumed_state: off 349 | optimistic: true 350 | on_turn_on: 351 | - lambda: id(disp1).send_command_printf("Home.disdim.val=1"); 352 | on_turn_off: 353 | - lambda: id(disp1).send_command_printf("Home.disdim.val=0"); 354 | 355 | # Disable Screensaver-function on screen 356 | - platform: template 357 | name: $device_name Disable screensaver 358 | id: disp1_dissleep 359 | restore_state: true 360 | assumed_state: off 361 | optimistic: true 362 | on_turn_on: 363 | - lambda: id(disp1).send_command_printf("Home.dissleep.val=1"); 364 | on_turn_off: 365 | - lambda: id(disp1).send_command_printf("Home.dissleep.val=0"); 366 | 367 | # Disable Go to Home page-function on screen 368 | - platform: template 369 | name: $device_name Disable go to home 370 | id: disp1_disgth 371 | restore_state: true 372 | assumed_state: off 373 | optimistic: true 374 | on_turn_on: 375 | - lambda: id(disp1).send_command_printf("Home.disgth.val=1"); 376 | on_turn_off: 377 | - lambda: id(disp1).send_command_printf("Home.disgth.val=0"); 378 | 379 | 380 | # Rtttl function for buzzer 381 | rtttl: 382 | id: buzzer 383 | output: buzzer_out 384 | 385 | sensor: 386 | # Internal temperature sensor, adc value 387 | - platform: adc 388 | id: ntc_source 389 | pin: 38 390 | update_interval: 10s 391 | attenuation: 11db 392 | 393 | # Internal temperature sensor, adc reading converted to resistance (calculation) 394 | - platform: resistance 395 | id: resistance_sensor 396 | sensor: ntc_source 397 | configuration: DOWNSTREAM 398 | resistor: 11.2kOhm 399 | 400 | # Internal temperature sensor, resistance to temperature (calculation) 401 | - platform: ntc 402 | id: temperature 403 | sensor: resistance_sensor 404 | calibration: 405 | b_constant: 3950 406 | reference_temperature: 25°C 407 | reference_resistance: 10kOhm 408 | name: $device_name Temperature 409 | 410 | # Uptime for the display. Also updates a human readable one (further down) 411 | - platform: uptime 412 | name: $device_name Uptime Sensor 413 | id: uptime_sensor 414 | update_interval: 60s 415 | on_raw_value: 416 | then: 417 | - text_sensor.template.publish: 418 | id: uptime_human 419 | state: !lambda |- 420 | int seconds = round(id(uptime_sensor).raw_state); 421 | int days = seconds / (24 * 3600); 422 | seconds = seconds % (24 * 3600); 423 | int hours = seconds / 3600; 424 | seconds = seconds % 3600; 425 | int minutes = seconds / 60; 426 | seconds = seconds % 60; 427 | return ( 428 | (days ? to_string(days) + "d " : "") + 429 | (hours ? to_string(hours) + "h " : "") + 430 | (minutes ? to_string(minutes) + "m " : "") + 431 | (to_string(seconds) + "s") 432 | ).c_str(); 433 | 434 | # WiFi signals strength sensor 435 | - platform: wifi_signal 436 | name: $device_name WiFi Signal Sensor 437 | update_interval: 60s 438 | 439 | # Current page displayed on the HMi 440 | - platform: nextion 441 | name: $device_name Current display page 442 | id: disp1_current_page 443 | variable_name: dp 444 | update_interval: 1s 445 | 446 | # Temperature outside, fetched from HA 447 | - platform: homeassistant 448 | id: current_temperature 449 | entity_id: weather.home 450 | attribute: temperature 451 | on_value: 452 | then: 453 | - wait_until: 454 | switch.is_on: nextion_init 455 | - lambda: id(disp1).set_component_text_printf("Home.temp", "%.1f", id(current_temperature).state); 456 | 457 | # Temperature outside feels like, fetched from HA 458 | - platform: homeassistant 459 | id: temp_feelslike 460 | entity_id: sensor.home_temperature_feels_like 461 | on_value: 462 | then: 463 | - wait_until: 464 | switch.is_on: nextion_init 465 | - lambda: id(disp1).set_component_text_printf("Home.tempfl", "%.1f", id(temp_feelslike).state); 466 | 467 | text_sensor: 468 | # IP address of device. Not really needed for HA (as HA already knows it), but for showing on the display during startup. The startup screen will leave on if no instance connects to the API. 469 | - platform: wifi_info 470 | ip_address: 471 | name: $device_name IP address 472 | id: ip_address 473 | on_value: 474 | then: 475 | - wait_until: 476 | switch.is_on: nextion_init 477 | - lambda: id(disp1).set_component_text_printf("Connecting.ip_addr", "%s", id(ip_address).state.c_str()); 478 | 479 | # Uptime in a human readable form. Updated from the uptime sensor 480 | - platform: template 481 | name: $device_name Uptime Human Readable 482 | id: uptime_human 483 | icon: mdi:clock-start 484 | 485 | # ESPHome version used to compile the app 486 | - platform: version 487 | name: $device_name ESPHome Version 488 | 489 | # Media player entity (or any text entity) to pull currently playing song name from 490 | - platform: homeassistant 491 | id: music_artist 492 | entity_id: media_player.sonos_vardagsrum 493 | attribute: media_artist 494 | on_value: 495 | then: 496 | - lambda: id(disp1).set_component_text_printf("Music.music_sn", "%s", id(music_artist).state.c_str()); 497 | 498 | # Media player entity (or any text entity) to pull currently playing artist name from 499 | - platform: homeassistant 500 | id: music_title 501 | entity_id: media_player.sonos_vardagsrum 502 | attribute: media_title 503 | on_value: 504 | then: 505 | - lambda: id(disp1).set_component_text_printf("Music.music_an", "%s", id(music_title).state.c_str()); 506 | 507 | # Sun sensor from HA. Used to decide whether a sun or moon weather symbol should be used. 508 | - platform: homeassistant 509 | id: sun_sun 510 | entity_id: sun.sun 511 | 512 | # Weather symbol, HA weather entity to pull data from 513 | - platform: homeassistant 514 | id: weather_symbol 515 | entity_id: weather.home 516 | on_value: 517 | then: 518 | - wait_until: 519 | switch.is_on: nextion_init 520 | - lambda: |- 521 | int symbol=5; // 5 is a empty box. 522 | if (id(weather_symbol).state == "clear-night") { 523 | symbol=6; 524 | } else if (id(weather_symbol).state == "cloudy") { 525 | symbol=7; 526 | if (id(sun_sun).state == "below_horizon") { 527 | symbol=8; 528 | } 529 | } else if (id(weather_symbol).state == "fog") { 530 | symbol=9; 531 | } else if (id(weather_symbol).state == "hail" || id(weather_symbol).state == "snowy-rainy") { 532 | symbol=10; 533 | } else if (id(weather_symbol).state == "lightning") { 534 | symbol=11; 535 | } else if (id(weather_symbol).state == "lightning-rainy" || id(weather_symbol).state == "exceptional") { 536 | symbol=12; 537 | if (id(sun_sun).state == "below_horizon") { 538 | symbol=13; 539 | } 540 | } else if (id(weather_symbol).state == "partlycloudy") { 541 | symbol=14; 542 | if (id(sun_sun).state == "below_horizon") { 543 | symbol=8; 544 | } 545 | } else if (id(weather_symbol).state == "pouring") { 546 | symbol=15; 547 | } else if (id(weather_symbol).state == "rainy") { 548 | symbol=16; 549 | } else if (id(weather_symbol).state == "snowy") { 550 | symbol=17; 551 | } else if (id(weather_symbol).state == "sunny") { 552 | symbol=18; 553 | if (id(sun_sun).state == "below_horizon") { 554 | symbol = 6; 555 | } 556 | } else if (id(weather_symbol).state == "windy" || id(weather_symbol).state == "windy-variant") { 557 | symbol=19; 558 | } 559 | id(disp1).send_command_printf("Home.weather_symbol.pic=%i", symbol); 560 | 561 | # Light setup, first light. If you want to leave a light out, just comment out the section for the light and name. 562 | - platform: homeassistant 563 | id: secto 564 | entity_id: light.secto 565 | on_value: 566 | then: 567 | - wait_until: 568 | switch.is_on: nextion_init 569 | - lambda: |- 570 | int symbol = 23; 571 | if (id(secto).state == "off") { 572 | symbol=22; 573 | } 574 | id(disp1).send_command_printf("Lights.light0.pic=%i", symbol); 575 | 576 | # Light setup, first light's name 577 | - platform: homeassistant 578 | id: secto_name 579 | entity_id: light.secto 580 | attribute: friendly_name 581 | on_value: 582 | then: 583 | - wait_until: 584 | switch.is_on: nextion_init 585 | - lambda: id(disp1).set_component_text_printf("Lights.light0t", "%s", id(secto_name).state.c_str()); 586 | 587 | # Light setup, second light. If you want to leave a light out, just comment out the section for the light and name. 588 | - platform: homeassistant 589 | id: sarfatti 590 | entity_id: light.sarfatti 591 | on_value: 592 | then: 593 | - wait_until: 594 | switch.is_on: nextion_init 595 | - lambda: |- 596 | int symbol = 25; 597 | if (id(sarfatti).state == "off") { 598 | symbol=24; 599 | } 600 | id(disp1).send_command_printf("Lights.light1.pic=%i", symbol); 601 | 602 | # Light setup, second light's name 603 | - platform: homeassistant 604 | id: sarfatti_name 605 | entity_id: light.sarfatti 606 | attribute: friendly_name 607 | on_value: 608 | then: 609 | - wait_until: 610 | switch.is_on: nextion_init 611 | - lambda: id(disp1).set_component_text_printf("Lights.light1t", "%s", id(sarfatti_name).state.c_str()); 612 | 613 | # Light setup, third light. If you want to leave a light out, just comment out the section for the light and name. 614 | - platform: homeassistant 615 | id: kok_lillabanken 616 | entity_id: light.kok_lillabanken 617 | on_value: 618 | then: 619 | - wait_until: 620 | switch.is_on: nextion_init 621 | - lambda: |- 622 | int symbol = 29; 623 | if (id(kok_lillabanken).state == "off") { 624 | symbol=28; 625 | } 626 | id(disp1).send_command_printf("Lights.light2.pic=%i", symbol); 627 | 628 | # Light setup, third light's name 629 | - platform: homeassistant 630 | id: kok_lillabanken_name 631 | entity_id: light.kok_lillabanken 632 | attribute: friendly_name 633 | on_value: 634 | then: 635 | - wait_until: 636 | switch.is_on: nextion_init 637 | - lambda: id(disp1).set_component_text_printf("Lights.light2t", "%s", id(kok_lillabanken_name).state.c_str()); 638 | 639 | # Light setup, fourth light. If you want to leave a light out, just comment out the section for the light and name. 640 | - platform: homeassistant 641 | id: tamburslampan 642 | entity_id: switch.tamburslampan 643 | on_value: 644 | then: 645 | - wait_until: 646 | switch.is_on: nextion_init 647 | - lambda: |- 648 | int symbol = 27; 649 | if (id(tamburslampan).state == "off") { 650 | symbol=26; 651 | } 652 | id(disp1).send_command_printf("Lights.light3.pic=%i", symbol); 653 | 654 | # Light setup, fourth light's name 655 | - platform: homeassistant 656 | id: tamburslampan_name 657 | entity_id: switch.tamburslampan 658 | attribute: friendly_name 659 | on_value: 660 | then: 661 | - wait_until: 662 | switch.is_on: nextion_init 663 | - lambda: id(disp1).set_component_text_printf("Lights.light3t", "%s", id(tamburslampan_name).state.c_str()); 664 | 665 | # Light setup, fifth light. If you want to leave a light out, just comment out the section for the light and name. 666 | - platform: homeassistant 667 | id: tvpentik 668 | entity_id: light.pentiklampa 669 | on_value: 670 | then: 671 | - wait_until: 672 | switch.is_on: nextion_init 673 | - lambda: |- 674 | int symbol = 33; 675 | if (id(tvpentik).state == "off") { 676 | symbol=32; 677 | } 678 | id(disp1).send_command_printf("Lights.light4.pic=%i", symbol); 679 | 680 | # Light setup, fifth light's name 681 | - platform: homeassistant 682 | id: tvpentik_name 683 | entity_id: light.pentiklampa 684 | attribute: friendly_name 685 | on_value: 686 | then: 687 | - wait_until: 688 | switch.is_on: nextion_init 689 | - lambda: id(disp1).set_component_text_printf("Lights.light4t", "%s", id(tvpentik_name).state.c_str()); 690 | 691 | # Light setup, sixth light. If you want to leave a light out, just comment out the section for the light and name. 692 | - platform: homeassistant 693 | id: kontorsfonster 694 | entity_id: switch.kontorsfonster 695 | on_value: 696 | then: 697 | - wait_until: 698 | switch.is_on: nextion_init 699 | - lambda: |- 700 | int symbol = 33; 701 | if (id(kontorsfonster).state == "off") { 702 | symbol=32; 703 | } 704 | id(disp1).send_command_printf("Lights.light5.pic=%i", symbol); 705 | 706 | # Light setup, sixths light's name 707 | - platform: homeassistant 708 | id: kontorsfonster_name 709 | entity_id: switch.kontorsfonster 710 | attribute: friendly_name 711 | on_value: 712 | then: 713 | - wait_until: 714 | switch.is_on: nextion_init 715 | - lambda: id(disp1).set_component_text_printf("Lights.light5t", "%s", id(kontorsfonster_name).state.c_str()); 716 | 717 | # Light setup, seventh light. If you want to leave a light out, just comment out the section for the light and name. 718 | - platform: homeassistant 719 | id: kontorspentik 720 | entity_id: light.kontorspentik 721 | on_value: 722 | then: 723 | - wait_until: 724 | switch.is_on: nextion_init 725 | - lambda: |- 726 | int symbol = 33; 727 | if (id(kontorspentik).state == "off") { 728 | symbol=32; 729 | } 730 | id(disp1).send_command_printf("Lights.light6.pic=%i", symbol); 731 | 732 | # Light setup, seventh light's name 733 | - platform: homeassistant 734 | id: kontorspentik_name 735 | entity_id: light.kontorspentik 736 | attribute: friendly_name 737 | on_value: 738 | then: 739 | - wait_until: 740 | switch.is_on: nextion_init 741 | - lambda: id(disp1).set_component_text_printf("Lights.light6t", "%s", id(kontorspentik_name).state.c_str()); 742 | 743 | # Light setup, eighth light. If you want to leave a light out, just comment out the section for the light and name. 744 | - platform: homeassistant 745 | id: oscars 746 | entity_id: switch.oscars 747 | on_value: 748 | then: 749 | - wait_until: 750 | switch.is_on: nextion_init 751 | - lambda: |- 752 | int symbol = 31; 753 | if (id(oscars).state == "off") { 754 | symbol=30; 755 | } 756 | id(disp1).send_command_printf("Lights.light7.pic=%i", symbol); 757 | 758 | # Light setup, eighths light's name 759 | - platform: homeassistant 760 | id: oscarsdb_name 761 | entity_id: switch.oscars 762 | attribute: friendly_name 763 | on_value: 764 | then: 765 | - wait_until: 766 | switch.is_on: nextion_init 767 | - lambda: id(disp1).set_component_text_printf("Lights.light7t", "%s", id(oscarsdb_name).state.c_str()); 768 | 769 | # Home page, text line 1 (lower right part of screen) 770 | - platform: homeassistant 771 | id: home_text1 772 | entity_id: sensor.nspanel_v90_range 773 | on_value: 774 | then: 775 | - wait_until: 776 | switch.is_on: nextion_init 777 | - lambda: id(disp1).set_component_text_printf("Home.text1", "%s", id(home_text1).state.c_str()); 778 | 779 | # Home page, text line 2 (lower right part of screen) 780 | - platform: homeassistant 781 | id: home_text2 782 | entity_id: sensor.nspanel_id4_range 783 | on_value: 784 | then: 785 | - wait_until: 786 | switch.is_on: nextion_init 787 | - lambda: id(disp1).set_component_text_printf("Home.text2", "%s", id(home_text2).state.c_str()); 788 | 789 | 790 | number: 791 | # Screen brightness 792 | - platform: template 793 | name: $device_name Brightness 794 | id: brightness 795 | entity_category: config 796 | unit_of_measurement: '%' 797 | min_value: 0 798 | max_value: 100 799 | step: 1 800 | initial_value: 30 801 | set_action: 802 | then: 803 | - lambda: 'id(disp1).set_backlight_brightness(x/100);' 804 | - lambda: 'id(disp1).send_command_printf("Home.brightness.val=%i", int(x));' 805 | 806 | # Screen brightness dimmed down 807 | - platform: template 808 | name: $device_name Brightness dimdown 809 | id: brightness_dim 810 | entity_category: config 811 | unit_of_measurement: '%' 812 | min_value: 0 813 | max_value: 100 814 | step: 1 815 | initial_value: 1 816 | set_action: 817 | then: 818 | - lambda: 'id(disp1).send_command_printf("Home.brightdd.val=%i", int(x));' 819 | 820 | 821 | # Configure the screen itself 822 | display: 823 | - platform: nextion 824 | id: disp1 825 | uart_id: tf_uart 826 | tft_url: !secret nextion_update_url 827 | # A little fun... 828 | on_setup: 829 | then: 830 | # Enable 1 light page (up to 4 available) 831 | - lambda: id(disp1).send_command_printf("Lights.pages.val=1"); 832 | - number.set: 833 | id: brightness 834 | value: 30 835 | - lambda: id(disp1).send_command_printf("page 4"); 836 | - wait_until: 837 | api.connected 838 | - switch.template.publish: 839 | id: nextion_init 840 | state: on 841 | - if: 842 | condition: 843 | - switch.is_on: alarm_activated 844 | then: 845 | - lambda: id(disp1).send_command_printf("page 5"); 846 | else: 847 | - delay: 5s 848 | - lambda: id(disp1).send_command_printf("page 0"); 849 | --------------------------------------------------------------------------------