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