mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-27 20:56:35 +00:00
decode-config.py: fix --restore-file, replace pycurl by requests
- fix error during --restore-file function - replace lib pycurl by requests
This commit is contained in:
parent
7d6330a8ba
commit
ac357986c4
@ -1,7 +1,8 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
VER = '2.4.0037'
|
from past.builtins import long
|
||||||
|
VER = '2.4.0039'
|
||||||
|
|
||||||
"""
|
"""
|
||||||
decode-config.py - Backup/Restore Tasmota configuration data
|
decode-config.py - Backup/Restore Tasmota configuration data
|
||||||
@ -23,8 +24,8 @@ VER = '2.4.0037'
|
|||||||
|
|
||||||
|
|
||||||
Requirements:
|
Requirements:
|
||||||
- Python
|
- Python 2.x:
|
||||||
- pip install json pycurl urllib2 configargparse
|
pip install json requests urllib2 configargparse
|
||||||
|
|
||||||
|
|
||||||
Instructions:
|
Instructions:
|
||||||
@ -198,7 +199,7 @@ try:
|
|||||||
import inspect
|
import inspect
|
||||||
import json
|
import json
|
||||||
import configargparse
|
import configargparse
|
||||||
import pycurl
|
import requests
|
||||||
if sys.version_info.major==2:
|
if sys.version_info.major==2:
|
||||||
import urllib2
|
import urllib2
|
||||||
else:
|
else:
|
||||||
@ -1246,6 +1247,38 @@ def exit(status=0, msg="end", type_=LogType.ERROR, src=None, doexit=True, line=N
|
|||||||
sys.exit(exitcode)
|
sys.exit(exitcode)
|
||||||
|
|
||||||
|
|
||||||
|
def debug(args):
|
||||||
|
"""
|
||||||
|
Get debug level
|
||||||
|
|
||||||
|
@param args:
|
||||||
|
configargparse.parse_args() result
|
||||||
|
|
||||||
|
@return:
|
||||||
|
debug level
|
||||||
|
"""
|
||||||
|
return 0 if args.debug is None else args.debug
|
||||||
|
|
||||||
|
|
||||||
|
def instance(type_):
|
||||||
|
"""
|
||||||
|
Creates Python2/3 compatible isinstance test type(s)
|
||||||
|
|
||||||
|
@param args:
|
||||||
|
Python3 instance type
|
||||||
|
|
||||||
|
@return:
|
||||||
|
Python2/3 compatible isinstance type(s)
|
||||||
|
"""
|
||||||
|
newtype = type_
|
||||||
|
if sys.version_info.major==2:
|
||||||
|
if type_==str:
|
||||||
|
newtype = (str,unicode)
|
||||||
|
elif isinstance(type_, tuple) and str in type_:
|
||||||
|
newtype = newtype + (unicode,)
|
||||||
|
return newtype
|
||||||
|
|
||||||
|
|
||||||
def ShortHelp(doexit=True):
|
def ShortHelp(doexit=True):
|
||||||
"""
|
"""
|
||||||
Show short help (usage) only - ued by own -h handling
|
Show short help (usage) only - ued by own -h handling
|
||||||
@ -1262,36 +1295,6 @@ def ShortHelp(doexit=True):
|
|||||||
sys.exit(ExitCode.OK)
|
sys.exit(ExitCode.OK)
|
||||||
|
|
||||||
|
|
||||||
class HTTPHeader:
|
|
||||||
"""
|
|
||||||
pycurl helper class retrieving the request header
|
|
||||||
"""
|
|
||||||
def __init__(self):
|
|
||||||
self.contents = ''
|
|
||||||
|
|
||||||
def clear(self):
|
|
||||||
self.contents = ''
|
|
||||||
|
|
||||||
def store(self, _buffer):
|
|
||||||
self.contents = "{}{}".format(self.contents, _buffer)
|
|
||||||
|
|
||||||
def response(self):
|
|
||||||
header = str(self.contents).split('\n')
|
|
||||||
if len(header) > 0:
|
|
||||||
return header[0].rstrip()
|
|
||||||
return ''
|
|
||||||
|
|
||||||
def contenttype(self):
|
|
||||||
for item in str(self.contents).split('\n'):
|
|
||||||
ditem = item.split(":")
|
|
||||||
if ditem[0].strip().lower() == 'content-type' and len(ditem) > 1:
|
|
||||||
return ditem[1].strip()
|
|
||||||
return ''
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.contents
|
|
||||||
|
|
||||||
|
|
||||||
class CustomHelpFormatter(configargparse.HelpFormatter):
|
class CustomHelpFormatter(configargparse.HelpFormatter):
|
||||||
"""
|
"""
|
||||||
Class for customizing the help output
|
Class for customizing the help output
|
||||||
@ -1337,9 +1340,6 @@ def GetTemplateSizes():
|
|||||||
"""
|
"""
|
||||||
Get all possible template sizes as list
|
Get all possible template sizes as list
|
||||||
|
|
||||||
@param version:
|
|
||||||
<int> version number from read binary data to search for
|
|
||||||
|
|
||||||
@return:
|
@return:
|
||||||
template sizes as list []
|
template sizes as list []
|
||||||
"""
|
"""
|
||||||
@ -1472,7 +1472,7 @@ def GetVersionStr(version):
|
|||||||
@return:
|
@return:
|
||||||
version string
|
version string
|
||||||
"""
|
"""
|
||||||
if isinstance(version, (unicode,str)):
|
if isinstance(version, instance(str)):
|
||||||
version = int(version, 0)
|
version = int(version, 0)
|
||||||
major = ((version>>24) & 0xff)
|
major = ((version>>24) & 0xff)
|
||||||
minor = ((version>>16) & 0xff)
|
minor = ((version>>16) & 0xff)
|
||||||
@ -1629,43 +1629,21 @@ def TasmotaGet(cmnd, host, port, username=DEFAULTS['source']['username'], passwo
|
|||||||
@return:
|
@return:
|
||||||
binary config data (encrypted) or None on error
|
binary config data (encrypted) or None on error
|
||||||
"""
|
"""
|
||||||
body = None
|
|
||||||
|
|
||||||
# read config direct from device via http
|
# read config direct from device via http
|
||||||
c = pycurl.Curl()
|
url = MakeUrl(host, port, cmnd)
|
||||||
buffer = io.BytesIO()
|
auth = None
|
||||||
c.setopt(c.WRITEDATA, buffer)
|
|
||||||
header = HTTPHeader()
|
|
||||||
c.setopt(c.HEADERFUNCTION, header.store)
|
|
||||||
c.setopt(c.FOLLOWLOCATION, True)
|
|
||||||
c.setopt(c.URL, MakeUrl(host, port, cmnd))
|
|
||||||
if username is not None and password is not None:
|
if username is not None and password is not None:
|
||||||
c.setopt(c.HTTPAUTH, c.HTTPAUTH_BASIC)
|
auth = (username, password)
|
||||||
c.setopt(c.USERPWD, username + ':' + password)
|
res = requests.get(url, auth=auth)
|
||||||
c.setopt(c.HTTPGET, True)
|
|
||||||
c.setopt(c.VERBOSE, False)
|
|
||||||
|
|
||||||
responsecode = 200
|
if not res.ok:
|
||||||
try:
|
exit(res.status_code, "Error on http GET request for {} - {}".format(url,res.reason), line=inspect.getlineno(inspect.currentframe()))
|
||||||
c.perform()
|
|
||||||
responsecode = c.getinfo(c.RESPONSE_CODE)
|
|
||||||
response = header.response()
|
|
||||||
except Exception as e:
|
|
||||||
exit(e.args[0], e.args[1], line=inspect.getlineno(inspect.currentframe()))
|
|
||||||
finally:
|
|
||||||
c.close()
|
|
||||||
|
|
||||||
if responsecode >= 400:
|
if contenttype is not None and res.headers['Content-Type']!=contenttype:
|
||||||
exit(responsecode, 'HTTP result: {}'.format(header.response()),line=inspect.getlineno(inspect.currentframe()))
|
|
||||||
elif contenttype is not None and header.contenttype()!=contenttype:
|
|
||||||
exit(ExitCode.DOWNLOAD_CONFIG_ERROR, "Device did not response properly, may be Tasmota webserver admin mode is disabled (WebServer 2)",line=inspect.getlineno(inspect.currentframe()))
|
exit(ExitCode.DOWNLOAD_CONFIG_ERROR, "Device did not response properly, may be Tasmota webserver admin mode is disabled (WebServer 2)",line=inspect.getlineno(inspect.currentframe()))
|
||||||
|
|
||||||
try:
|
return res.status_code, res.content
|
||||||
body = buffer.getvalue()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return responsecode, body
|
|
||||||
|
|
||||||
|
|
||||||
def GetTasmotaHostname(host, port, username=DEFAULTS['source']['username'], password=None):
|
def GetTasmotaHostname(host, port, username=DEFAULTS['source']['username'], password=None):
|
||||||
@ -1741,7 +1719,7 @@ def PushTasmotaConfig(encode_cfg, host, port, username=DEFAULTS['source']['usern
|
|||||||
errorcode, errorstring
|
errorcode, errorstring
|
||||||
errorcode=0 if success, otherwise http response or exception code
|
errorcode=0 if success, otherwise http response or exception code
|
||||||
"""
|
"""
|
||||||
if isinstance(encode_cfg, bytearray):
|
if isinstance(encode_cfg, (bytes,bytearray)):
|
||||||
encode_cfg = str(encode_cfg)
|
encode_cfg = str(encode_cfg)
|
||||||
|
|
||||||
# get restore config page first to set internal Tasmota vars
|
# get restore config page first to set internal Tasmota vars
|
||||||
@ -1749,48 +1727,21 @@ def PushTasmotaConfig(encode_cfg, host, port, username=DEFAULTS['source']['usern
|
|||||||
if body is None:
|
if body is None:
|
||||||
return responsecode, "ERROR"
|
return responsecode, "ERROR"
|
||||||
|
|
||||||
# post data
|
# ~ # post data
|
||||||
c = pycurl.Curl()
|
url = MakeUrl(host, port, "u2")
|
||||||
header = HTTPHeader()
|
auth = None
|
||||||
buffer_ = io.BytesIO()
|
|
||||||
c.setopt(c.HEADERFUNCTION, header.store)
|
|
||||||
c.setopt(c.WRITEFUNCTION, lambda x: None)
|
|
||||||
c.setopt(c.WRITEDATA, buffer_)
|
|
||||||
c.setopt(c.POST, 1)
|
|
||||||
c.setopt(c.URL, MakeUrl(host, port, 'u2'))
|
|
||||||
if username is not None and password is not None:
|
if username is not None and password is not None:
|
||||||
c.setopt(c.HTTPAUTH, c.HTTPAUTH_BASIC)
|
auth = (username, password)
|
||||||
c.setopt(c.USERPWD, username + ':' + password)
|
files = {'u2':('{sprog}_v{sver}.dmp'.format(sprog=os.path.basename(sys.argv[0]), sver=VER), encode_cfg)}
|
||||||
try:
|
res = requests.post(url, auth=auth, files=files)
|
||||||
isfile = os.path.isfile(encode_cfg)
|
|
||||||
except:
|
|
||||||
isfile = False
|
|
||||||
if isfile:
|
|
||||||
c.setopt(c.HTTPPOST, [("file", (c.FORM_FILE, encode_cfg))])
|
|
||||||
else:
|
|
||||||
# use as binary data
|
|
||||||
c.setopt(c.HTTPPOST, [
|
|
||||||
('fileupload', (
|
|
||||||
c.FORM_BUFFER, '{sprog}_v{sver}.dmp'.format(sprog=os.path.basename(sys.argv[0]), sver=VER),
|
|
||||||
c.FORM_BUFFERPTR, encode_cfg
|
|
||||||
)),
|
|
||||||
])
|
|
||||||
|
|
||||||
responsecode = 200
|
if not res.ok:
|
||||||
try:
|
exit(res.status_code, "Error on http POST request for {} - {}".format(url,res.reason), line=inspect.getlineno(inspect.currentframe()))
|
||||||
c.perform()
|
|
||||||
responsecode = c.getinfo(c.RESPONSE_CODE)
|
|
||||||
except Exception as e:
|
|
||||||
return e.args[0], e.args[1]
|
|
||||||
|
|
||||||
c.close()
|
if res.headers['Content-Type']!='text/html':
|
||||||
|
exit(ExitCode.DOWNLOAD_CONFIG_ERROR, "Device did not response properly, may be Tasmota webserver admin mode is disabled (WebServer 2)",line=inspect.getlineno(inspect.currentframe()))
|
||||||
|
|
||||||
if responsecode >= 400:
|
body = res.content
|
||||||
return responsecode, header.response()
|
|
||||||
elif header.contenttype() != 'text/html':
|
|
||||||
return ExitCode.UPLOAD_CONFIG_ERROR, "Device did not response properly, may be Tasmota webserver admin mode is disabled (WebServer 2)"
|
|
||||||
|
|
||||||
body = buffer_.getvalue()
|
|
||||||
|
|
||||||
findUpload = body.find("Upload")
|
findUpload = body.find("Upload")
|
||||||
if findUpload < 0:
|
if findUpload < 0:
|
||||||
@ -1818,7 +1769,7 @@ def DecryptEncrypt(obj):
|
|||||||
@return:
|
@return:
|
||||||
decrypted configuration (if obj contains encrypted data)
|
decrypted configuration (if obj contains encrypted data)
|
||||||
"""
|
"""
|
||||||
if isinstance(obj, bytearray):
|
if isinstance(obj, (bytes,bytearray)):
|
||||||
obj = str(obj)
|
obj = str(obj)
|
||||||
dobj = obj[0:2]
|
dobj = obj[0:2]
|
||||||
for i in range(2, len(obj)):
|
for i in range(2, len(obj)):
|
||||||
@ -1837,7 +1788,7 @@ def GetSettingsCrc(dobj):
|
|||||||
2 byte unsigned integer crc value
|
2 byte unsigned integer crc value
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if isinstance(dobj, bytearray):
|
if isinstance(dobj, (bytes,bytearray)):
|
||||||
dobj = str(dobj)
|
dobj = str(dobj)
|
||||||
version, size, setting = GetTemplateSetting(dobj)
|
version, size, setting = GetTemplateSetting(dobj)
|
||||||
if version < 0x06060007 or version > 0x0606000A:
|
if version < 0x06060007 or version > 0x0606000A:
|
||||||
@ -1862,7 +1813,7 @@ def GetSettingsCrc32(dobj):
|
|||||||
4 byte unsigned integer crc value
|
4 byte unsigned integer crc value
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if isinstance(dobj, bytearray):
|
if isinstance(dobj, (bytes,bytearray)):
|
||||||
dobj = str(dobj)
|
dobj = str(dobj)
|
||||||
crc = 0
|
crc = 0
|
||||||
for i in range(0, len(dobj)-4):
|
for i in range(0, len(dobj)-4):
|
||||||
@ -1907,35 +1858,35 @@ def GetFieldDef(fielddef, fields="format_, addrdef, baseaddr, bits, bitshift, da
|
|||||||
raise SyntaxError('<fielddef> error')
|
raise SyntaxError('<fielddef> error')
|
||||||
|
|
||||||
# ignore calls with 'root' setting
|
# ignore calls with 'root' setting
|
||||||
if isinstance(format_, dict) and baseaddr is None and datadef is None:
|
if isinstance(format_, instance(dict)) and baseaddr is None and datadef is None:
|
||||||
return eval(fields)
|
return eval(fields)
|
||||||
|
|
||||||
if not isinstance(format_, (unicode,str,dict)):
|
if not isinstance(format_, instance((str,dict))):
|
||||||
print('wrong <format> {} type {} in <fielddef> {}'.format(format_, type(format_), fielddef), file=sys.stderr)
|
print('wrong <format> {} type {} in <fielddef> {}'.format(format_, type(format_), fielddef), file=sys.stderr)
|
||||||
raise SyntaxError('<fielddef> error')
|
raise SyntaxError('<fielddef> error')
|
||||||
|
|
||||||
# extract addrdef items
|
# extract addrdef items
|
||||||
baseaddr = addrdef
|
baseaddr = addrdef
|
||||||
if isinstance(baseaddr, (list,tuple)):
|
if isinstance(baseaddr, instance((list,tuple))):
|
||||||
if len(baseaddr) == 3:
|
if len(baseaddr) == 3:
|
||||||
# baseaddr bit definition
|
# baseaddr bit definition
|
||||||
baseaddr, bits, bitshift = baseaddr
|
baseaddr, bits, bitshift = baseaddr
|
||||||
if not isinstance(bits, int):
|
if not isinstance(bits, instance(int)):
|
||||||
print('<bits> must be defined as integer in <fielddef> {}'.format(bits, fielddef), file=sys.stderr)
|
print('<bits> must be defined as integer in <fielddef> {}'.format(bits, fielddef), file=sys.stderr)
|
||||||
raise SyntaxError('<fielddef> error')
|
raise SyntaxError('<fielddef> error')
|
||||||
if not isinstance(bitshift, int):
|
if not isinstance(bitshift, instance(int)):
|
||||||
print('<bitshift> must be defined as integer in <fielddef> {}'.format(bitshift, fielddef), file=sys.stderr)
|
print('<bitshift> must be defined as integer in <fielddef> {}'.format(bitshift, fielddef), file=sys.stderr)
|
||||||
raise SyntaxError('<fielddef> error')
|
raise SyntaxError('<fielddef> error')
|
||||||
else:
|
else:
|
||||||
print('wrong <addrdef> {} length ({}) in <fielddef> {}'.format(addrdef, len(addrdef), fielddef), file=sys.stderr)
|
print('wrong <addrdef> {} length ({}) in <fielddef> {}'.format(addrdef, len(addrdef), fielddef), file=sys.stderr)
|
||||||
raise SyntaxError('<fielddef> error')
|
raise SyntaxError('<fielddef> error')
|
||||||
if not isinstance(baseaddr, int):
|
if not isinstance(baseaddr, instance(int)):
|
||||||
print('<baseaddr> must be defined as integer in <fielddef> {}'.format(baseaddr, fielddef), file=sys.stderr)
|
print('<baseaddr> must be defined as integer in <fielddef> {}'.format(baseaddr, fielddef), file=sys.stderr)
|
||||||
raise SyntaxError('<fielddef> error')
|
raise SyntaxError('<fielddef> error')
|
||||||
|
|
||||||
# extract datadef items
|
# extract datadef items
|
||||||
arraydef = datadef
|
arraydef = datadef
|
||||||
if isinstance(datadef, (tuple)):
|
if isinstance(datadef, instance((tuple))):
|
||||||
if len(datadef) == 2:
|
if len(datadef) == 2:
|
||||||
# datadef has a validator
|
# datadef has a validator
|
||||||
arraydef, validate = datadef
|
arraydef, validate = datadef
|
||||||
@ -1943,19 +1894,19 @@ def GetFieldDef(fielddef, fields="format_, addrdef, baseaddr, bits, bitshift, da
|
|||||||
# datadef has a validator and cmd set
|
# datadef has a validator and cmd set
|
||||||
arraydef, validate, cmd = datadef
|
arraydef, validate, cmd = datadef
|
||||||
# cmd must be a tuple with 2 objects
|
# cmd must be a tuple with 2 objects
|
||||||
if isinstance(cmd, (tuple)) and len(cmd) == 2:
|
if isinstance(cmd, instance((tuple))) and len(cmd) == 2:
|
||||||
group, tasmotacmnd = cmd
|
group, tasmotacmnd = cmd
|
||||||
if group is not None and not isinstance(group, (str, unicode)):
|
if group is not None and not isinstance(group, instance(str)):
|
||||||
print('wrong <group> {} in <fielddef> {}'.format(group, fielddef), file=sys.stderr)
|
print('wrong <group> {} in <fielddef> {}'.format(group, fielddef), file=sys.stderr)
|
||||||
raise SyntaxError('<fielddef> error')
|
raise SyntaxError('<fielddef> error')
|
||||||
if tasmotacmnd is isinstance(tasmotacmnd, tuple):
|
if tasmotacmnd is isinstance(tasmotacmnd, instance(tuple)):
|
||||||
tasmotacmnds = tasmotacmnd
|
tasmotacmnds = tasmotacmnd
|
||||||
for tasmotacmnd in tasmotacmnds:
|
for tasmotacmnd in tasmotacmnds:
|
||||||
if tasmotacmnd is not None and not callable(tasmotacmnd) and not isinstance(tasmotacmnd, (str, unicode)):
|
if tasmotacmnd is not None and not callable(tasmotacmnd) and not isinstance(tasmotacmnd, instance(str)):
|
||||||
print('wrong <tasmotacmnd> {} in <fielddef> {}'.format(tasmotacmnd, fielddef), file=sys.stderr)
|
print('wrong <tasmotacmnd> {} in <fielddef> {}'.format(tasmotacmnd, fielddef), file=sys.stderr)
|
||||||
raise SyntaxError('<fielddef> error')
|
raise SyntaxError('<fielddef> error')
|
||||||
else:
|
else:
|
||||||
if tasmotacmnd is not None and not callable(tasmotacmnd) and not isinstance(tasmotacmnd, (str, unicode)):
|
if tasmotacmnd is not None and not callable(tasmotacmnd) and not isinstance(tasmotacmnd, instance(str)):
|
||||||
print('wrong <tasmotacmnd> {} in <fielddef> {}'.format(tasmotacmnd, fielddef), file=sys.stderr)
|
print('wrong <tasmotacmnd> {} in <fielddef> {}'.format(tasmotacmnd, fielddef), file=sys.stderr)
|
||||||
raise SyntaxError('<fielddef> error')
|
raise SyntaxError('<fielddef> error')
|
||||||
else:
|
else:
|
||||||
@ -1965,28 +1916,28 @@ def GetFieldDef(fielddef, fields="format_, addrdef, baseaddr, bits, bitshift, da
|
|||||||
print('wrong <datadef> {} length ({}) in <fielddef> {}'.format(datadef, len(datadef), fielddef), file=sys.stderr)
|
print('wrong <datadef> {} length ({}) in <fielddef> {}'.format(datadef, len(datadef), fielddef), file=sys.stderr)
|
||||||
raise SyntaxError('<fielddef> error')
|
raise SyntaxError('<fielddef> error')
|
||||||
|
|
||||||
if validate is not None and (not isinstance(validate, (unicode,str)) and not callable(validate)):
|
if validate is not None and (not isinstance(validate, instance(str)) and not callable(validate)):
|
||||||
print('wrong <validate> {} type {} in <fielddef> {}'.format(validate, type(validate), fielddef), file=sys.stderr)
|
print('wrong <validate> {} type {} in <fielddef> {}'.format(validate, type(validate), fielddef), file=sys.stderr)
|
||||||
raise SyntaxError('<fielddef> error')
|
raise SyntaxError('<fielddef> error')
|
||||||
|
|
||||||
# convert single int into one-dimensional list
|
# convert single int into one-dimensional list
|
||||||
if isinstance(arraydef, int):
|
if isinstance(arraydef, instance(int)):
|
||||||
arraydef = [arraydef]
|
arraydef = [arraydef]
|
||||||
|
|
||||||
if arraydef is not None and not isinstance(arraydef, (list)):
|
if arraydef is not None and not isinstance(arraydef, instance((list))):
|
||||||
print('wrong <arraydef> {} type {} in <fielddef> {}'.format(arraydef, type(arraydef), fielddef), file=sys.stderr)
|
print('wrong <arraydef> {} type {} in <fielddef> {}'.format(arraydef, type(arraydef), fielddef), file=sys.stderr)
|
||||||
raise SyntaxError('<fielddef> error')
|
raise SyntaxError('<fielddef> error')
|
||||||
|
|
||||||
# get read/write converter items
|
# get read/write converter items
|
||||||
readconverter = converter
|
readconverter = converter
|
||||||
if isinstance(converter, (tuple)):
|
if isinstance(converter, instance((tuple))):
|
||||||
if len(converter) == 2:
|
if len(converter) == 2:
|
||||||
# converter has read/write converter
|
# converter has read/write converter
|
||||||
readconverter, writeconverter = converter
|
readconverter, writeconverter = converter
|
||||||
if readconverter is not None and not isinstance(readconverter, (str,unicode)) and not callable(readconverter):
|
if readconverter is not None and not isinstance(readconverter, instance(str)) and not callable(readconverter):
|
||||||
print('wrong <readconverter> {} type {} in <fielddef> {}'.format(readconverter, type(readconverter), fielddef), file=sys.stderr)
|
print('wrong <readconverter> {} type {} in <fielddef> {}'.format(readconverter, type(readconverter), fielddef), file=sys.stderr)
|
||||||
raise SyntaxError('<fielddef> error')
|
raise SyntaxError('<fielddef> error')
|
||||||
if writeconverter is not None and (not isinstance(writeconverter, (bool,str,unicode)) and not callable(writeconverter)):
|
if writeconverter is not None and (not isinstance(writeconverter, instance((bool,str))) and not callable(writeconverter)):
|
||||||
print('wrong <writeconverter> {} type {} in <fielddef> {}'.format(writeconverter, type(writeconverter), fielddef), file=sys.stderr)
|
print('wrong <writeconverter> {} type {} in <fielddef> {}'.format(writeconverter, type(writeconverter), fielddef), file=sys.stderr)
|
||||||
raise SyntaxError('<fielddef> error')
|
raise SyntaxError('<fielddef> error')
|
||||||
else:
|
else:
|
||||||
@ -2024,7 +1975,7 @@ def ReadWriteConverter(value, fielddef, read=True, raw=False):
|
|||||||
if not raw and converter is not None:
|
if not raw and converter is not None:
|
||||||
conv = readconverter if read else writeconverter
|
conv = readconverter if read else writeconverter
|
||||||
try:
|
try:
|
||||||
if isinstance(conv, str): # evaluate strings
|
if isinstance(conv, instance(str)): # evaluate strings
|
||||||
return eval(conv.replace('$','value'))
|
return eval(conv.replace('$','value'))
|
||||||
elif callable(conv): # use as format function
|
elif callable(conv): # use as format function
|
||||||
return conv(value)
|
return conv(value)
|
||||||
@ -2061,7 +2012,7 @@ def CmndConverter(valuemapping, value, idx, fielddef):
|
|||||||
if tasmotacmnd is not None and (callable(tasmotacmnd) or len(tasmotacmnd) > 0):
|
if tasmotacmnd is not None and (callable(tasmotacmnd) or len(tasmotacmnd) > 0):
|
||||||
if idx is not None:
|
if idx is not None:
|
||||||
idx += 1
|
idx += 1
|
||||||
if isinstance(tasmotacmnd, str): # evaluate strings
|
if isinstance(tasmotacmnd, instance(str)): # evaluate strings
|
||||||
if idx is not None:
|
if idx is not None:
|
||||||
evalstr = tasmotacmnd.replace('$','value').replace('#','idx').replace('@','valuemapping')
|
evalstr = tasmotacmnd.replace('$','value').replace('#','idx').replace('@','valuemapping')
|
||||||
else:
|
else:
|
||||||
@ -2100,7 +2051,7 @@ def ValidateValue(value, fielddef):
|
|||||||
|
|
||||||
valid = True
|
valid = True
|
||||||
try:
|
try:
|
||||||
if isinstance(validate, str): # evaluate strings
|
if isinstance(validate, instance(str)): # evaluate strings
|
||||||
valid = eval(validate.replace('$','value'))
|
valid = eval(validate.replace('$','value'))
|
||||||
elif callable(validate): # use as format function
|
elif callable(validate): # use as format function
|
||||||
valid = validate(value)
|
valid = validate(value)
|
||||||
@ -2121,7 +2072,7 @@ def GetFormatCount(format_):
|
|||||||
prefix count or 1 if not specified
|
prefix count or 1 if not specified
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if isinstance(format_, str):
|
if isinstance(format_, instance(str)):
|
||||||
match = re.search("\s*(\d+)", format_)
|
match = re.search("\s*(\d+)", format_)
|
||||||
if match:
|
if match:
|
||||||
return int(match.group(0))
|
return int(match.group(0))
|
||||||
@ -2142,7 +2093,7 @@ def GetFormatType(format_):
|
|||||||
|
|
||||||
formattype = format_
|
formattype = format_
|
||||||
bitsize = 0
|
bitsize = 0
|
||||||
if isinstance(format_, str):
|
if isinstance(format_, instance(str)):
|
||||||
match = re.search("\s*(\D+)", format_)
|
match = re.search("\s*(\D+)", format_)
|
||||||
if match:
|
if match:
|
||||||
formattype = match.group(0)
|
formattype = match.group(0)
|
||||||
@ -2204,7 +2155,7 @@ def GetFieldLength(fielddef):
|
|||||||
format_, addrdef, arraydef = GetFieldDef(fielddef, fields='format_, addrdef, arraydef')
|
format_, addrdef, arraydef = GetFieldDef(fielddef, fields='format_, addrdef, arraydef')
|
||||||
|
|
||||||
# <arraydef> contains a integer list
|
# <arraydef> contains a integer list
|
||||||
if isinstance(arraydef, list) and len(arraydef) > 0:
|
if isinstance(arraydef, instance(list)) and len(arraydef) > 0:
|
||||||
# arraydef contains a list
|
# arraydef contains a list
|
||||||
# calc size recursive by sum of all elements
|
# calc size recursive by sum of all elements
|
||||||
for i in range(0, arraydef[0]):
|
for i in range(0, arraydef[0]):
|
||||||
@ -2215,7 +2166,7 @@ def GetFieldLength(fielddef):
|
|||||||
else:
|
else:
|
||||||
length += GetFieldLength( (format_, addrdef, None) )
|
length += GetFieldLength( (format_, addrdef, None) )
|
||||||
|
|
||||||
elif isinstance(format_, dict):
|
elif isinstance(format_, instance(dict)):
|
||||||
# -> iterate through format
|
# -> iterate through format
|
||||||
addr = None
|
addr = None
|
||||||
setting = format_
|
setting = format_
|
||||||
@ -2227,7 +2178,7 @@ def GetFieldLength(fielddef):
|
|||||||
length += _len
|
length += _len
|
||||||
|
|
||||||
# a simple value
|
# a simple value
|
||||||
elif isinstance(format_, str):
|
elif isinstance(format_, instance(str)):
|
||||||
length = struct.calcsize(format_)
|
length = struct.calcsize(format_)
|
||||||
|
|
||||||
return length
|
return length
|
||||||
@ -2253,7 +2204,7 @@ def GetSubfieldDef(fielddef):
|
|||||||
arraydef = None
|
arraydef = None
|
||||||
|
|
||||||
# create new datadef
|
# create new datadef
|
||||||
if isinstance(datadef, tuple):
|
if isinstance(datadef, instance(tuple)):
|
||||||
if cmd is not None:
|
if cmd is not None:
|
||||||
datadef = (arraydef, validate, cmd)
|
datadef = (arraydef, validate, cmd)
|
||||||
else:
|
else:
|
||||||
@ -2346,7 +2297,7 @@ def SetFieldValue(fielddef, dobj, addr, value):
|
|||||||
format_, bits, bitshift = GetFieldDef(fielddef, fields='format_, bits, bitshift')
|
format_, bits, bitshift = GetFieldDef(fielddef, fields='format_, bits, bitshift')
|
||||||
formatcnt = GetFormatCount(format_)
|
formatcnt = GetFormatCount(format_)
|
||||||
singletype, bitsize = GetFormatType(format_)
|
singletype, bitsize = GetFormatType(format_)
|
||||||
if args.debug >= 2:
|
if debug(args) >= 2:
|
||||||
print("SetFieldValue(): fielddef {}, addr 0x{:04x} value {} formatcnt {} singletype {} bitsize {} ".format(fielddef,addr,value,formatcnt,singletype,bitsize), file=sys.stderr)
|
print("SetFieldValue(): fielddef {}, addr 0x{:04x} value {} formatcnt {} singletype {} bitsize {} ".format(fielddef,addr,value,formatcnt,singletype,bitsize), file=sys.stderr)
|
||||||
if not format_[-1:].lower() in ['s','p']:
|
if not format_[-1:].lower() in ['s','p']:
|
||||||
addr += (bitsize / 8) * formatcnt
|
addr += (bitsize / 8) * formatcnt
|
||||||
@ -2355,9 +2306,9 @@ def SetFieldValue(fielddef, dobj, addr, value):
|
|||||||
maxunsigned = ((2**bitsize) - 1)
|
maxunsigned = ((2**bitsize) - 1)
|
||||||
maxsigned = ((2**bitsize)>>1)-1
|
maxsigned = ((2**bitsize)>>1)-1
|
||||||
val = value & maxunsigned
|
val = value & maxunsigned
|
||||||
if isinstance(value,int) and value < 0 and val > maxsigned:
|
if isinstance(value,instance(int)) and value < 0 and val > maxsigned:
|
||||||
val = ((maxunsigned+1)-val) * (-1)
|
val = ((maxunsigned+1)-val) * (-1)
|
||||||
if args.debug >= 3:
|
if debug(args) >= 3:
|
||||||
print("SetFieldValue(): Single type - fielddef {}, addr 0x{:04x} value {} singletype {} bitsize {}".format(fielddef,addr,val,singletype,bitsize), file=sys.stderr)
|
print("SetFieldValue(): Single type - fielddef {}, addr 0x{:04x} value {} singletype {} bitsize {}".format(fielddef,addr,val,singletype,bitsize), file=sys.stderr)
|
||||||
try:
|
try:
|
||||||
struct.pack_into(singletype, dobj, addr, val)
|
struct.pack_into(singletype, dobj, addr, val)
|
||||||
@ -2369,7 +2320,7 @@ def SetFieldValue(fielddef, dobj, addr, value):
|
|||||||
line=inspect.getlineno(inspect.currentframe()))
|
line=inspect.getlineno(inspect.currentframe()))
|
||||||
value >>= bitsize
|
value >>= bitsize
|
||||||
else:
|
else:
|
||||||
if args.debug >= 3:
|
if debug(args) >= 3:
|
||||||
print("SetFieldValue(): String type - fielddef {}, addr 0x{:04x} value {} format_ {}".format(fielddef,addr,value,format_), file=sys.stderr)
|
print("SetFieldValue(): String type - fielddef {}, addr 0x{:04x} value {} format_ {}".format(fielddef,addr,value,format_), file=sys.stderr)
|
||||||
try:
|
try:
|
||||||
struct.pack_into(format_, dobj, addr, value)
|
struct.pack_into(format_, dobj, addr, value)
|
||||||
@ -2402,7 +2353,7 @@ def GetField(dobj, fieldname, fielddef, raw=False, addroffset=0):
|
|||||||
field mapping
|
field mapping
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if isinstance(dobj, bytearray):
|
if isinstance(dobj, instance((bytes,bytearray))):
|
||||||
dobj = str(dobj)
|
dobj = str(dobj)
|
||||||
|
|
||||||
valuemapping = None
|
valuemapping = None
|
||||||
@ -2415,7 +2366,7 @@ def GetField(dobj, fieldname, fielddef, raw=False, addroffset=0):
|
|||||||
return valuemapping
|
return valuemapping
|
||||||
|
|
||||||
# <arraydef> contains a integer list
|
# <arraydef> contains a integer list
|
||||||
if isinstance(arraydef, list) and len(arraydef) > 0:
|
if isinstance(arraydef, instance(list)) and len(arraydef) > 0:
|
||||||
valuemapping = []
|
valuemapping = []
|
||||||
offset = 0
|
offset = 0
|
||||||
for i in range(0, arraydef[0]):
|
for i in range(0, arraydef[0]):
|
||||||
@ -2427,7 +2378,7 @@ def GetField(dobj, fieldname, fielddef, raw=False, addroffset=0):
|
|||||||
offset += length
|
offset += length
|
||||||
|
|
||||||
# <format> contains a dict
|
# <format> contains a dict
|
||||||
elif isinstance(format_, dict):
|
elif isinstance(format_, instance(dict)):
|
||||||
mapping_value = {}
|
mapping_value = {}
|
||||||
# -> iterate through format
|
# -> iterate through format
|
||||||
for name in format_:
|
for name in format_:
|
||||||
@ -2439,7 +2390,7 @@ def GetField(dobj, fieldname, fielddef, raw=False, addroffset=0):
|
|||||||
valuemapping = copy.deepcopy(mapping_value)
|
valuemapping = copy.deepcopy(mapping_value)
|
||||||
|
|
||||||
# a simple value
|
# a simple value
|
||||||
elif isinstance(format_, (str, bool, int, float, long)):
|
elif isinstance(format_, instance((str, bool, int, float, long))):
|
||||||
if GetFieldLength(fielddef) != 0:
|
if GetFieldLength(fielddef) != 0:
|
||||||
valuemapping = ReadWriteConverter(GetFieldValue(fielddef, dobj, baseaddr+addroffset), fielddef, read=True, raw=raw)
|
valuemapping = ReadWriteConverter(GetFieldValue(fielddef, dobj, baseaddr+addroffset), fielddef, read=True, raw=raw)
|
||||||
|
|
||||||
@ -2479,12 +2430,12 @@ def SetField(dobj, fieldname, fielddef, restore, addroffset=0, filename=""):
|
|||||||
|
|
||||||
# do not write readonly values
|
# do not write readonly values
|
||||||
if writeconverter is False:
|
if writeconverter is False:
|
||||||
if args.debug >= 2:
|
if debug(args) >= 2:
|
||||||
print("SetField(): Readonly '{}' using '{}'/{}{} @{} skipped".format(fieldname, format_, arraydef, bits, hex(baseaddr+addroffset)), file=sys.stderr)
|
print("SetField(): Readonly '{}' using '{}'/{}{} @{} skipped".format(fieldname, format_, arraydef, bits, hex(baseaddr+addroffset)), file=sys.stderr)
|
||||||
return dobj
|
return dobj
|
||||||
|
|
||||||
# <arraydef> contains a list
|
# <arraydef> contains a list
|
||||||
if isinstance(arraydef, list) and len(arraydef) > 0:
|
if isinstance(arraydef, instance(list)) and len(arraydef) > 0:
|
||||||
offset = 0
|
offset = 0
|
||||||
if len(restore) > arraydef[0]:
|
if len(restore) > arraydef[0]:
|
||||||
exit(ExitCode.RESTORE_DATA_ERROR, "file '{sfile}', array '{sname}[{selem}]' exceeds max number of elements [{smax}]".format(sfile=filename, sname=fieldname, selem=len(restore), smax=arraydef[0]), type_=LogType.WARNING, doexit=not args.ignorewarning, line=inspect.getlineno(inspect.currentframe()))
|
exit(ExitCode.RESTORE_DATA_ERROR, "file '{sfile}', array '{sname}[{selem}]' exceeds max number of elements [{smax}]".format(sfile=filename, sname=fieldname, selem=len(restore), smax=arraydef[0]), type_=LogType.WARNING, doexit=not args.ignorewarning, line=inspect.getlineno(inspect.currentframe()))
|
||||||
@ -2499,13 +2450,13 @@ def SetField(dobj, fieldname, fielddef, restore, addroffset=0, filename=""):
|
|||||||
offset += length
|
offset += length
|
||||||
|
|
||||||
# <format> contains a dict
|
# <format> contains a dict
|
||||||
elif isinstance(format_, dict):
|
elif isinstance(format_, instance(dict)):
|
||||||
for name in format_: # -> iterate through format
|
for name in format_: # -> iterate through format
|
||||||
if name in restore:
|
if name in restore:
|
||||||
dobj = SetField(dobj, name, format_[name], restore[name], addroffset=addroffset, filename=filename)
|
dobj = SetField(dobj, name, format_[name], restore[name], addroffset=addroffset, filename=filename)
|
||||||
|
|
||||||
# a simple value
|
# a simple value
|
||||||
elif isinstance(format_, (str, bool, int, float, long)):
|
elif isinstance(format_, instance((str, bool, int, float, long))):
|
||||||
valid = True
|
valid = True
|
||||||
err = ""
|
err = ""
|
||||||
errformat = ""
|
errformat = ""
|
||||||
@ -2533,7 +2484,7 @@ def SetField(dobj, fieldname, fielddef, restore, addroffset=0, filename=""):
|
|||||||
# integer
|
# integer
|
||||||
elif format_[-1:] in ['b','B','h','H','i','I','l','L','q','Q','P']:
|
elif format_[-1:] in ['b','B','h','H','i','I','l','L','q','Q','P']:
|
||||||
value = ReadWriteConverter(restore, fielddef, read=False)
|
value = ReadWriteConverter(restore, fielddef, read=False)
|
||||||
if isinstance(value, (str, unicode)):
|
if isinstance(value, instance(str)):
|
||||||
value = int(value, 0)
|
value = int(value, 0)
|
||||||
else:
|
else:
|
||||||
value = int(value)
|
value = int(value)
|
||||||
@ -2605,14 +2556,14 @@ def SetField(dobj, fieldname, fielddef, restore, addroffset=0, filename=""):
|
|||||||
# copy value before possible change below
|
# copy value before possible change below
|
||||||
_value = value
|
_value = value
|
||||||
|
|
||||||
if isinstance(_value, (str, unicode)):
|
if isinstance(_value, instance(str)):
|
||||||
_value = "'{}'".format(_value)
|
_value = "'{}'".format(_value)
|
||||||
|
|
||||||
if valid:
|
if valid:
|
||||||
if not skip:
|
if not skip:
|
||||||
if args.debug >= 2:
|
if debug(args) >= 2:
|
||||||
sbits = " {} bits shift {}".format(bits, bitshift) if bits else ""
|
sbits = " {} bits shift {}".format(bits, bitshift) if bits else ""
|
||||||
strvalue = "{} [{}]".format(_value, hex(value)) if isinstance(_value, int) else _value
|
strvalue = "{} [{}]".format(_value, hex(value)) if isinstance(_value, instance(int)) else _value
|
||||||
print("SetField(): Set '{}' using '{}'/{}{} @{} to {}".format(fieldname, format_, arraydef, sbits, hex(baseaddr+addroffset), strvalue), file=sys.stderr)
|
print("SetField(): Set '{}' using '{}'/{}{} @{} to {}".format(fieldname, format_, arraydef, sbits, hex(baseaddr+addroffset), strvalue), file=sys.stderr)
|
||||||
if fieldname != 'cfg_crc' and fieldname != '_':
|
if fieldname != 'cfg_crc' and fieldname != '_':
|
||||||
prevvalue = GetFieldValue(fielddef, dobj, baseaddr+addroffset)
|
prevvalue = GetFieldValue(fielddef, dobj, baseaddr+addroffset)
|
||||||
@ -2621,7 +2572,7 @@ def SetField(dobj, fieldname, fielddef, restore, addroffset=0, filename=""):
|
|||||||
if prevvalue != curvalue and args.verbose:
|
if prevvalue != curvalue and args.verbose:
|
||||||
message("Value for '{}' changed from {} to {}".format(fieldname, prevvalue, curvalue), type_=LogType.INFO)
|
message("Value for '{}' changed from {} to {}".format(fieldname, prevvalue, curvalue), type_=LogType.INFO)
|
||||||
else:
|
else:
|
||||||
if args.debug >= 2:
|
if debug(args) >= 2:
|
||||||
print("SetField(): Special field '{}' using '{}'/{}{} @{} skipped".format(fieldname, format_, arraydef, bits, hex(baseaddr+addroffset)), file=sys.stderr)
|
print("SetField(): Special field '{}' using '{}'/{}{} @{} skipped".format(fieldname, format_, arraydef, bits, hex(baseaddr+addroffset)), file=sys.stderr)
|
||||||
else:
|
else:
|
||||||
sformat = "file '{sfile}' - {{'{sname}': {svalue}}} ({serror})"+errformat
|
sformat = "file '{sfile}' - {{'{sname}': {svalue}}} ({serror})"+errformat
|
||||||
@ -2662,7 +2613,7 @@ def SetCmnd(cmnds, fieldname, fielddef, valuemapping, mappedvalue, addroffset=0,
|
|||||||
return cmnds
|
return cmnds
|
||||||
|
|
||||||
# <arraydef> contains a list
|
# <arraydef> contains a list
|
||||||
if isinstance(arraydef, list) and len(arraydef) > 0:
|
if isinstance(arraydef, instance(list)) and len(arraydef) > 0:
|
||||||
offset = 0
|
offset = 0
|
||||||
if len(mappedvalue) > arraydef[0]:
|
if len(mappedvalue) > arraydef[0]:
|
||||||
exit(ExitCode.RESTORE_DATA_ERROR, "array '{sname}[{selem}]' exceeds max number of elements [{smax}]".format(sname=fieldname, selem=len(mappedvalue), smax=arraydef[0]), type_=LogType.WARNING, doexit=not args.ignorewarning, line=inspect.getlineno(inspect.currentframe()))
|
exit(ExitCode.RESTORE_DATA_ERROR, "array '{sname}[{selem}]' exceeds max number of elements [{smax}]".format(sname=fieldname, selem=len(mappedvalue), smax=arraydef[0]), type_=LogType.WARNING, doexit=not args.ignorewarning, line=inspect.getlineno(inspect.currentframe()))
|
||||||
@ -2677,23 +2628,23 @@ def SetCmnd(cmnds, fieldname, fielddef, valuemapping, mappedvalue, addroffset=0,
|
|||||||
offset += length
|
offset += length
|
||||||
|
|
||||||
# <format> contains a dict
|
# <format> contains a dict
|
||||||
elif isinstance(format_, dict):
|
elif isinstance(format_, instance(dict)):
|
||||||
for name in format_: # -> iterate through format
|
for name in format_: # -> iterate through format
|
||||||
if name in mappedvalue:
|
if name in mappedvalue:
|
||||||
cmnds = SetCmnd(cmnds, name, format_[name], valuemapping, mappedvalue[name], addroffset=addroffset, idx=idx)
|
cmnds = SetCmnd(cmnds, name, format_[name], valuemapping, mappedvalue[name], addroffset=addroffset, idx=idx)
|
||||||
|
|
||||||
# a simple value
|
# a simple value
|
||||||
elif isinstance(format_, (str, bool, int, float, long)):
|
elif isinstance(format_, instance((str, bool, int, float, long))):
|
||||||
if group is not None:
|
if group is not None:
|
||||||
group = group.title();
|
group = group.title();
|
||||||
if isinstance(tasmotacmnd, tuple):
|
if isinstance(tasmotacmnd, instance(tuple)):
|
||||||
tasmotacmnds = tasmotacmnd
|
tasmotacmnds = tasmotacmnd
|
||||||
for tasmotacmnd in tasmotacmnds:
|
for tasmotacmnd in tasmotacmnds:
|
||||||
cmnd = CmndConverter(valuemapping, mappedvalue, idx, fielddef)
|
cmnd = CmndConverter(valuemapping, mappedvalue, idx, fielddef)
|
||||||
if group is not None and cmnd is not None:
|
if group is not None and cmnd is not None:
|
||||||
if group not in cmnds:
|
if group not in cmnds:
|
||||||
cmnds[group] = []
|
cmnds[group] = []
|
||||||
if isinstance(cmnd, list):
|
if isinstance(cmnd, instance(list)):
|
||||||
for c in cmnd:
|
for c in cmnd:
|
||||||
cmnds[group].append(c)
|
cmnds[group].append(c)
|
||||||
else:
|
else:
|
||||||
@ -2703,7 +2654,7 @@ def SetCmnd(cmnds, fieldname, fielddef, valuemapping, mappedvalue, addroffset=0,
|
|||||||
if group is not None and cmnd is not None:
|
if group is not None and cmnd is not None:
|
||||||
if group not in cmnds:
|
if group not in cmnds:
|
||||||
cmnds[group] = []
|
cmnds[group] = []
|
||||||
if isinstance(cmnd, list):
|
if isinstance(cmnd, instance(list)):
|
||||||
for c in cmnd:
|
for c in cmnd:
|
||||||
cmnds[group].append(c)
|
cmnds[group].append(c)
|
||||||
else:
|
else:
|
||||||
@ -2722,7 +2673,7 @@ def Bin2Mapping(decode_cfg):
|
|||||||
@return:
|
@return:
|
||||||
valuemapping data as mapping dictionary
|
valuemapping data as mapping dictionary
|
||||||
"""
|
"""
|
||||||
if isinstance(decode_cfg, bytearray):
|
if isinstance(decode_cfg, instance((bytes,bytearray))):
|
||||||
decode_cfg = str(decode_cfg)
|
decode_cfg = str(decode_cfg)
|
||||||
|
|
||||||
# get binary header and template to use
|
# get binary header and template to use
|
||||||
@ -2814,7 +2765,7 @@ def Mapping2Bin(decode_cfg, jsonconfig, filename=""):
|
|||||||
@return:
|
@return:
|
||||||
changed binary config data (decrypted) or None on error
|
changed binary config data (decrypted) or None on error
|
||||||
"""
|
"""
|
||||||
if isinstance(decode_cfg, str):
|
if isinstance(decode_cfg, instance(str)):
|
||||||
decode_cfg = bytearray(decode_cfg)
|
decode_cfg = bytearray(decode_cfg)
|
||||||
|
|
||||||
|
|
||||||
@ -2864,7 +2815,7 @@ def Mapping2Cmnd(decode_cfg, valuemapping, filename=""):
|
|||||||
@return:
|
@return:
|
||||||
Tasmota command mapping {group: [cmnd <,cmnd <,...>>]}
|
Tasmota command mapping {group: [cmnd <,cmnd <,...>>]}
|
||||||
"""
|
"""
|
||||||
if isinstance(decode_cfg, str):
|
if isinstance(decode_cfg, instance(str)):
|
||||||
decode_cfg = bytearray(decode_cfg)
|
decode_cfg = bytearray(decode_cfg)
|
||||||
|
|
||||||
# get binary header data to use the correct version template from device
|
# get binary header data to use the correct version template from device
|
||||||
@ -3297,7 +3248,7 @@ def ParseArgs():
|
|||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if args.debug >= 1:
|
if debug(args) >= 1:
|
||||||
print(parser.format_values(), file=sys.stderr)
|
print(parser.format_values(), file=sys.stderr)
|
||||||
print("Settings:", file=sys.stderr)
|
print("Settings:", file=sys.stderr)
|
||||||
for k in args.__dict__:
|
for k in args.__dict__:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user