Sonoff NSPanel by ITead - Smart Scene Wall Switch based on ESP32 and custom Nextion Touch Screen Panel Display (non-Pro variant)

Leacho. ill share my setup, and a few automations that control my lights.

This is my config.yaml. i use this for various automations and also receiving the raw JSON on raw.

  - platform: mqtt
    state_topic: 'tele/LoungeRoomSwitch/RESULT'
    unique_id: 'NSPPanel_RAW'
    name: 'NSPanel Raw Data'

  - platform: mqtt
    state_topic: 'tele/LoungeRoomSwitch/RESULT'
    unique_id: 'NSPPanel_LivingRoom'
    name: 'NSPanel Living Room'
    value_template: "{{ value_json.NSPanel.params }}"
    json_attributes_topic: "tele/LoungeRoomSwitch/RESULT"
    json_attributes_template: "{{ value_json.NSPanel.params | tojson }}"
    

  - platform: mqtt
    state_topic: 'tele/LoungeRoomSwitch/RESULT'
    unique_id: 'NSPPanel_ID'
    name: 'NS Panel ID'
    value_template: '{{ value_json.NSPanel.id }}'

  - platform: mqtt
    state_topic: 'tele/LoungeRoomSwitch/RESULT'
    unique_id: 'NSPPanel_Switch'
    name: 'NS Panel Switch'
    value_template: '{{ value_json.NSPanel.params.switch }}'  


  - platform: mqtt
    state_topic: 'tele/LoungeRoomSwitch/RESULT'
    unique_id: 'NSPPanel_Ltype'
    name: 'NS Panel Light Type'
    value_template: '{{ value_json.NSPanel.params.ltype }}'
    
  - platform: mqtt
    state_topic: 'tele/LoungeRoomSwitch/RESULT'
    unique_id: 'NSPPanel_Ledtype'
    name: 'NS Panel LED Type'
    value_template: '{{ value_json.NSPanel.params.light_type }}'
    
  - platform: mqtt
    state_topic: 'tele/LoungeRoomSwitch/RESULT'
    unique_id: 'NSPPanel_LED_Red'
    name: 'NS Panel LED Red'
    value_template: '{{ value_json.NSPanel.params.colorR }}'  
    
  - platform: mqtt
    state_topic: 'tele/LoungeRoomSwitch/RESULT'
    unique_id: 'NSPPanel_LED_Green'
    name: 'NS Panel LED Green'
    value_template: '{{ value_json.NSPanel.params.colorG }}'  
    
  - platform: mqtt
    state_topic: 'tele/LoungeRoomSwitch/RESULT'
    unique_id: 'NSPPanel_LED_Blue'
    name: 'NS Panel LED Blue'
    value_template: '{{ value_json.NSPanel.params.colorB }}'   

  - platform: mqtt
    state_topic: 'tele/LoungeRoomSwitch/RESULT'
    unique_id: 'NSPPanel_LED_BR'
    name: 'NS Panel LED Brightness'
    value_template: '{{ value_json.NSPanel.params.bright }}'      

  - platform: mqtt
    state_topic: 'tele/LoungeRoomSwitch/RESULT'
    unique_id: 'NSPPanel_BR'
    name: 'NS Panel White Brightness'
    value_template: '{{ value_json.NSPanel.params.white.br }}'  
    
  - platform: mqtt
    state_topic: 'tele/LoungeRoomSwitch/RESULT'
    unique_id: 'NSPPanel_CT'
    name: 'NS Panel Colour Temp'
    value_template: '{{ value_json.NSPanel.params.white.ct }}'  
    
  - platform: mqtt
    state_topic: 'tele/LoungeRoomSwitch/RESULT'
    unique_id: 'NSPPanel_Red'
    name: 'NS Panel Red'
    value_template: '{{ value_json.NSPanel.params.color.r }}'  
    
  - platform: mqtt
    state_topic: 'tele/LoungeRoomSwitch/RESULT'
    unique_id: 'NSPPanel_Green'
    name: 'NS Panel Green'
    value_template: '{{ value_json.NSPanel.params.color.g }}'  
    
  - platform: mqtt
    state_topic: 'tele/LoungeRoomSwitch/RESULT'
    unique_id: 'NSPPanel_Blue'
    name: 'NS Panel Blue'
    value_template: '{{ value_json.NSPanel.params.color.b }}'      
    
  - platform: mqtt
    state_topic: 'tele/LoungeRoomSwitch/RESULT'
    unique_id: 'NSPPanel_CBR'
    name: 'NS Panel Colour Brightness'
    value_template: '{{ value_json.NSPanel.params.color.br }}'   

When you press a switch on the screen, you need Home assistant to reply with a JSON reply telling the NS PANEL to update the widget on the screen with the change, otherwise every second, tasmota updates the NSPanel with its weather and time, the widget resets.
So you need to respond using the following automation.

alias: nspanel send data back
description: ''
trigger:
  - platform: state
    entity_id: sensor.ns_panel_raw_data
condition: []
action:
  - service: mqtt.publish
    data_template:
      topic: cmnd/LoungeRoomSwitch/NSPSend
      payload: |

        {{'{{"relation":{}}}'.format(trigger.to_state.state)}}
mode: single

I use the following automation that runs when the RAW item is updated, and it grabs information from each of my other items.

I use this automation to update a CCT lightbulb

alias: NSPanel CCT Light ON
description: ''
trigger:
  - platform: state
    entity_id: sensor.ns_panel_raw_data
condition: []
action:
  - service: light.turn_on
    target:
      entity_id: |
        {% if states.sensor.ns_panel_id.state == "1" %}
          light.tall_lamp
        {% elif  states.sensor.ns_panel_id.state == "2" %}
          light.small_lamp
        {% elif  states.sensor.ns_panel_id.state == "5" %}
          light.christmas_lights
        {% endif %}
    data_template:
      brightness_pct: |
        {% if states.sensor.ns_panel_light_type.state == "white" %}
          {% if states.sensor.ns_panel_brightness.state | int >= 0 %}
            {{ states.sensor.ns_panel_brightness.state | int }}
          {% else %}
            100
          {% endif %}
        {% elif  states.sensor.ns_panel_light_type.state == "color" %}
          {% if states.sensor.ns_panel_colour_brightness.state | int >= 0 %}
            {{ states.sensor.ns_panel_colour_brightness.state | int }}
          {% else %}
            100
          {% endif %}
        {% else %}
          100
        {% endif %}
      rgb_color:
        - '{{ states.sensor.ns_panel_red.state | int }}'
        - '{{ states.sensor.ns_panel_green.state | int }}'
        - '{{ states.sensor.ns_panel_blue.state | int }}'
mode: single

This one to update an LED strip

alias: NSPanel LED Light ON
description: ''
trigger:
  - platform: state
    entity_id: sensor.ns_panel_raw_data
condition: []
action:
  - service: light.turn_on
    target:
      entity_id: |
        {% if states.sensor.ns_panel_id.state == "3" %}
          light.tasmota
        {% endif %}
    data_template:
      brightness_pct: |

        {% if states.sensor.ns_panel_led_brightness.state | int >= 0 %}
          {{ states.sensor.ns_panel_led_brightness.state | int }}
        {% else %}
          100
        {% endif %}
      rgb_color:
        - '{{ states.sensor.ns_panel_led_red.state | int }}'
        - '{{ states.sensor.ns_panel_led_green.state | int }}'
        - '{{ states.sensor.ns_panel_led_blue.state | int }}'
mode: single

This one to turn any of my lights off

alias: nspanel Light OFF
description: ''
trigger:
  - platform: state
    entity_id: sensor.ns_panel_raw_data
condition:
  - condition: state
    entity_id: sensor.ns_panel_switch
    state: 'off'
action:
  - service: light.turn_OFF
    target:
      entity_id: |
        {% if states.sensor.ns_panel_id.state == "1" %}
          light.tall_lamp
        {% elif  states.sensor.ns_panel_id.state == "2" %}
          light.small_lamp
        {% elif  states.sensor.ns_panel_id.state == "3" %}
          light.tasmota
        {% elif  states.sensor.ns_panel_id.state == "5" %}
          light.christmas_lights
        {% endif %}
mode: single

and this one to update the switch position on my widgets if i turn a bulb or the LED strip on any other way other than through the panel

alias: NSPanel Update Widget State when device changes
description: ''
trigger:
  - platform: device
    type: turned_on
    device_id: 8d2bd172ff304d1d97502e1ffc9edaee
    entity_id: light.tall_lamp
    domain: light
    id: tall on
  - platform: device
    type: turned_on
    device_id: ec57922dd96ed593581f9c5c978ba5ad
    entity_id: light.small_lamp
    domain: light
    id: small on
  - platform: device
    type: turned_on
    device_id: 63b3caa3d98370f6874b31e82a1cfa4b
    entity_id: light.tasmota
    domain: light
    id: led on
  - platform: device
    type: turned_off
    device_id: 8d2bd172ff304d1d97502e1ffc9edaee
    entity_id: light.tall_lamp
    domain: light
    id: tall off
  - platform: device
    type: turned_off
    device_id: ec57922dd96ed593581f9c5c978ba5ad
    entity_id: light.small_lamp
    domain: light
    id: small off
  - platform: device
    type: turned_off
    device_id: 63b3caa3d98370f6874b31e82a1cfa4b
    entity_id: light.tasmota
    domain: light
    id: led off
  - platform: state
    entity_id: light.christmas_lights
    id: xmasON
    to: 'on'
  - platform: state
    entity_id: light.christmas_lights
    id: xmasOFF
    to: 'off'
condition: []
action:
  - choose:
      - conditions:
          - condition: trigger
            id: tall on
        sequence:
          - service: mqtt.publish
            data:
              topic: cmnd/LoungeRoomSwitch/NSPSend
              payload: >-
                {"relation":{"NSPanel":{"ctype":"group","id":"1","params":{"switch":"on"}}}}
      - conditions:
          - condition: trigger
            id: small on
        sequence:
          - service: mqtt.publish
            data:
              topic: cmnd/LoungeRoomSwitch/NSPSend
              payload: >-
                {"relation":{"NSPanel":{"ctype":"group","id":"2","params":{"switch":"on"}}}}
      - conditions:
          - condition: trigger
            id: led on
        sequence:
          - service: mqtt.publish
            data:
              topic: cmnd/LoungeRoomSwitch/NSPSend
              payload: >-
                {"relation":{"NSPanel":{"ctype":"group","id":"3","params":{"switch":"on"}}}}
      - conditions:
          - condition: trigger
            id: tall off
        sequence:
          - service: mqtt.publish
            data:
              topic: cmnd/LoungeRoomSwitch/NSPSend
              payload: >-
                {"relation":{"NSPanel":{"ctype":"group","id":"1","params":{"switch":"off"}}}}
      - conditions:
          - condition: trigger
            id: small off
        sequence:
          - service: mqtt.publish
            data:
              topic: cmnd/LoungeRoomSwitch/NSPSend
              payload: >-
                {"relation":{"NSPanel":{"ctype":"group","id":"2","params":{"switch":"off"}}}}
      - conditions:
          - condition: trigger
            id: led off
        sequence:
          - service: mqtt.publish
            data:
              topic: cmnd/LoungeRoomSwitch/NSPSend
              payload: >-
                {"relation":{"NSPanel":{"ctype":"group","id":"3","params":{"switch":"off"}}}}
      - conditions:
          - condition: trigger
            id: xmasON
        sequence:
          - service: mqtt.publish
            data:
              topic: cmnd/LoungeRoomSwitch/NSPSend
              payload: >-
                {"relation":{"NSPanel":{"ctype":"group","id":"5","params":{"switch":"on"}}}}
      - conditions:
          - condition: trigger
            id: xmasOFF
        sequence:
          - service: mqtt.publish
            data:
              topic: cmnd/LoungeRoomSwitch/NSPSend
              payload: >-
                {"relation":{"NSPanel":{"ctype":"group","id":"5","params":{"switch":"off"}}}}
    default: []
mode: queued
max: 20

I havenā€™t set up automations yet to update the panel with the colour or temp yet, but im sure you could figure that out with this information.

This is also my autoexec.be file. The beginning section is where you set your widgets

# index "name   ", "ctype", uiid | name max 8 characters, rest will be truncated)
  1: ["TallLmp", "group", 69],
  2: ["SmllLmp", "group", 69],
  3: ["LEDStrip", "group", 33],
  4: ["Blinds", "group", 11],
  5: ["Xmastree", "group", 1],
  6: [],
  7: [],
  8: [],
}

To add, something that blakadder has not documented is a device UIID of 11 is Blinds control.

I also have all of my items as a ā€˜groupā€™ rather than a ā€˜deviceā€™ so i dont have to update the device with ā€˜onlineā€™.

if any part of this is not clear let me know.
Im loving my panel. and with the current setup of tasmota, and automations you can do anything. Even use the thermostat page to turn on or off air con in your house.

i have also had to tune my ADCPARAM1 with the following to get the temp to actually match what is in my house

18:13:38.052 CMD: adcparam1
18:13:38.074 MQT: stat/LoungeRoomSwitch/RESULT = {"AdcParam1":[2,68000,10000,3450]}

again, im sure i can use attributes of the RAW data entity to send information instead of breaking down each JSON item into its own entity, but this was how i got mine working for now.

6 Likes

Thank you for this detailed post! What does blinds support look like in the interface?

you get open stop and close. and a position slider.
You can pass all that information with similar automations and rules

I now have an automation that updates the CCT bulb widget on the NS Panel when a lightbulb state changes

alias: NS Panel Update widget when state entity changes 2
description: ''
trigger:
  - platform: state
    entity_id: light.tall_lamp
    id: '1'
  - platform: state
    entity_id: light.small_lamp
    id: '2'
  - platform: state
    entity_id: light.tasmota
    id: '3'
condition: []
action:
  - choose:
      - conditions:
          - condition: or
            conditions:
              - condition: trigger
                id: '1'
              - condition: trigger
                id: '2'
        sequence:
          - service: mqtt.publish
            data_template:
              topic: cmnd/LoungeRoomSwitch/NSPSend
              payload: >-
                {% if trigger.to_state.state == 'off' %}
                    {"relation":{"NSPanel":{"id":"{{trigger.id}}","params":{"switch":"{{trigger.to_state.state}}"}}}}    
                {% elif trigger.to_state.attributes.color_mode == 'hs' %}
                    {"relation":{"NSPanel":{"id":"{{trigger.id}}","params":{"switch":"{{trigger.to_state.state}}","ltype":"color","color":{
                    "r":{{trigger.to_state.attributes.rgb_color[0]}},
                    "g":{{trigger.to_state.attributes.rgb_color[1]}},
                    "b":{{trigger.to_state.attributes.rgb_color[2]}},
                    "br":{{trigger.to_state.attributes.brightness    
                    | multiply(0.392156862745098) | int}}
                    }}}}}
                {% elif trigger.to_state.attributes.color_mode == 'color_temp'
                %}
                    {"relation":{"NSPanel":{"id":"{{trigger.id}}","params":{"switch":"{{trigger.to_state.state}}","ltype":"white",
                    "white":{"br":{{trigger.to_state.attributes.brightness | multiply(0.392156862745098) | int}},
                    "ct":{{ (154 - trigger.to_state.attributes.color_temp|float) / -0.85 }}        
                    }}}}}
                {% endif %}
    default: []
mode: single

you would have to add different trigger idā€™s for LED strips. As it uses a different pattern for R G B and brightness, no idea why.

for instance the above will send a MQTT message looking like this when the colour is set to red

{"relation":{"NSPanel":{"id":"1","params":{"switch":"on","ltype":"color","color":{
    "r":255,
    "g":0,
    "b":0,
    "br":99
    }}}}}

and the following when the colour is set to white and colour temp cool

{"relation":{"NSPanel":{"id":"1","params":{"switch":"on","ltype":"white",
    "white":{"br":99,
    "ct":-0.0        
    }}}}}

and when colour temp set to warm

{"relation":{"NSPanel":{"id":"1","params":{"switch":"on","ltype":"white",
    "white":{"br":99,
    "ct":254.11764705882354        
    }}}}}

I would use this automation for CCT RGB bulbs widget. and use another trigger condition to 3 to change the MQTT for LED strips
.

1 Like

Iā€™ve manage to install ESPHome on mine.
Works but itā€™s a beginning. Weather, devices (curtain, lights) and thermostat are not currently supported. Only groups are supported but it seems that there are some bugs with it (I think because there is no documentation currently available).
I really hope that support for ESPHome will be extended, the NSPanel is a great device

@Chris_Hemmings thank you so much for this! - thatā€™s great information - Iā€™ll have a play around over the next couple of days and Iā€™ll come back to you to let you know how I get on :slight_smile:

Why in the world they put two relays instead of a dimmer

1 Like

Dimmers cost more + dimmer implementations are complicated and have different compatibility issues.

Size restrictions in some implementations can also be a factor depending on the technology used, just look at their Sonoff branded dimmer ā†’ https://itead.cc/product/sonoff-d1-smart-dimmer-switch/ compared to the smaller Shelly Dimmer 2 ā†’ https://shelly.cloud/products/shelly-dimmer-2-smart-home-light-controller/ or the even smaller and much more expensive Qubino Mini Dimmer ā†’ https://qubino.com/products/mini-dimmer/

I have several of those myself and not counting traditional incandescent lightbulbs they all have different compatibility issues with different types of dimmable LED lights and dimmable transformers so in most cases I had to buy and test a lot of different dimmable LED light for such dimmers to get them to work at an acceptable level as they will otherwise flicker or just not dim properly.

not a problem mate. My automations certainly are not the most efficient. But they work

@Chris_Hemmings your post has been the key for me. I donā€™t know enough about MQTT to create what you have done but I am learning from your work and installed MQTT Explorer to see what is coming and going. The assumption is that any integration from the touch panel will need to be coded to automations. Thank you again. FYI I am not able to see the blinds device 11 on my US version.

definitely.
There might be a way to have entities update without automations but i find it working perfectly with my automations above.

Curious why you did not try Tasmota which seems further along based on the work from blakadder and now @Chris_Hemmings providing the HA integration info

I prefer ESPHome over Tasmota and MQTT :man_shrugging:

1 Like

Can we hope that Esphome will be able to unlock that soon ?
Iā€™m planning to upload a custom hmi inside so iā€™m a bit impatient.

@Raspiaigle what will your custom hmi will do? I am hoping to learn and use the Nextion Editor to someday code an Alarm Panel page. Very far off from what I can do now.

My custom hmi will be personalised with my HA. Some basic commands like light buttons and cover or media players.
An alarm panel would be a bit more difficult. You may have to create a script to communicate with home assistant.

1 Like

This worked, thanks! I found that the third line for wasnā€™t necessary ā€“ the comok string contains a -0, indicating itā€™s not actually in Address Mode. Sending that resulted in an unexpected response that isnā€™t handled well by the existing code, and IIUC if it were really in address mode, it would be necessary to either turn it off or rewrite everything to send the address prefix. Anyway, Iā€™m not handing that but I did need another small change to make it work. Itā€™s over here: Handle Nextion displays that are in Protocol Reparse Mode by masto Ā· Pull Request #2956 Ā· esphome/esphome Ā· GitHub

The proof of the pudding, I was able to upload a new .tft:

5 Likes

I just got mine today and flashed it with Tasmota. Everything is working and connecting to Home Assistant automatically. I can see states of relays and I can read of user actions on the thermostat control, two things I havenā€™t figured out yet:

  • How do you switch the unit from Celsius to Faregate once itā€™s flashed with Tasmota. Tried regular Tasmota command, but it doesnā€™t seem to work.
  • Is there a way to update thermostat screen with MQTT messages somehow? Iā€™ve tried, and it seems to ignore them.

Iā€™m really looking forward to getting thermostat functionality to work completely. I have 7 mini-splits in the house, and they currently have wall control units, which are very dumb and hard to deal with to the point that I donā€™t even bother setting up schedule on them. However, somebody much smarter then me created a esp8266 code that can control those mini-splits from MQTT. Would love to get rid of wall control units and replace them with NSPanels. Just need to be able to update thermostate UI values from HomeAssistant or NodeRed.

Edit:
After some tweaking and reading awesome post from @Chris_Hemmings and this documentation: NSPanel Protocol | nspanel I was able to do both things above. Temperature Units do flip back to Celsius randomly, but for now I can just reissue mqtt command every 30 seconds or so.

1 Like

Nice! Is there a way to backup the original TFT file?

After issuing the console command SetOption8 1 I got lazy and hardcoded line 401 of the driver nspanel.be to:
var temp_payload = '{"temperature":' + str(value) + ',"tempUnit":1}'
The original driver code sets persist.tempunit to ā€œFā€ and then setting the display indoor temp with {tempUnit: ā€œFā€} which did not work.