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

I did flash the NSPanel with ESPHOME, which works like a charm, and I try as many of the codes here to see if I can understand how things are done. So I run test hmi on it and some examples from here.
And I get how to send a printf to HA and actuate a switch in there, but I do not know how to make a feedback of a switch set in HA to a button change in the NSPanel.

Is there any documentation? I would to build an music control screen for my Sonos. The cover widget looks a good preview to customize

It seems like they lack any safety certification. Seems odd for a high voltage device.

Thereā€™s a compliance section here for both EU and US versions :-

Can you share this code?

@Mwdouble : to avoid triggering the physical relays, see the on_click instruction commented below:

# Binary sensors
binary_sensor:
  
  # Left button below the display
  - platform: gpio
    name: $device_name Left Button
    pin:
      number: 14
      inverted: true
    #on_click:
    #  - switch.toggle: relay_1


  # Right button below the display
  - platform: gpio
    name: $device_name Right Button
    pin:
      number: 27
      inverted: true
    #on_click:
    #  - switch.toggle: relay_2


1 Like

Thanks! The test report really seems to indicate they are doing something that is not just a toy!

But for all intended purposes, theses test report do only mean that the tested units were safe a according standard. The certification aim at recognizing that the proper standard was used, that the whole manufacturing process is reliable, and that the company is accountable for their product. The CE import certification does not apply to US or Canada.

So currently, it is illegal to install theses on live voltages.

So it is kind of half-way doneā€¦

You guys make it look so easy. Got my NSPanel (EU version) yesterday. Already had Home Assistant preconfigured and flash esp home. All good. Then I transfered my own Nextion tft (nothing exiting just a few images with buttons layed out) to see it in action for the first time.

Then the nightmare began. TFT flashing looked ok, finished very quickly but file was 700kb so thought nothing of it. Then the unit restarted and was greeted with a white screen. Thought Iā€™d make a mistake somewhere so retraced my config, dubbelchecked using marcfager or masto their config, even loaded their config and tft file but it didnā€™t do anything. Checked the logs and am seeing similar errors as previous stated in this topic:

[20:44:02][D][nextion_upload:169]: Connected
[20:44:02][D][nextion_upload:175]: Requesting URL: http://10.13.0.160:8123/local/nspanel_demo.tft
[20:44:03][D][nextion_upload:209]: Updating Nextion ...
[20:44:03][D][nextion_upload:235]: Waiting for upgrade response
[20:44:03][E][uart:015]: Reading from UART timed out at byte 0!
<<>>
[20:44:05][E][uart:015]: Reading from UART timed out at byte 0!
[20:44:05][D][nextion_upload:239]: Upgrade response is  19
[20:44:05][D][nextion_upload:242]: Available 0 : 0x00
[20:44:05][D][nextion_upload:242]: Available 1 : 0x00
[20:44:05][D][nextion_upload:242]: Available 2 : 0x00
[20:44:05][D][nextion_upload:242]: Available 3 : 0x00
[20:44:05][D][nextion_upload:242]: Available 4 : 0x00
[20:44:05][D][nextion_upload:242]: Available 5 : 0x00
[20:44:05][D][nextion_upload:242]: Available 6 : 0x00
[20:44:05][D][nextion_upload:242]: Available 7 : 0x00
[20:44:05][D][nextion_upload:242]: Available 8 : 0x00
[20:44:05][D][nextion_upload:242]: Available 9 : 0x00
[20:44:05][D][nextion_upload:242]: Available 10 : 0x00
[20:44:05][D][nextion_upload:242]: Available 11 : 0x00
[20:44:05][D][nextion_upload:242]: Available 12 : 0x00
[20:44:05][D][nextion_upload:242]: Available 13 : 0x00
[20:44:05][D][nextion_upload:242]: Available 14 : 0x00
[20:44:05][D][nextion_upload:242]: Available 15 : 0x00
[20:44:05][D][nextion_upload:242]: Available 16 : 0x00
[20:44:05][D][nextion_upload:242]: Available 17 : 0x00
[20:44:05][D][nextion_upload:242]: Available 18 : 0x00
[20:44:05][D][nextion_upload:248]: preparation for tft update failed 0 ""
[20:44:05][D][nextion_upload:324]: Restarting Nextion

Have the necessary things placed in my config from day 0 (pr#2956), but unable to flash the screen with a tft file (my own design or masto or marcfager their design)

Do you guys have any clue or remedy? Am thinking about hooking up my ft232 programer to the tx rx pads of the screen and trying to flash directly from the nextion editor.

I had problems with my display sleeping and interrupting updates.

If you have ESPHome setup to use a service call to send commands to the display then ensuring it is awake and sleep is disabled is something to try.

1 Like

Iā€™m using the NSPanel with ESPHome and the original HMI. Thanks to @DeanoXā€™s code I can use the light and curtain widgets!!

Iā€™m sharing my code if that can help someone:

Click here!
substitutions:
  devicename: NSPanel

esphome:
  name: nspanel
  comment: "NSPanel"

esp32:
  board: esp32dev

uart:
  tx_pin: 16
  rx_pin: 17
  baud_rate: 115200

external_components:
  - source: github://pr#2702
    components: ["nspanel"]

nspanel:
  id: nspanel_id
  time_id: current_time
  temperature: temperature
  screen_power_switch: screen_power
  eco_mode_switch: eco_mode
  relays:
    - relay_1
    - relay_2
  on_json_message:
    then:
      # Widget 1 (type:0x86 id:l_salon) 
      - if:
          condition:
            lambda: 'return (type == 0x86 && root.containsKey("id") && strcasecmp(root["id"], "l_salon") == 0);'
          then:
            - if:
                condition:
                  lambda: 'return (root["params"].containsKey("switch") && root["params"]["switch"] == "on");'
                then:
                  - homeassistant.service:
                      service: light.turn_on
                      data:
                        entity_id: light.salon_bulb
            - if:
                condition:
                  lambda: 'return (root["params"].containsKey("switch") && root["params"]["switch"] == "off");'
                then:
                  - homeassistant.service:
                      service: light.turn_off
                      data:
                        entity_id: light.salon_bulb
            - if:
                condition:
                  lambda: 'return (root["params"].containsKey("white"));'
                then:
                  - homeassistant.service:
                      service: light.turn_on
                      data:
                        entity_id: light.salon_bulb
                        brightness: !lambda 'return int(root["params"]["white"]["br"].as<float>() / 100 * 254);'
      # Widget 2 (type:0x86 id:l_entree) 
      - if:
          condition:
            lambda: 'return (type == 0x86 && root.containsKey("id") && strcasecmp(root["id"], "l_entree") == 0);'
          then:
            - if:
                condition:
                  lambda: 'return (root["params"].containsKey("switch") && root["params"]["switch"] == "on");'
                then:
                  - homeassistant.service:
                      service: light.turn_on
                      data:
                        entity_id: light.entree_bulb
            - if:
                condition:
                  lambda: 'return (root["params"].containsKey("switch") && root["params"]["switch"] == "off");'
                then:
                  - homeassistant.service:
                      service: light.turn_off
                      data:
                        entity_id: light.entree_bulb
            - if:
                condition:
                  lambda: 'return (root["params"].containsKey("white"));'
                then:
                  - sensor.template.publish:
                      id: l_entree_ct
                      state: !lambda 'return int(root["params"]["white"]["ct"].as<float>());'
                  - homeassistant.service:
                      service: light.turn_on
                      data:
                        entity_id: light.entree_bulb
                        brightness: !lambda 'return int(root["params"]["white"]["br"].as<float>() / 100 * 254);'
                        color_temp: !lambda 'return int(id(l_entree_ct).state);'
      # Widget 3 (type:0x86 id:vr_salon) 
      - if:
          condition:
            lambda: 'return (type == 0x86 && root.containsKey("id") && strcasecmp(root["id"], "vr_salon") == 0);'
          then:
            - if:
                condition:
                  lambda: 'return (root["params"].containsKey("switch") && root["params"]["switch"] == "on");'
                then:
                  - homeassistant.service:
                      service: cover.open_cover
                      data:
                        entity_id: cover.salon_volet_roulant
            - if:
                condition:
                  lambda: 'return (root["params"].containsKey("switch") && root["params"]["switch"] == "off");'
                then:
                  - homeassistant.service:
                      service: cover.close_cover
                      data:
                        entity_id: cover.salon_volet_roulant
            - if:
                condition:
                  lambda: 'return (root["params"].containsKey("switch") && root["params"]["switch"] == "pause");'
                then:
                  - homeassistant.service:
                      service: cover.stop_cover
                      data:
                        entity_id: cover.salon_volet_roulant
            - if:
                condition:
                  lambda: 'return (root["params"].containsKey("setclose"));'
                then:
                  - homeassistant.service:
                      service: cover.set_cover_position
                      data:
                        entity_id: cover.salon_volet_roulant
                        position: !lambda 'return 100 - root["params"]["setclose"].as<int>();'
      # Widget 4 (type:0x86 id:vr_cuisine) 
      - if:
          condition:
            lambda: 'return (type == 0x86 && root.containsKey("id") && strcasecmp(root["id"], "vr_cuisine") == 0);'
          then:
            - if:
                condition:
                  lambda: 'return (root["params"].containsKey("switch") && root["params"]["switch"] == "on");'
                then:
                  - homeassistant.service:
                      service: cover.open_cover
                      data:
                        entity_id: cover.cuisine_volet_roulant
            - if:
                condition:
                  lambda: 'return (root["params"].containsKey("switch") && root["params"]["switch"] == "off");'
                then:
                  - homeassistant.service:
                      service: cover.close_cover
                      data:
                        entity_id: cover.cuisine_volet_roulant
            - if:
                condition:
                  lambda: 'return (root["params"].containsKey("switch") && root["params"]["switch"] == "pause");'
                then:
                  - homeassistant.service:
                      service: cover.stop_cover
                      data:
                        entity_id: cover.cuisine_volet_roulant
            - if:
                condition:
                  lambda: 'return (root["params"].containsKey("setclose"));'
                then:
                  - homeassistant.service:
                      service: cover.set_cover_position
                      data:
                        entity_id: cover.cuisine_volet_roulant
                        position: !lambda 'return 100 - root["params"]["setclose"].as<int>();'
      # Widget 5 (type:0x86 id:p_terrasse) 
      - if:
          condition:
            lambda: 'return (type == 0x86 && root.containsKey("id") && strcasecmp(root["id"], "p_terrasse") == 0);'
          then:
            - if:
                condition:
                  lambda: 'return (root["params"].containsKey("switch") && root["params"]["switch"] == "on");'
                then:
                  - homeassistant.service:
                      service: switch.turn_on
                      data:
                        entity_id: switch.terrasse_plug
            - if:
                condition:
                  lambda: 'return (root["params"].containsKey("switch") && root["params"]["switch"] == "off");'
                then:
                  - homeassistant.service:
                      service: switch.turn_off
                      data:
                        entity_id: switch.terrasse_plug

binary_sensor:
  - platform: status
    name: "$devicename Status"

  - platform: gpio
    name: "$devicename Left Button"
    pin:
      number: 14
      inverted: true
    on_click:
      - switch.toggle: relay_1

  - platform: gpio
    name: "$devicename Right Button"
    pin:
      number: 27
      inverted: true
    on_multi_click:
#      - timing:
#          - ON for at most 1s
#          - OFF for at least 0.2s
#        then:
#          - switch.toggle: relay_2
      - timing:
          - ON for at least 5s
        then:
          - button.press: restart_button

  - platform: homeassistant
    id: salon_light
    entity_id: light.salon_bulb
    on_press:
      then:
        - lambda: 'id(nspanel_id).send_json_command(0x86,"{\"id\":\"l_salon\",\"params\":{\"switch\":\"on\"}}");'
    on_release:
      then:
        - lambda: 'id(nspanel_id).send_json_command(0x86,"{\"id\":\"l_salon\",\"params\":{\"switch\":\"off\"}}");'

  - platform: homeassistant
    id: entree_light
    entity_id: light.entree_bulb
    on_press:
      then:
        - lambda: 'id(nspanel_id).send_json_command(0x86,"{\"id\":\"l_entree\",\"params\":{\"switch\":\"on\"}}");'
    on_release:
      then:
        - lambda: 'id(nspanel_id).send_json_command(0x86,"{\"id\":\"l_entree\",\"params\":{\"switch\":\"off\"}}");'

  - platform: homeassistant
    id: terrasse_plug
    entity_id: switch.terrasse_plug
    on_press:
      then:
        - lambda: 'id(nspanel_id).send_json_command(0x86,"{\"id\":\"p_terrasse\",\"params\":{\"switch\":\"on\"}}");'
    on_release:
      then:
        - lambda: 'id(nspanel_id).send_json_command(0x86,"{\"id\":\"p_terrasse\",\"params\":{\"switch\":\"off\"}}");'

button:
  - platform: restart
    name: "$devicename Restart"
    id: restart_button

sensor:
  - platform: uptime
    id: uptime_sec

  - platform: wifi_signal
    name: "$devicename WiFi Signal"
    update_interval: 120s

  - platform: template
    id: uptime_timestamp
    name: "$devicename Uptime"
    device_class: timestamp
    entity_category: diagnostic
    accuracy_decimals: 0
    update_interval: never
    lambda: |-
      static float timestamp = (
        id(current_time).utcnow().timestamp - id(uptime_sec).state
      );
      return timestamp;

  - platform: adc
    id: ntc_source
    pin: 38
    attenuation: 11db

  - platform: resistance
    id: resistance_sensor
    sensor: ntc_source
    configuration: DOWNSTREAM
    resistor: 11.2kOhm

  - platform: ntc
    name: "$devicename Temperature"
    id: temperature
    sensor: resistance_sensor
    calibration:
      b_constant: 3950
      reference_temperature: 25Ā°C
      reference_resistance: 10kOhm
    internal: true

  - platform: homeassistant
    id: entree_light_brightness
    entity_id: light.entree_bulb
    attribute: brightness
    filters:
      - calibrate_linear:
         - 1 -> 1
         - 254 -> 100
    on_value:
      then:
        - script.execute: ha_light_entree_update

  - platform: homeassistant
    id: entree_light_color_temp
    entity_id: light.entree_bulb
    attribute: color_temp
    filters:
      - calibrate_linear:
         - 250 -> 254
         - 454 -> 0
    on_value:
      then:
        - script.execute: ha_light_entree_update

  - platform: homeassistant
    id: salon_light_brightness
    entity_id: light.salon_bulb
    attribute: brightness
    filters:
      - calibrate_linear:
         - 1 -> 1
         - 254 -> 100
    on_value:
      then:
        - script.execute: ha_light_salon_update

  - platform: homeassistant
    id: salon_cover_position
    entity_id: cover.salon_volet_roulant
    attribute: current_position
    filters:
      - calibrate_linear:
         - 0 -> 100
         - 100 -> 0
    on_value:
      then:
        - script.execute: ha_curtain_salon_update_pos

  - platform: homeassistant
    id: cuisine_cover_position
    entity_id: cover.cuisine_volet_roulant
    attribute: current_position
    filters:
      - calibrate_linear:
         - 0 -> 100
         - 100 -> 0
    on_value:
      then:
        - script.execute: ha_curtain_cuisine_update_pos

  - platform: template
    id: l_entree_ct
    filters:
      - calibrate_linear:
         - 0 -> 454
         - 254 -> 250

switch:
  - platform: gpio
    name: "$devicename Relay 1"
    id: relay_1
    pin: 22

  - platform: gpio
    name: "$devicename Relay 2"
    id: relay_2
    pin: 19

  - platform: gpio
    name: "$devicename Screen Power"
    id: screen_power
    entity_category: config
    pin:
      number: 4
      inverted: true
    restore_mode: ALWAYS_OFF
    internal: true
    on_turn_on:
      then:
        - delay: 6s
        - script.execute: nspanel_init

  - platform: template
    name: "$devicename Energy Saving Mode"
    id: eco_mode
    entity_category: config
    restore_state: true
    optimistic: true
    internal: true

text_sensor:
  - platform: version
    name: "$devicename Version"
    hide_timestamp: true

  - platform: wifi_info
    ip_address:
      name: "$devicename IPv4"
      icon: "mdi:server-network"
    ssid:
      name: "$devicename Connected SSID"
      icon: "mdi:wifi"

  - platform: homeassistant
    id: salon_cover
    entity_id: cover.salon_volet_roulant
    on_value:
      then:
        - script.execute: ha_curtain_salon_update_state

  - platform: homeassistant
    id: cuisine_cover
    entity_id: cover.cuisine_volet_roulant
    on_value:
      then:
        - script.execute: ha_curtain_cuisine_update_state

script:
  - id: nspanel_init
    # Script to initialise panel on full power on (or when screen is powered on from ESP)
    then:
      # Setup Widgets - must send all 8
      # Widget 1
      - lambda: |-
          id(nspanel_id).send_json_command(0x86,"{\"HMI_resources\":[{\"index\":1,\"ctype\":\"device\",\"id\":\"l_salon\",\"uiid\":52}]}"); 
          id(nspanel_id).send_json_command(0x86,"{\"relation\":[{\"ctype\":\"device\",\"id\":\"l_salon\",\"name\":\"Salon\",\"online\":1,\"params\":{\"switch\":\"off\",\"ltype\":\"white\",\"white\":{\"br\":0,\"ct\":0}}]}");
      # Widget 2
      - lambda: |-
          id(nspanel_id).send_json_command(0x86,"{\"HMI_resources\":[{\"index\":2,\"ctype\":\"device\",\"id\":\"l_entree\",\"uiid\":52}]}");
          id(nspanel_id).send_json_command(0x86,"{\"relation\":[{\"ctype\":\"device\",\"id\":\"l_entree\",\"name\":\"EntrƩe\",\"online\":1,\"params\":{\"switch\":\"off\",\"ltype\":\"white\",\"white\":{\"br\":0,\"ct\":0}}]}");
      # Widget 3
      - lambda: |-
          id(nspanel_id).send_json_command(0x86,"{\"HMI_resources\":[{\"index\":3,\"ctype\":\"device\",\"id\":\"vr_salon\",\"uiid\":11}]}");
          id(nspanel_id).send_json_command(0x86,"{\"relation\":[{\"ctype\":\"device\",\"id\":\"vr_salon\",\"name\":\"Salon\",\"online\":1,\"params\":{\"switch\":\"on\"}]}");
      # Widget 4
      - lambda: |-
          id(nspanel_id).send_json_command(0x86,"{\"HMI_resources\":[{\"index\":4,\"ctype\":\"device\",\"id\":\"vr_cuisine\",\"uiid\":11}]}");
          id(nspanel_id).send_json_command(0x86,"{\"relation\":[{\"ctype\":\"device\",\"id\":\"vr_cuisine\",\"name\":\"Cuisine\",\"online\":1,\"params\":{\"switch\":\"on\"}]}");
      # Widget 5
      - lambda: |-
          id(nspanel_id).send_json_command(0x86,"{\"HMI_resources\":[{\"index\":5,\"ctype\":\"device\",\"id\":\"p_terrasse\",\"uiid\":1}]}");
          id(nspanel_id).send_json_command(0x86,"{\"relation\":[{\"ctype\":\"device\",\"id\":\"p_terrasse\",\"name\":\"Pompe\",\"online\":1,\"params\":{\"switch\":\"off\"}]}");
      # Widget 6
      - lambda: 'id(nspanel_id).send_json_command(0x86,"{\"index\":6,\"type\":\"delete\"}");'
      # Widget 7
      - lambda: 'id(nspanel_id).send_json_command(0x86,"{\"index\":7,\"type\":\"delete\"}");'
      # Widget 8
      - lambda: 'id(nspanel_id).send_json_command(0x86,"{\"index\":8,\"type\":\"delete\"}");'
      # Update existing Entities / Widgets
      - script.execute: ha_light_salon_update
      - script.execute: ha_light_entree_update
      - script.execute: ha_curtain_salon_update_state
      - script.execute: ha_curtain_cuisine_update_state
      - script.execute: ha_plug_terrasse_update

  - id: ha_light_salon_update
    then:
      - lambda: |-
          if (id(salon_light).state) {
            int i_brightness = int(id(salon_light_brightness).state);
            id(nspanel_id).send_json_command(0x86,"{\"id\":\"l_salon\",\"params\":{\"switch\":\"on\",\"ltype\":\"white\",\"white\":{\"br\":" + to_string(i_brightness) + ",\"ct\":0}}}");
          } else {
            id(nspanel_id).send_json_command(0x86,"{\"id\":\"l_salon\",\"params\":{\"switch\":\"off\"}}");
          }

  - id: ha_light_entree_update
    then:
      - lambda: |-
          if (id(entree_light).state) {
            int i_brightness = int(id(entree_light_brightness).state);
            int i_color_temp = int(id(entree_light_color_temp).state);
            id(nspanel_id).send_json_command(0x86,"{\"id\":\"l_entree\",\"params\":{\"switch\":\"on\",\"ltype\":\"white\",\"white\":{\"br\":" + to_string(i_brightness) + ",\"ct\":" + to_string(i_color_temp) + "}}}");
          } else {
            id(nspanel_id).send_json_command(0x86,"{\"id\":\"l_entree\",\"params\":{\"switch\":\"off\"}}");
          }

  - id: ha_curtain_salon_update_state
    then:
      - lambda: |-
         if(id(salon_cover).state == "open") {
            id(nspanel_id).send_json_command(0x86,"{\"id\":\"vr_salon\",\"params\":{\"switch\":\"on\"}}");
          } else {
            id(nspanel_id).send_json_command(0x86,"{\"id\":\"vr_salon\",\"params\":{\"switch\":\"off\"}}");
          }
  - id: ha_curtain_salon_update_pos
    then:
      - lambda: |-
         int vr_pos = int(id(salon_cover_position).state);
         id(nspanel_id).send_json_command(0x86,"{\"id\":\"vr_salon\",\"params\":{\"setclose\":" + to_string(vr_pos) + "}}");

  - id: ha_curtain_cuisine_update_state
    then:
      - lambda: |-
         if(id(cuisine_cover).state == "open") {
            id(nspanel_id).send_json_command(0x86,"{\"id\":\"vr_cuisine\",\"params\":{\"switch\":\"on\"}}");
          } else {
            id(nspanel_id).send_json_command(0x86,"{\"id\":\"vr_cuisine\",\"params\":{\"switch\":\"off\"}}");
          }
  - id: ha_curtain_cuisine_update_pos
    then:
      - lambda: |-
         int vr_pos = int(id(cuisine_cover_position).state);
         id(nspanel_id).send_json_command(0x86,"{\"id\":\"vr_cuisine\",\"params\":{\"setclose\":" + to_string(vr_pos) + "}}");

  - id: ha_plug_terrasse_update
    then:
      - lambda: |-
          if(id(terrasse_plug).state) {
            id(nspanel_id).send_json_command(0x86,"{\"id\":\"p_terrasse\",\"params\":{\"switch\":\"on\"}}");
          } else {
            id(nspanel_id).send_json_command(0x86,"{\"id\":\"p_terrasse\",\"params\":{\"switch\":\"off\"}}");
          }

time:
  - platform: homeassistant
    timezone: Europe/Paris
    id: current_time
    on_time_sync:
      - component.update: uptime_timestamp

output:
  - platform: ledc
    id: buzzer_out
    pin: 21

rtttl:
  output: buzzer_out
  id: buzzer

wifi:
  networks:
    - ssid: !secret ssid
      password: !secret password
    - ssid: !secret ssid_live
      password: !secret password_live
  ap:
    ssid: "$devicename Fallback Hotspot"
    password: !secret api_ota_pwd

captive_portal:

web_server:
  port: 80
  include_internal: true
  auth:
    username: admin
    password: !secret api_ota_pwd

logger:

api:
  password: !secret api_ota_pwd
  services:
    - service: weather_data
      variables:
        icon: int
        temperature: int
        min: int
        max: int
      then:
        - lambda: id(nspanel_id).send_weather_data((nspanel::WeatherIcon)icon, temperature, min, max);

ota:
  password: !secret api_ota_pwd

Iā€™ve managed to use filters to share brightness, color temperature and coverā€™s position between HA and ESPHome.

2 Likes

Excellent - Glad its working. The flexibility of the original HMI is really quite easy to open up. Love the filters to scale/reverse the brightness and cover posn received from HA. And I hadnā€™t spotted the available function to send weather data rather than use the JSON directlyā€¦

1 Like

Iā€™m working currently on my setup, Iā€™ll post on GitHub as I finish

So, what I managed to configure in NSPanel, using ESP Home and original UI:

  • Time updates
  • Weather updates (independent from HA)
  • BLE tracker
  • Light control
  • RGB light control
  • Scenes activations + cheated (a bit) alarm control

Many thanks to @DeanoX code

My variation you can find here: HomeAssistantConfig/NSPanel at master Ā· peetereczek/HomeAssistantConfig Ā· GitHub

4 Likes

Iā€™m using this automation in HA:

Summary
- alias: Weather - Send Weather to NSPanel
  id: 6ad8caed-c79f-4820-984c
  initial_state: true
  trigger:
    - platform: state
      entity_id: weather.home
      attribute: temperature
    - platform: state
      entity_id: weather.home
      to:
    - platform: state
      entity_id: binary_sensor.nspanel_status
      from: "off"
      to: "on"
  condition:
    - condition: state
      entity_id: binary_sensor.nspanel_status
      state: "on"
  max_exceeded: silent
  action:
    - service: esphome.nspanel_weather_data
      data:
        icon: >-
          {% set weather = states('weather.home') %}
          {% if weather == 'clear-night' %} {{ 1|int }}
          {% elif weather == 'cloudy' %} {{ 2|int }}
          {% elif weather == 'exceptionnal' %} {{ 30|int }}
          {% elif weather == 'fog' %} {{ 11|int }}
          {% elif weather == 'hail' %} {{ 24|int }}
          {% elif weather == 'lightning' %} {{ 15|int }}
          {% elif weather == 'lightning-rainy' %} {{ 15|int }}
          {% elif weather == 'partlycloudy' %} {{ 2|int }}
          {% elif weather == 'pouring' %} {{ 12|int }}
          {% elif weather == 'rainy' %} {{ 12|int }}
          {% elif weather == 'snowy' %} {{ 20|int }}
          {% elif weather == 'snowy-rainy' %} {{ 29|int }}
          {% elif weather == 'sunny' %} {{ 1|int }}
          {% elif weather == 'windy' %} {{ 32|int }}
          {% elif weather == 'windy-variant' %} {{ 32|int }}
          {% endif %}
        temperature: "{{ state_attr('weather.home', 'temperature') }}"
        min: "{{ state_attr('weather.home', 'forecast')[0].templow }}"
        max: "{{ state_attr('weather.home', 'forecast')[0].temperature }}"

it uses the services from my ESPHome config:

Summary
api:
  password: !secret api_ota_pwd
  services:
    - service: weather_data
      variables:
        icon: int
        temperature: int
        min: int
        max: int
      then:
        - lambda: id(nspanel_id).send_weather_data((nspanel::WeatherIcon)icon, temperature, min, max);
2 Likes

Did anyone figured out how to setup display brightness with original GUI?
I have tried sending json command {ā€œdimā€:52} into 0x87 and 0x86 channel, but no luck so far :frowning:

Many thanx to DeanoXX! I use panel as thermostat controller with original ui! DeanoXXā€™s code is working like a charm.
I have a question. Please can anyone give an advice where could i solder an 1-wire? I have a pair of dallas temp sensors inside the floor and i want to use them in ESPHome.
Thanks!

1 Like

I had problems as well. Seems like they forgot to wash out flux from the high voltage part. I cleaned everything up and device started normally

What do you think it is possible to make this design ?

2 Likes

I like the glass-like reflection. Doable, itā€™s all pixel art.

what do you think ?
background (2)

background: WeTransfer - Send Large Files & Share Photos Online - Up to 2GB Free

3 Likes