NEWS
Sonoff NSpanel und mqtt
-
@thorsten47 sagte in Sonoff NSpanel und mqtt:
Ware es möglich die Temperatur -Daten auch per MQTT an das Sonoff NSPanel zu senden und statt der voreingestellten Temperatur die von der Wetterstation anzeigen zu lassen
zeig mal den Inhalt der Variable
weatherEntityPath
im Skript sowie den Teil des Objektbaums, auf den dort referenziert wird. -
@marc-berg
wo finde ich das denn ich hab die autoexec.be und die nspanel.be und eine _persist.json an Dateien bin absuluter neuling mit dem sonoff nspanel hab auch in der hinsicht noch nix eingestellt hab das erst heute morgen mit Tasmota geflasht# Sonoff NSPanel Tasmota driver v0.47 | code by blakadder and s-hadinger var mode = "NSPanel" import persist var devicename = tasmota.cmd("DeviceName")["DeviceName"] persist.tempunit = tasmota.get_option(8) == 1 ? "F" : "C" if persist.has("dim") else persist.dim = "1" end var loc = persist.has("loc") ? persist.loc : "North Pole" var weather_interval = persist.has("weather_interval") ? persist.weather_interval : "60" persist.save() # save persist file until serial bug fixed var widget = { # 1 = toggle switch horizontal # 2 = toggle switch double horizontal # 3 = toggle switch triple horizontal # 4 = toggle switch quad horizontal # 6 = toggle switch vertical # 7 = toggle switch double vertical # 8 = toggle switch triple vertical # 9 = toggle switch quad vertical # 33 = RGB light strip # 52 = CCT bulb # 69 = RGB+CCT bulb # leave empty brackets if you don't want a widget there # ctype scene doesn't have an uiid # index "name ", "ctype", uiid | name max 8 characters, rest will be truncated) 1: ["Index 1", "group", 1], 2: ["Index 2", "group", 2], 3: ["Index 3", "group", 3], 4: ["Index 4", "group", 4], 5: ["Index 5", "group", 33], 6: ["Index 6", "device", 52], 7: ["Index 7", "device", 69], 8: ["Index 8", "scene"], } class NSPanel : Driver # set thermostat options static atc = { "id": "thermostat", "outlet": "0", # outlet to use for trigger "etype": "hot", # hot or cold "mirror": false, # if true Tasmota will resend triggers as commands to keep the state on screen } static types = { '"switches":[{"outlet":': 0x87, "relation": 0x86, "ATC": 0x84, "index": 0x86, "params": 0x86, "wifiState": 0x85, "HMI_resources":0x86, "temp": 0x83, "year": 0x82, "weather": 0x81, "queryInfo": 0x80, "HMI_dimOpen": 0x87, "HMI_wallpaper":0x87, } static header = bytes('55AA') var ser # create serial port object # intialize the serial port, if unspecified Tx/Rx are GPIO 16/17 def init(tx, rx) if !tx tx = 16 end if !rx rx = 17 end self.ser = serial(rx, tx, 115200, serial.SERIAL_8N1) tasmota.add_driver(self) end # determine type of message def findtype(value) import string for k:self.types.keys() if string.find(value, k) >= 0 return self.types[k] end end return 0 end def crc16(data, poly) if !poly poly = 0xA001 end # CRC-16 MODBUS HASHING ALGORITHM var crc = 0xFFFF for i:0..size(data)-1 crc = crc ^ data[i] for j:0..7 if crc & 1 crc = (crc >> 1) ^ poly else crc = crc >> 1 end end end return crc end # encode using NSPanel protocol # input: payload:json string def encode(payload) var b = bytes() var nsp_type = self.findtype(payload) b += self.header b.add(nsp_type) # add a single byte b.add(size(payload), 2) # add size as 2 bytes, little endian b += bytes().fromstring(payload) var msg_crc = self.crc16(b) b.add(msg_crc, 2) # crc 2 bytes, little endian return b end def split_55(b) var ret = [] var s = size(b) var i = s-2 # start from last-1 while i > 0 if b[i] == 0x55 && b[i+1] == 0xAA ret.push(b[i..s-1]) # push last msg to list b = b[(0..i-1)] # write the rest back to b end i -= 1 end ret.push(b) return ret end # send a string payload (needs to be a valid json string) def send(payload) print("NSP: Sent =", payload) var payload_bin = self.encode(payload) self.ser.write(payload_bin) # print("NSP: Sent =", payload) log("NSP: NSPanel payload sent = " + str(payload_bin), 3) end # send a nextion payload def encodenx(payload) var b = bytes().fromstring(payload) b += bytes('FFFFFF') return b end def sendnx(payload) var payload_bin = self.encodenx(payload) self.ser.write(payload_bin) # print("NSP: Sent =", payload_bin) log("NSP: Nextion command sent = " + str(payload_bin), 3) end # sets time and date according to Tasmota local time def set_clock() var now = tasmota.rtc() var time_raw = now['local'] var nsp_time = tasmota.time_dump(time_raw) var time_payload = '{"year":' + str(nsp_time['year']) + ',"mon":' + str(nsp_time['month']) + ',"day":' + str(nsp_time['day']) + ',"hour":' + str(nsp_time['hour']) + ',"min":' + str(nsp_time['min']) + ',"week":' + str(nsp_time['weekday']) + '}' log('NSP: Time and date synced with ' + time_payload, 3) self.send(time_payload) end # sync main screen power bars with tasmota POWER status def set_power() var ps = tasmota.get_power() for i:0..1 if ps[i] == true ps[i] = "on" else ps[i] = "off" end end var json_payload = '{\"switches\":[{\"outlet\":0,\"switch\":\"' + ps[0] + '\"},{\"outlet\":1,\"switch\":\"' + ps[1] + '\"}]}' log('NSP: Switch state updated with ' + json_payload) self.send(json_payload) end # draw widgets def draw() var i = 1 while i < 9 if size(widget[i]) > 1 var wdgt = "" if widget[i][1] == "scene" wdgt = '{"HMI_resources":[{"index":' + str(i) + ',"ctype":"' + widget[i][1] + '","id":"' + str(i) + '"}]}' else wdgt = '{"HMI_resources":[{"index":' + str(i) + ',"ctype":"' + widget[i][1] + '","id":"' + str(i) + '","uiid":' + str(widget[i][2]) + '}]}' end var name = '{"relation":[{"ctype":"' + widget[i][1] + '","id":"' + str(i) + '","name":"' + widget[i][0][0..7] + '"}]}' self.send(wdgt) self.send(name) else self.send('{"index":' + str(i) + ',"type":"delete"}') end i += 1 end end # update weather forecast, since the provider doesn't support range I winged it with FeelsLike temperature def set_weather() import json var weather_icon = { "": 30, # Unknown "113": 1, # Sunny "116": 2, # PartlyCloudy "119": 2, # Cloudy "122": 7, # VeryCloudy "143": 11, # Fog "176": 40, # LightShowers "179": 24, # LightSleetShowers "182": 24, # LightSleet "185": 24, # LightSleet "200": 42, # ThunderyShowers "227": 20, # LightSnow "230": 22, # HeavySnow "248": 11, # Fog "260": 11, # Fog "263": 40, # LightShowers "266": 40, # LightRain "281": 24, # LightSleet "284": 24, # LightSleet "293": 40, # LightRain "296": 40, # LightRain "299": 18, # HeavyShowers "302": 18, # HeavyRain "305": 18, # HeavyShowers "308": 18, # HeavyRain "311": 24, # LightSleet "314": 24, # LightSleet "317": 24, # LightSleet "320": 20, # LightSnow "323": 22, # LightSnowShowers "326": 22, # LightSnowShowers "329": 22, # HeavySnow "332": 22, # HeavySnow "335": 29, # HeavySnowShowers "338": 22, # HeavySnow "350": 24, # LightSleet "353": 24, # LightSleet "356": 18, # HeavyShowers "359": 18, # HeavyRain "362": 24, # LightSleetShowers "365": 24, # LightSleetShowers "368": 22, # LightSnowShowers "371": 29, # HeavySnowShowers "374": 24, # LightSleetShowers "377": 24, # LightSleet "386": 42, # ThunderyShowers "389": 42, # ThunderyHeavyRain "392": 42, # ThunderySnowShowers "395": 29, # HeavySnowShowers } var temp var tmin var tmax var cl = webclient() var url = "http://wttr.in/" + loc + '?format=j2' cl.set_useragent("curl/7.72.0") cl.set_follow_redirects(true) cl.begin(url) if cl.GET() == "200" || cl.GET() == 200 var b = json.load(cl.get_string()) if persist.tempunit == "F" temp = b['current_condition'][0]['temp_F'] tmin = b['weather'][0]['mintempF'] tmax = b['weather'][0]['maxtempF'] else temp = b['current_condition'][0]['temp_C'] tmin = b['weather'][0]['mintempC'] tmax = b['weather'][0]['maxtempC'] end var wttr = '{"HMI_weather":' + str(weather_icon[b['current_condition'][0]['weatherCode']]) + ',"HMI_outdoorTemp":{"current":' + temp + ',"range":" ' + tmin + ', ' + tmax + '"}}' self.send(wttr) log('NSP: Weather update for location: ' + b['nearest_area'][0]['areaName'][0]['value'] + ", "+ b['nearest_area'][0]['country'][0]['value']) else log('NSP: Weather update failed!', 3) end end # commands to populate an empty screen, should be executed when screen initializes def screeninit() # self.send('{"queryInfo":"version"}') self.send('{"HMI_ATCDevice":{"ctype":"device","id":"' + self.atc['id'] + '","outlet":' + self.atc['outlet'] + ',"etype":"' + self.atc['etype'] + '"}') self.send('{"relation":[{"ctype":"device","id":"panel","name":"' + devicename + '","online":true}]}') self.send('{"HMI_dimOpen":' + persist.dim + '}') self.set_clock() self.set_power() self.set_weather() self.draw() tasmota.cmd("State") tasmota.cmd("TelePeriod") end # read serial port and decode messages according to protocol used def every_100ms() if self.ser.available() > 0 var msg = self.ser.read() # read bytes from serial as bytes import string if size(msg) > 0 print("NSP: Received Raw =", msg) if msg[0..1] == self.header mode = "NSPanel" var lst = self.split_55(msg) for i:0..size(lst)-1 msg = lst[i] if self.atc['mirror'] == true if msg[2] == 0x84 self.ser.write(msg) # resend messages with type 0x84 for thermostat page end end var j = size(msg) - 1 while msg[j] != 0x7D msg = msg[0..-1] j -= 1 end msg = msg[5..j] if size(msg) > 2 if msg == bytes('7B226572726F72223A307D') # don't publish {"error":0} else var jm = string.format("{\"NSPanel\":%s}",msg.asstring()) tasmota.publish_result(jm, "RESULT") end end end elif msg == bytes('000000FFFFFF88FFFFFF') log("NSP: Screen Initialized") # print the message as string self.screeninit() else var jm = string.format("{\"NSPanel\":{\"Nextion\":\"%s\"}}",str(msg[0..-4])) tasmota.publish_result(jm, "RESULT") end end end end end nsp=NSPanel() tasmota.add_rule("power1#state", /-> nsp.set_power()) tasmota.add_rule("power2#state", /-> nsp.set_power()) # add NSPSend command to Tasmota def nspsend(cmd, idx, payload, payload_json) # NSPSend2 sends Nextion commands if idx == 2 var command = nsp.sendnx(payload) tasmota.resp_cmnd_done() # NSPSend sends NSPanel commands, requires valid payload else import json var command = nsp.send(json.dump(payload_json)) tasmota.resp_cmnd_done() end end tasmota.add_cmd('NSPSend', nspsend) # add NSPMode command to Tasmota def modeselect(NSPMode, idx, payload) if payload == "1" nsp.sendnx('DRAKJHSUYDGBNCJHGJKSHBDN') tasmota.resp_cmnd_done() mode = "Nextion" elif payload == "0" nsp.sendnx('recmod=1') nsp.sendnx('recmod=1') mode = "NSPanel" tasmota.resp_cmnd_done() else tasmota.resp_cmnd_str('{"Mode":"' + mode + '"}') end end tasmota.add_cmd('NSPMode', modeselect) # add NSPDim command to Tasmota def dimopen(NSPDim, idx, payload) if payload == "0" || payload == "1" persist.dim = payload nsp.send('{"HMI_dimOpen":' + payload + '}') tasmota.resp_cmnd_done() else payload = str(persist.dim) end import string var jm = string.format("{\"NSPanel\":{\"Energy-saving\":%s}}",payload) tasmota.publish_result(jm, "RESULT") end tasmota.add_cmd('NSPDim', dimopen) # add NSPLocation command to Tasmota def setloc(NSPLocation, idx, payload) if size(payload) > 1 persist.loc = payload tasmota.resp_cmnd_done() persist.save() loc = persist.loc nsp.set_weather() else payload = loc end import string var jm = string.format("{\"NSPanel\":{\"Location\":\"%s\"}}",payload) tasmota.publish_result(jm, "RESULT") end tasmota.add_cmd('NSPLocation', setloc) # add NSPWInterval command to Tasmota def setWInterval(NSPLocation, idx, p) var payload = int(p) if payload > 0 persist.weather_interval = payload tasmota.resp_cmnd_done() persist.save() weather_interval = persist.weather_interval nsp.set_weather() else payload = weather_interval end import string var jm = string.format("{\"NSPanel\":{\"Weather Interval\":\"%d\"}}",payload) tasmota.publish_result(jm, "RESULT") end tasmota.add_cmd('NSPWInterval', setWInterval) # set displayed indoor temperature to value:int def set_temp(value) var temp_payload = '{"temperature":' + str(value) + ',"tempUnit":"' + persist.tempunit + '"}' log('NSP: Indoor temperature set with ' + temp_payload, 3) nsp.send(temp_payload) end tasmota.add_rule("Tele#ANALOG#Temperature1", set_temp) # rule to run set_temp on teleperiod # set wifi icon status def set_wifi(value) var rssi = (value-1)/20 rssi = '{"wifiState":"connected","rssiLevel":' + str(rssi) + '}' log('NSP: Wi-Fi icon set with ' + rssi, 3) nsp.send(rssi) end def set_disconnect() nsp.send('{"wifiState":"nonetwork","rssiLevel":0}') end def sync_weather() # set weather every 60 minutes var interval = persist.has("weather_interval") ? int(persist.weather_interval) : 60 nsp.set_weather() print("Weather forecast synced") tasmota.set_timer(interval*60*1000, sync_weather) end tasmota.cmd("Rule3 1") # needed until Berry bug fixed tasmota.cmd("State") tasmota.add_rule("Time#Minute", /-> nsp.set_clock()) # set rule to update clock every minute tasmota.add_rule("Tele#Wifi#RSSI", set_wifi) # set rule to update wifi icon tasmota.add_rule("wifi#disconnected", set_disconnect) # set rule to change wifi icon on disconnect tasmota.add_rule("mqtt#disconnected", set_disconnect) # set rule to change wifi icon on disconnect tasmota.add_rule("system#boot", /-> nsp.screeninit()) tasmota.add_rule("time#initialized", sync_weather) tasmota.cmd("TelePeriod") Das steht in der nspanel.be drinne
-
@thorsten47 sagte in Sonoff NSpanel und mqtt:
bin absuluter neuling
Okay, dann stehst Du aber wirklich noch ganz am Anfang und bist wahrscheinlich hier:
https://forum.iobroker.net/topic/58170/sonoff-nspanel-mit-lovelace-ui
besser aufgehoben.
-
@marc-berg
mit esp 8266 hab ich schon vieles gemacht aber noch nie mit tasmota ich werde mir das mal durchlesen hab heute morgen gegoogelt und nix gefunden -
Hi @Thorsten47,
habe nicht ganz verstanden, welches System jetzt dein Primärsystem ist? HA oder ioBroker und unter welchem System soll das NSPanel laufen?
Das "NSPanel Lovelace UI" Projekt ist eine Zusammenarbeit mit unterschiedlichsten SmartHome Systemen. Es funktioniert daher im ioBroker und im Home Assistant.
Die Integration für den ioBroker findest du im Wiki:
https://github.com/joBr99/nspanel-lovelace-ui/wikiDie Integration für den Home Assistant unter HACS:
und die Doku:
https://docs.nspanel.pky.eu/stable/P.S.: wir haben natürlich die Kalibrierung des Temperatursensors ebenfalls im Wiki beschrieben (Funktioniert natürlich für beide Systeme so, da Tasmota):
https://github.com/joBr99/nspanel-lovelace-ui/wiki/NSPanel-Tasmota-FAQ#21--interner-raum-temperatursensorEDIT: Für den ioBroker findest du den Support-Thread unter:
https://forum.iobroker.net/topic/58170/sonoff-nspanel-mit-lovelace-ui?_=1716146183145Im ioBroker ist die Funktionalität etwas größer als im Home Assistant. Auch lassen sich komplexe Anforderungen wie Integrationen mit Charts im ioBroker lösen (Aktuell im HA nicht machbar...)
Hier auch ein paar Beispiele:
https://forum.iobroker.net/topic/69942/sonoff-nspanel-mit-lovelace-ui-zeigt-her-eure-cards -
@armilar mein System auf dem nspanel ist tasmota
und ich habe 2 raspberry pi im einsatz einer ist der home assitant der andere mein io broker das funktioniert auch alles moechte nur auf dem nspanel statt der vergegebenen Temperaturen die von meiner MQTT Wetterstation einbinden -
schon klar, dass auf dem NSPanel Tasmota läuft.
Unter welchem System (ioBroker oder Home Assistant) soll die Steuerung für das NSPanel laufen? Das ist die Frage
In einem vorherigen Beispiel hast du einen Auszug aus der Tasmota mit Stock-TFT gepostet
Die ist natürlich maximal nutzlos, da sich damit so ziemlich gar nichts umsetzen lässt...
Wir sprechen hier von einer alternativen TFT-Firmware mit Lovelace UI um alle Funktionalitäten des Smart Homes zu nutzen
-
@thorsten47 wie @Armilar schon schrieb über welches System kommen die Daten. Kommen sie von homeAssistment oder vom Iobroker. Das müssen wir erstmal klären. Die Daten vom mqtt wo kommen sie denn an??
-
@TT-Tom welche ist die einfachste form des ganzen. Scheint ja sehr komplex zu sein aber steuern möchte ich eigentlich alles zentral mit dem home-assistant
Hab gestern Abend nochmal eine Anleitung befolgt nu macht das display sowas. Dazu meine frage komme ich da wieder zur original Firmware zurück wenn ja wie und wo bekomme ich die her.
Hab schon 2. NS Panel bestellt
-
@thorsten47 sagte in Sonoff NSpanel und mqtt:
Dazu meine frage komme ich da wieder zur original Firmware zurück wenn ja wie und wo bekomme ich die her.
Gar nicht... Sobald der Weg mit Tasmota beschritten ist, gibt es für das NSPanel kein zurück zur Original-Firmware von iTead mehr.
Scheint ja sehr komplex zu sein aber steuern möchte ich eigentlich alles zentral mit dem home-assistant
Das Panel benötigt jetzt ein Backend um die Entitäten des Home Assistant zu steuern und Seiten aufzubauen --> Augen zu und durch... sieht schlimmer aus, als es ist... Immer die Anleitung für HA befolgen...
Diese findest du in der Beschreibung für den Home Assistant:
https://docs.nspanel.pky.eu/stable/EDIT: Hier wird es doch ganz ordentlich für HA erklärt...
https://www.youtube.com/watch?v=3kOQ4lhF8u0 -
@armilar Hab das nach der Anleitung versucht aber klappt nicht hab die die Verzeichnissstruktur
( /addon_configs/a0d7b954_appdaemon/appdeamon.yaml) so auch nicht. sondersn so (/homeassistant/appdaemon/apps/apps.yaml ) die apps.yaml hatte ich auch nicht hab ich angelegt
aber irgendwie klappt nix davon -
Ich kann dir leider nur beim Betreiben des NSPanels auf der ioBroker Seite helfen.
Mit Home Assistant müsstest du auf ein Forum für Home Assistant um dir Hilfe zu suchen.
@joBr99 - gibt es für HA ein Forum in dem solche Fragen geklärt werden können?
-
@armilar moentan funktioniert es noch nicht werde mich damit in ruhe befassen erstmal muss ich die SD card von meinem Home Assistand reparieren die ist kaputt deswegen startet der auch nicht oder installiert nix