mirror of https://github.com/arendst/Tasmota.git
Merge remote-tracking branch 'Tasmota/development' into development
This commit is contained in:
commit
dba875c849
|
@ -52,9 +52,10 @@ The following binary downloads have been compiled with ESP8266/Arduino library c
|
|||
|
||||
## Changelog
|
||||
|
||||
### Version 8.3.0.1
|
||||
### Version 8.3.0.2
|
||||
|
||||
- Change KNX pow function to approximative pow saving 5k of code space
|
||||
- Change Mutichannel Gas sensor pow function to approximative pow saving 5k of code space
|
||||
- Change Quick Power Cycle detection from 4 to 7 power interrupts (#4066)
|
||||
- Fix default state of ``SetOption73 0`` for button decoupling and send multi-press and hold MQTT messages
|
||||
- Add command ``DeviceName`` defaults to FriendlyName1 and replaces FriendlyName1 in GUI
|
||||
|
|
|
@ -0,0 +1,513 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Python Class for compressing short strings.
|
||||
|
||||
This class contains a highly modified and optimized version of Unishox
|
||||
for Tasmota converted in C ported to Pyhton3.
|
||||
|
||||
It was basically developed to individually compress and decompress small strings
|
||||
(see https://github.com/siara-cc/Unishox)
|
||||
In general compression utilities such as zip, gzip do not compress short strings
|
||||
well and often expand them. They also use lots of memory which makes them unusable
|
||||
in constrained environments like Arduino.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
class Unishox:
|
||||
"""
|
||||
This is a highly modified and optimized version of Unishox
|
||||
for Tasmota, aimed at compressing `Rules` which are typically
|
||||
short strings from 50 to 500 bytes.
|
||||
|
||||
@author Stephan Hadinger
|
||||
@revised Norbert Richter
|
||||
"""
|
||||
|
||||
# pylint: disable=bad-continuation,bad-whitespace,line-too-long
|
||||
cl_95 = [0x4000 + 3, 0x3F80 + 11, 0x3D80 + 11, 0x3C80 + 10, 0x3BE0 + 12, 0x3E80 + 10, 0x3F40 + 11, 0x3EC0 + 10, 0x3BA0 + 11, 0x3BC0 + 11, 0x3D60 + 11, 0x3B60 + 11, 0x3A80 + 10, 0x3AC0 + 10, 0x3A00 + 9, 0x3B00 + 10, 0x38C0 + 10, 0x3900 + 10, 0x3940 + 11, 0x3960 + 11, 0x3980 + 11, 0x39A0 + 11, 0x39C0 + 11, 0x39E0 + 12, 0x39F0 + 12, 0x3880 + 10, 0x3CC0 + 10, 0x3C00 + 9, 0x3D00 + 10, 0x3E00 + 9, 0x3F00 + 10, 0x3B40 + 11, 0x3BF0 + 12, 0x2B00 + 8, 0x21C0 + 11, 0x20C0 + 10, 0x2100 + 10, 0x2600 + 7, 0x2300 + 11, 0x21E0 + 12, 0x2140 + 11, 0x2D00 + 8, 0x2358 + 13, 0x2340 + 12, 0x2080 + 10, 0x21A0 + 11, 0x2E00 + 8, 0x2C00 + 8, 0x2180 + 11, 0x2350 + 13, 0x2F80 + 9, 0x2F00 + 9, 0x2A00 + 8, 0x2160 + 11, 0x2330 + 12, 0x21F0 + 12, 0x2360 + 13, 0x2320 + 12, 0x2368 + 13, 0x3DE0 + 12, 0x3FA0 + 11, 0x3DF0 + 12, 0x3D40 + 11, 0x3F60 + 11, 0x3FF0 + 12, 0xB000 + 4, 0x1C00 + 7, 0x0C00 + 6, 0x1000 + 6, 0x6000 + 3, 0x3000 + 7, 0x1E00 + 8, 0x1400 + 7, 0xD000 + 4, 0x3580 + 9, 0x3400 + 8, 0x0800 + 6, 0x1A00 + 7, 0xE000 + 4, 0xC000 + 4, 0x1800 + 7, 0x3500 + 9, 0xF800 + 5, 0xF000 + 5, 0xA000 + 4, 0x1600 + 7, 0x3300 + 8, 0x1F00 + 8, 0x3600 + 9, 0x3200 + 8, 0x3680 + 9, 0x3DA0 + 11, 0x3FC0 + 11, 0x3DC0 + 11, 0x3FE0 + 12]
|
||||
|
||||
# enum {SHX_STATE_1 = 1, SHX_STATE_2}; // removed Unicode state
|
||||
SHX_STATE_1 = 1
|
||||
SHX_STATE_2 = 2
|
||||
|
||||
SHX_SET1 = 0
|
||||
SHX_SET1A = 1
|
||||
SHX_SET1B = 2
|
||||
SHX_SET2 = 3
|
||||
|
||||
sets = [[0, ' ', 'e', 0, 't', 'a', 'o', 'i', 'n', 's', 'r'],
|
||||
[0, 'l', 'c', 'd', 'h', 'u', 'p', 'm', 'b', 'g', 'w'],
|
||||
['f', 'y', 'v', 'k', 'q', 'j', 'x', 'z', 0, 0, 0],
|
||||
[0, '9', '0', '1', '2', '3', '4', '5', '6', '7', '8'],
|
||||
['.', ',', '-', '/', '?', '+', ' ', '(', ')', '$', '@'],
|
||||
[';', '#', ':', '<', '^', '*', '"', '{', '}', '[', ']'],
|
||||
['=', '%', '\'', '>', '&', '_', '!', '\\', '|', '~', '`']]
|
||||
|
||||
us_vcode = [2 + (0 << 3), 3 + (3 << 3), 3 + (1 << 3), 4 + (6 << 3), 0,
|
||||
# 5, 6, 7, 8, 9, 10
|
||||
4 + (4 << 3), 3 + (2 << 3), 4 + (8 << 3), 0, 0, 0,
|
||||
# 11, 12, 13, 14, 15
|
||||
4 + (7 << 3), 0, 4 + (5 << 3), 0, 5 + (9 << 3),
|
||||
# 16, 17, 18, 19, 20, 21, 22, 23
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
# 24, 25, 26, 27, 28, 29, 30, 31
|
||||
0, 0, 0, 0, 0, 0, 0, 5 + (10 << 3) ]
|
||||
# 0, 1, 2, 3, 4, 5, 6, 7,
|
||||
us_hcode = [1 + (1 << 3), 2 + (0 << 3), 0, 3 + (2 << 3), 0, 0, 0, 5 + (3 << 3),
|
||||
# 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
0, 0, 0, 0, 0, 0, 0, 5 + (5 << 3),
|
||||
# 16, 17, 18, 19, 20, 21, 22, 23
|
||||
0, 0, 0, 0, 0, 0, 0, 5 + (4 << 3),
|
||||
# 24, 25, 26, 27, 28, 29, 30, 31
|
||||
0, 0, 0, 0, 0, 0, 0, 5 + (6 << 3) ]
|
||||
# pylint: enable=bad-continuation,bad-whitespace
|
||||
|
||||
ESCAPE_MARKER = 0x2A
|
||||
|
||||
TERM_CODE = 0x37C0
|
||||
# TERM_CODE_LEN = 10
|
||||
DICT_CODE = 0x0000
|
||||
DICT_CODE_LEN = 5
|
||||
#DICT_OTHER_CODE = 0x0000
|
||||
#DICT_OTHER_CODE_LEN = 6
|
||||
RPT_CODE_TASMOTA = 0x3780
|
||||
RPT_CODE_TASMOTA_LEN = 10
|
||||
BACK2_STATE1_CODE = 0x2000
|
||||
BACK2_STATE1_CODE_LEN = 4
|
||||
#BACK_FROM_UNI_CODE = 0xFE00
|
||||
#BACK_FROM_UNI_CODE_LEN = 8
|
||||
LF_CODE = 0x3700
|
||||
LF_CODE_LEN = 9
|
||||
TAB_CODE = 0x2400
|
||||
TAB_CODE_LEN = 7
|
||||
ALL_UPPER_CODE = 0x2200
|
||||
ALL_UPPER_CODE_LEN = 8
|
||||
SW2_STATE2_CODE = 0x3800
|
||||
SW2_STATE2_CODE_LEN = 7
|
||||
ST2_SPC_CODE = 0x3B80
|
||||
ST2_SPC_CODE_LEN = 11
|
||||
BIN_CODE_TASMOTA = 0x8000
|
||||
BIN_CODE_TASMOTA_LEN = 3
|
||||
|
||||
NICE_LEN = 5
|
||||
|
||||
mask = [0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF]
|
||||
|
||||
# pylint: disable=missing-function-docstring,invalid-name
|
||||
|
||||
# Input
|
||||
# out = bytearray
|
||||
def append_bits(self, out, ol, code, clen, state):
|
||||
#print("Append bits {ol} {code} {clen} {state}".format(ol=ol, code=code, clen=clen, state=state))
|
||||
if state == self.SHX_STATE_2:
|
||||
# remove change state prefix
|
||||
if (code >> 9) == 0x1C:
|
||||
code <<= 7
|
||||
clen -= 7
|
||||
while clen > 0:
|
||||
cur_bit = ol % 8
|
||||
blen = 8 if (clen > 8) else clen
|
||||
a_byte = (code >> 8) & self.mask[blen - 1]
|
||||
#print("append_bits a_byte {ab} blen {blen}".format(ab=a_byte,blen=blen))
|
||||
a_byte >>= cur_bit
|
||||
if blen + cur_bit > 8:
|
||||
blen = (8 - cur_bit)
|
||||
if cur_bit == 0:
|
||||
out[ol // 8] = a_byte
|
||||
else:
|
||||
out[ol // 8] |= a_byte
|
||||
code <<= blen
|
||||
ol += blen
|
||||
if 0 == ol % 8: # pylint: disable=misplaced-comparison-constant
|
||||
# we completed a full byte
|
||||
last_c = out[(ol // 8) - 1]
|
||||
if last_c in (0, self.ESCAPE_MARKER):
|
||||
out[ol // 8] = 1 + last_c # increment to 0x01 or 0x2B
|
||||
out[(ol // 8) -1] = self.ESCAPE_MARKER # replace old value with marker
|
||||
ol += 8 # add one full byte
|
||||
clen -= blen
|
||||
return ol
|
||||
|
||||
codes = [0x82, 0xC3, 0xE5, 0xED, 0xF5] # pylint: disable=bad-whitespace
|
||||
bit_len = [ 5, 7, 9, 12, 16] # pylint: disable=bad-whitespace
|
||||
|
||||
def encodeCount(self, out, ol, count):
|
||||
#print("encodeCount ol = {ol}, count = {count}".format(ol=ol, count=count))
|
||||
till = 0
|
||||
base = 0
|
||||
for i in range(len(self.bit_len)):
|
||||
bit_len_i = self.bit_len[i]
|
||||
till += (1 << bit_len_i)
|
||||
if count < till:
|
||||
codes_i = self.codes[i]
|
||||
ol = self.append_bits(out, ol, (codes_i & 0xF8) << 8, codes_i & 0x07, 1)
|
||||
#print("encodeCount append_bits ol = {ol}, code = {code}, len = {len}".format(ol=ol,code=(codes_i & 0xF8) << 8,len=codes_i & 0x07))
|
||||
ol = self.append_bits(out, ol, (count - base) << (16 - bit_len_i), bit_len_i, 1)
|
||||
#print("encodeCount append_bits ol = {ol}, code = {code}, len = {len}".format(ol=ol,code=(count - base) << (16 - bit_len_i),len=bit_len_i))
|
||||
return ol
|
||||
base = till
|
||||
return ol
|
||||
|
||||
# Returns (int, ol, state, is_all_upper)
|
||||
def matchOccurance(self, inn, len_, l_, out, ol, state, is_all_upper):
|
||||
# int j, k;
|
||||
longest_dist = 0
|
||||
longest_len = 0
|
||||
#for (j = l_ - self.NICE_LEN; j >= 0; j--) {
|
||||
j = l_ - self.NICE_LEN
|
||||
while j >= 0:
|
||||
k = l_
|
||||
#for (k = l_; k < len && j + k - l_ < l_; k++) {
|
||||
while k < len_ and j + k - l_ < l_:
|
||||
if inn[k] != inn[j + k - l_]:
|
||||
break
|
||||
k += 1
|
||||
if k - l_ > self.NICE_LEN - 1:
|
||||
match_len = k - l_ - self.NICE_LEN
|
||||
match_dist = l_ - j - self.NICE_LEN + 1
|
||||
if match_len > longest_len:
|
||||
longest_len = match_len
|
||||
longest_dist = match_dist
|
||||
j -= 1
|
||||
|
||||
if longest_len:
|
||||
#print("longest_len {ll}".format(ll=longest_len))
|
||||
#ol_save = ol
|
||||
if state == self.SHX_STATE_2 or is_all_upper:
|
||||
is_all_upper = 0
|
||||
state = self.SHX_STATE_1
|
||||
ol = self.append_bits(out, ol, self.BACK2_STATE1_CODE, self.BACK2_STATE1_CODE_LEN, state)
|
||||
|
||||
ol = self.append_bits(out, ol, self.DICT_CODE, self.DICT_CODE_LEN, 1)
|
||||
ol = self.encodeCount(out, ol, longest_len)
|
||||
ol = self.encodeCount(out, ol, longest_dist)
|
||||
#print("longest_len {ll} longest_dist {ld} ol {ols}-{ol}".format(ll=longest_len, ld=longest_dist, ol=ol, ols=ol_save))
|
||||
l_ += longest_len + self.NICE_LEN
|
||||
l_ -= 1
|
||||
|
||||
return l_, ol, state, is_all_upper
|
||||
return -l_, ol, state, is_all_upper
|
||||
|
||||
|
||||
def compress(self, inn, len_, out, len_out):
|
||||
ol = 0
|
||||
state = self.SHX_STATE_1
|
||||
is_all_upper = 0
|
||||
l = 0
|
||||
while l < len_:
|
||||
# for (l=0; l<len_; l++) {
|
||||
|
||||
c_in = inn[l]
|
||||
|
||||
if l and l < len_ - 4:
|
||||
if c_in == inn[l - 1] and c_in == inn[l + 1] and c_in == inn[l + 2] and c_in == inn[l + 3]:
|
||||
rpt_count = l + 4
|
||||
while rpt_count < len_ and inn[rpt_count] == c_in:
|
||||
rpt_count += 1
|
||||
rpt_count -= l
|
||||
|
||||
if state == self.SHX_STATE_2 or is_all_upper:
|
||||
is_all_upper = 0
|
||||
state = self.SHX_STATE_1
|
||||
ol = self.append_bits(out, ol, self.BACK2_STATE1_CODE, self.BACK2_STATE1_CODE_LEN, state) # back to lower case and Set1
|
||||
|
||||
ol = self.append_bits(out, ol, self.RPT_CODE_TASMOTA, self.RPT_CODE_TASMOTA_LEN, 1) # reusing CRLF for RPT
|
||||
ol = self.encodeCount(out, ol, rpt_count - 4)
|
||||
l += rpt_count
|
||||
#l -= 1
|
||||
continue
|
||||
|
||||
if l < (len_ - self.NICE_LEN + 1):
|
||||
#l_old = l
|
||||
(l, ol, state, is_all_upper) = self.matchOccurance(inn, len_, l, out, ol, state, is_all_upper)
|
||||
if l > 0:
|
||||
#print("matchOccurance l = {l} l_old = {lo}".format(l=l,lo=l_old))
|
||||
l += 1 # for loop
|
||||
continue
|
||||
|
||||
l = -l
|
||||
|
||||
if state == self.SHX_STATE_2: # if Set2
|
||||
if ord(' ') <= c_in <= ord('@') or ord('[') <= c_in <= ord('`') or ord('{') <= c_in <= ord('~'):
|
||||
pass
|
||||
else:
|
||||
state = self.SHX_STATE_1 # back to Set1 and lower case
|
||||
ol = self.append_bits(out, ol, self.BACK2_STATE1_CODE, self.BACK2_STATE1_CODE_LEN, state)
|
||||
|
||||
is_upper = 0
|
||||
if ord('A') <= c_in <= ord('Z'):
|
||||
is_upper = 1
|
||||
else:
|
||||
if is_all_upper:
|
||||
is_all_upper = 0
|
||||
ol = self.append_bits(out, ol, self.BACK2_STATE1_CODE, self.BACK2_STATE1_CODE_LEN, state)
|
||||
|
||||
if 32 <= c_in <= 126:
|
||||
if is_upper and not is_all_upper:
|
||||
ll = l+5
|
||||
# for (ll=l+5; ll>=l && ll<len_; ll--) {
|
||||
while l <= ll < len_:
|
||||
if inn[ll] < ord('A') or inn[ll] > ord('Z'):
|
||||
break
|
||||
|
||||
ll -= 1
|
||||
|
||||
if ll == l-1:
|
||||
ol = self.append_bits(out, ol, self.ALL_UPPER_CODE, self.ALL_UPPER_CODE_LEN, state) # CapsLock
|
||||
is_all_upper = 1
|
||||
|
||||
if state == self.SHX_STATE_1 and ord('0') <= c_in <= ord('9'):
|
||||
ol = self.append_bits(out, ol, self.SW2_STATE2_CODE, self.SW2_STATE2_CODE_LEN, state) # Switch to sticky Set2
|
||||
state = self.SHX_STATE_2
|
||||
|
||||
c_in -= 32
|
||||
if is_all_upper and is_upper:
|
||||
c_in += 32
|
||||
if c_in == 0 and state == self.SHX_STATE_2:
|
||||
ol = self.append_bits(out, ol, self.ST2_SPC_CODE, self.ST2_SPC_CODE_LEN, state) # space from Set2 ionstead of Set1
|
||||
else:
|
||||
# ol = self.append_bits(out, ol, pgm_read_word(&c_95[c_in]), pgm_read_byte(&l_95[c_in]), state); // original version with c/l in split arrays
|
||||
cl = self.cl_95[c_in]
|
||||
ol = self.append_bits(out, ol, cl & 0xFFF0, cl & 0x000F, state)
|
||||
|
||||
elif c_in == 10:
|
||||
ol = self.append_bits(out, ol, self.LF_CODE, self.LF_CODE_LEN, state) # LF
|
||||
elif c_in == '\t':
|
||||
ol = self.append_bits(out, ol, self.TAB_CODE, self.TAB_CODE_LEN, state) # TAB
|
||||
else:
|
||||
ol = self.append_bits(out, ol, self.BIN_CODE_TASMOTA, self.BIN_CODE_TASMOTA_LEN, state) # Binary, we reuse the Unicode marker which 3 bits instead of 9
|
||||
ol = self.encodeCount(out, ol, (255 - c_in) & 0xFF)
|
||||
|
||||
|
||||
# check that we have some headroom in the output buffer
|
||||
if ol // 8 >= len_out - 4:
|
||||
return -1 # we risk overflow and crash
|
||||
|
||||
l += 1
|
||||
|
||||
bits = ol % 8
|
||||
if bits:
|
||||
ol = self.append_bits(out, ol, self.TERM_CODE, 8 - bits, 1) # 0011 0111 1100 0000 TERM = 0011 0111 11
|
||||
return (ol + 7) // 8
|
||||
# return ol // 8 + 1 if (ol%8) else 0
|
||||
|
||||
|
||||
def getBitVal(self, inn, bit_no, count):
|
||||
c_in = inn[bit_no >> 3]
|
||||
if bit_no >> 3 and self.ESCAPE_MARKER == inn[(bit_no >> 3) - 1]:
|
||||
c_in -= 1
|
||||
r = 1 << count if (c_in & (0x80 >> (bit_no % 8))) else 0
|
||||
#print("getBitVal r={r}".format(r=r))
|
||||
return r
|
||||
|
||||
# Returns:
|
||||
# 0..11
|
||||
# or -1 if end of stream
|
||||
def getCodeIdx(self, code_type, inn, len_, bit_no_p):
|
||||
code = 0
|
||||
count = 0
|
||||
while count < 5:
|
||||
# detect marker
|
||||
if self.ESCAPE_MARKER == inn[bit_no_p >> 3]:
|
||||
bit_no_p += 8 # skip marker
|
||||
|
||||
if bit_no_p >= len_:
|
||||
return -1, bit_no_p
|
||||
|
||||
code += self.getBitVal(inn, bit_no_p, count)
|
||||
bit_no_p += 1
|
||||
count += 1
|
||||
code_type_code = code_type[code]
|
||||
if code_type_code and (code_type_code & 0x07) == count:
|
||||
#print("getCodeIdx = {r}".format(r=code_type_code >> 3))
|
||||
return code_type_code >> 3, bit_no_p
|
||||
|
||||
#print("getCodeIdx not found = {r}".format(r=1))
|
||||
return 1, bit_no_p
|
||||
|
||||
def getNumFromBits(self, inn, bit_no, count):
|
||||
ret = 0
|
||||
while count:
|
||||
count -= 1
|
||||
if self.ESCAPE_MARKER == inn[bit_no >> 3]:
|
||||
bit_no += 8 # skip marker
|
||||
ret += self.getBitVal(inn, bit_no, count)
|
||||
bit_no += 1
|
||||
return ret
|
||||
|
||||
def readCount(self, inn, bit_no_p, len_):
|
||||
(idx, bit_no_p) = self.getCodeIdx(self.us_hcode, inn, len_, bit_no_p)
|
||||
if idx >= 1:
|
||||
idx -= 1 # we skip v = 1 (code '0') since we no more accept 2 bits encoding
|
||||
if idx >= 5 or idx < 0:
|
||||
return 0, bit_no_p # unsupported or end of stream
|
||||
till = 0
|
||||
bit_len_idx = 0
|
||||
base = 0
|
||||
#for (uint32_t i = 0; i <= idx; i++) {
|
||||
i = 0
|
||||
while i <= idx:
|
||||
# for i in range(idx):
|
||||
base = till
|
||||
bit_len_idx = self.bit_len[i]
|
||||
till += (1 << bit_len_idx)
|
||||
i += 1
|
||||
|
||||
count = self.getNumFromBits(inn, bit_no_p, bit_len_idx) + base
|
||||
#print("readCount getNumFromBits = {count} ({bl})".format(count=count,bl=bit_len_idx))
|
||||
|
||||
bit_no_p += bit_len_idx
|
||||
return count, bit_no_p
|
||||
|
||||
def decodeRepeat(self, inn, len_, out, ol, bit_no):
|
||||
#print("decodeRepeat Enter")
|
||||
(dict_len, bit_no) = self.readCount(inn, bit_no, len_)
|
||||
dict_len += self.NICE_LEN
|
||||
(dist, bit_no) = self.readCount(inn, bit_no, len_)
|
||||
dist += self.NICE_LEN - 1
|
||||
#memcpy(out + ol, out + ol - dist, dict_len);
|
||||
i = 0
|
||||
while i < dict_len:
|
||||
#for i in range(dict_len):
|
||||
out[ol + i] = out[ol - dist + i]
|
||||
i += 1
|
||||
ol += dict_len
|
||||
|
||||
return ol, bit_no
|
||||
|
||||
def decompress(self, inn, len_, out, len_out):
|
||||
ol = 0
|
||||
bit_no = 0
|
||||
dstate = self.SHX_SET1
|
||||
is_all_upper = 0
|
||||
|
||||
len_ <<= 3 # *8, len_ in bits
|
||||
out[ol] = 0
|
||||
while bit_no < len_:
|
||||
c = 0
|
||||
is_upper = is_all_upper
|
||||
(v, bit_no) = self.getCodeIdx(self.us_vcode, inn, len_, bit_no) # read vCode
|
||||
#print("bit_no {b}. v = {v}".format(b=bit_no,v=v))
|
||||
if v < 0:
|
||||
break # end of stream
|
||||
h = dstate # Set1 or Set2
|
||||
if v == 0: # Switch which is common to Set1 and Set2, first entry
|
||||
(h, bit_no) = self.getCodeIdx(self.us_hcode, inn, len_, bit_no) # read hCode
|
||||
#print("bit_no {b}. h = {h}".format(b=bit_no,h=h))
|
||||
if h < 0:
|
||||
break # end of stream
|
||||
if h == self.SHX_SET1: # target is Set1
|
||||
if dstate == self.SHX_SET1: # Switch from Set1 to Set1 us UpperCase
|
||||
if is_all_upper: # if CapsLock, then back to LowerCase
|
||||
is_upper = 0
|
||||
is_all_upper = 0
|
||||
continue
|
||||
|
||||
(v, bit_no) = self.getCodeIdx(self.us_vcode, inn, len_, bit_no) # read again vCode
|
||||
if v < 0:
|
||||
break # end of stream
|
||||
if v == 0:
|
||||
(h, bit_no) = self.getCodeIdx(self.us_hcode, inn, len_, bit_no) # read second hCode
|
||||
if h < 0:
|
||||
break # end of stream
|
||||
if h == self.SHX_SET1: # If double Switch Set1, the CapsLock
|
||||
is_all_upper = 1
|
||||
continue
|
||||
|
||||
is_upper = 1 # anyways, still uppercase
|
||||
else:
|
||||
dstate = self.SHX_SET1 # if Set was not Set1, switch to Set1
|
||||
continue
|
||||
|
||||
elif h == self.SHX_SET2: # If Set2, switch dstate to Set2
|
||||
if dstate == self.SHX_SET1:
|
||||
dstate = self.SHX_SET2
|
||||
continue
|
||||
|
||||
if h != self.SHX_SET1: # all other Sets (why not else)
|
||||
(v, bit_no) = self.getCodeIdx(self.us_vcode, inn, len_, bit_no) # we changed set, now read vCode for char
|
||||
if v < 0:
|
||||
break # end of stream
|
||||
|
||||
if v == 0 and h == self.SHX_SET1A:
|
||||
#print("v = 0, h = self.SHX_SET1A")
|
||||
if is_upper:
|
||||
(temp, bit_no) = self.readCount(inn, bit_no, len_)
|
||||
out[ol] = 255 - temp # binary
|
||||
ol += 1
|
||||
else:
|
||||
(ol, bit_no) = self.decodeRepeat(inn, len_, out, ol, bit_no) # dist
|
||||
continue
|
||||
|
||||
if h == self.SHX_SET1 and v == 3:
|
||||
# was Unicode, will do Binary instead
|
||||
(temp, bit_no) = self.readCount(inn, bit_no, len_)
|
||||
out[ol] = 255 - temp # binary
|
||||
ol += 1
|
||||
continue
|
||||
|
||||
if h < 7 and v < 11:
|
||||
#print("h {h} v {v}".format(h=h,v=v))
|
||||
c = ord(self.sets[h][v])
|
||||
if ord('a') <= c <= ord('z'):
|
||||
if is_upper:
|
||||
c -= 32 # go to UpperCase for letters
|
||||
else: # handle all other cases
|
||||
if is_upper and dstate == self.SHX_SET1 and v == 1:
|
||||
c = ord('\t') # If UpperCase Space, change to TAB
|
||||
if h == self.SHX_SET1B:
|
||||
if 8 == v: # was LF or RPT, now only LF # pylint: disable=misplaced-comparison-constant
|
||||
out[ol] = ord('\n')
|
||||
ol += 1
|
||||
continue
|
||||
|
||||
if 9 == v: # was CRLF, now RPT # pylint: disable=misplaced-comparison-constant
|
||||
(count, bit_no) = self.readCount(inn, bit_no, len_)
|
||||
count += 4
|
||||
if ol + count >= len_out:
|
||||
return -1 # overflow
|
||||
|
||||
rpt_c = out[ol - 1]
|
||||
while count:
|
||||
count -= 1
|
||||
out[ol] = rpt_c
|
||||
ol += 1
|
||||
continue
|
||||
|
||||
if 10 == v: # pylint: disable=misplaced-comparison-constant
|
||||
break # TERM, stop decoding
|
||||
|
||||
out[ol] = c
|
||||
ol += 1
|
||||
|
||||
if ol >= len_out:
|
||||
return -1 # overflow
|
||||
|
||||
return ol
|
||||
|
||||
# pylint: enable=missing-function-docstring
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# pylint: disable=line-too-long
|
||||
UNISHOX = Unishox()
|
||||
BYTES_ = bytearray(2048)
|
||||
INN = bytearray(b'ON Switch1#State==1 DO Add1 1 ENDON ON Var1#State==0 DO ShutterStop1 ENDON ON Var1#State==1 DO ShutterClose1 ENDON ON Var1#State>=2 DO Var1 0 ENDON ON Shutter1#Close DO Var1 0 ENDON ON Switch2#State==1 DO Add2 1 ENDON ON Var2#State==0 DO ShutterStop1 ENDON ON Var2#State==1 DO ShutterOpen1 ENDON ON Var2#State>=2 DO Var2 0 ENDON ON Shutter1#Open DO Var2 0 ENDON')
|
||||
LEN_ = UNISHOX.compress(INN, len(INN), BYTES_, len(BYTES_))
|
||||
print("Compressed from {fromm} to {to} ({p}%)".format(fromm=len(INN), to=LEN_, p=(100-LEN_/len(INN)*100)))
|
||||
|
||||
OUT = bytearray(2048)
|
||||
LEN_ = UNISHOX.decompress(BYTES_, LEN_, OUT, len(OUT))
|
||||
print(str(OUT, 'utf-8').split('\x00')[0])
|
|
@ -153,52 +153,47 @@ const uint16_t BIN_CODE_TASMOTA_LEN = 3;
|
|||
// uint16_t mask[] PROGMEM = {0x8000, 0xC000, 0xE000, 0xF000, 0xF800, 0xFC00, 0xFE00, 0xFF00};
|
||||
uint8_t mask[] PROGMEM = {0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF};
|
||||
|
||||
int append_bits(char *out, size_t ol, unsigned int code, int clen, byte state) {
|
||||
|
||||
byte cur_bit;
|
||||
byte blen;
|
||||
unsigned char a_byte;
|
||||
|
||||
if (state == SHX_STATE_2) {
|
||||
// remove change state prefix
|
||||
if ((code >> 9) == 0x1C) {
|
||||
code <<= 7;
|
||||
clen -= 7;
|
||||
void Unishox::append_bits(unsigned int code, int clen) {
|
||||
|
||||
byte cur_bit;
|
||||
byte blen;
|
||||
unsigned char a_byte;
|
||||
|
||||
if (state == SHX_STATE_2) {
|
||||
// remove change state prefix
|
||||
if ((code >> 9) == 0x1C) {
|
||||
code <<= 7;
|
||||
clen -= 7;
|
||||
}
|
||||
}
|
||||
while (clen > 0) {
|
||||
cur_bit = ol % 8;
|
||||
blen = (clen > 8 ? 8 : clen);
|
||||
a_byte = (code >> 8) & pgm_read_word(&mask[blen - 1]);
|
||||
a_byte >>= cur_bit;
|
||||
if (blen + cur_bit > 8)
|
||||
blen = (8 - cur_bit);
|
||||
if (out) { // if out == nullptr, then we are in dry-run mode
|
||||
if (cur_bit == 0)
|
||||
out[ol >> 3] = a_byte;
|
||||
else
|
||||
out[ol >> 3] |= a_byte;
|
||||
}
|
||||
code <<= blen;
|
||||
ol += blen;
|
||||
if ((out) && (0 == ol % 8)) { // if out == nullptr, dry-run mode. We miss the escaping of characters in the length
|
||||
// we completed a full byte
|
||||
char last_c = out[(ol / 8) - 1];
|
||||
if ((0 == last_c) || (ESCAPE_MARKER == last_c)) {
|
||||
out[ol >> 3] = 1 + last_c; // increment to 0x01 or 0x2B
|
||||
out[(ol >>3) -1] = ESCAPE_MARKER; // replace old value with marker
|
||||
ol += 8; // add one full byte
|
||||
}
|
||||
//if (code == 14272 && clen == 10) {
|
||||
// code = 9084;
|
||||
// clen = 14;
|
||||
//}
|
||||
}
|
||||
while (clen > 0) {
|
||||
cur_bit = ol % 8;
|
||||
blen = (clen > 8 ? 8 : clen);
|
||||
// a_byte = (code & pgm_read_word(&mask[blen - 1])) >> 8;
|
||||
// a_byte = (code & (pgm_read_word(&mask[blen - 1]) << 8)) >> 8;
|
||||
a_byte = (code >> 8) & pgm_read_word(&mask[blen - 1]);
|
||||
a_byte >>= cur_bit;
|
||||
if (blen + cur_bit > 8)
|
||||
blen = (8 - cur_bit);
|
||||
if (out) { // if out == nullptr, then we are in dry-run mode
|
||||
if (cur_bit == 0)
|
||||
out[ol / 8] = a_byte;
|
||||
else
|
||||
out[ol / 8] |= a_byte;
|
||||
}
|
||||
code <<= blen;
|
||||
ol += blen;
|
||||
if ((out) && (0 == ol % 8)) { // if out == nullptr, dry-run mode. We miss the escaping of characters in the length
|
||||
// we completed a full byte
|
||||
char last_c = out[(ol / 8) - 1];
|
||||
if ((0 == last_c) || (ESCAPE_MARKER == last_c)) {
|
||||
out[ol / 8] = 1 + last_c; // increment to 0x01 or 0x2B
|
||||
out[(ol / 8) -1] = ESCAPE_MARKER; // replace old value with marker
|
||||
ol += 8; // add one full byte
|
||||
}
|
||||
}
|
||||
clen -= blen;
|
||||
}
|
||||
return ol;
|
||||
}
|
||||
clen -= blen;
|
||||
}
|
||||
}
|
||||
|
||||
// First five bits are code and Last three bits of codes represent length
|
||||
|
@ -210,40 +205,36 @@ byte codes[] PROGMEM = { 0x82, 0xC3, 0xE5, 0xED, 0xF5 };
|
|||
byte bit_len[] PROGMEM = { 5, 7, 9, 12, 16 };
|
||||
// uint16_t adder[7] PROGMEM = { 0, 32, 160, 672, 4768 }; // no more used
|
||||
|
||||
int encodeCount(char *out, int ol, int count) {
|
||||
void Unishox::encodeCount(int32_t count) {
|
||||
int till = 0;
|
||||
int base = 0;
|
||||
for (int i = 0; i < sizeof(bit_len); i++) {
|
||||
for (uint32_t i = 0; i < sizeof(bit_len); i++) {
|
||||
uint32_t bit_len_i = pgm_read_byte(&bit_len[i]);
|
||||
till += (1 << bit_len_i);
|
||||
if (count < till) {
|
||||
byte codes_i = pgm_read_byte(&codes[i]);
|
||||
ol = append_bits(out, ol, (codes_i & 0xF8) << 8, codes_i & 0x07, 1);
|
||||
append_bits((codes_i & 0xF8) << 8, codes_i & 0x07);
|
||||
// ol = append_bits(out, ol, (count - pgm_read_word(&adder[i])) << (16 - bit_len_i), bit_len_i, 1);
|
||||
ol = append_bits(out, ol, (count - base) << (16 - bit_len_i), bit_len_i, 1);
|
||||
return ol;
|
||||
append_bits((count - base) << (16 - bit_len_i), bit_len_i);
|
||||
return;
|
||||
}
|
||||
base = till;
|
||||
}
|
||||
return ol;
|
||||
return;
|
||||
}
|
||||
|
||||
int matchOccurance(const char *in, int len, int l, char *out, int *ol, byte *state, byte *is_all_upper) {
|
||||
int j, k;
|
||||
int longest_dist = 0;
|
||||
int longest_len = 0;
|
||||
bool Unishox::matchOccurance(void) {
|
||||
int32_t j, k;
|
||||
uint32_t longest_dist = 0;
|
||||
uint32_t longest_len = 0;
|
||||
for (j = l - NICE_LEN; j >= 0; j--) {
|
||||
for (k = l; k < len && j + k - l < l; k++) {
|
||||
if (in[k] != in[j + k - l])
|
||||
break;
|
||||
}
|
||||
// while ((((unsigned char) in[k]) >> 6) == 2)
|
||||
// k--; // Skip partial UTF-8 matches
|
||||
//if ((in[k - 1] >> 3) == 0x1E || (in[k - 1] >> 4) == 0x0E || (in[k - 1] >> 5) == 0x06)
|
||||
// k--;
|
||||
if (k - l > NICE_LEN - 1) {
|
||||
int match_len = k - l - NICE_LEN;
|
||||
int match_dist = l - j - NICE_LEN + 1;
|
||||
uint32_t match_len = k - l - NICE_LEN;
|
||||
uint32_t match_dist = l - j - NICE_LEN + 1;
|
||||
if (match_len > longest_len) {
|
||||
longest_len = match_len;
|
||||
longest_dist = match_dist;
|
||||
|
@ -251,19 +242,18 @@ int matchOccurance(const char *in, int len, int l, char *out, int *ol, byte *sta
|
|||
}
|
||||
}
|
||||
if (longest_len) {
|
||||
if (*state == SHX_STATE_2 || *is_all_upper) {
|
||||
*is_all_upper = 0;
|
||||
*state = SHX_STATE_1;
|
||||
*ol = append_bits(out, *ol, BACK2_STATE1_CODE, BACK2_STATE1_CODE_LEN, *state);
|
||||
if (state == SHX_STATE_2 || is_all_upper) {
|
||||
is_all_upper = 0;
|
||||
state = SHX_STATE_1;
|
||||
append_bits(BACK2_STATE1_CODE, BACK2_STATE1_CODE_LEN);
|
||||
}
|
||||
*ol = append_bits(out, *ol, DICT_CODE, DICT_CODE_LEN, 1);
|
||||
*ol = encodeCount(out, *ol, longest_len);
|
||||
*ol = encodeCount(out, *ol, longest_dist);
|
||||
l += (longest_len + NICE_LEN);
|
||||
l--;
|
||||
return l;
|
||||
append_bits(DICT_CODE, DICT_CODE_LEN);
|
||||
encodeCount(longest_len);
|
||||
encodeCount(longest_dist);
|
||||
l += longest_len + NICE_LEN - 1;
|
||||
return true;
|
||||
}
|
||||
return -l;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compress a buffer.
|
||||
|
@ -275,15 +265,18 @@ int matchOccurance(const char *in, int len, int l, char *out, int *ol, byte *sta
|
|||
// Output:
|
||||
// - if >= 0: size of the compressed buffer. The output buffer does not contain NULL bytes, and it is not NULL terminated
|
||||
// - if < 0: an error occured, most certainly the output buffer was not large enough
|
||||
int32_t unishox_compress(const char *in, size_t len, char *out, size_t len_out) {
|
||||
int32_t Unishox::unishox_compress(const char *p_in, size_t p_len, char *p_out, size_t p_len_out) {
|
||||
in = p_in;
|
||||
len = p_len;
|
||||
out = p_out;
|
||||
len_out = p_len_out;
|
||||
|
||||
char *ptr;
|
||||
byte bits;
|
||||
byte state;
|
||||
|
||||
int l, ll, ol;
|
||||
int ll;
|
||||
char c_in, c_next;
|
||||
byte is_upper, is_all_upper;
|
||||
byte is_upper;
|
||||
|
||||
ol = 0;
|
||||
state = SHX_STATE_1;
|
||||
|
@ -302,23 +295,20 @@ int32_t unishox_compress(const char *in, size_t len, char *out, size_t len_out)
|
|||
if (state == SHX_STATE_2 || is_all_upper) {
|
||||
is_all_upper = 0;
|
||||
state = SHX_STATE_1;
|
||||
ol = append_bits(out, ol, BACK2_STATE1_CODE, BACK2_STATE1_CODE_LEN, state); // back to lower case and Set1
|
||||
append_bits(BACK2_STATE1_CODE, BACK2_STATE1_CODE_LEN); // back to lower case and Set1
|
||||
}
|
||||
// ol = append_bits(out, ol, RPT_CODE, RPT_CODE_LEN, 1);
|
||||
ol = append_bits(out, ol, RPT_CODE_TASMOTA, RPT_CODE_TASMOTA_LEN, 1); // reusing CRLF for RPT
|
||||
ol = encodeCount(out, ol, rpt_count - 4);
|
||||
l += rpt_count;
|
||||
l--;
|
||||
append_bits(RPT_CODE_TASMOTA, RPT_CODE_TASMOTA_LEN); // reusing CRLF for RPT
|
||||
encodeCount(rpt_count - 4);
|
||||
l += rpt_count - 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (l < (len - NICE_LEN + 1)) {
|
||||
l = matchOccurance(in, len, l, out, &ol, &state, &is_all_upper);
|
||||
if (l > 0) {
|
||||
continue;
|
||||
}
|
||||
l = -l;
|
||||
if (matchOccurance()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (state == SHX_STATE_2) { // if Set2
|
||||
if ((c_in >= ' ' && c_in <= '@') ||
|
||||
|
@ -326,7 +316,7 @@ int32_t unishox_compress(const char *in, size_t len, char *out, size_t len_out)
|
|||
(c_in >= '{' && c_in <= '~')) {
|
||||
} else {
|
||||
state = SHX_STATE_1; // back to Set1 and lower case
|
||||
ol = append_bits(out, ol, BACK2_STATE1_CODE, BACK2_STATE1_CODE_LEN, state);
|
||||
append_bits(BACK2_STATE1_CODE, BACK2_STATE1_CODE_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -336,7 +326,7 @@ int32_t unishox_compress(const char *in, size_t len, char *out, size_t len_out)
|
|||
else {
|
||||
if (is_all_upper) {
|
||||
is_all_upper = 0;
|
||||
ol = append_bits(out, ol, BACK2_STATE1_CODE, BACK2_STATE1_CODE_LEN, state);
|
||||
append_bits(BACK2_STATE1_CODE, BACK2_STATE1_CODE_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -351,37 +341,30 @@ int32_t unishox_compress(const char *in, size_t len, char *out, size_t len_out)
|
|||
break;
|
||||
}
|
||||
if (ll == l-1) {
|
||||
ol = append_bits(out, ol, ALL_UPPER_CODE, ALL_UPPER_CODE_LEN, state); // CapsLock
|
||||
append_bits(ALL_UPPER_CODE, ALL_UPPER_CODE_LEN); // CapsLock
|
||||
is_all_upper = 1;
|
||||
}
|
||||
}
|
||||
if (state == SHX_STATE_1 && c_in >= '0' && c_in <= '9') {
|
||||
ol = append_bits(out, ol, SW2_STATE2_CODE, SW2_STATE2_CODE_LEN, state); // Switch to sticky Set2
|
||||
append_bits(SW2_STATE2_CODE, SW2_STATE2_CODE_LEN); // Switch to sticky Set2
|
||||
state = SHX_STATE_2;
|
||||
}
|
||||
c_in -= 32;
|
||||
if (is_all_upper && is_upper)
|
||||
c_in += 32;
|
||||
if (c_in == 0 && state == SHX_STATE_2)
|
||||
ol = append_bits(out, ol, ST2_SPC_CODE, ST2_SPC_CODE_LEN, state); // space from Set2 ionstead of Set1
|
||||
append_bits(ST2_SPC_CODE, ST2_SPC_CODE_LEN); // space from Set2 ionstead of Set1
|
||||
else {
|
||||
// ol = append_bits(out, ol, pgm_read_word(&c_95[c_in]), pgm_read_byte(&l_95[c_in]), state); // original version with c/l in split arrays
|
||||
uint16_t cl = pgm_read_word(&cl_95[c_in]);
|
||||
ol = append_bits(out, ol, cl & 0xFFF0, cl & 0x000F, state);
|
||||
append_bits(cl & 0xFFF0, cl & 0x000F);
|
||||
}
|
||||
} else
|
||||
// if (c_in == 13 && c_next == 10) { // CRLF disabled
|
||||
// ol = append_bits(out, ol, CRLF_CODE, CRLF_CODE_LEN, state); // CRLF
|
||||
// l++;
|
||||
// } else
|
||||
if (c_in == 10) {
|
||||
ol = append_bits(out, ol, LF_CODE, LF_CODE_LEN, state); // LF
|
||||
} else
|
||||
if (c_in == '\t') {
|
||||
ol = append_bits(out, ol, TAB_CODE, TAB_CODE_LEN, state); // TAB
|
||||
} else if (c_in == 10) {
|
||||
append_bits(LF_CODE, LF_CODE_LEN); // LF
|
||||
} else if (c_in == '\t') {
|
||||
append_bits(TAB_CODE, TAB_CODE_LEN); // TAB
|
||||
} else {
|
||||
ol = append_bits(out, ol, BIN_CODE_TASMOTA, BIN_CODE_TASMOTA_LEN, state); // Binary, we reuse the Unicode marker which 3 bits instead of 9
|
||||
ol = encodeCount(out, ol, (unsigned char) 255 - c_in);
|
||||
append_bits(BIN_CODE_TASMOTA, BIN_CODE_TASMOTA_LEN); // Binary, we reuse the Unicode marker which 3 bits instead of 9
|
||||
encodeCount((unsigned char) 255 - c_in);
|
||||
}
|
||||
|
||||
// check that we have some headroom in the output buffer
|
||||
|
@ -392,50 +375,46 @@ int32_t unishox_compress(const char *in, size_t len, char *out, size_t len_out)
|
|||
|
||||
bits = ol % 8;
|
||||
if (bits) {
|
||||
ol = append_bits(out, ol, TERM_CODE, 8 - bits, 1); // 0011 0111 1100 0000 TERM = 0011 0111 11
|
||||
state = SHX_STATE_1;
|
||||
append_bits(TERM_CODE, 8 - bits); // 0011 0111 1100 0000 TERM = 0011 0111 11
|
||||
}
|
||||
return ol/8+(ol%8?1:0);
|
||||
}
|
||||
|
||||
int getBitVal(const char *in, int bit_no, int count) {
|
||||
char c_in = in[bit_no >> 3];
|
||||
if ((bit_no >> 3) && (ESCAPE_MARKER == in[(bit_no >> 3) - 1])) { // if previous byte is a marker, decrement
|
||||
c_in--;
|
||||
uint32_t Unishox::getNextBit(void) {
|
||||
if (8 == bit_no) {
|
||||
byte_in = in[byte_no++];
|
||||
if (ESCAPE_MARKER == byte_in) {
|
||||
byte_in = in[byte_no++] - 1;
|
||||
}
|
||||
bit_no = 0;
|
||||
}
|
||||
return (c_in & (0x80 >> (bit_no % 8)) ? 1 << count : 0);
|
||||
return byte_in & (0x80 >> bit_no++) ? 1 : 0;
|
||||
}
|
||||
|
||||
// Returns:
|
||||
// 0..11
|
||||
// or -1 if end of stream
|
||||
int getCodeIdx(char *code_type, const char *in, int len, int *bit_no_p) {
|
||||
int code = 0;
|
||||
int count = 0;
|
||||
int32_t Unishox::getCodeIdx(const char *code_type) {
|
||||
int32_t code = 0;
|
||||
int32_t count = 0;
|
||||
do {
|
||||
// detect marker
|
||||
if (ESCAPE_MARKER == in[*bit_no_p >> 3]) {
|
||||
*bit_no_p += 8; // skip marker
|
||||
}
|
||||
if (*bit_no_p >= len)
|
||||
if (bit_no >= len)
|
||||
return -1; // invalid state
|
||||
code += getBitVal(in, *bit_no_p, count);
|
||||
(*bit_no_p)++;
|
||||
code += getNextBit() << count;
|
||||
count++;
|
||||
uint8_t code_type_code = pgm_read_byte(&code_type[code]);
|
||||
if (code_type_code && (code_type_code & 0x07) == count) {
|
||||
return code_type_code >> 3;
|
||||
}
|
||||
} while (count < 5);
|
||||
return 1; // skip if code not found
|
||||
return -1; // skip if code not found
|
||||
}
|
||||
|
||||
int getNumFromBits(const char *in, int bit_no, int count) {
|
||||
int32_t Unishox::getNumFromBits(uint32_t count) {
|
||||
int ret = 0;
|
||||
while (count--) {
|
||||
if (ESCAPE_MARKER == in[bit_no >> 3]) {
|
||||
bit_no += 8; // skip marker
|
||||
}
|
||||
ret += getBitVal(in, bit_no++, count);
|
||||
ret += getNextBit() << count;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -452,8 +431,8 @@ int getNumFromBits(const char *in, int bit_no, int count) {
|
|||
// uint16_t adder_read[] PROGMEM = {0, 32, 160, 672, 4768 };
|
||||
|
||||
// Code size optimized, recalculate adder[] like in encodeCount
|
||||
int readCount(const char *in, int *bit_no_p, int len) {
|
||||
int idx = getCodeIdx(us_hcode, in, len, bit_no_p);
|
||||
uint32_t Unishox::readCount(void) {
|
||||
int32_t idx = getCodeIdx(us_hcode);
|
||||
if (idx >= 1) idx--; // we skip v = 1 (code '0') since we no more accept 2 bits encoding
|
||||
if ((idx >= sizeof(bit_len)) || (idx < 0)) return 0; // unsupported or end of stream
|
||||
|
||||
|
@ -465,44 +444,41 @@ int readCount(const char *in, int *bit_no_p, int len) {
|
|||
bit_len_idx = pgm_read_byte(&bit_len[i]);
|
||||
till += (1 << bit_len_idx);
|
||||
}
|
||||
int count = getNumFromBits(in, *bit_no_p, bit_len_idx) + base;
|
||||
int count = getNumFromBits(bit_len_idx) + base;
|
||||
|
||||
(*bit_no_p) += bit_len_idx;
|
||||
return count;
|
||||
}
|
||||
|
||||
int decodeRepeat(const char *in, int len, char *out, int ol, int *bit_no) {
|
||||
int dict_len = readCount(in, bit_no, len) + NICE_LEN;
|
||||
int dist = readCount(in, bit_no, len) + NICE_LEN - 1;
|
||||
void Unishox::decodeRepeat(void) {
|
||||
uint32_t dict_len = readCount() + NICE_LEN;
|
||||
uint32_t dist = readCount() + NICE_LEN - 1;
|
||||
memcpy(out + ol, out + ol - dist, dict_len);
|
||||
ol += dict_len;
|
||||
|
||||
return ol;
|
||||
}
|
||||
|
||||
int32_t unishox_decompress(const char *in, size_t len, char *out, size_t len_out) {
|
||||
int32_t Unishox::unishox_decompress(const char *p_in, size_t p_len, char *p_out, size_t p_len_out) {
|
||||
in = p_in;
|
||||
len = p_len;
|
||||
out = p_out;
|
||||
len_out = p_len_out;
|
||||
|
||||
int dstate;
|
||||
int bit_no;
|
||||
byte is_all_upper;
|
||||
|
||||
int ol = 0;
|
||||
bit_no = 0;
|
||||
ol = 0;
|
||||
bit_no = 8; // force load of first byte, pretending we expired the last one
|
||||
byte_no = 0;
|
||||
dstate = SHX_SET1;
|
||||
is_all_upper = 0;
|
||||
|
||||
len <<= 3; // *8, len in bits
|
||||
out[ol] = 0;
|
||||
while (bit_no < len) {
|
||||
int h, v;
|
||||
int32_t h, v;
|
||||
char c = 0;
|
||||
byte is_upper = is_all_upper;
|
||||
int orig_bit_no = bit_no;
|
||||
v = getCodeIdx(us_vcode, in, len, &bit_no); // read vCode
|
||||
v = getCodeIdx(us_vcode); // read vCode
|
||||
if (v < 0) break; // end of stream
|
||||
h = dstate; // Set1 or Set2
|
||||
if (v == 0) { // Switch which is common to Set1 and Set2, first entry
|
||||
h = getCodeIdx(us_hcode, in, len, &bit_no); // read hCode
|
||||
h = getCodeIdx(us_hcode); // read hCode
|
||||
if (h < 0) break; // end of stream
|
||||
if (h == SHX_SET1) { // target is Set1
|
||||
if (dstate == SHX_SET1) { // Switch from Set1 to Set1 us UpperCase
|
||||
|
@ -510,10 +486,10 @@ int32_t unishox_decompress(const char *in, size_t len, char *out, size_t len_out
|
|||
is_upper = is_all_upper = 0;
|
||||
continue;
|
||||
}
|
||||
v = getCodeIdx(us_vcode, in, len, &bit_no); // read again vCode
|
||||
v = getCodeIdx(us_vcode); // read again vCode
|
||||
if (v < 0) break; // end of stream
|
||||
if (v == 0) {
|
||||
h = getCodeIdx(us_hcode, in, len, &bit_no); // read second hCode
|
||||
h = getCodeIdx(us_hcode); // read second hCode
|
||||
if (h < 0) break; // end of stream
|
||||
if (h == SHX_SET1) { // If double Switch Set1, the CapsLock
|
||||
is_all_upper = 1;
|
||||
|
@ -532,23 +508,23 @@ int32_t unishox_decompress(const char *in, size_t len, char *out, size_t len_out
|
|||
continue;
|
||||
}
|
||||
if (h != SHX_SET1) { // all other Sets (why not else)
|
||||
v = getCodeIdx(us_vcode, in, len, &bit_no); // we changed set, now read vCode for char
|
||||
v = getCodeIdx(us_vcode); // we changed set, now read vCode for char
|
||||
if (v < 0) break; // end of stream
|
||||
}
|
||||
}
|
||||
|
||||
if (v == 0 && h == SHX_SET1A) {
|
||||
if (is_upper) {
|
||||
out[ol++] = 255 - readCount(in, &bit_no, len); // binary
|
||||
out[ol++] = 255 - readCount(); // binary
|
||||
} else {
|
||||
ol = decodeRepeat(in, len, out, ol, &bit_no); // dist
|
||||
decodeRepeat(); // dist
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (h == SHX_SET1 && v == 3) {
|
||||
// was Unicode, will do Binary instead
|
||||
out[ol++] = 255 - readCount(in, &bit_no, len); // binary
|
||||
out[ol++] = 255 - readCount(); // binary
|
||||
continue;
|
||||
}
|
||||
if (h < 7 && v < 11) // TODO: are these the actual limits? Not 11x7 ?
|
||||
|
@ -561,22 +537,11 @@ int32_t unishox_decompress(const char *in, size_t len, char *out, size_t len_out
|
|||
c = '\t'; // If UpperCase Space, change to TAB
|
||||
if (h == SHX_SET1B) {
|
||||
if (8 == v) { // was LF or RPT, now only LF
|
||||
// if (is_upper) { // rpt
|
||||
// int count = readCount(in, &bit_no, len);
|
||||
// count += 4;
|
||||
// char rpt_c = out[ol - 1];
|
||||
// while (count--)
|
||||
// out[ol++] = rpt_c;
|
||||
// } else {
|
||||
out[ol++] = '\n';
|
||||
// }
|
||||
continue;
|
||||
}
|
||||
if (9 == v) { // was CRLF, now RPT
|
||||
// out[ol++] = '\r'; // CRLF removed
|
||||
// out[ol++] = '\n';
|
||||
int count = readCount(in, &bit_no, len);
|
||||
count += 4;
|
||||
uint32_t count = readCount() + 4;
|
||||
if (ol + count >= len_out) {
|
||||
return -1; // overflow
|
||||
}
|
||||
|
@ -598,5 +563,4 @@ int32_t unishox_decompress(const char *in, size_t len, char *out, size_t len_out
|
|||
}
|
||||
|
||||
return ol;
|
||||
|
||||
}
|
||||
|
|
|
@ -20,7 +20,45 @@
|
|||
#define unishox
|
||||
|
||||
extern int32_t unishox_compress(const char *in, size_t len, char *out, size_t len_out);
|
||||
extern int32_t unishox_decompress(const char *in, size_t len, char *out, size_t len_out);
|
||||
//extern int32_t unishox_decompress(const char *in, size_t len, char *out, size_t len_out);
|
||||
|
||||
class Unishox {
|
||||
|
||||
public:
|
||||
Unishox() {};
|
||||
|
||||
int32_t unishox_decompress(const char *in, size_t len, char *out, size_t len_out);
|
||||
int32_t unishox_compress(const char *in, size_t len, char *out, size_t len_out);
|
||||
|
||||
private:
|
||||
|
||||
void append_bits(unsigned int code, int clen);
|
||||
void encodeCount(int32_t count);
|
||||
bool matchOccurance(void);
|
||||
|
||||
uint32_t getNextBit(void);
|
||||
int32_t getCodeIdx(const char *code_type);
|
||||
uint32_t readCount(void);
|
||||
void decodeRepeat(void);
|
||||
int32_t getNumFromBits(uint32_t count);
|
||||
|
||||
inline void writeOut(char c) { out[ol++] = c; }
|
||||
|
||||
int32_t l;
|
||||
uint32_t ol;
|
||||
int32_t bit_no;
|
||||
uint32_t byte_no;
|
||||
const char * in;
|
||||
char * out;
|
||||
size_t len;
|
||||
size_t len_out;
|
||||
|
||||
uint8_t dstate;
|
||||
unsigned char byte_in;
|
||||
uint8_t state;
|
||||
uint8_t is_all_upper;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -188,7 +188,7 @@ build_flags = ${esp_defaults.build_flags}
|
|||
-D sint16_t=int16_t
|
||||
-D memcpy_P=memcpy
|
||||
-D memcmp_P=memcmp
|
||||
; -D USE_CONFIG_OVERRIDE
|
||||
-D USE_CONFIG_OVERRIDE
|
||||
|
||||
lib_extra_dirs =
|
||||
libesp32
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
## Unreleased (development)
|
||||
|
||||
### 8.3.0.2 20200517
|
||||
|
||||
- Add command ``DeviceName`` defaults to FriendlyName1 and replaces FriendlyName1 in GUI
|
||||
|
||||
### 8.3.0.1 20200514
|
||||
|
||||
- Change KNX pow function to approximative pow saving 5k of code space
|
||||
|
|
|
@ -276,6 +276,7 @@
|
|||
#define D_WCFG_5_WAIT "Wait"
|
||||
#define D_WCFG_6_SERIAL "Serial"
|
||||
#define D_WCFG_7_WIFIMANAGER_RESET_ONLY "ManagerRst"
|
||||
#define D_CMND_DEVICENAME "DeviceName"
|
||||
#define D_CMND_FRIENDLYNAME "FriendlyName"
|
||||
#define D_CMND_SWITCHMODE "SwitchMode"
|
||||
#define D_CMND_INTERLOCK "Interlock"
|
||||
|
|
|
@ -302,6 +302,7 @@
|
|||
#define D_OTHER_PARAMETERS "Други параметри"
|
||||
#define D_TEMPLATE "Модел"
|
||||
#define D_ACTIVATE "Активирай"
|
||||
#define D_DEVICE_NAME "Device Name"
|
||||
#define D_WEB_ADMIN_PASSWORD "Парола на уеб администратора"
|
||||
#define D_MQTT_ENABLE "Активиране на MQTT"
|
||||
#define D_FRIENDLY_NAME "Приятелско име"
|
||||
|
|
|
@ -302,6 +302,7 @@
|
|||
#define D_OTHER_PARAMETERS "Další nastavení"
|
||||
#define D_TEMPLATE "Šablona"
|
||||
#define D_ACTIVATE "Aktivovat"
|
||||
#define D_DEVICE_NAME "Device Name"
|
||||
#define D_WEB_ADMIN_PASSWORD "Heslo Web administrátora"
|
||||
#define D_MQTT_ENABLE "MQTT aktivní"
|
||||
#define D_FRIENDLY_NAME "Friendly Name"
|
||||
|
|
|
@ -302,6 +302,7 @@
|
|||
#define D_OTHER_PARAMETERS "Sonstige Einstellungen"
|
||||
#define D_TEMPLATE "Vorlage"
|
||||
#define D_ACTIVATE "Aktivieren"
|
||||
#define D_DEVICE_NAME "Device Name"
|
||||
#define D_WEB_ADMIN_PASSWORD "Passwort für Web Oberfläche"
|
||||
#define D_MQTT_ENABLE "MQTT aktivieren"
|
||||
#define D_FRIENDLY_NAME "Name [friendly name]"
|
||||
|
|
|
@ -302,6 +302,7 @@
|
|||
#define D_OTHER_PARAMETERS "Άλλες παράμετροι"
|
||||
#define D_TEMPLATE "Πρότυπο"
|
||||
#define D_ACTIVATE "Ενεργοποίηση"
|
||||
#define D_DEVICE_NAME "Device Name"
|
||||
#define D_WEB_ADMIN_PASSWORD "Κωδικός διαχειριστή"
|
||||
#define D_MQTT_ENABLE "Ενεργοποίηση MQTT"
|
||||
#define D_FRIENDLY_NAME "Φιλική ονομασία"
|
||||
|
|
|
@ -302,6 +302,7 @@
|
|||
#define D_OTHER_PARAMETERS "Other parameters"
|
||||
#define D_TEMPLATE "Template"
|
||||
#define D_ACTIVATE "Activate"
|
||||
#define D_DEVICE_NAME "Device Name"
|
||||
#define D_WEB_ADMIN_PASSWORD "Web Admin Password"
|
||||
#define D_MQTT_ENABLE "MQTT enable"
|
||||
#define D_FRIENDLY_NAME "Friendly Name"
|
||||
|
|
|
@ -302,6 +302,7 @@
|
|||
#define D_OTHER_PARAMETERS "Otros parámetros"
|
||||
#define D_TEMPLATE "Plantilla"
|
||||
#define D_ACTIVATE "Activar"
|
||||
#define D_DEVICE_NAME "Device Name"
|
||||
#define D_WEB_ADMIN_PASSWORD "Clave Administrador Web"
|
||||
#define D_MQTT_ENABLE "Habilitar MQTT"
|
||||
#define D_FRIENDLY_NAME "Nombre Amigable"
|
||||
|
|
|
@ -302,6 +302,7 @@
|
|||
#define D_OTHER_PARAMETERS "Autres paramètres"
|
||||
#define D_TEMPLATE "Modèle"
|
||||
#define D_ACTIVATE "Activer"
|
||||
#define D_DEVICE_NAME "Device Name"
|
||||
#define D_WEB_ADMIN_PASSWORD "Mot de passe Web Admin"
|
||||
#define D_MQTT_ENABLE "MQTT activé"
|
||||
#define D_FRIENDLY_NAME "Surnom"
|
||||
|
|
|
@ -302,6 +302,7 @@
|
|||
#define D_OTHER_PARAMETERS "פרמטרים שונים"
|
||||
#define D_TEMPLATE "תבנית"
|
||||
#define D_ACTIVATE "הפעל"
|
||||
#define D_DEVICE_NAME "Device Name"
|
||||
#define D_WEB_ADMIN_PASSWORD "סיסמת מנהל"
|
||||
#define D_MQTT_ENABLE "MQTT אפשר"
|
||||
#define D_FRIENDLY_NAME "שם ידידותי"
|
||||
|
|
|
@ -302,6 +302,7 @@
|
|||
#define D_OTHER_PARAMETERS "Egyéb beállítások"
|
||||
#define D_TEMPLATE "Template"
|
||||
#define D_ACTIVATE "Activate"
|
||||
#define D_DEVICE_NAME "Device Name"
|
||||
#define D_WEB_ADMIN_PASSWORD "Web admin jelszó"
|
||||
#define D_MQTT_ENABLE "MQTT engedélyezése"
|
||||
#define D_FRIENDLY_NAME "Név"
|
||||
|
|
|
@ -302,6 +302,7 @@
|
|||
#define D_OTHER_PARAMETERS "Altri parametri"
|
||||
#define D_TEMPLATE "Modello"
|
||||
#define D_ACTIVATE "Attiva"
|
||||
#define D_DEVICE_NAME "Device Name"
|
||||
#define D_WEB_ADMIN_PASSWORD "Password amministratore web"
|
||||
#define D_MQTT_ENABLE "Abilita MQTT"
|
||||
#define D_FRIENDLY_NAME "Nome amichevole"
|
||||
|
|
|
@ -302,6 +302,7 @@
|
|||
#define D_OTHER_PARAMETERS "기타 설정"
|
||||
#define D_TEMPLATE "템플릿"
|
||||
#define D_ACTIVATE "활성화"
|
||||
#define D_DEVICE_NAME "Device Name"
|
||||
#define D_WEB_ADMIN_PASSWORD "Web Admin 비밀번호"
|
||||
#define D_MQTT_ENABLE "MQTT 사용"
|
||||
#define D_FRIENDLY_NAME "Friendly Name"
|
||||
|
|
|
@ -302,6 +302,7 @@
|
|||
#define D_OTHER_PARAMETERS "Overige parameters"
|
||||
#define D_TEMPLATE "Sjabloon"
|
||||
#define D_ACTIVATE "Activeer"
|
||||
#define D_DEVICE_NAME "Apparaatnaam"
|
||||
#define D_WEB_ADMIN_PASSWORD "Web Admin Wachtwoord"
|
||||
#define D_MQTT_ENABLE "MQTT ingeschakeld"
|
||||
#define D_FRIENDLY_NAME "Beschrijvende naam"
|
||||
|
|
|
@ -302,6 +302,7 @@
|
|||
#define D_OTHER_PARAMETERS "Inne parametry"
|
||||
#define D_TEMPLATE "Szablon"
|
||||
#define D_ACTIVATE "Aktywuj"
|
||||
#define D_DEVICE_NAME "Device Name"
|
||||
#define D_WEB_ADMIN_PASSWORD "Hasło administratora"
|
||||
#define D_MQTT_ENABLE "Załącz MQTT"
|
||||
#define D_FRIENDLY_NAME "Nazwa"
|
||||
|
|
|
@ -302,6 +302,7 @@
|
|||
#define D_OTHER_PARAMETERS "Outros parâmetros"
|
||||
#define D_TEMPLATE "Modelo"
|
||||
#define D_ACTIVATE "Activate"
|
||||
#define D_DEVICE_NAME "Device Name"
|
||||
#define D_WEB_ADMIN_PASSWORD "Senha de WEB Admin"
|
||||
#define D_MQTT_ENABLE "MQTT habilitado"
|
||||
#define D_FRIENDLY_NAME "Nome amigável"
|
||||
|
|
|
@ -302,6 +302,7 @@
|
|||
#define D_OTHER_PARAMETERS "Outros parametros"
|
||||
#define D_TEMPLATE "Modelo"
|
||||
#define D_ACTIVATE "Ativar"
|
||||
#define D_DEVICE_NAME "Device Name"
|
||||
#define D_WEB_ADMIN_PASSWORD "Palavra Chave do Admin WEB"
|
||||
#define D_MQTT_ENABLE "MQTT habilitado"
|
||||
#define D_FRIENDLY_NAME "Nome amigável"
|
||||
|
|
|
@ -302,6 +302,7 @@
|
|||
#define D_OTHER_PARAMETERS "Alți paramatri"
|
||||
#define D_TEMPLATE "Template"
|
||||
#define D_ACTIVATE "Activare"
|
||||
#define D_DEVICE_NAME "Device Name"
|
||||
#define D_WEB_ADMIN_PASSWORD "Parolă Web Admin"
|
||||
#define D_MQTT_ENABLE "Activare MQTT"
|
||||
#define D_FRIENDLY_NAME "Friendly Name"
|
||||
|
|
|
@ -302,6 +302,7 @@
|
|||
#define D_OTHER_PARAMETERS "Параметры Прочие"
|
||||
#define D_TEMPLATE "Template"
|
||||
#define D_ACTIVATE "Activate"
|
||||
#define D_DEVICE_NAME "Device Name"
|
||||
#define D_WEB_ADMIN_PASSWORD "Пароль Web администратора"
|
||||
#define D_MQTT_ENABLE "MQTT активен"
|
||||
#define D_FRIENDLY_NAME "Дружественное Имя"
|
||||
|
|
|
@ -302,6 +302,7 @@
|
|||
#define D_OTHER_PARAMETERS "Ostatné nastavenia"
|
||||
#define D_TEMPLATE "Template"
|
||||
#define D_ACTIVATE "Activate"
|
||||
#define D_DEVICE_NAME "Device Name"
|
||||
#define D_WEB_ADMIN_PASSWORD "Heslo Web administrátora"
|
||||
#define D_MQTT_ENABLE "MQTT aktívne"
|
||||
#define D_FRIENDLY_NAME "Friendly Name"
|
||||
|
|
|
@ -302,6 +302,7 @@
|
|||
#define D_OTHER_PARAMETERS "Andra parametrar"
|
||||
#define D_TEMPLATE "Template"
|
||||
#define D_ACTIVATE "Activate"
|
||||
#define D_DEVICE_NAME "Device Name"
|
||||
#define D_WEB_ADMIN_PASSWORD "Webbadmin-lösenord"
|
||||
#define D_MQTT_ENABLE "MQTT aktivera"
|
||||
#define D_FRIENDLY_NAME "Läsbart namn"
|
||||
|
|
|
@ -302,6 +302,7 @@
|
|||
#define D_OTHER_PARAMETERS "Diğer parametreler"
|
||||
#define D_TEMPLATE "Template"
|
||||
#define D_ACTIVATE "Activate"
|
||||
#define D_DEVICE_NAME "Device Name"
|
||||
#define D_WEB_ADMIN_PASSWORD "Web Yönetici Şifresi"
|
||||
#define D_MQTT_ENABLE "MQTT aktif"
|
||||
#define D_FRIENDLY_NAME "Kullanıcı Dostu İsim"
|
||||
|
|
|
@ -302,6 +302,7 @@
|
|||
#define D_OTHER_PARAMETERS "Параметри Інше"
|
||||
#define D_TEMPLATE "Шаблони"
|
||||
#define D_ACTIVATE "Активований"
|
||||
#define D_DEVICE_NAME "Device Name"
|
||||
#define D_WEB_ADMIN_PASSWORD "Гасло адміністратора Web"
|
||||
#define D_MQTT_ENABLE "MQTT активний"
|
||||
#define D_FRIENDLY_NAME "Дружня назва"
|
||||
|
|
|
@ -302,6 +302,7 @@
|
|||
#define D_OTHER_PARAMETERS "其他设置"
|
||||
#define D_TEMPLATE "模板"
|
||||
#define D_ACTIVATE "启用"
|
||||
#define D_DEVICE_NAME "Device Name"
|
||||
#define D_WEB_ADMIN_PASSWORD "WEB 管理密码"
|
||||
#define D_MQTT_ENABLE "启用MQTT"
|
||||
#define D_FRIENDLY_NAME "昵称"
|
||||
|
|
|
@ -302,6 +302,7 @@
|
|||
#define D_OTHER_PARAMETERS "其他設置"
|
||||
#define D_TEMPLATE "Template"
|
||||
#define D_ACTIVATE "Activate"
|
||||
#define D_DEVICE_NAME "Device Name"
|
||||
#define D_WEB_ADMIN_PASSWORD "WEB管理密碼"
|
||||
#define D_MQTT_ENABLE "啟用MQTT"
|
||||
#define D_FRIENDLY_NAME "昵稱"
|
||||
|
|
|
@ -397,7 +397,7 @@
|
|||
// -- Rules or Script ----------------------------
|
||||
// Select none or only one of the below defines USE_RULES or USE_SCRIPT
|
||||
#define USE_RULES // Add support for rules (+8k code)
|
||||
#define USE_RULES_COMPRESSION // Compresses rules in Flash at about ~50% (+3.8k code)
|
||||
#define USE_RULES_COMPRESSION // Compresses rules in Flash at about ~50% (+3.3k code)
|
||||
//#define USE_SCRIPT // Add support for script (+17k code)
|
||||
//#define USE_SCRIPT_FATFS 4 // Script: Add FAT FileSystem Support
|
||||
|
||||
|
|
|
@ -754,6 +754,7 @@ void SettingsDefaultSet2(void)
|
|||
SettingsUpdateText(SET_FRIENDLYNAME2, PSTR(FRIENDLY_NAME"2"));
|
||||
SettingsUpdateText(SET_FRIENDLYNAME3, PSTR(FRIENDLY_NAME"3"));
|
||||
SettingsUpdateText(SET_FRIENDLYNAME4, PSTR(FRIENDLY_NAME"4"));
|
||||
SettingsUpdateText(SET_DEVICENAME, SettingsText(SET_FRIENDLYNAME1));
|
||||
SettingsUpdateText(SET_OTAURL, PSTR(OTA_URL));
|
||||
|
||||
// Power
|
||||
|
@ -1411,6 +1412,10 @@ void SettingsDelta(void)
|
|||
if (Settings.rules[2][0] == 0) { Settings.rules[2][1] = 0; }
|
||||
}
|
||||
|
||||
if (Settings.version < 0x08030002) {
|
||||
SettingsUpdateText(SET_DEVICENAME, SettingsText(SET_FRIENDLYNAME1));
|
||||
}
|
||||
|
||||
Settings.version = VERSION;
|
||||
SettingsSave(1);
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ const char kTasmotaCommands[] PROGMEM = "|" // No prefix
|
|||
D_CMND_MODULE "|" D_CMND_MODULES "|" D_CMND_GPIO "|" D_CMND_GPIOS "|" D_CMND_TEMPLATE "|" D_CMND_PWM "|" D_CMND_PWMFREQUENCY "|" D_CMND_PWMRANGE "|"
|
||||
D_CMND_BUTTONDEBOUNCE "|" D_CMND_SWITCHDEBOUNCE "|" D_CMND_SYSLOG "|" D_CMND_LOGHOST "|" D_CMND_LOGPORT "|" D_CMND_SERIALSEND "|" D_CMND_BAUDRATE "|" D_CMND_SERIALCONFIG "|"
|
||||
D_CMND_SERIALDELIMITER "|" D_CMND_IPADDRESS "|" D_CMND_NTPSERVER "|" D_CMND_AP "|" D_CMND_SSID "|" D_CMND_PASSWORD "|" D_CMND_HOSTNAME "|" D_CMND_WIFICONFIG "|"
|
||||
D_CMND_FRIENDLYNAME "|" D_CMND_SWITCHMODE "|" D_CMND_INTERLOCK "|" D_CMND_TELEPERIOD "|" D_CMND_RESET "|" D_CMND_TIME "|" D_CMND_TIMEZONE "|" D_CMND_TIMESTD "|"
|
||||
D_CMND_DEVICENAME "|" D_CMND_FRIENDLYNAME "|" D_CMND_SWITCHMODE "|" D_CMND_INTERLOCK "|" D_CMND_TELEPERIOD "|" D_CMND_RESET "|" D_CMND_TIME "|" D_CMND_TIMEZONE "|" D_CMND_TIMESTD "|"
|
||||
D_CMND_TIMEDST "|" D_CMND_ALTITUDE "|" D_CMND_LEDPOWER "|" D_CMND_LEDSTATE "|" D_CMND_LEDMASK "|" D_CMND_WIFIPOWER "|" D_CMND_TEMPOFFSET "|" D_CMND_HUMOFFSET "|"
|
||||
D_CMND_SPEEDUNIT "|" D_CMND_GLOBAL_TEMP "|" D_CMND_GLOBAL_HUM "|"
|
||||
#ifdef USE_I2C
|
||||
|
@ -48,7 +48,7 @@ void (* const TasmotaCommand[])(void) PROGMEM = {
|
|||
&CmndModule, &CmndModules, &CmndGpio, &CmndGpios, &CmndTemplate, &CmndPwm, &CmndPwmfrequency, &CmndPwmrange,
|
||||
&CmndButtonDebounce, &CmndSwitchDebounce, &CmndSyslog, &CmndLoghost, &CmndLogport, &CmndSerialSend, &CmndBaudrate, &CmndSerialConfig,
|
||||
&CmndSerialDelimiter, &CmndIpAddress, &CmndNtpServer, &CmndAp, &CmndSsid, &CmndPassword, &CmndHostname, &CmndWifiConfig,
|
||||
&CmndFriendlyname, &CmndSwitchMode, &CmndInterlock, &CmndTeleperiod, &CmndReset, &CmndTime, &CmndTimezone, &CmndTimeStd,
|
||||
&CmndDevicename, &CmndFriendlyname, &CmndSwitchMode, &CmndInterlock, &CmndTeleperiod, &CmndReset, &CmndTime, &CmndTimezone, &CmndTimeStd,
|
||||
&CmndTimeDst, &CmndAltitude, &CmndLedPower, &CmndLedState, &CmndLedMask, &CmndWifiPower, &CmndTempOffset, &CmndHumOffset,
|
||||
&CmndSpeedUnit, &CmndGlobalTemp, &CmndGlobalHum,
|
||||
#ifdef USE_I2C
|
||||
|
@ -395,11 +395,11 @@ void CmndStatus(void)
|
|||
for (uint32_t i = 0; i < MAX_SWITCHES; i++) {
|
||||
snprintf_P(stemp2, sizeof(stemp2), PSTR("%s%s%d" ), stemp2, (i > 0 ? "," : ""), Settings.switchmode[i]);
|
||||
}
|
||||
Response_P(PSTR("{\"" D_CMND_STATUS "\":{\"" D_CMND_MODULE "\":%d,\"" D_CMND_FRIENDLYNAME "\":[%s],\"" D_CMND_TOPIC "\":\"%s\",\""
|
||||
Response_P(PSTR("{\"" D_CMND_STATUS "\":{\"" D_CMND_MODULE "\":%d,\"" D_CMND_DEVICENAME "\":\"%s\",\"" D_CMND_FRIENDLYNAME "\":[%s],\"" D_CMND_TOPIC "\":\"%s\",\""
|
||||
D_CMND_BUTTONTOPIC "\":\"%s\",\"" D_CMND_POWER "\":%d,\"" D_CMND_POWERONSTATE "\":%d,\"" D_CMND_LEDSTATE "\":%d,\""
|
||||
D_CMND_LEDMASK "\":\"%04X\",\"" D_CMND_SAVEDATA "\":%d,\"" D_JSON_SAVESTATE "\":%d,\"" D_CMND_SWITCHTOPIC "\":\"%s\",\""
|
||||
D_CMND_SWITCHMODE "\":[%s],\"" D_CMND_BUTTONRETAIN "\":%d,\"" D_CMND_SWITCHRETAIN "\":%d,\"" D_CMND_SENSORRETAIN "\":%d,\"" D_CMND_POWERRETAIN "\":%d}}"),
|
||||
ModuleNr(), stemp, mqtt_topic,
|
||||
ModuleNr(), SettingsText(SET_DEVICENAME), stemp, mqtt_topic,
|
||||
SettingsText(SET_MQTT_BUTTON_TOPIC), power, Settings.poweronstate, Settings.ledstate,
|
||||
Settings.ledmask, Settings.save_data,
|
||||
Settings.flag.save_state, // SetOption0 - Save power state and use after restart
|
||||
|
@ -1488,6 +1488,14 @@ void CmndWifiConfig(void)
|
|||
Response_P(S_JSON_COMMAND_NVALUE_SVALUE, XdrvMailbox.command, Settings.sta_config, GetTextIndexed(stemp1, sizeof(stemp1), Settings.sta_config, kWifiConfig));
|
||||
}
|
||||
|
||||
void CmndDevicename(void)
|
||||
{
|
||||
if (!XdrvMailbox.grpflg && (XdrvMailbox.data_len > 0)) {
|
||||
SettingsUpdateText(SET_DEVICENAME, ('"' == XdrvMailbox.data[0]) ? "" : (SC_DEFAULT == Shortcut()) ? SettingsText(SET_FRIENDLYNAME1) : XdrvMailbox.data);
|
||||
}
|
||||
ResponseCmndChar(SettingsText(SET_DEVICENAME));
|
||||
}
|
||||
|
||||
void CmndFriendlyname(void)
|
||||
{
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_FRIENDLYNAMES)) {
|
||||
|
|
|
@ -292,6 +292,7 @@ enum SettingsTextIndex { SET_OTAURL,
|
|||
SET_MQTT_GRP_TOPIC2, SET_MQTT_GRP_TOPIC3, SET_MQTT_GRP_TOPIC4,
|
||||
SET_TEMPLATE_NAME,
|
||||
SET_DEV_GROUP_NAME1, SET_DEV_GROUP_NAME2, SET_DEV_GROUP_NAME3, SET_DEV_GROUP_NAME4,
|
||||
SET_DEVICENAME,
|
||||
SET_MAX };
|
||||
|
||||
enum DevGroupMessageType { DGR_MSGTYP_FULL_STATUS, DGR_MSGTYP_PARTIAL_UPDATE, DGR_MSGTYP_UPDATE, DGR_MSGTYP_UPDATE_MORE_TO_COME, DGR_MSGTYP_UPDATE_DIRECT, DGR_MSGTYPE_UPDATE_COMMAND };
|
||||
|
|
|
@ -307,7 +307,7 @@ void setup(void) {
|
|||
|
||||
SetPowerOnState();
|
||||
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_PROJECT " %s %s " D_VERSION " %s%s-" ARDUINO_CORE_RELEASE), PROJECT, SettingsText(SET_FRIENDLYNAME1), my_version, my_image);
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_PROJECT " %s %s " D_VERSION " %s%s-" ARDUINO_CORE_RELEASE), PROJECT, SettingsText(SET_DEVICENAME), my_version, my_image);
|
||||
#ifdef FIRMWARE_MINIMAL
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_WARNING_MINIMAL_VERSION));
|
||||
#endif // FIRMWARE_MINIMAL
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#ifndef _TASMOTA_VERSION_H_
|
||||
#define _TASMOTA_VERSION_H_
|
||||
|
||||
const uint32_t VERSION = 0x08030001;
|
||||
const uint32_t VERSION = 0x08030002;
|
||||
|
||||
// Lowest compatible version
|
||||
const uint32_t VERSION_COMPATIBLE = 0x07010006;
|
||||
|
|
|
@ -455,6 +455,8 @@ const char HTTP_FORM_OTHER[] PROGMEM =
|
|||
"<label><b>" D_WEB_ADMIN_PASSWORD "</b><input type='checkbox' onclick='sp(\"wp\")'></label><br><input id='wp' type='password' placeholder='" D_WEB_ADMIN_PASSWORD "' value='" D_ASTERISK_PWD "'><br>"
|
||||
"<br>"
|
||||
"<label><input id='b1' type='checkbox'%s><b>" D_MQTT_ENABLE "</b></label><br>"
|
||||
"<br>"
|
||||
"<label><b>" D_DEVICE_NAME "</b> (%s)</label><br><input id='dn' placeholder='' value='%s'><br>"
|
||||
"<br>";
|
||||
|
||||
const char HTTP_FORM_END[] PROGMEM =
|
||||
|
@ -849,7 +851,7 @@ void WSContentStart_P(const char* title, bool auth)
|
|||
WSContentBegin(200, CT_HTML);
|
||||
|
||||
if (title != nullptr) {
|
||||
WSContentSend_P(HTTP_HEADER1, SettingsText(SET_FRIENDLYNAME1), title);
|
||||
WSContentSend_P(HTTP_HEADER1, SettingsText(SET_DEVICENAME), title);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -893,7 +895,7 @@ void WSContentSendStyle_P(const char* formatP, ...)
|
|||
WebColor(COL_TEXT_WARNING),
|
||||
#endif
|
||||
WebColor(COL_TITLE),
|
||||
ModuleName().c_str(), SettingsText(SET_FRIENDLYNAME1));
|
||||
ModuleName().c_str(), SettingsText(SET_DEVICENAME));
|
||||
if (Settings.flag3.gui_hostname_ip) { // SetOption53 - Show hostanme and IP address in GUI main menu
|
||||
bool lip = (static_cast<uint32_t>(WiFi.localIP()) != 0);
|
||||
bool sip = (static_cast<uint32_t>(WiFi.softAPIP()) != 0);
|
||||
|
@ -1992,7 +1994,9 @@ void HandleOtherConfiguration(void)
|
|||
TemplateJson();
|
||||
char stemp[strlen(mqtt_data) +1];
|
||||
strlcpy(stemp, mqtt_data, sizeof(stemp)); // Get JSON template
|
||||
WSContentSend_P(HTTP_FORM_OTHER, stemp, (USER_MODULE == Settings.module) ? " checked disabled" : "", (Settings.flag.mqtt_enabled) ? " checked" : ""); // SetOption3 - Enable MQTT
|
||||
WSContentSend_P(HTTP_FORM_OTHER, stemp, (USER_MODULE == Settings.module) ? " checked disabled" : "",
|
||||
(Settings.flag.mqtt_enabled) ? " checked" : "", // SetOption3 - Enable MQTT
|
||||
SettingsText(SET_FRIENDLYNAME1), SettingsText(SET_DEVICENAME));
|
||||
|
||||
uint32_t maxfn = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : (!devices_present) ? 1 : devices_present;
|
||||
#ifdef USE_SONOFF_IFAN
|
||||
|
@ -2042,6 +2046,8 @@ void OtherSaveSettings(void)
|
|||
char friendlyname[TOPSZ];
|
||||
char message[LOGSZ];
|
||||
|
||||
WebGetArg("dn", tmp, sizeof(tmp));
|
||||
SettingsUpdateText(SET_DEVICENAME, (!strlen(tmp)) ? "" : (!strcmp(tmp,"1")) ? SettingsText(SET_FRIENDLYNAME1) : tmp);
|
||||
WebGetArg("wp", tmp, sizeof(tmp));
|
||||
SettingsUpdateText(SET_WEBPWD, (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? SettingsText(SET_WEBPWD) : tmp);
|
||||
Settings.flag.mqtt_enabled = Webserver->hasArg("b1"); // SetOption3 - Enable MQTT
|
||||
|
@ -2053,7 +2059,8 @@ void OtherSaveSettings(void)
|
|||
#endif // USE_EMULATION_WEMO || USE_EMULATION_HUE
|
||||
#endif // USE_EMULATION
|
||||
|
||||
snprintf_P(message, sizeof(message), PSTR(D_LOG_OTHER D_MQTT_ENABLE " %s, " D_CMND_EMULATION " %d, " D_CMND_FRIENDLYNAME), GetStateText(Settings.flag.mqtt_enabled), Settings.flag2.emulation);
|
||||
snprintf_P(message, sizeof(message), PSTR(D_LOG_OTHER D_MQTT_ENABLE " %s, " D_CMND_EMULATION " %d, " D_CMND_DEVICENAME " %s, " D_CMND_FRIENDLYNAME),
|
||||
GetStateText(Settings.flag.mqtt_enabled), Settings.flag2.emulation, SettingsText(SET_DEVICENAME));
|
||||
for (uint32_t i = 0; i < MAX_FRIENDLYNAMES; i++) {
|
||||
snprintf_P(webindex, sizeof(webindex), PSTR("a%d"), i);
|
||||
WebGetArg(webindex, tmp, sizeof(tmp));
|
||||
|
|
|
@ -213,6 +213,7 @@ char rules_vars[MAX_RULE_VARS][33] = {{ 0 }};
|
|||
#ifdef USE_RULES_COMPRESSION
|
||||
// Statically allocate one String per rule
|
||||
String k_rules[MAX_RULE_SETS] = { String(), String(), String() }; // Strings are created empty
|
||||
Unishox compressor; // singleton
|
||||
#endif // USE_RULES_COMPRESSION
|
||||
|
||||
// Returns whether the rule is uncompressed, which means the first byte is not NULL
|
||||
|
@ -256,6 +257,7 @@ size_t GetRuleLenStorage(uint32_t idx) {
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_RULES_COMPRESSION
|
||||
// internal function, do the actual decompression
|
||||
void GetRule_decompress(String &rule, const char *rule_head) {
|
||||
size_t buf_len = 1 + *rule_head * 8; // the first byte contains size of buffer for uncompressed rule / 8, buf_len may overshoot by 7
|
||||
|
@ -268,12 +270,13 @@ void GetRule_decompress(String &rule, const char *rule_head) {
|
|||
rule.reserve(buf_len);
|
||||
char* buf = rule.begin();
|
||||
|
||||
int32_t len_decompressed = unishox_decompress(rule_head, strlen(rule_head), buf, buf_len);
|
||||
int32_t len_decompressed = compressor.unishox_decompress(rule_head, strlen(rule_head), buf, buf_len);
|
||||
buf[len_decompressed] = 0; // add NULL terminator
|
||||
|
||||
// AddLog_P2(LOG_LEVEL_INFO, PSTR("RUL: Rawdecompressed: %d"), len_decompressed);
|
||||
rule = buf; // assign the raw string to the String object (in reality re-writing the same data in the same place)
|
||||
}
|
||||
#endif // USE_RULES_COMPRESSION
|
||||
|
||||
//
|
||||
// Read rule in memory, uncompress if needed
|
||||
|
@ -308,7 +311,7 @@ String GetRule(uint32_t idx) {
|
|||
// If out == nullptr, we are in dry-run mode, so don't keep rule in cache
|
||||
int32_t SetRule_compress(uint32_t idx, const char *in, size_t in_len, char *out, size_t out_len) {
|
||||
int32_t len_compressed;
|
||||
len_compressed = unishox_compress(in, in_len, out, out_len);
|
||||
len_compressed = compressor.unishox_compress(in, in_len, out, out_len);
|
||||
|
||||
if (len_compressed >= 0) { // negative means compression failed because of buffer too small, we leave the rule untouched
|
||||
// check if we need to store in cache
|
||||
|
@ -357,7 +360,7 @@ int32_t SetRule(uint32_t idx, const char *content, bool append = false) {
|
|||
int32_t len_compressed, len_uncompressed;
|
||||
|
||||
len_uncompressed = strlen(Settings.rules[idx]);
|
||||
len_compressed = unishox_compress(Settings.rules[idx], len_uncompressed, nullptr /* dry-run */, MAX_RULE_SIZE + 8);
|
||||
len_compressed = compressor.unishox_compress(Settings.rules[idx], len_uncompressed, nullptr /* dry-run */, MAX_RULE_SIZE + 8);
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("RUL: Stored uncompressed, would compress from %d to %d (-%d%%)"), len_uncompressed, len_compressed, 100 - changeUIntScale(len_compressed, 0, len_uncompressed, 0, 100));
|
||||
}
|
||||
|
||||
|
|
|
@ -233,7 +233,7 @@ void HAssAnnounceRelayLight(void)
|
|||
} else {
|
||||
if (Settings.flag.hass_discovery && (RelayX || (Light.device > 0) && (max_lights > 0)) && !err_flag )
|
||||
{ // SetOption19 - Control Home Assistantautomatic discovery (See SetOption59)
|
||||
char name[33 + 2]; // friendlyname(33) + " " + index
|
||||
char name[TOPSZ]; // friendlyname(33) + " " + index
|
||||
char value_template[33];
|
||||
char prefix[TOPSZ];
|
||||
char *command_topic = stemp1;
|
||||
|
@ -241,9 +241,9 @@ void HAssAnnounceRelayLight(void)
|
|||
char *availability_topic = stemp3;
|
||||
|
||||
if (i > MAX_FRIENDLYNAMES) {
|
||||
snprintf_P(name, sizeof(name), PSTR("%s %d"), SettingsText(SET_FRIENDLYNAME1), i-1);
|
||||
snprintf_P(name, sizeof(name), PSTR("%s %s %d"), SettingsText(SET_DEVICENAME), SettingsText(SET_FRIENDLYNAME1), i-1);
|
||||
} else {
|
||||
snprintf_P(name, sizeof(name), SettingsText(SET_FRIENDLYNAME1 + i-1));
|
||||
snprintf_P(name, sizeof(name), PSTR ("%s %s"), SettingsText(SET_DEVICENAME), SettingsText(SET_FRIENDLYNAME1 + i-1));
|
||||
}
|
||||
|
||||
GetPowerDevice(value_template, i, sizeof(value_template), Settings.flag.device_index_enable); // SetOption26 - Switch between POWER or POWER1
|
||||
|
@ -339,7 +339,7 @@ void HAssAnnouncerTriggers(uint8_t device, uint8_t present, uint8_t key, uint8_t
|
|||
snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/device_automation/%s/config"), unique_id);
|
||||
|
||||
if (Settings.flag.hass_discovery && present) { // SetOption19 - Control Home Assistantautomatic discovery (See SetOption59)
|
||||
char name[33 + 6]; // friendlyname(33) + " " + "BTN" + " " + index
|
||||
char name[TOPSZ]; // friendlyname(33) + " " + "BTN" + " " + index
|
||||
char value_template[33];
|
||||
char prefix[TOPSZ];
|
||||
char *state_topic = stemp1;
|
||||
|
@ -391,7 +391,7 @@ void HAssAnnouncerBinSensors(uint8_t device, uint8_t present, uint8_t dual, uint
|
|||
|
||||
if (Settings.flag.hass_discovery && present ) { // SetOption19 - Control Home Assistantautomatic discovery (See SetOption59)
|
||||
if (!toggle || dual) {
|
||||
char name[33 + 6]; // friendlyname(33) + " " + "BTN" + " " + index
|
||||
char name[TOPSZ]; // friendlyname(33) + " " + "BTN" + " " + index
|
||||
char value_template[33];
|
||||
char prefix[TOPSZ];
|
||||
char *state_topic = stemp1;
|
||||
|
@ -403,7 +403,7 @@ void HAssAnnouncerBinSensors(uint8_t device, uint8_t present, uint8_t dual, uint
|
|||
GetTopic_P(state_topic, STAT, mqtt_topic, jsoname);
|
||||
GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT);
|
||||
|
||||
snprintf_P(name, sizeof(name), PSTR("%s Switch%d"), ModuleName().c_str(), device + 1);
|
||||
snprintf_P(name, sizeof(name), PSTR("%s Switch%d"), SettingsText(SET_DEVICENAME), device + 1);
|
||||
Response_P(HASS_DISCOVER_BASE, name, state_topic, availability_topic);
|
||||
if (!pir) {
|
||||
TryResponseAppend_P(HASS_DISCOVER_BIN_SWITCH, PSTR(D_RSLT_STATE), SettingsText(SET_STATE_TXT2), SettingsText(SET_STATE_TXT1));
|
||||
|
@ -553,13 +553,13 @@ void HAssAnnounceSensor(const char *sensorname, const char *subsensortype, const
|
|||
|
||||
if (Settings.flag.hass_discovery)
|
||||
{ // SetOption19 - Control Home Assistantautomatic discovery (See SetOption59)
|
||||
char name[33 + 42]; // friendlyname(33) + " " + sensorname(20?) + " " + sensortype(20?)
|
||||
char name[TOPSZ]; // friendlyname(33) + " " + sensorname(20?) + " " + sensortype(20?)
|
||||
char prefix[TOPSZ];
|
||||
char *state_topic = stemp1;
|
||||
char *availability_topic = stemp2;
|
||||
|
||||
GetTopic_P(state_topic, TELE, mqtt_topic, PSTR(D_RSLT_SENSOR));
|
||||
snprintf_P(name, sizeof(name), PSTR("%s %s %s"), ModuleName().c_str(), sensorname, MultiSubName);
|
||||
snprintf_P(name, sizeof(name), PSTR("%s %s %s"), SettingsText(SET_DEVICENAME), sensorname, MultiSubName);
|
||||
GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT);
|
||||
|
||||
Response_P(HASS_DISCOVER_BASE, name, state_topic, availability_topic);
|
||||
|
@ -694,18 +694,18 @@ void HAssAnnounceDeviceInfoAndStatusSensor(void)
|
|||
|
||||
if (Settings.flag.hass_discovery)
|
||||
{ // SetOption19 - Control Home Assistantautomatic discovery (See SetOption59)
|
||||
char name[33 + 7]; // friendlyname(33) + " " + "status"
|
||||
char name[TOPSZ]; // friendlyname(33) + " " + "status"
|
||||
char prefix[TOPSZ];
|
||||
char *state_topic = stemp1;
|
||||
char *availability_topic = stemp2;
|
||||
|
||||
snprintf_P(name, sizeof(name), PSTR("%s status"), ModuleName().c_str());
|
||||
snprintf_P(name, sizeof(name), PSTR("%s status"), SettingsText(SET_DEVICENAME));
|
||||
GetTopic_P(state_topic, TELE, mqtt_topic, PSTR(D_RSLT_HASS_STATE));
|
||||
GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT);
|
||||
|
||||
Response_P(HASS_DISCOVER_BASE, name, state_topic, availability_topic);
|
||||
TryResponseAppend_P(HASS_DISCOVER_SENSOR_HASS_STATUS, state_topic);
|
||||
TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO, unique_id, ESP_getChipId(), ModuleName().c_str(),
|
||||
TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO, unique_id, ESP_getChipId(), SettingsText(SET_DEVICENAME),
|
||||
ModuleName().c_str(), my_version, my_image);
|
||||
TryResponseAppend_P(PSTR("}"));
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
typedef uint64_t Z_IEEEAddress;
|
||||
typedef uint16_t Z_ShortAddress;
|
||||
|
||||
const uint16_t BAD_SHORTADDR = 0xFFFE;
|
||||
|
||||
enum ZnpCommandType {
|
||||
Z_POLL = 0x00,
|
||||
Z_SREQ = 0x20,
|
||||
|
|
|
@ -103,7 +103,7 @@ public:
|
|||
// Probe the existence of device keys
|
||||
// Results:
|
||||
// - 0x0000 = not found
|
||||
// - 0xFFFF = bad parameter
|
||||
// - BAD_SHORTADDR = bad parameter
|
||||
// - 0x<shortaddr> = the device's short address
|
||||
uint16_t isKnownShortAddr(uint16_t shortaddr) const;
|
||||
uint16_t isKnownLongAddr(uint64_t longaddr) const;
|
||||
|
@ -295,18 +295,16 @@ void Z_Devices::freeDeviceEntry(Z_Device *device) {
|
|||
// Scan all devices to find a corresponding shortaddr
|
||||
// Looks info device.shortaddr entry
|
||||
// In:
|
||||
// shortaddr (non null)
|
||||
// shortaddr (not BAD_SHORTADDR)
|
||||
// Out:
|
||||
// index in _devices of entry, -1 if not found
|
||||
//
|
||||
int32_t Z_Devices::findShortAddr(uint16_t shortaddr) const {
|
||||
if (!shortaddr) { return -1; } // does not make sense to look for 0x0000 shortaddr (localhost)
|
||||
if (BAD_SHORTADDR == shortaddr) { return -1; } // does not make sense to look for BAD_SHORTADDR shortaddr (broadcast)
|
||||
int32_t found = 0;
|
||||
if (shortaddr) {
|
||||
for (auto &elem : _devices) {
|
||||
if (elem->shortaddr == shortaddr) { return found; }
|
||||
found++;
|
||||
}
|
||||
for (auto &elem : _devices) {
|
||||
if (elem->shortaddr == shortaddr) { return found; }
|
||||
found++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -321,11 +319,9 @@ int32_t Z_Devices::findShortAddr(uint16_t shortaddr) const {
|
|||
int32_t Z_Devices::findLongAddr(uint64_t longaddr) const {
|
||||
if (!longaddr) { return -1; }
|
||||
int32_t found = 0;
|
||||
if (longaddr) {
|
||||
for (auto &elem : _devices) {
|
||||
if (elem->longaddr == longaddr) { return found; }
|
||||
found++;
|
||||
}
|
||||
for (auto &elem : _devices) {
|
||||
if (elem->longaddr == longaddr) { return found; }
|
||||
found++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -358,7 +354,7 @@ uint16_t Z_Devices::isKnownShortAddr(uint16_t shortaddr) const {
|
|||
if (found >= 0) {
|
||||
return shortaddr;
|
||||
} else {
|
||||
return 0; // unknown
|
||||
return BAD_SHORTADDR; // unknown
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -368,7 +364,7 @@ uint16_t Z_Devices::isKnownLongAddr(uint64_t longaddr) const {
|
|||
const Z_Device & device = devicesAt(found);
|
||||
return device.shortaddr; // can be zero, if not yet registered
|
||||
} else {
|
||||
return 0;
|
||||
return BAD_SHORTADDR;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -377,18 +373,18 @@ uint16_t Z_Devices::isKnownIndex(uint32_t index) const {
|
|||
const Z_Device & device = devicesAt(index);
|
||||
return device.shortaddr;
|
||||
} else {
|
||||
return 0;
|
||||
return BAD_SHORTADDR;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t Z_Devices::isKnownFriendlyName(const char * name) const {
|
||||
if ((!name) || (0 == strlen(name))) { return 0xFFFF; } // Error
|
||||
if ((!name) || (0 == strlen(name))) { return BAD_SHORTADDR; } // Error
|
||||
int32_t found = findFriendlyName(name);
|
||||
if (found >= 0) {
|
||||
const Z_Device & device = devicesAt(found);
|
||||
return device.shortaddr; // can be zero, if not yet registered
|
||||
} else {
|
||||
return 0;
|
||||
return BAD_SHORTADDR;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -398,10 +394,10 @@ uint64_t Z_Devices::getDeviceLongAddr(uint16_t shortaddr) const {
|
|||
}
|
||||
|
||||
//
|
||||
// We have a seen a shortaddr on the network, get the corresponding
|
||||
// We have a seen a shortaddr on the network, get the corresponding device object
|
||||
//
|
||||
Z_Device & Z_Devices::getShortAddr(uint16_t shortaddr) {
|
||||
if (!shortaddr) { return *(Z_Device*) nullptr; } // this is not legal
|
||||
if (BAD_SHORTADDR == shortaddr) { return *(Z_Device*) nullptr; } // this is not legal
|
||||
int32_t found = findShortAddr(shortaddr);
|
||||
if (found >= 0) {
|
||||
return *(_devices[found]);
|
||||
|
@ -411,7 +407,7 @@ Z_Device & Z_Devices::getShortAddr(uint16_t shortaddr) {
|
|||
}
|
||||
// Same version but Const
|
||||
const Z_Device & Z_Devices::getShortAddrConst(uint16_t shortaddr) const {
|
||||
if (!shortaddr) { return *(Z_Device*) nullptr; } // this is not legal
|
||||
if (BAD_SHORTADDR == shortaddr) { return *(Z_Device*) nullptr; } // this is not legal
|
||||
int32_t found = findShortAddr(shortaddr);
|
||||
if (found >= 0) {
|
||||
return *(_devices[found]);
|
||||
|
@ -471,7 +467,7 @@ void Z_Devices::updateDevice(uint16_t shortaddr, uint64_t longaddr) {
|
|||
dirty();
|
||||
} else {
|
||||
// neither short/lonf addr are found.
|
||||
if (shortaddr || longaddr) {
|
||||
if ((BAD_SHORTADDR != shortaddr) || longaddr) {
|
||||
createDeviceEntry(shortaddr, longaddr);
|
||||
}
|
||||
}
|
||||
|
@ -481,7 +477,6 @@ void Z_Devices::updateDevice(uint16_t shortaddr, uint64_t longaddr) {
|
|||
// Clear all endpoints
|
||||
//
|
||||
void Z_Devices::clearEndpoints(uint16_t shortaddr) {
|
||||
if (!shortaddr) { return; }
|
||||
Z_Device &device = getShortAddr(shortaddr);
|
||||
if (&device == nullptr) { return; } // don't crash if not found
|
||||
|
||||
|
@ -495,7 +490,6 @@ void Z_Devices::clearEndpoints(uint16_t shortaddr) {
|
|||
// Add an endpoint to a shortaddr
|
||||
//
|
||||
void Z_Devices::addEndpoint(uint16_t shortaddr, uint8_t endpoint) {
|
||||
if (!shortaddr) { return; }
|
||||
if (0x00 == endpoint) { return; }
|
||||
Z_Device &device = getShortAddr(shortaddr);
|
||||
if (&device == nullptr) { return; } // don't crash if not found
|
||||
|
@ -922,7 +916,7 @@ uint16_t Z_Devices::parseDeviceParam(const char * param, bool short_must_be_know
|
|||
char dataBuf[param_len + 1];
|
||||
strcpy(dataBuf, param);
|
||||
RemoveSpace(dataBuf);
|
||||
uint16_t shortaddr = 0;
|
||||
uint16_t shortaddr = BAD_SHORTADDR; // start with unknown
|
||||
|
||||
if (strlen(dataBuf) < 4) {
|
||||
// simple number 0..99
|
||||
|
@ -1018,8 +1012,8 @@ String Z_Devices::dump(uint32_t dump_mode, uint16_t status_shortaddr) const {
|
|||
uint16_t shortaddr = device.shortaddr;
|
||||
char hex[22];
|
||||
|
||||
// ignore non-current device, if specified device is non-zero
|
||||
if ((status_shortaddr) && (status_shortaddr != shortaddr)) { continue; }
|
||||
// ignore non-current device, if device specified
|
||||
if ((BAD_SHORTADDR != status_shortaddr) && (status_shortaddr != shortaddr)) { continue; }
|
||||
|
||||
JsonObject& dev = devices.createNestedObject();
|
||||
|
||||
|
|
|
@ -66,41 +66,6 @@ public:
|
|||
const static uint32_t ZIGB_NAME = 0x3167697A; // 'zig1' little endian
|
||||
const static size_t Z_MAX_FLASH = z_block_len - sizeof(z_flashdata_t); // 2040
|
||||
|
||||
// encoding for the most commonly 32 clusters, used for binary encoding
|
||||
const uint16_t Z_ClusterNumber[] PROGMEM = {
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
|
||||
0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
|
||||
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
|
||||
0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
|
||||
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
|
||||
0x0100, 0x0101, 0x0102,
|
||||
0x0201, 0x0202, 0x0203, 0x0204,
|
||||
0x0300, 0x0301,
|
||||
0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406,
|
||||
0x0500, 0x0501, 0x0502,
|
||||
0x0700, 0x0701, 0x0702,
|
||||
0x0B00, 0x0B01, 0x0B02, 0x0B03, 0x0B04, 0x0B05,
|
||||
0x1000,
|
||||
0xFC0F,
|
||||
};
|
||||
|
||||
// convert a 1 byte cluster code to the actual cluster number
|
||||
uint16_t fromClusterCode(uint8_t c) {
|
||||
if (c >= ARRAY_SIZE(Z_ClusterNumber)) {
|
||||
return 0xFFFF; // invalid
|
||||
}
|
||||
return pgm_read_word(&Z_ClusterNumber[c]);
|
||||
}
|
||||
|
||||
// convert a cluster number to 1 byte, or 0xFF if not in table
|
||||
uint8_t toClusterCode(uint16_t c) {
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(Z_ClusterNumber); i++) {
|
||||
if (c == pgm_read_word(&Z_ClusterNumber[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0xFF; // not found
|
||||
}
|
||||
|
||||
class SBuffer hibernateDevice(const struct Z_Device &device) {
|
||||
SBuffer buf(128);
|
||||
|
@ -202,18 +167,8 @@ void hydrateDevices(const SBuffer &buf) {
|
|||
for (uint32_t i = 0; (i < num_devices) && (k < buf_len); i++) {
|
||||
uint32_t dev_record_len = buf.get8(k);
|
||||
|
||||
// AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Device %d Before Memory = %d // DIFF %d // record_len %d"), i, ESP_getFreeHeap(), before - ESP_getFreeHeap(), dev_record_len);
|
||||
// before = ESP_getFreeHeap();
|
||||
|
||||
SBuffer buf_d = buf.subBuffer(k, dev_record_len);
|
||||
|
||||
// char *hex_char = (char*) malloc((dev_record_len * 2) + 2);
|
||||
// if (hex_char) {
|
||||
// AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "/// SUB %s"),
|
||||
// ToHex_P(buf_d.getBuffer(), dev_record_len, hex_char, (dev_record_len * 2) + 2));
|
||||
// free(hex_char);
|
||||
// }
|
||||
|
||||
uint32_t d = 1; // index in device buffer
|
||||
uint16_t shortaddr = buf_d.get16(d); d += 2;
|
||||
uint64_t longaddr = buf_d.get64(d); d += 8;
|
||||
|
|
|
@ -79,16 +79,6 @@ uint8_t Z_getDatatypeLen(uint8_t t) {
|
|||
}
|
||||
}
|
||||
|
||||
// typedef struct Z_DataTypeMapping {
|
||||
// uint8_t datatype;
|
||||
// uint8_t len; // len in bytes and add 0x80 if DISCRETE
|
||||
// }
|
||||
|
||||
// const Z_DataTypeMapping Z_types[] PROGMEM = {
|
||||
// { Znodata, 0 },
|
||||
// { Zdata8, 0 },
|
||||
// };
|
||||
|
||||
typedef union ZCLHeaderFrameControl_t {
|
||||
struct {
|
||||
uint8_t frame_type : 2; // 00 = across entire profile, 01 = cluster specific
|
||||
|
@ -572,6 +562,9 @@ typedef struct Z_AttributeConverter {
|
|||
Z_AttrConverter func;
|
||||
} Z_AttributeConverter;
|
||||
|
||||
// Cluster numbers are store in 8 bits format to save space,
|
||||
// the following tables allows the conversion from 8 bits index Cx...
|
||||
// to the 16 bits actual cluster number
|
||||
enum Cx_cluster_short {
|
||||
Cx0000, Cx0001, Cx0002, Cx0003, Cx0004, Cx0005, Cx0006, Cx0007,
|
||||
Cx0008, Cx0009, Cx000A, Cx000B, Cx000C, Cx000D, Cx000E, Cx000F,
|
||||
|
|
|
@ -177,6 +177,9 @@ int32_t Z_ReadAttrCallback(uint16_t shortaddr, uint16_t groupaddr, uint16_t clus
|
|||
break;
|
||||
}
|
||||
if (attrs) {
|
||||
if (groupaddr) {
|
||||
shortaddr = BAD_SHORTADDR; // if group address, don't send to device
|
||||
}
|
||||
ZigbeeZCLSend_Raw(shortaddr, groupaddr, cluster, endpoint, ZCL_READ_ATTRIBUTES, false, 0, attrs, attrs_len, true /* we do want a response */, zigbee_devices.getNextSeqNumber(shortaddr));
|
||||
}
|
||||
}
|
||||
|
@ -184,7 +187,7 @@ int32_t Z_ReadAttrCallback(uint16_t shortaddr, uint16_t groupaddr, uint16_t clus
|
|||
|
||||
// This callback is registered after a an attribute read command was made to a light, and fires if we don't get any response after 1000 ms
|
||||
int32_t Z_Unreachable(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value) {
|
||||
if (shortaddr) {
|
||||
if (BAD_SHORTADDR != shortaddr) {
|
||||
zigbee_devices.setReachable(shortaddr, false); // mark device as reachable
|
||||
}
|
||||
}
|
||||
|
@ -208,7 +211,7 @@ void zigbeeSetCommandTimer(uint16_t shortaddr, uint16_t groupaddr, uint16_t clus
|
|||
}
|
||||
if (wait_ms) {
|
||||
zigbee_devices.setTimer(shortaddr, groupaddr, wait_ms, cluster, endpoint, Z_CAT_NONE, 0 /* value */, &Z_ReadAttrCallback);
|
||||
if (shortaddr) { // reachability test is not possible for group addresses, since we don't know the list of devices in the group
|
||||
if (BAD_SHORTADDR != shortaddr) { // reachability test is not possible for group addresses, since we don't know the list of devices in the group
|
||||
zigbee_devices.setTimer(shortaddr, groupaddr, wait_ms + Z_CAT_REACHABILITY_TIMEOUT, cluster, endpoint, Z_CAT_REACHABILITY, 0 /* value */, &Z_Unreachable);
|
||||
}
|
||||
}
|
||||
|
@ -314,12 +317,12 @@ void sendHueUpdate(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uin
|
|||
}
|
||||
if (z_cat >= 0) {
|
||||
uint8_t endpoint = 0;
|
||||
if (shortaddr) {
|
||||
if (BAD_SHORTADDR != shortaddr) {
|
||||
endpoint = zigbee_devices.findFirstEndpoint(shortaddr);
|
||||
}
|
||||
if ((!shortaddr) || (endpoint)) { // send if group address or endpoint is known
|
||||
if ((BAD_SHORTADDR == shortaddr) || (endpoint)) { // send if group address or endpoint is known
|
||||
zigbee_devices.setTimer(shortaddr, groupaddr, wait_ms, cluster, endpoint, z_cat, 0 /* value */, &Z_ReadAttrCallback);
|
||||
if (shortaddr) { // reachability test is not possible for group addresses, since we don't know the list of devices in the group
|
||||
if (BAD_SHORTADDR != shortaddr) { // reachability test is not possible for group addresses, since we don't know the list of devices in the group
|
||||
zigbee_devices.setTimer(shortaddr, groupaddr, wait_ms + Z_CAT_REACHABILITY_TIMEOUT, cluster, endpoint, Z_CAT_REACHABILITY, 0 /* value */, &Z_Unreachable);
|
||||
}
|
||||
|
||||
|
|
|
@ -584,18 +584,6 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = {
|
|||
ZI_WAIT_RECV(1000, ZBS_LOGTYPE_DEVICE) // it should be coordinator
|
||||
|
||||
ZI_GOTO(ZIGBEE_LABEL_START_ROUTER)
|
||||
// Device and Router code is common from now
|
||||
// ZI_LABEL(ZIGBEE_LABEL_START_DEVICE) // Init as a router
|
||||
// ZI_MQTT_STATE(ZIGBEE_STATUS_STARTING, kConfiguredDevice)
|
||||
// ZI_ON_ERROR_GOTO(ZIGBEE_LABEL_ABORT)
|
||||
// ZI_SEND(ZBS_AF_REGISTER_ALL) // Z_AF register for endpoint 01, profile 0x0104 Home Automation
|
||||
// ZI_WAIT_RECV(1000, ZBR_AF_REGISTER)
|
||||
// ZI_SEND(ZBS_STARTUPFROMAPP) // start router
|
||||
// ZI_WAIT_RECV(2000, ZBR_STARTUPFROMAPP) // wait for sync ack of command
|
||||
// ZI_WAIT_UNTIL_FUNC(0xFFFF, AREQ_STARTUPFROMAPP, &Z_ReceiveStateChange) // wait forever for async message that coordinator started
|
||||
// ZI_SEND(ZBS_GETDEVICEINFO) // GetDeviceInfo
|
||||
// ZI_WAIT_RECV_FUNC(2000, ZBR_GETDEVICEINFO, &Z_ReceiveDeviceInfo)
|
||||
// ZI_GOTO(ZIGBEE_LABEL_READY)
|
||||
|
||||
ZI_LABEL(ZIGBEE_LABEL_FACT_RESET_DEVICE) // Factory reset for router
|
||||
ZI_MQTT_STATE(ZIGBEE_STATUS_RESET_CONF, kResetting)
|
||||
|
@ -608,25 +596,12 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = {
|
|||
ZI_WAIT_RECV(1000, ZBR_W_OK)
|
||||
ZI_GOTO(ZIGBEE_LABEL_FACT_RESET_ROUTER_DEVICE_POST)
|
||||
|
||||
// ZI_SEND(ZBS_W_ALL_PAN) // write universal PAN ID = 0xFFFF
|
||||
// ZI_WAIT_RECV(1000, ZBR_W_OK)
|
||||
// ZI_SEND(ZBS_W_ALL_CHANN) // write Allows all CHANNELS = 0x07FFF800, 11-26
|
||||
// ZI_WAIT_RECV(1000, ZBR_W_OK)
|
||||
|
||||
// // Now mark the device as ready, writing 0x55 in memory slot 0x0F00
|
||||
// ZI_SEND(ZBS_WNV_INITZNPHC) // Init NV ZNP Has Configured
|
||||
// ZI_WAIT_RECV_FUNC(1000, ZBR_WNV_INIT_OK, &Z_CheckNVWrite)
|
||||
// ZI_SEND(ZBS_WNV_ZNPHC) // Write NV ZNP Has Configured
|
||||
// ZI_WAIT_RECV(1000, ZBR_WNV_OK)
|
||||
|
||||
// ZI_GOTO(ZIGBEE_LABEL_START_ROUTER)
|
||||
// ZI_GOTO(ZIGBEE_LABEL_START_DEVICE)
|
||||
|
||||
|
||||
// Error: version of Z-Stack is not supported
|
||||
ZI_LABEL(ZIGBEE_LABEL_UNSUPPORTED_VERSION)
|
||||
ZI_MQTT_STATE(ZIGBEE_STATUS_UNSUPPORTED_VERSION, kZNP12)
|
||||
ZI_GOTO(ZIGBEE_LABEL_ABORT)
|
||||
|
||||
// Abort state machine, general error
|
||||
ZI_LABEL(ZIGBEE_LABEL_ABORT) // Label 99: abort
|
||||
ZI_MQTT_STATE(ZIGBEE_STATUS_ABORT, kAbort)
|
||||
ZI_LOG(LOG_LEVEL_ERROR, kZigbeeAbort)
|
||||
|
|
|
@ -52,7 +52,7 @@ int32_t Z_ReceiveDeviceInfo(int32_t res, class SBuffer &buf) {
|
|||
ZIGBEE_STATUS_CC_INFO, hex, short_adr, device_type, device_state,
|
||||
device_associated);
|
||||
|
||||
if (device_associated > 0) {
|
||||
if (device_associated > 0) { // If there are devices registered in CC2530, print the list
|
||||
uint idx = 16;
|
||||
ResponseAppend_P(PSTR(",\"AssocDevicesList\":["));
|
||||
for (uint32_t i = 0; i < device_associated; i++) {
|
||||
|
@ -87,18 +87,20 @@ int32_t Z_Reboot(int32_t res, class SBuffer &buf) {
|
|||
// print information about the reboot of device
|
||||
// 4180.02.02.00.02.06.03
|
||||
//
|
||||
static const char Z_RebootReason[] PROGMEM = "Power-up|External|Watchdog";
|
||||
|
||||
uint8_t reason = buf.get8(2);
|
||||
uint8_t transport_rev = buf.get8(3);
|
||||
uint8_t product_id = buf.get8(4);
|
||||
uint8_t major_rel = buf.get8(5);
|
||||
uint8_t minor_rel = buf.get8(6);
|
||||
uint8_t hw_rev = buf.get8(7);
|
||||
char reason_str[12];
|
||||
const char *reason_str;
|
||||
|
||||
if (reason > 3) { reason = 3; }
|
||||
GetTextIndexed(reason_str, sizeof(reason_str), reason, Z_RebootReason);
|
||||
switch (reason) {
|
||||
case 0: reason_str = PSTR("Power-up"); break;
|
||||
case 1: reason_str = PSTR("External"); break;
|
||||
case 2: reason_str = PSTR("Watchdog"); break;
|
||||
default: reason_str = PSTR("Unknown"); break;
|
||||
}
|
||||
|
||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{"
|
||||
"\"Status\":%d,\"Message\":\"CC2530 booted\",\"RestartReason\":\"%s\""
|
||||
|
@ -201,7 +203,6 @@ int32_t Z_ReceivePermitJoinStatus(int32_t res, const class SBuffer &buf) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
const char* Z_DeviceType[] = { "Coordinator", "Router", "End Device", "Unknown" };
|
||||
int32_t Z_ReceiveNodeDesc(int32_t res, const class SBuffer &buf) {
|
||||
// Received ZDO_NODE_DESC_RSP
|
||||
Z_ShortAddress srcAddr = buf.get16(2);
|
||||
|
@ -217,15 +218,22 @@ int32_t Z_ReceiveNodeDesc(int32_t res, const class SBuffer &buf) {
|
|||
uint16_t maxOutTransferSize = buf.get16(17);
|
||||
uint8_t descriptorCapabilities = buf.get8(19);
|
||||
|
||||
|
||||
if (0 == status) {
|
||||
uint8_t deviceType = logicalType & 0x7; // 0=coordinator, 1=router, 2=end device
|
||||
if (deviceType > 3) { deviceType = 3; }
|
||||
const char * deviceTypeStr;
|
||||
switch (deviceType) {
|
||||
case 0: deviceTypeStr = PSTR("Coordinator"); break;
|
||||
case 1: deviceTypeStr = PSTR("Router"); break;
|
||||
case 2: deviceTypeStr = PSTR("Device"); break;
|
||||
default: deviceTypeStr = PSTR("Unknown"); break;
|
||||
}
|
||||
bool complexDescriptorAvailable = (logicalType & 0x08) ? 1 : 0;
|
||||
|
||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{"
|
||||
"\"Status\":%d,\"NodeType\":\"%s\",\"ComplexDesc\":%s}}"),
|
||||
ZIGBEE_STATUS_NODE_DESC, Z_DeviceType[deviceType],
|
||||
complexDescriptorAvailable ? "true" : "false"
|
||||
ZIGBEE_STATUS_NODE_DESC, deviceTypeStr,
|
||||
complexDescriptorAvailable ? PSTR("true") : PSTR("false")
|
||||
);
|
||||
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED));
|
||||
|
@ -282,15 +290,13 @@ int32_t Z_ReceiveIEEEAddr(int32_t res, const class SBuffer &buf) {
|
|||
Uint64toHex(ieeeAddr, hex, 64);
|
||||
// Ping response
|
||||
const char * friendlyName = zigbee_devices.getFriendlyName(nwkAddr);
|
||||
|
||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_PING "\":{\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\""
|
||||
",\"" D_JSON_ZIGBEE_IEEE "\":\"0x%s\""), nwkAddr, hex);
|
||||
if (friendlyName) {
|
||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_PING "\":{\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\""
|
||||
",\"" D_JSON_ZIGBEE_IEEE "\":\"0x%s\""
|
||||
",\"" D_JSON_ZIGBEE_NAME "\":\"%s\"}}"), nwkAddr, hex, friendlyName);
|
||||
} else {
|
||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_PING "\":{\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\""
|
||||
",\"" D_JSON_ZIGBEE_IEEE "\":\"0x%s\""
|
||||
"}}"), nwkAddr, hex);
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_ZIGBEE_NAME "\":\"%s\""), friendlyName);
|
||||
}
|
||||
ResponseAppend_P(PSTR("\"}}"));
|
||||
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED));
|
||||
XdrvRulesProcess();
|
||||
|
@ -398,9 +404,9 @@ int32_t Z_ReceiveEndDeviceAnnonce(int32_t res, const class SBuffer &buf) {
|
|||
"\"Status\":%d,\"IEEEAddr\":\"0x%s\",\"ShortAddr\":\"0x%04X\""
|
||||
",\"PowerSource\":%s,\"ReceiveWhenIdle\":%s,\"Security\":%s}}"),
|
||||
ZIGBEE_STATUS_DEVICE_ANNOUNCE, hex, nwkAddr,
|
||||
(capabilities & 0x04) ? "true" : "false",
|
||||
(capabilities & 0x08) ? "true" : "false",
|
||||
(capabilities & 0x40) ? "true" : "false"
|
||||
(capabilities & 0x04) ? PSTR("true") : PSTR("false"),
|
||||
(capabilities & 0x08) ? PSTR("true") : PSTR("false"),
|
||||
(capabilities & 0x40) ? PSTR("true") : PSTR("false")
|
||||
);
|
||||
// query the state of the bulb (for Alexa)
|
||||
uint32_t wait_ms = 2000; // wait for 2s
|
||||
|
@ -444,18 +450,15 @@ int32_t Z_BindRsp(int32_t res, const class SBuffer &buf) {
|
|||
uint8_t status = buf.get8(4);
|
||||
|
||||
const char * friendlyName = zigbee_devices.getFriendlyName(nwkAddr);
|
||||
|
||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_BIND "\":{\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\""), nwkAddr);
|
||||
if (friendlyName) {
|
||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_BIND "\":{\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\""
|
||||
",\"" D_JSON_ZIGBEE_NAME "\":\"%s\""
|
||||
",\"" D_JSON_ZIGBEE_STATUS "\":%d"
|
||||
",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\""
|
||||
"}}"), nwkAddr, friendlyName, status, getZigbeeStatusMessage(status).c_str());
|
||||
} else {
|
||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_BIND "\":{\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\""
|
||||
",\"" D_JSON_ZIGBEE_STATUS "\":%d"
|
||||
",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\""
|
||||
"}}"), nwkAddr, status, getZigbeeStatusMessage(status).c_str());
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_ZIGBEE_NAME "\":\"%s\""), friendlyName);
|
||||
}
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_ZIGBEE_STATUS "\":%d"
|
||||
",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\""
|
||||
"}}"), status, getZigbeeStatusMessage(status).c_str());
|
||||
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED));
|
||||
XdrvRulesProcess();
|
||||
|
||||
|
@ -470,18 +473,14 @@ int32_t Z_UnbindRsp(int32_t res, const class SBuffer &buf) {
|
|||
uint8_t status = buf.get8(4);
|
||||
|
||||
const char * friendlyName = zigbee_devices.getFriendlyName(nwkAddr);
|
||||
|
||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_UNBIND "\":{\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\""), nwkAddr);
|
||||
if (friendlyName) {
|
||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_UNBIND "\":{\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\""
|
||||
",\"" D_JSON_ZIGBEE_NAME "\":\"%s\""
|
||||
",\"" D_JSON_ZIGBEE_STATUS "\":%d"
|
||||
",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\""
|
||||
"}}"), nwkAddr, friendlyName, status, getZigbeeStatusMessage(status).c_str());
|
||||
} else {
|
||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_UNBIND "\":{\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\""
|
||||
",\"" D_JSON_ZIGBEE_STATUS "\":%d"
|
||||
",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\""
|
||||
"}}"), nwkAddr, status, getZigbeeStatusMessage(status).c_str());
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_ZIGBEE_NAME "\":\"%s\""), friendlyName);
|
||||
}
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\""
|
||||
"}}"), status, getZigbeeStatusMessage(status).c_str());
|
||||
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED));
|
||||
XdrvRulesProcess();
|
||||
|
||||
|
@ -506,7 +505,6 @@ int32_t Z_MgmtBindRsp(int32_t res, const class SBuffer &buf) {
|
|||
ResponseAppend_P(PSTR(",\"" D_JSON_ZIGBEE_STATUS "\":%d"
|
||||
",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\""
|
||||
",\"BindingsTotal\":%d"
|
||||
//",\"BindingsStart\":%d"
|
||||
",\"Bindings\":["
|
||||
), status, getZigbeeStatusMessage(status).c_str(), bind_total);
|
||||
|
||||
|
@ -631,7 +629,7 @@ int32_t Z_PublishAttributes(uint16_t shortaddr, uint16_t groupaddr, uint16_t clu
|
|||
int32_t Z_ReceiveAfIncomingMessage(int32_t res, const class SBuffer &buf) {
|
||||
uint16_t groupid = buf.get16(2);
|
||||
uint16_t clusterid = buf.get16(4);
|
||||
Z_ShortAddress srcaddr = buf.get16(6);
|
||||
uint16_t srcaddr = buf.get16(6);
|
||||
uint8_t srcendpoint = buf.get8(8);
|
||||
uint8_t dstendpoint = buf.get8(9);
|
||||
uint8_t wasbroadcast = buf.get8(10);
|
||||
|
|
|
@ -147,7 +147,7 @@ void ZigbeeInputLoop(void)
|
|||
// Initialize internal structures
|
||||
void ZigbeeInit(void)
|
||||
{
|
||||
// Check if settings if Flash are set
|
||||
// Check if settings in Flash are set
|
||||
if (0 == Settings.zb_channel) {
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Initializing Zigbee parameters from defaults"));
|
||||
Settings.zb_ext_panid = USE_ZIGBEE_EXTPANID;
|
||||
|
@ -314,7 +314,7 @@ void ZigbeeZCLSend_Raw(uint16_t shortaddr, uint16_t groupaddr, uint16_t clusterI
|
|||
SBuffer buf(32+len);
|
||||
buf.add8(Z_SREQ | Z_AF); // 24
|
||||
buf.add8(AF_DATA_REQUEST_EXT); // 02
|
||||
if (0x0000 == shortaddr) { // if no shortaddr we assume group address
|
||||
if (BAD_SHORTADDR == shortaddr) { // if no shortaddr we assume group address
|
||||
buf.add8(Z_Addr_Group); // 01
|
||||
buf.add64(groupaddr); // group address, only 2 LSB, upper 6 MSB are discarded
|
||||
buf.add8(0xFF); // dest endpoint is not used for group addresses
|
||||
|
@ -372,7 +372,7 @@ void zigbeeZCLSendStr(uint16_t shortaddr, uint16_t groupaddr, uint8_t endpoint,
|
|||
}
|
||||
}
|
||||
|
||||
if ((0 == endpoint) && (shortaddr)) {
|
||||
if ((0 == endpoint) && (BAD_SHORTADDR != shortaddr)) {
|
||||
// endpoint is not specified, let's try to find it from shortAddr, unless it's a group address
|
||||
endpoint = zigbee_devices.findFirstEndpoint(shortaddr);
|
||||
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZbSend: guessing endpoint 0x%02X"), endpoint);
|
||||
|
@ -380,7 +380,7 @@ void zigbeeZCLSendStr(uint16_t shortaddr, uint16_t groupaddr, uint8_t endpoint,
|
|||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZbSend: shortaddr 0x%04X, groupaddr 0x%04X, cluster 0x%04X, endpoint 0x%02X, cmd 0x%02X, data %s"),
|
||||
shortaddr, groupaddr, cluster, endpoint, cmd, param);
|
||||
|
||||
if ((0 == endpoint) && (shortaddr)) { // endpoint null is ok for group address
|
||||
if ((0 == endpoint) && (BAD_SHORTADDR != shortaddr)) { // endpoint null is ok for group address
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("ZbSend: unspecified endpoint"));
|
||||
return;
|
||||
}
|
||||
|
@ -415,7 +415,7 @@ void CmndZbSend(void) {
|
|||
|
||||
// params
|
||||
static char delim[] = ", "; // delimiters for parameters
|
||||
uint16_t device = 0x0000; // 0x0000 is local, so considered invalid
|
||||
uint16_t device = BAD_SHORTADDR; // 0x0000 is local, so considered invalid
|
||||
uint16_t groupaddr = 0x0000; // group address
|
||||
uint8_t endpoint = 0x00; // 0x00 is invalid for the dst endpoint
|
||||
uint16_t manuf = 0x0000; // Manuf Id in ZCL frame
|
||||
|
@ -430,9 +430,9 @@ void CmndZbSend(void) {
|
|||
const JsonVariant &val_device = getCaseInsensitive(json, PSTR("Device"));
|
||||
if (nullptr != &val_device) {
|
||||
device = zigbee_devices.parseDeviceParam(val_device.as<char*>());
|
||||
if (0xFFFF == device) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; }
|
||||
if (BAD_SHORTADDR == device) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; }
|
||||
}
|
||||
if (0x0000 == device) { // if not found, check if we have a group
|
||||
if (BAD_SHORTADDR == device) { // if not found, check if we have a group
|
||||
const JsonVariant &val_group = getCaseInsensitive(json, PSTR("Group"));
|
||||
if (nullptr != &val_group) {
|
||||
groupaddr = strToUInt(val_group);
|
||||
|
@ -571,8 +571,8 @@ void ZbBindUnbind(bool unbind) { // false = bind, true = unbind
|
|||
|
||||
// params
|
||||
// static char delim[] = ", "; // delimiters for parameters
|
||||
uint16_t srcDevice = 0xFFFF; // 0xFFFF is broadcast, so considered invalid
|
||||
uint16_t dstDevice = 0xFFFF; // 0xFFFF is broadcast, so considered invalid
|
||||
uint16_t srcDevice = BAD_SHORTADDR; // BAD_SHORTADDR is broadcast, so considered invalid
|
||||
uint16_t dstDevice = BAD_SHORTADDR; // BAD_SHORTADDR is broadcast, so considered invalid
|
||||
uint64_t dstLongAddr = 0;
|
||||
uint8_t endpoint = 0x00; // 0x00 is invalid for the src endpoint
|
||||
uint8_t toendpoint = 0x00; // 0x00 is invalid for the dst endpoint
|
||||
|
@ -585,9 +585,8 @@ void ZbBindUnbind(bool unbind) { // false = bind, true = unbind
|
|||
const JsonVariant &val_device = getCaseInsensitive(json, PSTR("Device"));
|
||||
if (nullptr != &val_device) {
|
||||
srcDevice = zigbee_devices.parseDeviceParam(val_device.as<char*>());
|
||||
if (0xFFFF == srcDevice) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; }
|
||||
}
|
||||
if ((nullptr == &val_device) || (0x0000 == srcDevice)) { ResponseCmndChar_P(PSTR("Unknown source device")); return; }
|
||||
if ((nullptr == &val_device) || (BAD_SHORTADDR == srcDevice)) { ResponseCmndChar_P(PSTR("Unknown source device")); return; }
|
||||
// check if IEEE address is known
|
||||
uint64_t srcLongAddr = zigbee_devices.getDeviceLongAddr(srcDevice);
|
||||
if (0 == srcLongAddr) { ResponseCmndChar_P(PSTR("Unknown source IEEE address")); return; }
|
||||
|
@ -605,7 +604,7 @@ void ZbBindUnbind(bool unbind) { // false = bind, true = unbind
|
|||
const JsonVariant &dst_device = getCaseInsensitive(json, PSTR("ToDevice"));
|
||||
if (nullptr != &dst_device) {
|
||||
dstDevice = zigbee_devices.parseDeviceParam(dst_device.as<char*>());
|
||||
if (0xFFFF == dstDevice) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; }
|
||||
if (BAD_SHORTADDR == dstDevice) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; }
|
||||
if (0x0000 == dstDevice) {
|
||||
dstLongAddr = localIEEEAddr;
|
||||
} else {
|
||||
|
@ -622,8 +621,8 @@ void ZbBindUnbind(bool unbind) { // false = bind, true = unbind
|
|||
if (nullptr != &to_group) { toGroup = strToUInt(to_group); }
|
||||
|
||||
// make sure we don't have conflicting parameters
|
||||
if (toGroup && dstLongAddr) { ResponseCmndChar_P(PSTR("Cannot have both \"ToDevice\" and \"ToGroup\"")); return; }
|
||||
if (!toGroup && !dstLongAddr) { ResponseCmndChar_P(PSTR("Missing \"ToDevice\" or \"ToGroup\"")); return; }
|
||||
if (&to_group && dstLongAddr) { ResponseCmndChar_P(PSTR("Cannot have both \"ToDevice\" and \"ToGroup\"")); return; }
|
||||
if (!&to_group && !dstLongAddr) { ResponseCmndChar_P(PSTR("Missing \"ToDevice\" or \"ToGroup\"")); return; }
|
||||
|
||||
SBuffer buf(34);
|
||||
buf.add8(Z_SREQ | Z_ZDO);
|
||||
|
@ -670,8 +669,7 @@ void CmndZbUnbind(void) {
|
|||
void CmndZbBindState(void) {
|
||||
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
||||
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data);
|
||||
if (0x0000 == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
if (0xFFFF == shortaddr) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; }
|
||||
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
|
||||
SBuffer buf(10);
|
||||
buf.add8(Z_SREQ | Z_ZDO); // 25
|
||||
|
@ -695,8 +693,7 @@ void CmndZbProbe(void) {
|
|||
void CmndZbProbeOrPing(boolean probe) {
|
||||
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
||||
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data);
|
||||
if (0x0000 == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
if (0xFFFF == shortaddr) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; }
|
||||
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
|
||||
// everything is good, we can send the command
|
||||
Z_SendIEEEAddrReq(shortaddr);
|
||||
|
@ -731,8 +728,7 @@ void CmndZbName(void) {
|
|||
|
||||
// parse first part, <device_id>
|
||||
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data, true); // in case of short_addr, it must be already registered
|
||||
if (0x0000 == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
if (0xFFFF == shortaddr) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; }
|
||||
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
|
||||
if (p == nullptr) {
|
||||
const char * friendlyName = zigbee_devices.getFriendlyName(shortaddr);
|
||||
|
@ -763,8 +759,7 @@ void CmndZbModelId(void) {
|
|||
|
||||
// parse first part, <device_id>
|
||||
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data, true); // in case of short_addr, it must be already registered
|
||||
if (0x0000 == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
if (0xFFFF == shortaddr) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; }
|
||||
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
|
||||
if (p == nullptr) {
|
||||
const char * modelId = zigbee_devices.getModelId(shortaddr);
|
||||
|
@ -793,8 +788,7 @@ void CmndZbLight(void) {
|
|||
|
||||
// parse first part, <device_id>
|
||||
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data, true); // in case of short_addr, it must be already registered
|
||||
if (0x0000 == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
if (0xFFFF == shortaddr) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; }
|
||||
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
|
||||
if (p) {
|
||||
int8_t bulbtype = strtol(p, nullptr, 10);
|
||||
|
@ -817,8 +811,7 @@ void CmndZbLight(void) {
|
|||
void CmndZbForget(void) {
|
||||
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
||||
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data);
|
||||
if (0x0000 == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
if (0xFFFF == shortaddr) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; }
|
||||
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
|
||||
// everything is good, we can send the command
|
||||
if (zigbee_devices.removeDevice(shortaddr)) {
|
||||
|
@ -906,7 +899,7 @@ void CmndZbRead(void) {
|
|||
if (!json.success()) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; }
|
||||
|
||||
// params
|
||||
uint16_t device = 0xFFFF; // 0xFFFF is braodcast, so considered valid
|
||||
uint16_t device = BAD_SHORTADDR; // BAD_SHORTADDR is broadcast, so considered invalid
|
||||
uint16_t groupaddr = 0x0000; // if 0x0000 ignore group adress
|
||||
uint16_t cluster = 0x0000; // default to general cluster
|
||||
uint8_t endpoint = 0x00; // 0x00 is invalid for the dst endpoint
|
||||
|
@ -917,9 +910,9 @@ void CmndZbRead(void) {
|
|||
const JsonVariant &val_device = getCaseInsensitive(json, PSTR("Device"));
|
||||
if (nullptr != &val_device) {
|
||||
device = zigbee_devices.parseDeviceParam(val_device.as<char*>());
|
||||
if (0xFFFF == device) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; }
|
||||
if (BAD_SHORTADDR == device) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; }
|
||||
}
|
||||
if (0x0000 == device) { // if not found, check if we have a group
|
||||
if (BAD_SHORTADDR == device) { // if not found, check if we have a group
|
||||
const JsonVariant &val_group = getCaseInsensitive(json, PSTR("Group"));
|
||||
if (nullptr != &val_group) {
|
||||
groupaddr = strToUInt(val_group);
|
||||
|
@ -960,9 +953,9 @@ void CmndZbRead(void) {
|
|||
|
||||
if ((0 == endpoint) && (device)) { // try to compute the endpoint
|
||||
endpoint = zigbee_devices.findFirstEndpoint(device);
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZbSend: guessing endpoint 0x%02X"), endpoint);
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZbRead: guessing endpoint 0x%02X"), endpoint);
|
||||
}
|
||||
if (0x0000 == device) {
|
||||
if (BAD_SHORTADDR == device) {
|
||||
endpoint = 0xFF; // endpoint not used for group addresses
|
||||
}
|
||||
|
||||
|
@ -1012,9 +1005,8 @@ void CmndZbStatus(void) {
|
|||
if (ZigbeeSerial) {
|
||||
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
|
||||
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data);
|
||||
if (0xFFFF == shortaddr) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; }
|
||||
if (XdrvMailbox.payload > 0) {
|
||||
if (0x0000 == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
|
||||
}
|
||||
|
||||
String dump = zigbee_devices.dump(XdrvMailbox.index, shortaddr);
|
||||
|
|
|
@ -243,10 +243,10 @@ void CseSnsInit(void)
|
|||
|
||||
void CseDrvInit(void)
|
||||
{
|
||||
Cse.rx_buffer = (uint8_t*)(malloc(CSE_BUFFER_SIZE));
|
||||
if (Cse.rx_buffer != nullptr) {
|
||||
// if (PinUsed(GPIO_CSE7766_RX) && PinUsed(GPIO_CSE7766_TX)) {
|
||||
if (PinUsed(GPIO_CSE7766_RX)) {
|
||||
// if (PinUsed(GPIO_CSE7766_RX) && PinUsed(GPIO_CSE7766_TX)) {
|
||||
if (PinUsed(GPIO_CSE7766_RX)) {
|
||||
Cse.rx_buffer = (uint8_t*)(malloc(CSE_BUFFER_SIZE));
|
||||
if (Cse.rx_buffer != nullptr) {
|
||||
energy_flg = XNRG_02;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue