Tasmota Firmware with Web-Server enabled:
-
+- This program is written in Python) so you need to install a working python environment for your operating system.
+
+Linux
+sudo apt-get install python python-pip libcurl4-openssl-dev libssl-dev
+
pip install pycurl configargparse
+
Windows 10
+Install Python 2.7 then install dependencies. For PyCurl you need to download pycurl‑7.43.0.3‑cp27‑cp27m‑win_amd64.whl for Windows 10 64bit.
+pip install pycurl-7.43.0.3-cp27-cp27m-win_amd64.whl configargparse
+
+
+pip install configargparse
+
+- Tasmota Firmware with Web-Server enabled:
- To backup or restore configurations from or to a Tasmota device you need a firmare with enabled web-server in admin mode (command WebServer 2). This is the Tasmota default.
- If using your own compiled firmware be aware to enable the web-server (
#define USE_WEBSERVER
and #define WEB_SERVER 2
).
File Types
-decode-config.py can handle the following backup file types:
+decode-config.py can handle the following backup file types:
-Configuration data as used by Tasmota "Backup/Restore Configuration" web interface.
This format is binary and encrypted.
+Configuration data as used by Tasmota "Backup/Restore Configuration" web interface.
+This format is binary and encrypted.
-Configuration data in JSON-format.
This format is decrypted, human readable and editable and can also be used for the --restore-file
parameter.
This file will be created by decode-config.py using the --backup-file
with --backup-type json
parameter, this is the default.
+Configuration data in JSON-format.
+This format is decrypted, human readable and editable and can also be used for the --restore-file
parameter.
+This file will be created by decode-config.py using the --backup-file
with --backup-type json
parameter, this is the default.
-Configuration data in binary format.
This format is binary decryptet, editable (e.g. using a hex editor) and can also be used for --restore-file
command.
It will be created by decode-config.py using --backup-file
with --backup-type bin
.
Note:
The .bin file contains the same information as the original .dmp file from Tasmota "Backup/Restore Configuration" but it is decrpted and 4 byte longer than an original (it is a prefix header at the beginning). .bin file data starting at address 4 contains the same as the struct SYSCFG from Tasmota settings.h in decrypted format.
+Configuration data in binary format.
+This format is binary decryptet, editable (e.g. using a hex editor) and can also be used for --restore-file
command.
+It will be created by decode-config.py using --backup-file
with --backup-type bin
.
+Note:
+The .bin file contains the same information as the original .dmp file from Tasmota "Backup/Restore Configuration" but it is decrpted and 4 byte longer than an original (it is a prefix header at the beginning). .bin file data starting at address 4 contains the same as the struct SYSCFG from Tasmota settings.h in decrypted format.
File extensions
You don't need to append exensions for your file name as decode-config.py uses auto extension as default. The extension will be choose based on file contents and --backup-type
parameter.
If you do not want using auto extensions use the --no-extension
parameter.
@@ -99,13 +115,13 @@ If you do not want using auto extensions use the --no-extension
par
After download don't forget to set the executable flag under linux with chmod +x decode-config.py
or call the program using python decode-config.py...
.
Basics
At least pass a source where you want to read the configuration data from using -f <filename>
or -d <host>
:
-The source can be either
+The source can be either
- a Tasmota device hostname or IP using the
-d <host>
parameter
- a Tasmota
*.dmp
configuration file using -f <filename>
parameter
-Example:
-decode-config.py -d sonoff-4281
+Example:
+decode-config.py -d tasmota-4281
will output a human readable configuration in JSON-format:
{
"altitude": 112,
@@ -120,24 +136,24 @@ If you do not want using auto extensions use the --no-extension
par
]
}
Save backup file
-To save the output as backup file use --backup-file <filename>
, you can use placeholder for Version, Friendlyname and Hostname:
-decode-config.py -d sonoff-4281 --backup-file Config_@f_@v
+To save the output as backup file use --backup-file <filename>
, you can use placeholder for Version, Friendlyname and Hostname:
+decode-config.py -d tasmota-4281 --backup-file Config_@f_@v
If you have setup a WebPassword within Tasmota, use
-decode-config.py -d sonoff-4281 -p <yourpassword> --backup-file Config_@f_@v
-
will create a file like Config_Sonoff_6.4.0.json
(the part Sonoff
and 6.4.0
will choosen related to your device configuration). Because the default backup file format is JSON, you can read and change it with any raw text editor.
+decode-config.py -d tasmota-4281 -p <yourpassword> --backup-file Config_@f_@v
+
will create a file like Config_Tasmota_6.4.0.json
(the part Tasmota
and 6.4.0
will choosen related to your device configuration). Because the default backup file format is JSON, you can read and change it with any raw text editor.
Restore backup file
Reading back a saved (and possible changed) backup file use the --restore-file <filename>
parameter. This will read the (changed) configuration data from this file and send it back to the source device or filename.
-To restore the previously save backup file Config_Sonoff_6.2.1.json
to device sonoff-4281
use:
-decode-config.py -d sonoff-4281 --restore-file Config_Sonoff_6.2.1.json
+To restore the previously save backup file Config_Tasmota_6.2.1.json
to device tasmota-4281
use:
+decode-config.py -d tasmota-4281 --restore-file Config_Tasmota_6.2.1.json
with password set by WebPassword:
-decode-config.py -d sonoff-4281 -p <yourpassword> --restore-file Config_Sonoff_6.2.1.json
+decode-config.py -d tasmota-4281 -p <yourpassword> --restore-file Config_Tasmota_6.2.1.json
Output to screen
To force screen output use the --output
parameter.
Output to screen is default enabled when calling the program with a source parameter (-f or -d) but without any backup or restore parameter.
JSON output
The default output format is JSON. You can force JSON output using the --output-format json
parameter.
Example:
-decode-config.py -d sonoff-4281 -c my.conf -x Wifi --output-format json
+decode-config.py -d tasmota-4281 -c my.conf -x Wifi --output-format json
{
...
@@ -171,7 +187,7 @@ If you do not want using auto extensions use the --no-extension
par
Tasmota command output
decode-config.py is able to translate the configuration data to (most all) Tasmota commands. To output your configuration as Tasmota commands use --output-format cmnd
or --output-format command
.
Example:
-decode-config.py -d sonoff-4281 -c my.conf -g Wifi --output-format cmnd
+decode-config.py -d tasmota-4281 -c my.conf -g Wifi --output-format cmnd
# Wifi:
AP 0
@@ -192,11 +208,11 @@ If you do not want using auto extensions use the --no-extension
par
WifiConfig 5
Note: A few very specific module commands like MPC230xx, KNX and some Display commands are not supported. These are still available by JSON output.
Filter data
-The huge number of Tasmota configuration data can be overstrained and confusing, so the most of the configuration data are grouped into categories.
-With decode-config.py the following categories are available: Display
, Domoticz
, Internal
, KNX
, Led
, Logging
, MCP230xx
, MQTT
, Main
, Management
, Pow
, Sensor
, Serial
, SetOption
, SonoffRF
, System
, Timers
, Wifi
+The huge number of Tasmota configuration data can be overstrained and confusing, so the most of the configuration data are grouped into categories.
+With decode-config.py the following categories are available: Display
, Domoticz
, Internal
, KNX
, Led
, Logging
, MCP230xx
, MQTT
, Main
, Management
, Pow
, Sensor
, Serial
, SetOption
, RF
, System
, Timers
, Wifi
These are similary to the categories on https://github.com/arendst/Tasmota/wiki/Commands.
To filter outputs to a subset of groups use the -g
or --group
arg concatenating the grooup you want, e. g.
-decode-config.py -d sonoff-4281 -c my.conf --output-format cmnd --group Main MQTT Management Wifi
+decode-config.py -d tasmota-4281 -c my.conf --output-format cmnd --group Main MQTT Management Wifi
Configuration file
Each argument that start with --
(eg. --file
) can also be set in a config file (specified via -c). Config file syntax allows: key=value, flag=true, stuff=[a,b,c] (for details, see syntax at https://pypi.org/project/ConfigArgParse).
If an argument is specified in more than one place, then commandline values override config file values which override defaults. This is usefull if you always use the same argument or a basic set of arguments.
@@ -206,7 +222,7 @@ If you do not want using auto extensions use the --no-extension
par
username = admin
password = myPaszxwo!z
To make a backup file from example above you can now pass the config file instead using the password on command line:
-decode-config.py -d sonoff-4281 -c my.conf --backup-file Config_@f_@v
+decode-config.py -d tasmota-4281 -c my.conf --backup-file Config_@f_@v
More program arguments
For better reading each short written arg (minus sign -
) has a corresponding long version (two minus signs --
), eg. --device
for -d
or --file
for -f
(note: not even all --
arg has a corresponding -
one).
A short list of possible program args is displayed using -h
or --help
.
@@ -219,7 +235,7 @@ If you do not want using auto extensions use the --no-extension
par
[--cmnd-indent <indent>] [--cmnd-groups]
[--cmnd-nogroups] [--cmnd-sort] [--cmnd-unsort]
[-c <filename>] [-S] [-T json|cmnd|command]
- [-g {Control,Devices,Display,Domoticz,Internal,KNX,Light,MQTT,Management,Power,Rules,Sensor,Serial,SetOption,SonoffRF,System,Timer,Wifi} [{Control,Devices,Display,Domoticz,Internal,KNX,Light,MQTT,Management,Power,Rules,Sensor,Serial,SetOption,SonoffRF,System,Timer,Wifi} ...]]
+ [-g {Control,Devices,Display,Domoticz,Internal,Knx,Light,Management,Mqtt,Power,Rf,Rules,Sensor,Serial,Setoption,Shutter,System,Timer,Wifi} [{Control,Devices,Display,Domoticz,Internal,Knx,Light,Management,Mqtt,Power,Rf,Rules,Sensor,Serial,Setoption,Shutter,System,Timer,Wifi} ...]]
[--ignore-warnings] [-h] [-H] [-v] [-V]
Backup/Restore Tasmota configuration data. Args that start with '--'
@@ -299,7 +315,7 @@ Common:
(default do not output on backup or restore usage)
-T, --output-format json|cmnd|command
display output format (default: 'json')
- -g, --group {Control,Devices,Display,Domoticz,Internal,Knx,Light,Management,Mqtt,Power,Rules,Sensor,Serial,Setoption,Shutter,Sonoffrf,System,Timer,Wifi}
+ -g, --group {Control,Devices,Display,Domoticz,Internal,Knx,Light,Management,Mqtt,Power,Rf,Rules,Sensor,Serial,Setoption,Shutter,System,Timer,Wifi}
limit data processing to command groups (default no
filter)
--ignore-warnings do not exit on warnings. Not recommended, used by your
@@ -331,26 +347,29 @@ json-indent 2
Using Tasmota binary configuration files
Restore a Tasmota configuration file
- decode-config.py -c my.conf -d sonoff --restore-file Config_Sonoff_6.2.1.dmp
+ decode-config.py -c my.conf -d tasmota --restore-file Config_Tasmota_6.2.1.dmp
Backup device using Tasmota configuration compatible format
a) use file extension to choice the file format
- decode-config.py -c my.conf -d sonoff --backup-file Config_@f_@v.dmp
+ decode-config.py -c my.conf -d tasmota --backup-file Config_@f_@v.dmp
b) use args to choice the file format
- decode-config.py -c my.conf -d sonoff --backup-type dmp --backup-file Config_@f_@v
+ decode-config.py -c my.conf -d tasmota --backup-type dmp --backup-file Config_@f_@v
Use batch processing
-for device in sonoff1 sonoff2 sonoff3; do ./decode-config.py -c my.conf -d $device -o Config_@f_@v
+for device in tasmota1 tasmota2 tasmota3; do ./decode-config.py -c my.conf -d $device -o Config_@f_@v
or under windows
-for device in (sonoff1 sonoff2 sonoff3) do python decode-config.py -c my.conf -d %device -o Config_@f_@v
-
will produce JSON configuration files for host sonoff1, sonoff2 and sonoff3 using friendly name and Tasmota firmware version for backup filenames.
+for device in (tasmota1 tasmota2 tasmota3) do python decode-config.py -c my.conf -d %device -o Config_@f_@v
+
will produce JSON configuration files for host tasmota1, tasmota2 and tasmota3 using friendly name and Tasmota firmware version for backup filenames.
Notes
Some general notes:
- Filename replacement macros @h and @H:
-- @h
The @h replacement macro uses the hostname configured with the Tasomta Wifi Hostname <host>
command (defaults to %s-%04d
). It will not use the network hostname of your device because this is not available when working with files only (e.g. --file <filename>
as source).
To prevent having a useless % in your filename, @h will not replaced by configuration data hostname if this contains '%' characters.
-- @H
If you want to use the network hostname within your filename, use the @H replacement macro instead - but be aware this will only replaced if you are using a network device as source (-d
, --device
, --host
); it will not work when using a file as source (-f
, --file
)
+- @h
+The @h replacement macro uses the hostname configured with the Tasomta Wifi
Hostname <host>
command (defaults to %s-%04d
). It will not use the network hostname of your device because this is not available when working with files only (e.g. --file <filename>
as source).
+To prevent having a useless % in your filename, @h will not replaced by configuration data hostname if this contains '%' characters.
+- @H
+If you want to use the network hostname within your filename, use the @H replacement macro instead - but be aware this will only replaced if you are using a network device as source (
-d
, --device
, --host
); it will not work when using a file as source (-f
, --file
)
diff --git a/tools/decode-config.md b/tools/decode-config.md
index 43fe807f3..add80549a 100644
--- a/tools/decode-config.md
+++ b/tools/decode-config.md
@@ -211,7 +211,7 @@ Note: A few very specific module commands like MPC230xx, KNX and some Display co
### Filter data
The huge number of Tasmota configuration data can be overstrained and confusing, so the most of the configuration data are grouped into categories.
-With _decode-config.py_ the following categories are available: `Display`, `Domoticz`, `Internal`, `KNX`, `Led`, `Logging`, `MCP230xx`, `MQTT`, `Main`, `Management`, `Pow`, `Sensor`, `Serial`, `SetOption`, `SonoffRF`, `System`, `Timers`, `Wifi`
+With _decode-config.py_ the following categories are available: `Display`, `Domoticz`, `Internal`, `KNX`, `Led`, `Logging`, `MCP230xx`, `MQTT`, `Main`, `Management`, `Pow`, `Sensor`, `Serial`, `SetOption`, `RF`, `System`, `Timers`, `Wifi`
These are similary to the categories on [https://github.com/arendst/Tasmota/wiki/Commands](Tasmota Command Wiki).
@@ -254,7 +254,7 @@ For advanced help use `-H` or `--full-help`:
[--cmnd-indent ] [--cmnd-groups]
[--cmnd-nogroups] [--cmnd-sort] [--cmnd-unsort]
[-c ] [-S] [-T json|cmnd|command]
- [-g {Control,Devices,Display,Domoticz,Internal,Knx,Light,Management,Mqtt,Power,Rules,Sensor,Serial,Setoption,Shutter,Sonoffrf,System,Timer,Wifi} [{Control,Devices,Display,Domoticz,Internal,Knx,Light,Management,Mqtt,Power,Rules,Sensor,Serial,Setoption,Shutter,Sonoffrf,System,Timer,Wifi} ...]]
+ [-g {Control,Devices,Display,Domoticz,Internal,Knx,Light,Management,Mqtt,Power,Rf,Rules,Sensor,Serial,Setoption,Shutter,System,Timer,Wifi} [{Control,Devices,Display,Domoticz,Internal,Knx,Light,Management,Mqtt,Power,Rf,Rules,Sensor,Serial,Setoption,Shutter,System,Timer,Wifi} ...]]
[--ignore-warnings] [-h] [-H] [-v] [-V]
Backup/Restore Tasmota configuration data. Args that start with '--'
@@ -334,7 +334,7 @@ For advanced help use `-H` or `--full-help`:
(default do not output on backup or restore usage)
-T, --output-format json|cmnd|command
display output format (default: 'json')
- -g, --group {Control,Devices,Display,Domoticz,Internal,Knx,Light,Management,Mqtt,Power,Rules,Sensor,Serial,Setoption,Shutter,Sonoffrf,System,Timer,Wifi}
+ -g, --group {Control,Devices,Display,Domoticz,Internal,Knx,Light,Management,Mqtt,Power,Rf,Rules,Sensor,Serial,Setoption,Shutter,System,Timer,Wifi}
limit data processing to command groups (default no
filter)
--ignore-warnings do not exit on warnings. Not recommended, used by your
diff --git a/tools/decode-config.py b/tools/decode-config.py
index 450c1d1cb..3288e550d 100755
--- a/tools/decode-config.py
+++ b/tools/decode-config.py
@@ -1,6 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-VER = '2.3.0036'
+from __future__ import print_function
+VER = '2.4.0037'
"""
decode-config.py - Backup/Restore Tasmota configuration data
@@ -43,7 +44,7 @@ Usage: decode-config.py [-f ] [-d ] [-P ]
[--cmnd-indent ] [--cmnd-groups]
[--cmnd-nogroups] [--cmnd-sort] [--cmnd-unsort]
[-c ] [-S] [-T json|cmnd|command]
- [-g {Control,Devices,Display,Domoticz,Internal,Knx,Light,Management,Mqtt,Power,Rules,Sensor,Serial,Setoption,Shutter,Sonoffrf,System,Timer,Wifi} [{Control,Devices,Display,Domoticz,Internal,Knx,Light,Management,Mqtt,Power,Rules,Sensor,Serial,Setoption,Shutter,Sonoffrf,System,Timer,Wifi} ...]]
+ [-g {Control,Devices,Display,Domoticz,Internal,Knx,Light,Management,Mqtt,Power,Rules,Sensor,Serial,Setoption,Shutter,Rf,System,Timer,Wifi} [{Control,Devices,Display,Domoticz,Internal,Knx,Light,Management,Mqtt,Power,Rules,Sensor,Serial,Setoption,Shutter,Rf,System,Timer,Wifi} ...]]
[--ignore-warnings] [-h] [-H] [-v] [-V]
Backup/Restore Tasmota configuration data. Args that start with '--'
@@ -123,7 +124,7 @@ Usage: decode-config.py [-f ] [-d ] [-P ]
(default do not output on backup or restore usage)
-T, --output-format json|cmnd|command
display output format (default: 'json')
- -g, --group {Control,Devices,Display,Domoticz,Internal,Knx,Light,Management,Mqtt,Power,Rules,Sensor,Serial,Setoption,Shutter,Sonoffrf,System,Timer,Wifi}
+ -g, --group {Control,Devices,Display,Domoticz,Internal,Knx,Light,Management,Mqtt,Power,Rules,Sensor,Serial,Setoption,Shutter,Rf,System,Timer,Wifi}
limit data processing to command groups (default no
filter)
--ignore-warnings do not exit on warnings. Not recommended, used by your
@@ -184,7 +185,7 @@ import io
import sys, platform
def ModuleImportError(module):
er = str(module)
- print >> sys.stderr, "{}. Try 'pip install {}' to install it".format(er,er.split(' ')[len(er.split(' '))-1])
+ print('{}, try "pip install {}"'.format(er,er.split(' ')[len(er.split(' '))-1]), file=sys.stderr)
sys.exit(ExitCode.MODULE_NOT_FOUND)
try:
from datetime import datetime
@@ -198,8 +199,11 @@ try:
import json
import configargparse
import pycurl
- import urllib2
-except ImportError, e:
+ if sys.version_info.major==2:
+ import urllib2
+ else:
+ import urllib
+except ImportError as e:
ModuleImportError(e)
# ======================================================================
@@ -276,7 +280,7 @@ Settings dictionary describes the config file fields definition:
defines the use of data at
format is defined in 'struct module format string'
see
- https://docs.python.org/2.7/library/struct.html#format-strings
+ https://docs.python.org/3.8/library/struct.html#format-strings
:
A dictionary describes a (sub)setting dictonary
and can recursively define another
@@ -556,7 +560,7 @@ Setting_5_10_0 = {
'pulse_counter_type4': ('> sys.stderr, '{styp}{sdelimiter}{sstatus}{slineno}{scolon}{smgs}'.format(\
- styp=type_ if type_ is not None else '',
- sdelimiter=' ' if status is not None and status > 0 and type_ is not None else '',
- sstatus=status if status is not None and status > 0 else '',
- scolon=': ' if type_ is not None or line is not None else '',
- smgs=msg,
- slineno=' (@{:04d})'.format(line) if line is not None else '')
+ print('{styp}{sdelimiter}{sstatus}{slineno}{scolon}{smgs}'.format(\
+ styp=type_ if type_ is not None else '',
+ sdelimiter=' ' if status is not None and status > 0 and type_ is not None else '',
+ sstatus=status if status is not None and status > 0 else '',
+ scolon=': ' if type_ is not None or line is not None else '',
+ smgs=msg,
+ slineno=' (@{:04d})'.format(line) if line is not None else '')
+ , file=sys.stderr)
def exit(status=0, msg="end", type_=LogType.ERROR, src=None, doexit=True, line=None):
@@ -1200,11 +1253,11 @@ def ShortHelp(doexit=True):
@param doexit:
sys.exit with OK if True
"""
- print parser.description
+ print(parser.description)
print
parser.print_usage()
print
- print "For advanced help use '{prog} -H' or '{prog} --full-help'".format(prog=os.path.basename(sys.argv[0]))
+ print("For advanced help use '{prog} -H' or '{prog} --full-help'".format(prog=os.path.basename(sys.argv[0])))
if doexit:
sys.exit(ExitCode.OK)
@@ -1554,8 +1607,8 @@ def LoadTasmotaConfig(filename):
try:
with open(filename, "rb") as tasmotafile:
encode_cfg = tasmotafile.read()
- except Exception, e:
- exit(e[0], "'{}' {}".format(filename, e[1]),line=inspect.getlineno(inspect.currentframe()))
+ except Exception as e:
+ exit(e.args[0], "'{}' {}".format(filename, e[1]),line=inspect.getlineno(inspect.currentframe()))
return encode_cfg
@@ -1597,8 +1650,8 @@ def TasmotaGet(cmnd, host, port, username=DEFAULTS['source']['username'], passwo
c.perform()
responsecode = c.getinfo(c.RESPONSE_CODE)
response = header.response()
- except Exception, e:
- exit(e[0], e[1],line=inspect.getlineno(inspect.currentframe()))
+ except Exception as e:
+ exit(e.args[0], e.args[1], line=inspect.getlineno(inspect.currentframe()))
finally:
c.close()
@@ -1727,8 +1780,8 @@ def PushTasmotaConfig(encode_cfg, host, port, username=DEFAULTS['source']['usern
try:
c.perform()
responsecode = c.getinfo(c.RESPONSE_CODE)
- except Exception, e:
- return e[0], e[1]
+ except Exception as e:
+ return e.args[0], e.args[1]
c.close()
@@ -1839,7 +1892,7 @@ def GetFieldDef(fielddef, fields="format_, addrdef, baseaddr, bits, bitshift, da
# calling with nothing is wrong
if fielddef is None:
- print >> sys.stderr, ' is None'
+ print(' is None', file=sys.stderr)
raise SyntaxError(' error')
# get top level items
@@ -1850,7 +1903,7 @@ def GetFieldDef(fielddef, fields="format_, addrdef, baseaddr, bits, bitshift, da
# converter present
format_, addrdef, datadef, converter = fielddef
else:
- print >> sys.stderr, 'wrong {} length ({}) in setting'.format(fielddef, len(fielddef))
+ print('wrong {} length ({}) in setting'.format(fielddef, len(fielddef)), file=sys.stderr)
raise SyntaxError(' error')
# ignore calls with 'root' setting
@@ -1858,7 +1911,7 @@ def GetFieldDef(fielddef, fields="format_, addrdef, baseaddr, bits, bitshift, da
return eval(fields)
if not isinstance(format_, (unicode,str,dict)):
- print >> sys.stderr, 'wrong {} type {} in {}'.format(format_, type(format_), fielddef)
+ print('wrong {} type {} in {}'.format(format_, type(format_), fielddef), file=sys.stderr)
raise SyntaxError(' error')
# extract addrdef items
@@ -1868,16 +1921,16 @@ def GetFieldDef(fielddef, fields="format_, addrdef, baseaddr, bits, bitshift, da
# baseaddr bit definition
baseaddr, bits, bitshift = baseaddr
if not isinstance(bits, int):
- print >> sys.stderr, ' must be defined as integer in {}'.format(bits, fielddef)
+ print(' must be defined as integer in {}'.format(bits, fielddef), file=sys.stderr)
raise SyntaxError(' error')
if not isinstance(bitshift, int):
- print >> sys.stderr, ' must be defined as integer in {}'.format(bitshift, fielddef)
+ print(' must be defined as integer in {}'.format(bitshift, fielddef), file=sys.stderr)
raise SyntaxError(' error')
else:
- print >> sys.stderr, 'wrong {} length ({}) in {}'.format(addrdef, len(addrdef), fielddef)
+ print('wrong {} length ({}) in {}'.format(addrdef, len(addrdef), fielddef), file=sys.stderr)
raise SyntaxError(' error')
if not isinstance(baseaddr, int):
- print >> sys.stderr, ' must be defined as integer in {}'.format(baseaddr, fielddef)
+ print(' must be defined as integer in {}'.format(baseaddr, fielddef), file=sys.stderr)
raise SyntaxError(' error')
# extract datadef items
@@ -1893,27 +1946,27 @@ def GetFieldDef(fielddef, fields="format_, addrdef, baseaddr, bits, bitshift, da
if isinstance(cmd, (tuple)) and len(cmd) == 2:
group, tasmotacmnd = cmd
if group is not None and not isinstance(group, (str, unicode)):
- print >> sys.stderr, 'wrong {} in {}'.format(group, fielddef)
+ print('wrong {} in {}'.format(group, fielddef), file=sys.stderr)
raise SyntaxError(' error')
if tasmotacmnd is isinstance(tasmotacmnd, tuple):
tasmotacmnds = tasmotacmnd
for tasmotacmnd in tasmotacmnds:
if tasmotacmnd is not None and not callable(tasmotacmnd) and not isinstance(tasmotacmnd, (str, unicode)):
- print >> sys.stderr, 'wrong {} in {}'.format(tasmotacmnd, fielddef)
+ print('wrong {} in {}'.format(tasmotacmnd, fielddef), file=sys.stderr)
raise SyntaxError(' error')
else:
if tasmotacmnd is not None and not callable(tasmotacmnd) and not isinstance(tasmotacmnd, (str, unicode)):
- print >> sys.stderr, 'wrong {} in {}'.format(tasmotacmnd, fielddef)
+ print('wrong {} in {}'.format(tasmotacmnd, fielddef), file=sys.stderr)
raise SyntaxError(' error')
else:
- print >> sys.stderr, 'wrong {} length ({}) in {}'.format(cmd, len(cmd), fielddef)
+ print('wrong {} length ({}) in {}'.format(cmd, len(cmd), fielddef), file=sys.stderr)
raise SyntaxError(' error')
else:
- print >> sys.stderr, 'wrong {} length ({}) in {}'.format(datadef, len(datadef), fielddef)
+ print('wrong {} length ({}) in {}'.format(datadef, len(datadef), fielddef), file=sys.stderr)
raise SyntaxError(' error')
if validate is not None and (not isinstance(validate, (unicode,str)) and not callable(validate)):
- print >> sys.stderr, 'wrong {} type {} in {}'.format(validate, type(validate), fielddef)
+ print('wrong {} type {} in {}'.format(validate, type(validate), fielddef), file=sys.stderr)
raise SyntaxError(' error')
# convert single int into one-dimensional list
@@ -1921,7 +1974,7 @@ def GetFieldDef(fielddef, fields="format_, addrdef, baseaddr, bits, bitshift, da
arraydef = [arraydef]
if arraydef is not None and not isinstance(arraydef, (list)):
- print >> sys.stderr, 'wrong {} type {} in {}'.format(arraydef, type(arraydef), fielddef)
+ print('wrong {} type {} in {}'.format(arraydef, type(arraydef), fielddef), file=sys.stderr)
raise SyntaxError(' error')
# get read/write converter items
@@ -1931,13 +1984,13 @@ def GetFieldDef(fielddef, fields="format_, addrdef, baseaddr, bits, bitshift, da
# converter has read/write converter
readconverter, writeconverter = converter
if readconverter is not None and not isinstance(readconverter, (str,unicode)) and not callable(readconverter):
- print >> sys.stderr, 'wrong {} type {} in {}'.format(readconverter, type(readconverter), fielddef)
+ print('wrong {} type {} in {}'.format(readconverter, type(readconverter), fielddef), file=sys.stderr)
raise SyntaxError(' error')
if writeconverter is not None and (not isinstance(writeconverter, (bool,str,unicode)) and not callable(writeconverter)):
- print >> sys.stderr, 'wrong {} type {} in {}'.format(writeconverter, type(writeconverter), fielddef)
+ print('wrong {} type {} in {}'.format(writeconverter, type(writeconverter), fielddef), file=sys.stderr)
raise SyntaxError(' error')
else:
- print >> sys.stderr, 'wrong {} length ({}) in {}'.format(converter, len(converter), fielddef)
+ print('wrong {} length ({}) in {}'.format(converter, len(converter), fielddef), file=sys.stderr)
raise SyntaxError(' error')
@@ -1975,8 +2028,8 @@ def ReadWriteConverter(value, fielddef, read=True, raw=False):
return eval(conv.replace('$','value'))
elif callable(conv): # use as format function
return conv(value)
- except Exception, e:
- exit(e[0], e[1], type_=LogType.WARNING, line=inspect.getlineno(inspect.currentframe()))
+ except Exception as e:
+ exit(e.args[0], e.args[1], type_=LogType.WARNING, line=inspect.getlineno(inspect.currentframe()))
return value
@@ -2294,7 +2347,7 @@ def SetFieldValue(fielddef, dobj, addr, value):
formatcnt = GetFormatCount(format_)
singletype, bitsize = GetFormatType(format_)
if args.debug >= 2:
- print >> sys.stderr, "SetFieldValue(): fielddef {}, addr 0x{:04x} value {} formatcnt {} singletype {} bitsize {} ".format(fielddef,addr,value,formatcnt,singletype,bitsize)
+ 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']:
addr += (bitsize / 8) * formatcnt
for _ in range(0, formatcnt):
@@ -2305,7 +2358,7 @@ def SetFieldValue(fielddef, dobj, addr, value):
if isinstance(value,int) and value < 0 and val > maxsigned:
val = ((maxunsigned+1)-val) * (-1)
if args.debug >= 3:
- print >> sys.stderr, "SetFieldValue(): Single type - fielddef {}, addr 0x{:04x} value {} singletype {} bitsize {}".format(fielddef,addr,val,singletype,bitsize)
+ print("SetFieldValue(): Single type - fielddef {}, addr 0x{:04x} value {} singletype {} bitsize {}".format(fielddef,addr,val,singletype,bitsize), file=sys.stderr)
try:
struct.pack_into(singletype, dobj, addr, val)
except struct.error as e:
@@ -2317,7 +2370,7 @@ def SetFieldValue(fielddef, dobj, addr, value):
value >>= bitsize
else:
if args.debug >= 3:
- print >> sys.stderr, "SetFieldValue(): String type - fielddef {}, addr 0x{:04x} value {} format_ {}".format(fielddef,addr,value,format_)
+ print("SetFieldValue(): String type - fielddef {}, addr 0x{:04x} value {} format_ {}".format(fielddef,addr,value,format_), file=sys.stderr)
try:
struct.pack_into(format_, dobj, addr, value)
except struct.error as e:
@@ -2427,7 +2480,7 @@ def SetField(dobj, fieldname, fielddef, restore, addroffset=0, filename=""):
# do not write readonly values
if writeconverter is False:
if args.debug >= 2:
- print >> sys.stderr, "SetField(): Readonly '{}' using '{}'/{}{} @{} skipped".format(fieldname, format_, arraydef, bits, hex(baseaddr+addroffset))
+ print("SetField(): Readonly '{}' using '{}'/{}{} @{} skipped".format(fieldname, format_, arraydef, bits, hex(baseaddr+addroffset)), file=sys.stderr)
return dobj
# contains a list
@@ -2465,16 +2518,16 @@ def SetField(dobj, fieldname, fielddef, restore, addroffset=0, filename=""):
if format_[-1:] in ['c']:
try:
value = ReadWriteConverter(restore.encode(STR_ENCODING)[0], fielddef, read=False)
- except Exception, e:
- exit(e[0], e[1], type_=LogType.WARNING, line=inspect.getlineno(inspect.currentframe()))
+ except Exception as e:
+ exit(e.args[0], e.args[1], type_=LogType.WARNING, line=inspect.getlineno(inspect.currentframe()))
valid = False
# bool
elif format_[-1:] in ['?']:
try:
value = ReadWriteConverter(bool(restore), fielddef, read=False)
- except Exception, e:
- exit(e[0], e[1], type_=LogType.WARNING, line=inspect.getlineno(inspect.currentframe()))
+ except Exception as e:
+ exit(e.args[0], e.args[1], type_=LogType.WARNING, line=inspect.getlineno(inspect.currentframe()))
valid = False
# integer
@@ -2560,7 +2613,7 @@ def SetField(dobj, fieldname, fielddef, restore, addroffset=0, filename=""):
if args.debug >= 2:
sbits = " {} bits shift {}".format(bits, bitshift) if bits else ""
strvalue = "{} [{}]".format(_value, hex(value)) if isinstance(_value, int) else _value
- print >> sys.stderr, "SetField(): Set '{}' using '{}'/{}{} @{} to {}".format(fieldname, format_, arraydef, sbits, hex(baseaddr+addroffset), strvalue)
+ print("SetField(): Set '{}' using '{}'/{}{} @{} to {}".format(fieldname, format_, arraydef, sbits, hex(baseaddr+addroffset), strvalue), file=sys.stderr)
if fieldname != 'cfg_crc' and fieldname != '_':
prevvalue = GetFieldValue(fielddef, dobj, baseaddr+addroffset)
dobj = SetFieldValue(fielddef, dobj, baseaddr+addroffset, value)
@@ -2569,7 +2622,7 @@ def SetField(dobj, fieldname, fielddef, restore, addroffset=0, filename=""):
message("Value for '{}' changed from {} to {}".format(fieldname, prevvalue, curvalue), type_=LogType.INFO)
else:
if args.debug >= 2:
- print >> sys.stderr, "SetField(): Special field '{}' using '{}'/{}{} @{} skipped".format(fieldname, format_, arraydef, bits, hex(baseaddr+addroffset))
+ print("SetField(): Special field '{}' using '{}'/{}{} @{} skipped".format(fieldname, format_, arraydef, bits, hex(baseaddr+addroffset)), file=sys.stderr)
else:
sformat = "file '{sfile}' - {{'{sname}': {svalue}}} ({serror})"+errformat
exit(ExitCode.RESTORE_DATA_ERROR, sformat.format(sfile=filename, sname=fieldname, serror=err, svalue=_value, smin=min_, smax=max_), type_=LogType.WARNING, doexit=not args.ignorewarning)
@@ -2871,8 +2924,8 @@ def Backup(backupfile, backupfileformat, encode_cfg, decode_cfg, configmapping):
try:
with open(backup_filename, "wb") as backupfp:
backupfp.write(encode_cfg)
- except Exception, e:
- exit(e[0], "'{}' {}".format(backup_filename, e[1]),line=inspect.getlineno(inspect.currentframe()))
+ except Exception as e:
+ exit(e.args[0], "'{}' {}".format(backup_filename, e[1]),line=inspect.getlineno(inspect.currentframe()))
# binary format
elif backupfileformat.lower() == FileType.BIN.lower():
@@ -2884,8 +2937,8 @@ def Backup(backupfile, backupfileformat, encode_cfg, decode_cfg, configmapping):
with open(backup_filename, "wb") as backupfp:
backupfp.write(struct.pack('= 1:
- print >> sys.stderr, parser.format_values()
- print >> sys.stderr, "Settings:"
+ print(parser.format_values(), file=sys.stderr)
+ print("Settings:", file=sys.stderr)
for k in args.__dict__:
- print >> sys.stderr, " "+str(k), "= ",eval('args.{}'.format(k))
+ print(" "+str(k), "= ",eval('args.{}'.format(k)), file=sys.stderr)
return args
@@ -3280,7 +3333,7 @@ if __name__ == "__main__":
# no config source given
ShortHelp(False)
print
- print parser.epilog
+ print(parser.epilog)
sys.exit(ExitCode.OK)
if len(encode_cfg) == 0:
@@ -3309,7 +3362,7 @@ if __name__ == "__main__":
# json screen output
if (args.backupfile is None and args.restorefile is None) or args.output:
if args.outputformat == 'json':
- print json.dumps(configmapping, sort_keys=args.jsonsort, indent=None if args.jsonindent<0 else args.jsonindent, separators=(',', ':') if args.jsoncompact else (', ', ': ') )
+ print(json.dumps(configmapping, sort_keys=args.jsonsort, indent=None if args.jsonindent<0 else args.jsonindent, separators=(',', ':') if args.jsoncompact else (', ', ': ') ))
if args.outputformat == 'cmnd' or args.outputformat == 'command':
tasmotacmnds = Mapping2Cmnd(decode_cfg, configmapping)