From 3241f929ea8dde5b56acf9a297a31a8a4d96fd63 Mon Sep 17 00:00:00 2001 From: joBr99 <29555657+joBr99@users.noreply.github.com> Date: Sat, 29 Jan 2022 14:37:41 +0100 Subject: [PATCH] first tests with tasmota --- README.md | 15 +- esphome/README.md | 11 + esphome.yaml => esphome/esphome.yaml | 0 tasmota/autoexec.be | 293 +++++++++++++++++++++++++++ 4 files changed, 309 insertions(+), 10 deletions(-) create mode 100644 esphome/README.md rename esphome.yaml => esphome/esphome.yaml (100%) create mode 100644 tasmota/autoexec.be diff --git a/README.md b/README.md index e3fd5504..c42d91b7 100644 --- a/README.md +++ b/README.md @@ -8,18 +8,13 @@ This is at a early stage, it is possible to set entities on the pages on the nsp ![image](https://user-images.githubusercontent.com/29555657/149628697-1f440086-fe67-498f-ac73-a2293af7a479.png) +# Tasmota + +x + # EspHome component -See my esphome.yaml for the config used on the nspanel device. -Messages are currently handled on the "on_incoming_msg" lambda. -An proper implementation where you can configure the pages within esphome yaml is currently missing. -It should be possible to recact to buttonPress Events within this lambda. (through calling a home assistant service or something like that) - -To flash a new tft file I'm currently switching to the offical nextion component, which is also in the esphome.yaml -It might be needed to switch to hidden page and disable recmod/reparse mod. To access hidden page press the hidden button 10 times. - -![image](https://user-images.githubusercontent.com/29555657/149628769-2caa3ebc-1019-421b-b316-1845c55acf09.png) - +See Readme in esphome folder. # NsPanel Custom UI diff --git a/esphome/README.md b/esphome/README.md new file mode 100644 index 00000000..1a616a7a --- /dev/null +++ b/esphome/README.md @@ -0,0 +1,11 @@ +# EspHome component + +See my esphome.yaml for the config used on the nspanel device. +Messages are currently handled on the "on_incoming_msg" lambda. +An proper implementation where you can configure the pages within esphome yaml is currently missing. +It should be possible to recact to buttonPress Events within this lambda. (through calling a home assistant service or something like that) + +To flash a new tft file I'm currently switching to the offical nextion component, which is also in the esphome.yaml +It might be needed to switch to hidden page and disable recmod/reparse mod. To access hidden page press the hidden button 10 times. + +![image](https://user-images.githubusercontent.com/29555657/149628769-2caa3ebc-1019-421b-b316-1845c55acf09.png) diff --git a/esphome.yaml b/esphome/esphome.yaml similarity index 100% rename from esphome.yaml rename to esphome/esphome.yaml diff --git a/tasmota/autoexec.be b/tasmota/autoexec.be new file mode 100644 index 00000000..fdc0a61b --- /dev/null +++ b/tasmota/autoexec.be @@ -0,0 +1,293 @@ +# Sonoff NSPanel Lovelance UI Serial Protocol driver by joBr99, based on nspanel impemementation of blakadder +# Sonoff NSPanel Tasmota (Nextion with Flashing) driver | code by peepshow-21 +# based on; +# Sonoff NSPanel Tasmota driver v0.47 | code by blakadder and s-hadinger + + +class Nextion : Driver + + static VERSION = "v0.1.2-beta" + static CHUNK_FILE = "nextion" + static header = bytes('55BB') + + var flash_mode + var ser + var chunk_url + var flash_size + var chunk + var tot_read + var last_per + + 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 + + def encode(payload) + var b = bytes() + b += self.header + var nsp_type = 0 # not used + 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 encodenx(payload) + var b = bytes().fromstring(payload) + b += bytes('FFFFFF') + return b + end + + def sendnx(payload) + import string + var payload_bin = self.encodenx(payload) + self.ser.write(payload_bin) + log(string.format("NSP: Nextion command sent = %s",str(payload_bin)), 3) + end + + def send(payload) + var payload_bin = self.encode(payload) + if self.flash_mode==1 + log("NSP: skipped command becuase still flashing", 3) + else + self.ser.write(payload_bin) + log("NSP: payload sent = " + str(payload_bin), 3) + end + end + + def getPage(url) + var s + var retry = 0 + while (retry>=0 && retry<5) + var wc = webclient() + wc.begin(url) + var r = wc.GET() + if (r==200) + s = wc.get_string() + retry = -1 + else + s = nil + retry = retry + 1 + log("NSP: HTTP retry required") + end + wc.close() + end + if (s==nil) + log("NSP: Failed to load chunk over http") + end + return s + end + + def write_to_file(b) + log("DBG: Write to file") + var f = open("test.bin","a") + f.write(b) + f.close() + end + + def write_to_nextion(b) + self.ser.write(b) + end + + def write_chunk() + import string + var name = string.format("%s/%s-%04d.hex",self.chunk_url,self.CHUNK_FILE,self.chunk) + var s = self.getPage(name) + var b = bytes(s) + #self.write_to_file(b) + self.write_to_nextion(b) + return b.size() + end + + def init() + log("NSP: Initializing Driver") + self.ser = serial(17, 16, 115200, serial.SERIAL_8N1) + self.sendnx('DRAKJHSUYDGBNCJHGJKSHBDN') + self.flash_mode = 0 + end + + def screeninit() + log("NSP: Screen Initialized") + self.sendnx("berry_ver.txt=\"berry: "+self.VERSION+"\"") + end + + def split_55(b) + var ret = [] + var s = size(b) + var i = s-1 # start from last + while i > 0 + if b[i] == 0x55 && b[i+1] == 0xBB + 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 + + def every_100ms() + import string + if self.ser.available() > 0 + var msg = self.ser.read() + if size(msg) > 0 + log(string.format("NSP: Received Raw = %s",str(msg)), 3) + if (self.flash_mode==1) + var str = msg[0..-4].asstring() + log(str, 3) + if (string.find(str,"comok 2")==0) + self.sendnx(string.format("whmi-wri %d,115200,res0",self.flash_size)) + elif (size(msg)==1 && msg[0]==0x05) + var x = self.write_chunk() + self.tot_read = self.tot_read + x + self.chunk = self.chunk + 1 + var per = (self.tot_read*100)/self.flash_size + if (self.last_per!=per) + self.last_per = per + tasmota.publish_result(string.format("{\"Flashing\":{\"complete\": %d}}",per), "RESULT") + end + if (self.tot_read==self.flash_size) + log("NSP: Flashing complete") + self.flash_mode = 0 + end + tasmota.yield() + end + else + if msg == bytes('000000FFFFFF88FFFFFF') + self.screeninit() + elif msg[0..1] == self.header + var jm3 = string.format("{\"raw\":\"%s\"}",str(msg)) + tasmota.publish_result(jm3, "RESULT") + var lst = self.split_55(msg) + for i:0..size(lst)-1 + msg = lst[i] + var j = msg[2]+2 + msg = msg[3..j] + if size(msg) > 2 + var jm2 = string.format("{\"csv\":\"%s\"}",msg.asstring()) + tasmota.publish_result(jm2, "RESULT") + end + end + elif msg[0]==0x7B + var jm = string.format("{\"json\":%s}",msg[0..-1].asstring()) + tasmota.publish_result(jm, "RESULT") + elif msg[0]==0x07 # T + tasmota.cmd("buzzer 1,1") + else + var jm = string.format("{\"nextion\":\"%s\"}",str(msg[0..-4])) + tasmota.publish_result(jm, "RESULT") + end + end + end + end + end + + + def begin_file_flash() + self.flash_mode = 1 + var f = open("test.bin","w") + f.close() + while self.tot_read nextion.set_power()) +tasmota.add_rule("power2#state", /-> nextion.set_power()) +tasmota.cmd("Rule3 1") # needed until Berry bug fixed +tasmota.add_rule("Time#Minute", /-> nextion.set_clock()) +tasmota.cmd("State") + +