diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino
index 7b0654a12..eb21f38c7 100644
--- a/sonoff/_releasenotes.ino
+++ b/sonoff/_releasenotes.ino
@@ -1,11 +1,15 @@
/* 5.14.0a
+ * Add feature information to Status 4
+ * Add tools folder with python script decode-status.py for decoding some status fields like SetOption and Features
* Add Eastron SDM630 energy meter (#2735)
* Add KNX communication enhancement (#2742)
* Add KNX energy data (#2750)
- * Add compiled feature information to Status 4
+ * Add python script fw-server.py in tools folder to create a simple OTA server (#2759)
* Fix display selection of un-available GPIO options in Module Configuration webpage (#2718)
* Fix timer re-trigger within one minute after restart (#2744)
* Fix IRSend not accepting data value of 0 (#2751)
+ * Fix vars on rules (#2769)
+ * Fix bug in KNX menu (#2770)
*
* 5.14.0 20180515
* Update language files
diff --git a/sonoff/support.ino b/sonoff/support.ino
index 454d4bdf0..720649c9f 100644
--- a/sonoff/support.ino
+++ b/sonoff/support.ino
@@ -655,7 +655,7 @@ void GetFeatures()
// feature_sns1 |= 0x00000001;
-#ifndef USE_ADC_VCC
+#ifdef USE_ADC_VCC
feature_sns1 |= 0x00000002; // support.ino (ADC)
#endif
#ifdef USE_ENERGY_SENSOR
diff --git a/tools/decode-status.py b/tools/decode-status.py
new file mode 100644
index 000000000..e94b2cb5f
--- /dev/null
+++ b/tools/decode-status.py
@@ -0,0 +1,183 @@
+#!/usr/bin/env python
+
+"""
+ decode-status.py - decode status for Sonoff-Tasmota
+
+ Copyright (C) 2018 Theo Arends
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Requirements:
+ - Python
+ - pip json pycurl
+
+Instructions:
+ Execute command with option -d to retrieve status report from device or
+ get a copy of the status message with http command http://sonoff/cm?cmnd=status%200
+ and store it in file status.json
+
+Usage:
+ ./decode-status.py -d
+ or
+ ./decode-status.py -f
+
+Example:
+ ./decode-status.py -d sonoff1
+ or
+ ./decode-status.py -f status.json
+"""
+
+import io
+import os.path
+import json
+import pycurl
+from sys import exit
+from optparse import OptionParser
+from StringIO import StringIO
+
+a_on_off = ["OFF","ON "]
+
+a_setoption = [
+ "Save power state and use after restart",
+ "Restrict button actions to single, double and hold",
+ "Show value units in JSON messages",
+ "MQTT",
+ "Respond as Command topic instead of RESULT",
+ "MQTT retain on Power",
+ "MQTT retain on Button",
+ "MQTT retain on Switch",
+ "Convert temperature to Fahrenheit",
+ "MQTT retain on Sensor",
+ "MQTT retained LWT to OFFLINE when topic changes",
+ "Swap Single and Double press Button",
+ "Do not use flash page rotate",
+ "Button single press only",
+ "Power interlock mode",
+ "Do not allow PWM control",
+ "Reverse clock",
+ "Allow entry of decimal color values",
+ "CO2 color to light signal",
+ "HASS discovery",
+ "Do not control Power with Dimmer",
+ "Energy monitoring while powered off",
+ "MQTT serial",
+ "Rules",
+ "Rules once mode",
+ "KNX",
+ "Use Power device index on single relay devices",
+ "KNX enhancement",
+ "","","",""]
+
+a_features = [[
+ "","","USE_I2C","USE_SPI",
+ "USE_DISCOVERY","USE_ARDUINO_OTA","USE_MQTT_TLS","USE_WEBSERVER",
+ "WEBSERVER_ADVERTISE","USE_EMULATION","MQTT_PUBSUBCLIENT","MQTT_TASMOTAMQTT",
+ "MQTT_ESPMQTTARDUINO","MQTT_HOST_DISCOVERY","USE_ARILUX_RF","USE_WS2812",
+ "USE_WS2812_DMA","USE_IR_REMOTE","USE_IR_HVAC","USE_IR_RECEIVE",
+ "USE_DOMOTICZ","USE_DISPLAY","USE_HOME_ASSISTANT","USE_SERIAL_BRIDGE",
+ "USE_TIMERS","USE_SUNRISE","USE_TIMERS_WEB","USE_RULES",
+ "USE_KNX","","",""],[
+ "USE_CONFIG_OVERRIDE","BE_MINIMAL","USE_ALL_SENSORS","USE_CLASSIC",
+ "USE_KNX_NO_EMULATION","","","",
+ "","","","",
+ "","","","",
+ "","","","",
+ "","","","",
+ "","","VTABLES_IN_FLASH","PIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH",
+ "PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY","PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH","DEBUG_THEO","USE_DEBUG_DRIVER"],[
+ "","USE_ADC_VCC","USE_ENERGY_SENSOR","USE_PZEM004T",
+ "USE_DS18B20","USE_DS18x20_LEGACY","USE_DS18x20","USE_DHT",
+ "USE_SHT","USE_HTU","USE_BMP","USE_BME680",
+ "USE_BH1750","USE_VEML6070","USE_ADS1115_I2CDEV","USE_ADS1115",
+ "USE_INA219","USE_SHT3X","USE_MHZ19","USE_TSL2561",
+ "USE_SENSEAIR","USE_PMS5003","USE_MGS","USE_NOVA_SDS",
+ "USE_SGP30","USE_SR04","USE_SDM120","USE_SI1145",
+ "USE_SDM630","","",""],[
+ "","","","",
+ "","","","",
+ "","","","",
+ "","","","",
+ "","","","",
+ "","","","",
+ "","","","",
+ "","","",""]]
+
+usage = "usage: decode-status {-d | -f} arg"
+parser = OptionParser(usage)
+parser.add_option("-d", "--dev", action="store", type="string",
+ dest="device", help="device to retrieve status from")
+parser.add_option("-f", "--file", metavar="FILE",
+ dest="jsonfile", default="status.json", help="status json file (default: status.json)")
+(options, args) = parser.parse_args()
+
+if (options.device):
+ buffer = StringIO()
+ url = str("http://{}/cm?cmnd=status%200".format(options.device))
+ c = pycurl.Curl()
+ c.setopt(c.URL, url)
+ c.setopt(c.WRITEDATA, buffer)
+ c.perform()
+ c.close()
+ body = buffer.getvalue()
+ obj = json.loads(body)
+else:
+ jsonfile = options.jsonfile
+ fp = open(jsonfile, "r")
+ obj = json.load(fp)
+ fp.close()
+
+def StartDecode():
+# print("Decoding\n{}".format(obj))
+
+ if ("Time" in obj["StatusSNS"]):
+ time = str(" from status report taken at {}".format(obj["StatusSNS"]["Time"]))
+ if ("FriendlyName" in obj["Status"]):
+ print("\nDecoding information for device {}{}".format(obj["Status"]["FriendlyName"][0], time))
+
+ if ("SetOption" in obj["StatusLOG"]):
+ options = []
+ option = obj["StatusLOG"]["SetOption"][0]
+ i_option = int(option,16)
+ for i in range(len(a_setoption)):
+ if (a_setoption[i]):
+ state = (i_option >> i) & 1
+ options.append(str("{0:2d} ({1}) {2}".format(i, a_on_off[state], a_setoption[i])))
+
+ print("\nOptions")
+ for i in range(len(options)):
+ print(" {}".format(options[i]))
+
+
+ if ("Features" in obj["StatusMEM"]):
+ features = []
+ for f in range(5):
+ feature = obj["StatusMEM"]["Features"][f]
+ i_feature = int(feature,16)
+ if (f == 0):
+ features.append(str("Language LCID = {}".format(i_feature & 0xFFFF)))
+ else:
+ for i in range(len(a_features[f -1])):
+ if ((i_feature >> i) & 1):
+ features.append(a_features[f -1][i])
+
+ features.sort()
+ print("\nFeatures")
+ for i in range(len(features)):
+ print(" {}".format(features[i]))
+
+if __name__ == "__main__":
+ try:
+ StartDecode()
+ except Exception as e:
+ print("E: {}".format(e))
\ No newline at end of file
diff --git a/api/fw-server.py b/tools/fw-server.py
old mode 100755
new mode 100644
similarity index 100%
rename from api/fw-server.py
rename to tools/fw-server.py
diff --git a/api/fw/README b/tools/fw/README
similarity index 100%
rename from api/fw/README
rename to tools/fw/README