HA SwitchPlate - DIY LCD Touchscreen wall switch replacement


Yep that’s 100% the plan. After printing it, the Wemos doesn’t really fit in there with the standard header wires so I’m gonna have to go back to it and make some more, larger changes and get creative.

It would be super nice to just have the D1 mini and the Nextion panel and that’s it, a single USB cable going into it, done and done.


In case you are looking for non-local display dimming, I’ve come up with this touch-to-brighten logic:

- alias: hasp_plate01_00_LightOnButton
      platform: mqtt
      topic: 'hasp/plate01/state/#'
      - condition: template
        value_template: "{{ state_attr('light.plate01_backlight', 'brightness') < 255 }}"
      - condition: template
        value_template: "{{ trigger.payload == 'ON' }}"
      - service: mqtt.publish
          topic: 'hasp/plate01/brightness/set'
          payload: "255"
      - delay: 0:00:10
      - service: mqtt.publish
          topic: 'hasp/plate01/brightness/set'
          payload_template: "{% if state_attr('sun.sun', 'elevation') >= 10 -%}255{% elif (state_attr('sun.sun', 'elevation') < 10) and (state_attr('sun.sun', 'elevation') > -10) %}{{ ((state_attr('sun.sun', 'elevation') + 10) * 12.5) | int + 5 }}{% else %}5{%- endif %}"


hi luma, want you to say that you created a really great project!

the last few days i had some time to play with the setup of my 2 HASPs (ok its only 1, the second is just a esp without LCD on my desk).
i really love how you did this, but what i didnt like is to have multiple views with basically the same information.

so i edited my hasp_xxxx_00_components.yaml files and after some trial-and-error i came up with this:

only one view but with interchangeable groups.

if someone wants to do the same, here are my 2 files. they are quit messy, but i added some coments. hope that helps

this is my “main HASP- instance”

this one is the “slave”, view is disabled

also added a retrain- flag to the backlight- topic to keep the brightness settings over restart

thanks for all your work!


Hey Luma, I am enjoying your HASP!! I was curious if there is anyway to get the weather to update more frequently? I am pulling data from a sensor for my temp but it really lags the data I see in Hass. seems it only pulls the data every 15 minutes or something?. Anyway, i looked thru the files but i don’t see any thing. thanks


Before I write a tft file myself… has someone created one for an alarm clock or a temperature setting page for a thermostat?


The default weather automation is triggered by any update to the default met.no sensor created (selected simply because they don’t require an API key). There isn’t a polling interval and there should be no delay. I suspect what might be happening is you also have another weather sensor configured from some other weather provider and you’re watching updates on that other sensor.

To resolve this, you can either change the weather automation to use whatever other sensor you prefer, or watch the met.no weather sensor and you should find that HASP tracks that directly.


thanks. Yes I have it configured to pull sensor data directly from a nodemcu at my house. This sensor reports very often, however the HASP does not track the reporting nearly as often. I see the temp in my hass frontend and i see how much it changes, but the hasp does not change nearly as quickly… So I guess it has something to do with the automations and the polling the automation does to see if any changes have occured. I was just curious if you knew how to make it poll faster.

EDIT: I noticed that I left the trigger to the automation as met.no and I think it is updating based on that enitity then showing the data from my sensor. that would explain it. I changed that to use “my sensor” as the trigger, and that seems to be updating right.


There you go :smiley: When triggering on state there is no polling, and thus no delay. Just make sure you’re triggering on the state of the thing you’re interested in and you should see changes happen instantly.


hey luma, have some issues with automations here, may you can help me :slight_smile:

in order to get the display into sleep- mode, i first added this to de arduino- code after line 770:

  else if (nextionReturnBuffer[0] == 0x86)
  { // Automatic enter into sleep mode
// 0X87+End
// issue Nextion command "thup=1" to wakeup on touch first, then issue Nextion command "thsp=x", where x is time to sleep mode after last touch event from 3 to 65.535 seconds
debugPrintln(String(F("HMI IN: [SLEEP!]")));
String mqttTouchTopic = mqttStateTopic + "/sleep";
debugPrintln(String(F("MQTT OUT: '")) + mqttTouchTopic + "' : 'ON'");
mqttClient.publish(mqttTouchTopic, "ON");
  else if (nextionReturnBuffer[0] == 0x87)
  { // Automatic wake up from sleep mode
// 0X87+End
// issue Nextion command "thup=1" to wakeup on touch first, then issue Nextion command "thsp=x", where x is time to sleep mode after last touch event from 3 to 65.535 seconds
debugPrintln(String(F("HMI IN: [WAKE UP!]")));
String mqttTouchTopic = mqttStateTopic + "/sleep";
debugPrintln(String(F("MQTT OUT: '")) + mqttTouchTopic + "' : 'OFF'");
mqttClient.publish(mqttTouchTopic, "OFF");

this part works as expected.

because the display does not refresh the button values in sleep mode (at least as i tried), i added this automation:

###     hasp_desk_00_sleepmode.yaml
  - alias: hasp_desk_00_sleepmode
    - platform: state
      entity_id: 'binary_sensor.desk_connected'
      to: 'on'
    - service: mqtt.publish
        topic: 'hasp/desk/command'
        payload: 'thup=1'      #enable wake up on touch
    - service: mqtt.publish
        topic: 'hasp/desk/command'
        payload: 'thsp=1800'    #automatic sleep after 30 minutes
  - alias: hasp_desk_00_exitsleep
    - platform: mqtt
      topic: 'hasp/desk/state/sleep'
      payload: 'OFF'
    - service: mqtt.publish
        topic: 'hasp/desk/command/p[2].b[4].font'
        payload: '3'
    - service: mqtt.publish
        topic: 'hasp/desk/command/p[2].b[4].txt'
        payload_template: "\"{{(now().strftime('%H')|int)~now().strftime(':%M')}}\""
    - service: mqtt.publish
        topic: 'hasp/desk/command/p[2].b[5].font'
        payload_template: '{% set datelength = (now().strftime("%B .") ~ now().day)|length %}{% if datelength <= 6 -%}3{% elif (datelength > 6) and (datelength <= 10) %}2{% elif (datelength > 10) and (datelength <= 15) %}1{% else %}0{%- endif %}'
    - service: mqtt.publish
        topic: 'hasp/desk/command/p[2].b[5].txt'
        payload_template: "\"{{now().day ~ now().strftime('. %B')}}\""
    - service: mqtt.publish
        topic: 'hasp/desk/command/p[2].b[7].txt'
#        payload_template: '"{{state_attr("weather.metno","temperature")}}C\r {{state_attr("weather.metno","humidity")}}%"'
        payload_template: '"{{states.sensor.buero_temperature.state}}C\r{{states.sensor.buero_humidity.state}}%"'
    - service: mqtt.publish
        topic: 'hasp/desk/command/p[2].b[6].font'
        payload_template: '{% if states.weather.metno.state|length <= 6 -%}3{% elif (states.weather.metno.state|length > 6) and (states.weather.metno.state|length <= 10) %}2{% elif (states.weather.metno.state|length > 10) and (states.weather.metno.state|length <= 15) %}1{% else %}0{%- endif %}'
    - service: mqtt.publish
        topic: 'hasp/desk/command/p[2].b[6].txt'
        payload_template: '"{{states.weather.metno.state|wordwrap(20, wrapstring="\\r")|title}}"'

the exit- automation works fine, but the sleepmode one does not. neither ESPs serial output, nor in the mqtt topic the thup and thsp- command shows up.
thought about adding these 2 directly to the HMI, but then i loose the oportunity not to enter sleep mode (thsp is one-way, once activated you can not turn it off or change the time until you power- cycle the display)

any ideas?


Can I ask what you’re looking to accomplish? Sleep mode is useful for power saving, but that is going to involve a whole lot of extra work from both a hardware and software perspective as the WeMos regulator, general circuit design, and Arduino code isn’t really setup for low power draw.

So, if power savings (presumably) isn’t the goal, are you looking just to cut the backlight so it isn’t obnoxious bright? If so, there is one automation example provided that will automatically adjust the backlight dimming in response to the sun which you can check out here. Alternately, you could use Home Assistant automations to have the backlight turn off (or really dim) after a period of time, then turn back on when a button press is received.

Just throwing out some options there. If you’d like to chase down the approach you’re taking, can you dump both your serial debug log output and mqtt traffic to hastebin and we can look at what’s happening in some more detail?

edit: Also I like what you’ve done for the Arduino side, and if you’re OK with it I’ll be including that in the next version.


you are right, the power-saving isn’t the goal.
my office is our guest- room at the same time, so i want the display to be complete dark (at least at night), but turn on wenn there is a touch event.
i first tried with a dim- automation, but wasn’t able to get it running and had a look at the Nextion- documentation. thought sleep mode is the answer :sweat_smile:

but to be honest, after a few days testing sleep mode brings a lot mor problems than expected. after one ore two hours sleeping the display freezes: i touch it, it turns on for about a second showing page 0 and turns off again. i see somethings is happening on the serial monitor, but the display stays dark. only way out is a power- cycle…
i think i’ll give the automations a new chance :wink:

I’m on vacation at the moment, as soon as I’m back home i will provide the log!

glad you like it, please feel free to use everything you want :slight_smile:


@irch I have had the same need and programmed it through automations.I switch off the backlight at night and I added conditions to all the other button automations to only trigger, when the backlight is on.
That works quite well. I use the plate as an alarm clock (also) and of course I do not want to have a display with backlight next to the bed. So at nighttime the display only turns on for about 30 secs…


@luma While I’m in the thread. I would suggest to add a long-press event. That would be nice to allow for more navigation options.

Additionally a press-button-to-dimm functionality would be great. Th e latter might be possible with automations but I’m not really sure how to distinguish between long and short presses.
Long press is easy with the for: statement. However when pressing long also the short press automation would always be triggered…


thanks for that man! one of my biggest problems was turning on/ off random lights when i just wanted to wake up the display.
this was another reason i tried with sleep mode, the first press to leave isn’t triggering any button presses


I was just thinking this one myself on my drive into work for some reason. It seems like it could be relatively easily handled in the Arduino code to interpret a press vs a long press and send the proper MQTT message in response.

But then the ESP would be doing a little more than just converting messages for the Nextion panel and that might be scope creep luma might not want.


If you change all of the automations to use the “OFF” state for trigger instead of the “ON” state you might have better luck differentiating between short and long press. Unfortunately the Nextion panel isn’t like a true industrial controls HMI panel. On a true HMI panel if you press a button but drag your finger off of it and release, then no button is actually pressed. The Nextion panel will always trigger the button pressed no matter where you drag your finger to on the screen.


HASP 0.33 release

Some minor fixes for various issues brought up by the user community.

ESP8266 code v0.33

  • Increase max MQTT message size to 4k
  • Add command/json MQTT command. Send a JSON array in the message payload like ["dim=5", "page 1"] and each item in the array will be executed as an individual command. This allows batching up several commands into one message, which may improve performance. Message size is limited to 4k.
  • Better input validation on web forms (thanks @m14t!)
  • Convert UTF-8 values to extended ASCII as Nextion doesn’t support them. Now we can use ° in our automations!

Home Assistant Automations

  • Massive reduction in MQTT traffic with the help of the JSON capabilities listed above. Automations that triggered loads of published message now trigger far fewer.
  • Snuck a ° in the weather automation. For demo purposes we’re using the Met.no component as it doesn’t require individual API keys. Sadly, it also doesn’t have a unit_of_measurement attribute. For other weather providers, you’ll probably want to change the automation to read something like {{state_attr("sensor.weather","unit_of_measurement")}}


  • Minor change to indicate acceptable devicename characters to the user

ESP8266 Update Procedure

If you’re using the AutoFirmwareUpdate automation your devices should pull this update at 3:00am. Otherwise, log into the admin web page and you can pull the update from the firmware page.

Home Assistant Update Procedure

Run the deployhasp.sh script to pull down the updated automations.

Links for more HASP info


luma, a quick question on wiring to the Nextion panel. I finally have some time to complete this (plus a new rework station to play with).

Looking at the pictures on your github, the pins on the connector you have don’t seem to align with the Nextion I have. I did a search but didn’t come across anything directly related (pardon me if this has been posted before).

+5V and GND are pretty straightforward, but what about TX and RX…

The blue wire goes to RX on your board as shown. Does that get soldered to TX on the Nextion?


Correct, the wires solder on in the same order, so red goes to +5V, then blue, then yellow, then black. What you’re seeing is just a serial communication thing - RX (receive) on one device connects to TX (transmit) on the other, and vice versa. So when the Nextion panel sends a command, it does so down TX, and that is wired to the HASP RX pin to receive the message. Make sense?


Your post has made me realize that the photo I had to illustrate the concept sucked in a couple important ways. I’ve snapped a new pic and updated the documentation here which should be a little more clear.

The result should look something like this: