From 949248fa170298822c7f115e5e739b8e2da94c70 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Sun, 17 May 2020 10:37:42 +0200 Subject: [PATCH 01/10] Add unishox Python --- lib/Unishox-1.0-shadinger/python/unishox.py | 496 ++++++++++++++++++++ 1 file changed, 496 insertions(+) create mode 100644 lib/Unishox-1.0-shadinger/python/unishox.py diff --git a/lib/Unishox-1.0-shadinger/python/unishox.py b/lib/Unishox-1.0-shadinger/python/unishox.py new file mode 100644 index 000000000..bc8fc97e6 --- /dev/null +++ b/lib/Unishox-1.0-shadinger/python/unishox.py @@ -0,0 +1,496 @@ + + + + +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 +SHX_SET3 = 4 +SHX_SET4 = 5 +SHX_SET4A = 6 + +# char sets[][11] PROGMEM = +# {{ 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'}, +# {'.', ',', '-', '/', '?', '+', ' ', '(', ')', '$', '@'}, +# {';', '#', ':', '<', '^', '*', '"', '{', '}', '[', ']'}, +# {'=', '%', '\'', '>', '&', '_', '!', '\\', '|', '~', '`'}}; +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) ] + +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 ] + +# Input +# out = bytearray +def append_bits(out, ol, code, clen, state): + #print("Append bits {ol} {code} {clen} {state}".format(ol=ol, code=code, clen=clen, state=state)) + 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 = 8 if (clen > 8) else clen + a_byte = (code >> 8) & 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): + # we completed a full byte + last_c = out[(ol // 8) - 1] + if ((0 == last_c) or (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 + + +codes = [ 0x82, 0xC3, 0xE5, 0xED, 0xF5 ] +bit_len = [ 5, 7, 9, 12, 16 ] + +def encodeCount(out, ol, count): + #print("encodeCount ol = {ol}, count = {count}".format(ol=ol, count=count)) + till = 0 + base = 0 + for i in range(len(bit_len)): + bit_len_i = bit_len[i] + till += (1 << bit_len_i) + if (count < till): + codes_i = codes[i] + ol = 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 = 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(inn, lenn, l, out, ol, state, is_all_upper): + +#int matchOccurance(const char *in, int len, int l, char *out, int *ol, byte *state, byte *is_all_upper) { + # int j, k; + longest_dist = 0 + longest_len = 0 + #for (j = l - NICE_LEN; j >= 0; j--) { + j = l - NICE_LEN + while (j >= 0): + + k = l + #for (k = l; k < len && j + k - l < l; k++) { + while ((k < lenn) and (j + k - l < l)): + if (inn[k] != inn[j + k - l]): + break + k += 1 + if (k - l > NICE_LEN - 1): + match_len = k - l - NICE_LEN + match_dist = l - j - 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 == SHX_STATE_2 or is_all_upper): + is_all_upper = 0 + state = SHX_STATE_1 + ol = append_bits(out, ol, BACK2_STATE1_CODE, BACK2_STATE1_CODE_LEN, state) + + ol = append_bits(out, ol, DICT_CODE, DICT_CODE_LEN, 1) + ol = encodeCount(out, ol, longest_len) + ol = 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 + NICE_LEN + l -= 1 + + return l, ol, state, is_all_upper + return -l, ol, state, is_all_upper + + +def unishox_compress(inn, len, out, len_out): +# int32_t unishox_compress(const char *in, size_t len, char *out, size_t len_out) { + + ol = 0 + state = SHX_STATE_1 + is_all_upper = 0 + l = 0 + while (l < len): + # for (l=0; l 0): + #print("matchOccurance l = {l} l_old = {lo}".format(l=l,lo=l_old)) + l += 1 # for loop + continue + + l = -l + + if (state == SHX_STATE_2): # if Set2 + if ((c_in >= ord(' ') and c_in <= ord('@')) or (c_in >= ord('[') and c_in <= ord('`')) or (c_in >= ord('{') and c_in <= ord('~'))): + pass + else: + state = SHX_STATE_1 # back to Set1 and lower case + ol = append_bits(out, ol, BACK2_STATE1_CODE, BACK2_STATE1_CODE_LEN, state) + + is_upper = 0 + if (c_in >= ord('A') and c_in <= ord('Z')): + is_upper = 1 + else: + if (is_all_upper): + is_all_upper = 0 + ol = append_bits(out, ol, BACK2_STATE1_CODE, BACK2_STATE1_CODE_LEN, state) + + c_next = 0 + if (l+1 < len): + c_next = inn[l+1] + + if (c_in >= 32 and c_in <= 126): + if (is_upper and not is_all_upper): + ll=l+5 + # for (ll=l+5; ll>=l && ll=l and ll ord('Z')): + break + + ll -= 1 + + if (ll == l-1): + ol = append_bits(out, ol, ALL_UPPER_CODE, ALL_UPPER_CODE_LEN, state) # CapsLock + is_all_upper = 1; + + if (state == SHX_STATE_1 and c_in >= ord('0') and c_in <= ord('9')): + ol = append_bits(out, ol, SW2_STATE2_CODE, SW2_STATE2_CODE_LEN, state) # Switch to sticky Set2 + state = SHX_STATE_2 + + c_in -= 32 + if (is_all_upper and is_upper): + c_in += 32 + if (c_in == 0 and state == SHX_STATE_2): + ol = append_bits(out, ol, ST2_SPC_CODE, ST2_SPC_CODE_LEN, state) # 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 + cl = cl_95[c_in] + ol = append_bits(out, ol, cl & 0xFFF0, cl & 0x000F, state) + + #lse: + # // if (c_in == 13 && c_next == 10) { // CRLF disabled + # // ol = append_bits(out, ol, CRLF_CODE, CRLF_CODE_LEN, state); // CRLF + # // l++; + # // } else + elif (c_in == 10): + ol = append_bits(out, ol, LF_CODE, LF_CODE_LEN, state) # LF + elif (c_in == '\t'): + ol = append_bits(out, ol, TAB_CODE, TAB_CODE_LEN, state) # 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, (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 = append_bits(out, ol, 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(inn, bit_no, count): + c_in = inn[bit_no >> 3] + if ((bit_no >> 3) and (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(code_type, inn, len, bit_no_p): + code = 0 + count = 0 + while (count < 5): + # detect marker + if (ESCAPE_MARKER == inn[bit_no_p >> 3]): + bit_no_p += 8 # skip marker + + if (bit_no_p >= len): + return -1, bit_no_p + + code += 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(inn, bit_no, count): + ret = 0 + while (count): + count -= 1 + if (ESCAPE_MARKER == inn[bit_no >> 3]): + bit_no += 8 # skip marker + ret += getBitVal(inn, bit_no, count) + bit_no += 1 + return ret + +def readCount(inn, bit_no_p, len): + (idx, bit_no_p) = getCodeIdx(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 = bit_len[i] + till += (1 << bit_len_idx) + i += 1 + + count = 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(inn, len, out, ol, bit_no): + #print("decodeRepeat Enter") + (dict_len, bit_no) = readCount(inn, bit_no, len) + dict_len += NICE_LEN + (dist, bit_no) = readCount(inn, bit_no, len) + dist += 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 unishox_decompress(inn, len, out, len_out): + ol = 0 + bit_no = 0 + dstate = 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 + orig_bit_no = bit_no + (v, bit_no) = getCodeIdx(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) = getCodeIdx(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 == SHX_SET1): # target is Set1 + if (dstate == 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) = getCodeIdx(us_vcode, inn, len, bit_no) # read again vCode + if (v < 0): break # end of stream + if (v == 0): + (h, bit_no) = getCodeIdx(us_hcode, inn, len, bit_no) # read second hCode + if (h < 0): break # end of stream + if (h == SHX_SET1): # If double Switch Set1, the CapsLock + is_all_upper = 1 + continue + + is_upper = 1 # anyways, still uppercase + else: + dstate = SHX_SET1 # if Set was not Set1, switch to Set1 + continue + + elif (h == SHX_SET2): # If Set2, switch dstate to Set2 + if (dstate == SHX_SET1): # TODO: is this test useful, there are only 2 states possible + dstate = SHX_SET2 + continue + + if (h != SHX_SET1): # all other Sets (why not else) + (v, bit_no) = getCodeIdx(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 == SHX_SET1A): + #print("v = 0, h = SHX_SET1A") + if (is_upper): + (temp, bit_no) = readCount(inn, bit_no, len) + out[ol] = 255 - temp # binary + ol += 1 + else: + (ol, bit_no) = decodeRepeat(inn, len, out, ol, bit_no) # dist + continue + + if (h == SHX_SET1 and v == 3): + # was Unicode, will do Binary instead + (temp, bit_no) = readCount(inn, bit_no, len) + out[ol] = 255 - temp # binary + ol += 1 + continue + + if (h < 7 and v < 11): # TODO: are these the actual limits? Not 11x7 ? + #print("h {h} v {v}".format(h=h,v=v)) + c = ord(sets[h][v]) # TODO + if (c >= ord('a') and c <= ord('z')): + if (is_upper): + c -= 32 # go to UpperCase for letters + else: # handle all other cases + if (is_upper and dstate == SHX_SET1 and v == 1): + c = ord('\t') # If UpperCase Space, change to TAB + if (h == SHX_SET1B): + if (8 == v): # was LF or RPT, now only LF + out[ol] = ord('\n') + ol += 1 + continue + + if (9 == v): # was CRLF, now RPT + (count, bit_no) = 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): + break # TERM, stop decoding + + out[ol] = c + ol += 1 + + if (ol >= len_out): + return -1 # overflow + + return ol + + + +if __name__ == "__main__": + 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') + b = bytearray(2048) + l = unishox_compress(inn, len(inn), b, len(b)) + print("Compressed from {fromm} to {to} ({p}%)".format(fromm=len(inn),to=l,p=(100-l/len(inn)*100))) + + out = bytearray(2048) + l = unishox_decompress(b, l, out, len(out)) \ No newline at end of file From 1c441f9059cf49d842a11661eab245fce96619f2 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 17 May 2020 12:04:55 +0200 Subject: [PATCH 02/10] Free unused buffer --- tasmota/xnrg_02_cse7766.ino | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tasmota/xnrg_02_cse7766.ino b/tasmota/xnrg_02_cse7766.ino index dae622845..f0aa210d1 100644 --- a/tasmota/xnrg_02_cse7766.ino +++ b/tasmota/xnrg_02_cse7766.ino @@ -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; } } From 5f7635e68ba30f08710472c5e1f0c104214549b6 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sun, 17 May 2020 14:55:00 +0200 Subject: [PATCH 03/10] Enable user_config_override.h for ESP32 by default since we have always a user_config_override.h generated with override_copy.py if there is none. --- platformio_override_sample.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio_override_sample.ini b/platformio_override_sample.ini index 5a66a3efb..071c28887 100644 --- a/platformio_override_sample.ini +++ b/platformio_override_sample.ini @@ -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 From 0cfea4add6dcfd7218aa551a891bd25619fe207e Mon Sep 17 00:00:00 2001 From: Norbert Richter Date: Sun, 17 May 2020 16:28:09 +0200 Subject: [PATCH 04/10] Refactor unishox Python --- lib/Unishox-1.0-shadinger/python/unishox.py | 949 ++++++++++---------- 1 file changed, 483 insertions(+), 466 deletions(-) diff --git a/lib/Unishox-1.0-shadinger/python/unishox.py b/lib/Unishox-1.0-shadinger/python/unishox.py index bc8fc97e6..feafe0500 100644 --- a/lib/Unishox-1.0-shadinger/python/unishox.py +++ b/lib/Unishox-1.0-shadinger/python/unishox.py @@ -1,496 +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 - - -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 -SHX_SET3 = 4 -SHX_SET4 = 5 -SHX_SET4A = 6 - -# char sets[][11] PROGMEM = -# {{ 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'}, -# {'.', ',', '-', '/', '?', '+', ' ', '(', ')', '$', '@'}, -# {';', '#', ':', '<', '^', '*', '"', '{', '}', '[', ']'}, -# {'=', '%', '\'', '>', '&', '_', '!', '\\', '|', '~', '`'}}; -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) ] - -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 ] - -# Input -# out = bytearray -def append_bits(out, ol, code, clen, state): - #print("Append bits {ol} {code} {clen} {state}".format(ol=ol, code=code, clen=clen, state=state)) - 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 = 8 if (clen > 8) else clen - a_byte = (code >> 8) & 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): - # we completed a full byte - last_c = out[(ol // 8) - 1] - if ((0 == last_c) or (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 - - -codes = [ 0x82, 0xC3, 0xE5, 0xED, 0xF5 ] -bit_len = [ 5, 7, 9, 12, 16 ] - -def encodeCount(out, ol, count): - #print("encodeCount ol = {ol}, count = {count}".format(ol=ol, count=count)) - till = 0 - base = 0 - for i in range(len(bit_len)): - bit_len_i = bit_len[i] - till += (1 << bit_len_i) - if (count < till): - codes_i = codes[i] - ol = 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 = 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(inn, lenn, l, out, ol, state, is_all_upper): - -#int matchOccurance(const char *in, int len, int l, char *out, int *ol, byte *state, byte *is_all_upper) { - # int j, k; - longest_dist = 0 - longest_len = 0 - #for (j = l - NICE_LEN; j >= 0; j--) { - j = l - NICE_LEN - while (j >= 0): - - k = l - #for (k = l; k < len && j + k - l < l; k++) { - while ((k < lenn) and (j + k - l < l)): - if (inn[k] != inn[j + k - l]): - break - k += 1 - if (k - l > NICE_LEN - 1): - match_len = k - l - NICE_LEN - match_dist = l - j - 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 == SHX_STATE_2 or is_all_upper): - is_all_upper = 0 - state = SHX_STATE_1 - ol = append_bits(out, ol, BACK2_STATE1_CODE, BACK2_STATE1_CODE_LEN, state) - - ol = append_bits(out, ol, DICT_CODE, DICT_CODE_LEN, 1) - ol = encodeCount(out, ol, longest_len) - ol = 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 + NICE_LEN - l -= 1 - - return l, ol, state, is_all_upper - return -l, ol, state, is_all_upper - - -def unishox_compress(inn, len, out, len_out): -# int32_t unishox_compress(const char *in, size_t len, char *out, size_t len_out) { - - ol = 0 - state = SHX_STATE_1 - is_all_upper = 0 - l = 0 - while (l < len): - # for (l=0; l 0): - #print("matchOccurance l = {l} l_old = {lo}".format(l=l,lo=l_old)) - l += 1 # for loop - continue - - l = -l - - if (state == SHX_STATE_2): # if Set2 - if ((c_in >= ord(' ') and c_in <= ord('@')) or (c_in >= ord('[') and c_in <= ord('`')) or (c_in >= ord('{') and c_in <= ord('~'))): - pass - else: - state = SHX_STATE_1 # back to Set1 and lower case - ol = append_bits(out, ol, BACK2_STATE1_CODE, BACK2_STATE1_CODE_LEN, state) - - is_upper = 0 - if (c_in >= ord('A') and c_in <= ord('Z')): - is_upper = 1 - else: - if (is_all_upper): + def compress(self, inn, len_, out, len_out): + ol = 0 + state = self.SHX_STATE_1 is_all_upper = 0 - ol = append_bits(out, ol, BACK2_STATE1_CODE, BACK2_STATE1_CODE_LEN, state) + l = 0 + while l < len_: + # for (l=0; l= 32 and c_in <= 126): - if (is_upper and not is_all_upper): - ll=l+5 - # for (ll=l+5; ll>=l && ll=l and ll ord('Z')): - break + 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 - ll -= 1 + 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 - if (ll == l-1): - ol = append_bits(out, ol, ALL_UPPER_CODE, ALL_UPPER_CODE_LEN, state) # CapsLock - is_all_upper = 1; + 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 (state == SHX_STATE_1 and c_in >= ord('0') and c_in <= ord('9')): - ol = append_bits(out, ol, SW2_STATE2_CODE, SW2_STATE2_CODE_LEN, state) # Switch to sticky Set2 - state = SHX_STATE_2 + 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 - c_in -= 32 - if (is_all_upper and is_upper): - c_in += 32 - if (c_in == 0 and state == SHX_STATE_2): - ol = append_bits(out, ol, ST2_SPC_CODE, ST2_SPC_CODE_LEN, state) # 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 - cl = cl_95[c_in] - ol = append_bits(out, ol, cl & 0xFFF0, cl & 0x000F, state) + l = -l - #lse: - # // if (c_in == 13 && c_next == 10) { // CRLF disabled - # // ol = append_bits(out, ol, CRLF_CODE, CRLF_CODE_LEN, state); // CRLF - # // l++; - # // } else - elif (c_in == 10): - ol = append_bits(out, ol, LF_CODE, LF_CODE_LEN, state) # LF - elif (c_in == '\t'): - ol = append_bits(out, ol, TAB_CODE, TAB_CODE_LEN, state) # 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, (255 - c_in) & 0xFF) - + 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) - # 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 = append_bits(out, ol, 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(inn, bit_no, count): - c_in = inn[bit_no >> 3] - if ((bit_no >> 3) and (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(code_type, inn, len, bit_no_p): - code = 0 - count = 0 - while (count < 5): - # detect marker - if (ESCAPE_MARKER == inn[bit_no_p >> 3]): - bit_no_p += 8 # skip marker - - if (bit_no_p >= len): - return -1, bit_no_p - - code += 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(inn, bit_no, count): - ret = 0 - while (count): - count -= 1 - if (ESCAPE_MARKER == inn[bit_no >> 3]): - bit_no += 8 # skip marker - ret += getBitVal(inn, bit_no, count) - bit_no += 1 - return ret - -def readCount(inn, bit_no_p, len): - (idx, bit_no_p) = getCodeIdx(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 = bit_len[i] - till += (1 << bit_len_idx) - i += 1 - - count = 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(inn, len, out, ol, bit_no): - #print("decodeRepeat Enter") - (dict_len, bit_no) = readCount(inn, bit_no, len) - dict_len += NICE_LEN - (dist, bit_no) = readCount(inn, bit_no, len) - dist += 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 unishox_decompress(inn, len, out, len_out): - ol = 0 - bit_no = 0 - dstate = 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 - orig_bit_no = bit_no - (v, bit_no) = getCodeIdx(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) = getCodeIdx(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 == SHX_SET1): # target is Set1 - if (dstate == 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 + 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) - (v, bit_no) = getCodeIdx(us_vcode, inn, len, bit_no) # read again vCode - if (v < 0): break # end of stream - if (v == 0): - (h, bit_no) = getCodeIdx(us_hcode, inn, len, bit_no) # read second hCode - if (h < 0): break # end of stream - if (h == SHX_SET1): # If double Switch Set1, the CapsLock - is_all_upper = 1 - continue + if 32 <= c_in <= 126: + if is_upper and not is_all_upper: + ll = l+5 + # for (ll=l+5; ll>=l && ll ord('Z'): + break - is_upper = 1 # anyways, still uppercase - else: - dstate = SHX_SET1 # if Set was not Set1, switch to Set1 - continue + ll -= 1 - elif (h == SHX_SET2): # If Set2, switch dstate to Set2 - if (dstate == SHX_SET1): # TODO: is this test useful, there are only 2 states possible - dstate = SHX_SET2 - continue + 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 (h != SHX_SET1): # all other Sets (why not else) - (v, bit_no) = getCodeIdx(us_vcode, inn, len, bit_no) # we changed set, now read vCode for char - if (v < 0): break # end of stream + 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 - if (v == 0 and h == SHX_SET1A): - #print("v = 0, h = SHX_SET1A") - if (is_upper): - (temp, bit_no) = readCount(inn, bit_no, len) - out[ol] = 255 - temp # binary - ol += 1 - else: - (ol, bit_no) = decodeRepeat(inn, len, out, ol, bit_no) # dist - continue + 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) - if (h == SHX_SET1 and v == 3): - # was Unicode, will do Binary instead - (temp, bit_no) = readCount(inn, bit_no, len) - out[ol] = 255 - temp # binary - ol += 1 - continue + 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) - if (h < 7 and v < 11): # TODO: are these the actual limits? Not 11x7 ? - #print("h {h} v {v}".format(h=h,v=v)) - c = ord(sets[h][v]) # TODO - if (c >= ord('a') and c <= ord('z')): - if (is_upper): - c -= 32 # go to UpperCase for letters - else: # handle all other cases - if (is_upper and dstate == SHX_SET1 and v == 1): - c = ord('\t') # If UpperCase Space, change to TAB - if (h == SHX_SET1B): - if (8 == v): # was LF or RPT, now only LF - out[ol] = ord('\n') - ol += 1 - continue - if (9 == v): # was CRLF, now RPT - (count, bit_no) = readCount(inn, bit_no, len) - count += 4 - if (ol + count >= len_out): - return -1 # overflow + # check that we have some headroom in the output buffer + if ol // 8 >= len_out - 4: + return -1 # we risk overflow and crash - rpt_c = out[ol - 1] - while (count): + 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 - out[ol] = rpt_c + 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 - continue - if (10 == v): - break # TERM, stop decoding + if ol >= len_out: + return -1 # overflow - out[ol] = c - ol += 1 - - if (ol >= len_out): - return -1 # overflow - - return ol + return ol + # pylint: enable=missing-function-docstring if __name__ == "__main__": - 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') - b = bytearray(2048) - l = unishox_compress(inn, len(inn), b, len(b)) - print("Compressed from {fromm} to {to} ({p}%)".format(fromm=len(inn),to=l,p=(100-l/len(inn)*100))) + # 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) - l = unishox_decompress(b, l, out, len(out)) \ No newline at end of file + OUT = bytearray(2048) + LEN_ = UNISHOX.decompress(BYTES_, LEN_, OUT, len(OUT)) + print(str(OUT, 'utf-8').split('\x00')[0]) From d7f6c78ed953f3d9fb7dbbe6a21407de32d85d1e Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 17 May 2020 17:10:17 +0200 Subject: [PATCH 05/10] Add command ``DeviceName`` Add command ``DeviceName`` defaults to FriendlyName1 and replaces FriendlyName1 in GUI --- RELEASENOTES.md | 3 ++- tasmota/CHANGELOG.md | 4 ++++ tasmota/i18n.h | 1 + tasmota/language/bg_BG.h | 1 + tasmota/language/cs_CZ.h | 1 + tasmota/language/de_DE.h | 1 + tasmota/language/el_GR.h | 1 + tasmota/language/en_GB.h | 1 + tasmota/language/es_ES.h | 1 + tasmota/language/fr_FR.h | 1 + tasmota/language/he_HE.h | 1 + tasmota/language/hu_HU.h | 1 + tasmota/language/it_IT.h | 1 + tasmota/language/ko_KO.h | 1 + tasmota/language/nl_NL.h | 1 + tasmota/language/pl_PL.h | 1 + tasmota/language/pt_BR.h | 1 + tasmota/language/pt_PT.h | 1 + tasmota/language/ro_RO.h | 1 + tasmota/language/ru_RU.h | 1 + tasmota/language/sk_SK.h | 1 + tasmota/language/sv_SE.h | 1 + tasmota/language/tr_TR.h | 1 + tasmota/language/uk_UA.h | 1 + tasmota/language/zh_CN.h | 1 + tasmota/language/zh_TW.h | 1 + tasmota/settings.ino | 5 +++++ tasmota/support_command.ino | 16 ++++++++++++---- tasmota/tasmota.h | 1 + tasmota/tasmota.ino | 2 +- tasmota/tasmota_version.h | 2 +- tasmota/xdrv_01_webserver.ino | 16 ++++++++++++---- 32 files changed, 62 insertions(+), 11 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 7c99a0a6d..dbbe42f3a 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -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 diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index 7f48c3918..f8fd969bc 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -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 diff --git a/tasmota/i18n.h b/tasmota/i18n.h index 089a9b55f..e8286e585 100644 --- a/tasmota/i18n.h +++ b/tasmota/i18n.h @@ -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" diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h index 03ae5bd6c..a40df8551 100644 --- a/tasmota/language/bg_BG.h +++ b/tasmota/language/bg_BG.h @@ -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 "Приятелско име" diff --git a/tasmota/language/cs_CZ.h b/tasmota/language/cs_CZ.h index 71a907a81..33839ed4d 100644 --- a/tasmota/language/cs_CZ.h +++ b/tasmota/language/cs_CZ.h @@ -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" diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h index fdd1ec18d..9f676f101 100644 --- a/tasmota/language/de_DE.h +++ b/tasmota/language/de_DE.h @@ -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]" diff --git a/tasmota/language/el_GR.h b/tasmota/language/el_GR.h index ddd1d5b0b..ec6275dbd 100644 --- a/tasmota/language/el_GR.h +++ b/tasmota/language/el_GR.h @@ -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 "Φιλική ονομασία" diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h index 0396ca3e6..48208a0bb 100644 --- a/tasmota/language/en_GB.h +++ b/tasmota/language/en_GB.h @@ -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" diff --git a/tasmota/language/es_ES.h b/tasmota/language/es_ES.h index 0602c3634..40b98f766 100644 --- a/tasmota/language/es_ES.h +++ b/tasmota/language/es_ES.h @@ -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" diff --git a/tasmota/language/fr_FR.h b/tasmota/language/fr_FR.h index c620572ca..dbe9c597a 100644 --- a/tasmota/language/fr_FR.h +++ b/tasmota/language/fr_FR.h @@ -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" diff --git a/tasmota/language/he_HE.h b/tasmota/language/he_HE.h index 4802b529e..fe77159c1 100644 --- a/tasmota/language/he_HE.h +++ b/tasmota/language/he_HE.h @@ -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 "שם ידידותי" diff --git a/tasmota/language/hu_HU.h b/tasmota/language/hu_HU.h index ee45ae083..844fa2f8f 100644 --- a/tasmota/language/hu_HU.h +++ b/tasmota/language/hu_HU.h @@ -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" diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index 88acefc92..5fa0d51dd 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -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" diff --git a/tasmota/language/ko_KO.h b/tasmota/language/ko_KO.h index 3e3bd17e0..5ab580ce8 100644 --- a/tasmota/language/ko_KO.h +++ b/tasmota/language/ko_KO.h @@ -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" diff --git a/tasmota/language/nl_NL.h b/tasmota/language/nl_NL.h index 49efcb622..84ce656e3 100644 --- a/tasmota/language/nl_NL.h +++ b/tasmota/language/nl_NL.h @@ -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" diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h index d9d05fbeb..8ee529292 100644 --- a/tasmota/language/pl_PL.h +++ b/tasmota/language/pl_PL.h @@ -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" diff --git a/tasmota/language/pt_BR.h b/tasmota/language/pt_BR.h index 4fb48c04d..39e7affb0 100644 --- a/tasmota/language/pt_BR.h +++ b/tasmota/language/pt_BR.h @@ -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" diff --git a/tasmota/language/pt_PT.h b/tasmota/language/pt_PT.h index 232b7494d..aabd353fe 100644 --- a/tasmota/language/pt_PT.h +++ b/tasmota/language/pt_PT.h @@ -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" diff --git a/tasmota/language/ro_RO.h b/tasmota/language/ro_RO.h index 79c66d779..77a2240ca 100644 --- a/tasmota/language/ro_RO.h +++ b/tasmota/language/ro_RO.h @@ -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" diff --git a/tasmota/language/ru_RU.h b/tasmota/language/ru_RU.h index b7d8adcb6..0e5cd24ac 100644 --- a/tasmota/language/ru_RU.h +++ b/tasmota/language/ru_RU.h @@ -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 "Дружественное Имя" diff --git a/tasmota/language/sk_SK.h b/tasmota/language/sk_SK.h index 9db574bf8..d8bdd2ece 100644 --- a/tasmota/language/sk_SK.h +++ b/tasmota/language/sk_SK.h @@ -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" diff --git a/tasmota/language/sv_SE.h b/tasmota/language/sv_SE.h index da8355215..64a540f96 100644 --- a/tasmota/language/sv_SE.h +++ b/tasmota/language/sv_SE.h @@ -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" diff --git a/tasmota/language/tr_TR.h b/tasmota/language/tr_TR.h index 9b205954b..c62981f8d 100644 --- a/tasmota/language/tr_TR.h +++ b/tasmota/language/tr_TR.h @@ -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" diff --git a/tasmota/language/uk_UA.h b/tasmota/language/uk_UA.h index 8c566eac3..0b90eaf53 100644 --- a/tasmota/language/uk_UA.h +++ b/tasmota/language/uk_UA.h @@ -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 "Дружня назва" diff --git a/tasmota/language/zh_CN.h b/tasmota/language/zh_CN.h index 143e49aec..e521054f5 100644 --- a/tasmota/language/zh_CN.h +++ b/tasmota/language/zh_CN.h @@ -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 "昵称" diff --git a/tasmota/language/zh_TW.h b/tasmota/language/zh_TW.h index 5c96ec688..bfa967b6d 100644 --- a/tasmota/language/zh_TW.h +++ b/tasmota/language/zh_TW.h @@ -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 "昵稱" diff --git a/tasmota/settings.ino b/tasmota/settings.ino index b189e1729..5214add7a 100644 --- a/tasmota/settings.ino +++ b/tasmota/settings.ino @@ -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); } diff --git a/tasmota/support_command.ino b/tasmota/support_command.ino index 6e0a74c93..91434b019 100644 --- a/tasmota/support_command.ino +++ b/tasmota/support_command.ino @@ -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, (SC_DEFAULT == Shortcut()) ? SettingsText(SET_FRIENDLYNAME1) : XdrvMailbox.data); + } + ResponseCmndChar(SettingsText(SET_DEVICENAME)); +} + void CmndFriendlyname(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_FRIENDLYNAMES)) { diff --git a/tasmota/tasmota.h b/tasmota/tasmota.h index 3cb309910..0376f3429 100644 --- a/tasmota/tasmota.h +++ b/tasmota/tasmota.h @@ -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 }; diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index 091b6eed3..ecf1127ec 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -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 diff --git a/tasmota/tasmota_version.h b/tasmota/tasmota_version.h index e0fa3a3ce..d9f248e55 100644 --- a/tasmota/tasmota_version.h +++ b/tasmota/tasmota_version.h @@ -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; diff --git a/tasmota/xdrv_01_webserver.ino b/tasmota/xdrv_01_webserver.ino index 75f309569..3f7ad8ec0 100644 --- a/tasmota/xdrv_01_webserver.ino +++ b/tasmota/xdrv_01_webserver.ino @@ -455,6 +455,8 @@ const char HTTP_FORM_OTHER[] PROGMEM = "

" "
" "
" + "
" + "

" "
"; 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(WiFi.localIP()) != 0); bool sip = (static_cast(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), SettingsText(SET_DEVICENAME)); uint32_t maxfn = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : (!devices_present) ? 1 : devices_present; #ifdef USE_SONOFF_IFAN @@ -2042,6 +2046,9 @@ void OtherSaveSettings(void) char friendlyname[TOPSZ]; char message[LOGSZ]; + WebGetArg("dn", tmp, sizeof(tmp)); + SettingsUpdateText(SET_DEVICENAME, (!strlen(tmp)) ? 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 +2060,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)); From 90e833238fcc130007e600ed3bf1dfafdf861588 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 17 May 2020 17:38:28 +0200 Subject: [PATCH 06/10] Allow no DeviceName --- tasmota/support_command.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/support_command.ino b/tasmota/support_command.ino index 91434b019..dbcd5a954 100644 --- a/tasmota/support_command.ino +++ b/tasmota/support_command.ino @@ -1491,7 +1491,7 @@ void CmndWifiConfig(void) void CmndDevicename(void) { if (!XdrvMailbox.grpflg && (XdrvMailbox.data_len > 0)) { - SettingsUpdateText(SET_DEVICENAME, (SC_DEFAULT == Shortcut()) ? SettingsText(SET_FRIENDLYNAME1) : XdrvMailbox.data); + SettingsUpdateText(SET_DEVICENAME, ('"' == XdrvMailbox.data[0]) ? "" : (SC_DEFAULT == Shortcut()) ? SettingsText(SET_FRIENDLYNAME1) : XdrvMailbox.data); } ResponseCmndChar(SettingsText(SET_DEVICENAME)); } From 4e38cb7ba9acae1db9f50330c10963e5044eeb41 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 17 May 2020 17:55:36 +0200 Subject: [PATCH 07/10] Allow empty DeviceName --- tasmota/xdrv_01_webserver.ino | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tasmota/xdrv_01_webserver.ino b/tasmota/xdrv_01_webserver.ino index 3f7ad8ec0..a1e4a247b 100644 --- a/tasmota/xdrv_01_webserver.ino +++ b/tasmota/xdrv_01_webserver.ino @@ -456,7 +456,7 @@ const char HTTP_FORM_OTHER[] PROGMEM = "
" "
" "
" - "

" + "

" "
"; const char HTTP_FORM_END[] PROGMEM = @@ -1996,7 +1996,7 @@ void HandleOtherConfiguration(void) 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 - SettingsText(SET_FRIENDLYNAME1), SettingsText(SET_DEVICENAME), SettingsText(SET_DEVICENAME)); + SettingsText(SET_FRIENDLYNAME1), SettingsText(SET_DEVICENAME)); uint32_t maxfn = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : (!devices_present) ? 1 : devices_present; #ifdef USE_SONOFF_IFAN @@ -2047,8 +2047,7 @@ void OtherSaveSettings(void) char message[LOGSZ]; WebGetArg("dn", tmp, sizeof(tmp)); - SettingsUpdateText(SET_DEVICENAME, (!strlen(tmp)) ? SettingsText(SET_FRIENDLYNAME1) : 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 From 20b2257c8c3911b729dd0104018fd0db7aba7991 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Sun, 17 May 2020 18:05:17 +0200 Subject: [PATCH 08/10] Unishox code optimized --- lib/Unishox-1.0-shadinger/src/unishox.cpp | 292 ++++++++++------------ lib/Unishox-1.0-shadinger/src/unishox.h | 40 ++- tasmota/my_user_config.h | 2 +- tasmota/xdrv_10_rules.ino | 9 +- 4 files changed, 174 insertions(+), 169 deletions(-) diff --git a/lib/Unishox-1.0-shadinger/src/unishox.cpp b/lib/Unishox-1.0-shadinger/src/unishox.cpp index 72c9d3915..4b17dce2e 100644 --- a/lib/Unishox-1.0-shadinger/src/unishox.cpp +++ b/lib/Unishox-1.0-shadinger/src/unishox.cpp @@ -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; - } diff --git a/lib/Unishox-1.0-shadinger/src/unishox.h b/lib/Unishox-1.0-shadinger/src/unishox.h index 4d6b81641..d1cda8976 100644 --- a/lib/Unishox-1.0-shadinger/src/unishox.h +++ b/lib/Unishox-1.0-shadinger/src/unishox.h @@ -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 diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 33d47d57f..9b04a2ea2 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -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 diff --git a/tasmota/xdrv_10_rules.ino b/tasmota/xdrv_10_rules.ino index 922014e49..ddb4de39d 100644 --- a/tasmota/xdrv_10_rules.ino +++ b/tasmota/xdrv_10_rules.ino @@ -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)); } From 1460f814901d1602d89c5d89c585ca4cf55e0848 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Sun, 17 May 2020 18:33:42 +0200 Subject: [PATCH 09/10] Zigbee allow zero shortaddr --- tasmota/xdrv_23_zigbee_0_constants.ino | 2 + tasmota/xdrv_23_zigbee_2_devices.ino | 48 ++++++------- tasmota/xdrv_23_zigbee_4_persistence.ino | 45 ------------- tasmota/xdrv_23_zigbee_5_converters.ino | 13 +--- tasmota/xdrv_23_zigbee_6_commands.ino | 13 ++-- tasmota/xdrv_23_zigbee_7_statemachine.ino | 29 +------- tasmota/xdrv_23_zigbee_8_parsers.ino | 82 +++++++++++------------ tasmota/xdrv_23_zigbee_9_impl.ino | 58 +++++++--------- 8 files changed, 101 insertions(+), 189 deletions(-) diff --git a/tasmota/xdrv_23_zigbee_0_constants.ino b/tasmota/xdrv_23_zigbee_0_constants.ino index 2aeade28d..28628f93c 100644 --- a/tasmota/xdrv_23_zigbee_0_constants.ino +++ b/tasmota/xdrv_23_zigbee_0_constants.ino @@ -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, diff --git a/tasmota/xdrv_23_zigbee_2_devices.ino b/tasmota/xdrv_23_zigbee_2_devices.ino index 76413e23e..74d52c73e 100644 --- a/tasmota/xdrv_23_zigbee_2_devices.ino +++ b/tasmota/xdrv_23_zigbee_2_devices.ino @@ -103,7 +103,7 @@ public: // Probe the existence of device keys // Results: // - 0x0000 = not found - // - 0xFFFF = bad parameter + // - BAD_SHORTADDR = bad parameter // - 0x = 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(); diff --git a/tasmota/xdrv_23_zigbee_4_persistence.ino b/tasmota/xdrv_23_zigbee_4_persistence.ino index 78cb79bec..ef67221c9 100644 --- a/tasmota/xdrv_23_zigbee_4_persistence.ino +++ b/tasmota/xdrv_23_zigbee_4_persistence.ino @@ -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; diff --git a/tasmota/xdrv_23_zigbee_5_converters.ino b/tasmota/xdrv_23_zigbee_5_converters.ino index 07b5f5ef1..dfb69d4a7 100644 --- a/tasmota/xdrv_23_zigbee_5_converters.ino +++ b/tasmota/xdrv_23_zigbee_5_converters.ino @@ -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, diff --git a/tasmota/xdrv_23_zigbee_6_commands.ino b/tasmota/xdrv_23_zigbee_6_commands.ino index e27f37f7a..949f4acb8 100644 --- a/tasmota/xdrv_23_zigbee_6_commands.ino +++ b/tasmota/xdrv_23_zigbee_6_commands.ino @@ -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); } diff --git a/tasmota/xdrv_23_zigbee_7_statemachine.ino b/tasmota/xdrv_23_zigbee_7_statemachine.ino index 3531ba0a7..590c795ac 100644 --- a/tasmota/xdrv_23_zigbee_7_statemachine.ino +++ b/tasmota/xdrv_23_zigbee_7_statemachine.ino @@ -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) diff --git a/tasmota/xdrv_23_zigbee_8_parsers.ino b/tasmota/xdrv_23_zigbee_8_parsers.ino index cae5441b7..20aecd0f9 100644 --- a/tasmota/xdrv_23_zigbee_8_parsers.ino +++ b/tasmota/xdrv_23_zigbee_8_parsers.ino @@ -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); diff --git a/tasmota/xdrv_23_zigbee_9_impl.ino b/tasmota/xdrv_23_zigbee_9_impl.ino index 983c76cf3..40053c5a7 100644 --- a/tasmota/xdrv_23_zigbee_9_impl.ino +++ b/tasmota/xdrv_23_zigbee_9_impl.ino @@ -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()); - 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()); - 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()); - 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, 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, 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, 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()); - 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); From 950a4dc998b37cdb0ec04edda874a07f2902be44 Mon Sep 17 00:00:00 2001 From: Federico Leoni Date: Sun, 17 May 2020 13:42:14 -0300 Subject: [PATCH 10/10] HA Discovery: Oops! New DeviceName --- tasmota/xdrv_12_home_assistant.ino | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tasmota/xdrv_12_home_assistant.ino b/tasmota/xdrv_12_home_assistant.ino index 3e8663d24..e9d8bd009 100644 --- a/tasmota/xdrv_12_home_assistant.ino +++ b/tasmota/xdrv_12_home_assistant.ino @@ -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("}")); }