mirror of https://github.com/arendst/Tasmota.git
Merge branch 'development' of https://github.com/arendst/Sonoff-Tasmota into development
This commit is contained in:
commit
99a4556bab
|
@ -0,0 +1,8 @@
|
|||
.pioenvs
|
||||
.piolibdeps
|
||||
.clang_complete
|
||||
.gcc-flags.json
|
||||
examples/*/platformio.ini
|
||||
examples/*/lib
|
||||
examples/*/.gitignore
|
||||
examples/*/.travis.yml
|
|
@ -0,0 +1,4 @@
|
|||
.pioenvs
|
||||
.piolibdeps
|
||||
.clang_complete
|
||||
.gcc-flags.json
|
|
@ -0,0 +1,55 @@
|
|||
# Continuous Integration (CI) is the practice, in software
|
||||
# engineering, of merging all developer working copies with a shared mainline
|
||||
# several times a day < http://docs.platformio.org/page/ci/index.html >
|
||||
#
|
||||
# Documentation:
|
||||
#
|
||||
# * Travis CI Embedded Builds with PlatformIO
|
||||
# < https://docs.travis-ci.com/user/integration/platformio/ >
|
||||
#
|
||||
# * PlatformIO integration with Travis CI
|
||||
# < http://docs.platformio.org/page/ci/travis.html >
|
||||
#
|
||||
# * User Guide for `platformio ci` command
|
||||
# < http://docs.platformio.org/page/userguide/cmd_ci.html >
|
||||
#
|
||||
#
|
||||
# Please choice one of the following templates (proposed below) and uncomment
|
||||
# it (remove "# " before each line) or use own configuration according to the
|
||||
# Travis CI documentation (see above).
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# Template #1: General project. Test it using existing `platformio.ini`.
|
||||
#
|
||||
|
||||
# language: python
|
||||
# python:
|
||||
# - "2.7"
|
||||
#
|
||||
# install:
|
||||
# - pip install -U platformio
|
||||
#
|
||||
# script:
|
||||
# - platformio run
|
||||
|
||||
|
||||
#
|
||||
# Template #2: The project is intended to by used as a library with examples
|
||||
#
|
||||
|
||||
# language: python
|
||||
# python:
|
||||
# - "2.7"
|
||||
#
|
||||
# env:
|
||||
# - PLATFORMIO_CI_SRC=path/to/test/file.c
|
||||
# - PLATFORMIO_CI_SRC=examples/file.ino
|
||||
# - PLATFORMIO_CI_SRC=path/to/test/directory
|
||||
#
|
||||
# install:
|
||||
# - pip install -U platformio
|
||||
#
|
||||
# script:
|
||||
# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N
|
|
@ -1,4 +1,4 @@
|
|||
This is a library for the TSL2561 digital luminosity sensors from Ams (Taos).
|
||||
This is an Arduino library for the TSL2561 digital luminosity sensors from Ams (Taos).
|
||||
|
||||
Design goals:
|
||||
* It is modularized so you can use only what you need if space/ram is constrained.
|
||||
|
@ -18,3 +18,5 @@ The library has 3 classes:
|
|||
Tsl2561 All register access as described in the datasheet, except for interrupts
|
||||
Tsl2561Util Convenience functions like lux calculation or automatic gain
|
||||
Tsl2561Int TODO, Interrupt related stuff (not needed if int pin unconnected)
|
||||
|
||||
Tested with boards Nano, ESP8266 and ESP32
|
|
@ -21,7 +21,7 @@ This file is part of the Joba_Tsl2561 Library.
|
|||
|
||||
#include <Tsl2561Util.h>
|
||||
|
||||
// to mimic Serial.printf() of esp8266 core for other platforms
|
||||
// to mimic Serial.printf() of esp cores for other platforms
|
||||
char *format( const char *fmt, ... ) {
|
||||
static char buf[128];
|
||||
va_list arg;
|
||||
|
@ -37,7 +37,7 @@ uint8_t id;
|
|||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Wire.begin();
|
||||
Wire.begin(TSL2561_SDA, TSL2561_SCL);
|
||||
while( !Tsl.begin() )
|
||||
; // wait until chip detected or wdt reset
|
||||
Serial.println("\nStarting Tsl2561Util autogain loop");
|
|
@ -21,7 +21,7 @@ This file is part of the Joba_Tsl2561 Library.
|
|||
|
||||
#include <Tsl2561.h>
|
||||
|
||||
// to mimic Serial.printf() of esp8266 core for other platforms
|
||||
// to mimic Serial.printf() of esp cores for other platforms
|
||||
char *format( const char *fmt, ... ) {
|
||||
static char buf[128];
|
||||
va_list arg;
|
||||
|
@ -36,7 +36,7 @@ Tsl2561 Tsl(Wire);
|
|||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Wire.begin();
|
||||
Wire.begin(TSL2561_SDA, TSL2561_SCL);
|
||||
Serial.println("\nStarting Tsl2561 simple loop");
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ void loop() {
|
|||
Tsl.off();
|
||||
}
|
||||
else {
|
||||
Serial.println("No Tsl2561 found. Check wiring.");
|
||||
Serial.print(format("No Tsl2561 found. Check wiring: SCL=%u, SDA=%u\n", TSL2561_SCL, TSL2561_SDA));
|
||||
}
|
||||
|
||||
delay(5000);
|
|
@ -22,7 +22,7 @@ This file is part of the Joba_Tsl2561 Library.
|
|||
|
||||
#include <Tsl2561.h>
|
||||
|
||||
// to mimic Serial.printf() of esp8266 core for other platforms
|
||||
// to mimic Serial.printf() of esp cores for other platforms
|
||||
char *format( const char *fmt, ... ) {
|
||||
static char buf[128];
|
||||
va_list arg;
|
||||
|
@ -158,7 +158,7 @@ void test( Tsl2561 &tsl ) {
|
|||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Wire.begin();
|
||||
Wire.begin(TSL2561_SDA, TSL2561_SCL);
|
||||
Serial.println("\nStarting Tsl2561 testing loop");
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@ This file is part of the Joba_Tsl2561 Library.
|
|||
|
||||
#include <Tsl2561Util.h>
|
||||
|
||||
// to mimic Serial.printf() of esp8266 core for other platforms
|
||||
// to mimic Serial.printf() of esp cores for other platforms
|
||||
char *format( const char *fmt, ... ) {
|
||||
static char buf[128];
|
||||
va_list arg;
|
||||
|
@ -37,7 +37,7 @@ Tsl2561 Tsl(Wire);
|
|||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Wire.begin();
|
||||
Wire.begin(TSL2561_SDA, TSL2561_SCL);
|
||||
Serial.println("\nStarting Tsl2561Util loop");
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ void loop() {
|
|||
}
|
||||
|
||||
if( !found ) {
|
||||
Serial.println("No Tsl2561 found. Check wiring.");
|
||||
Serial.print(format("No Tsl2561 found. Check wiring: SCL=%u, SDA=%u\n", TSL2561_SCL, TSL2561_SDA));
|
||||
}
|
||||
|
||||
delay(5000);
|
|
@ -18,9 +18,13 @@
|
|||
|
||||
|
||||
[platformio]
|
||||
src_dir = .
|
||||
lib_dir = ../..
|
||||
|
||||
; uncomment one, if you want to build only one
|
||||
; env_default = nodemcuv2
|
||||
; env_default = nano328
|
||||
; env_default = espressif32
|
||||
|
||||
|
||||
[env:nodemcuv2]
|
||||
|
@ -28,12 +32,12 @@
|
|||
; ------------
|
||||
; GND <-> GND
|
||||
; VCC <-> 3V
|
||||
; SCL <-> D1
|
||||
; SDA <-> D2
|
||||
; SCL <-> D1 (other pin can be defined below)
|
||||
; SDA <-> D2 (other pin can be defined below)
|
||||
platform = espressif8266
|
||||
board = nodemcuv2
|
||||
framework = arduino
|
||||
build_flags = -Wall
|
||||
build_flags = -Wall -DTSL2561_SCL=D1 -DTSL2561_SDA=D2
|
||||
|
||||
monitor_speed = 115200
|
||||
|
||||
|
@ -53,6 +57,25 @@ upload_resetmethod = nodemcu
|
|||
platform = atmelavr
|
||||
board = nanoatmega328
|
||||
framework = arduino
|
||||
build_flags = -Wall
|
||||
build_flags = -Wall -DTSL2561_SCL=A5 -DTSL2561_SDA=A4
|
||||
|
||||
monitor_speed = 115200
|
||||
;upload_port = /dev/ttyUSB[1-9]
|
||||
|
||||
|
||||
[env:espressif32]
|
||||
; TSL <-> ESP32
|
||||
; ------------
|
||||
; GND <-> GND
|
||||
; VCC <-> 3V
|
||||
; SCL <-> IO22 (other pin can be defined below)
|
||||
; SDA <-> IO21 (other pin can be defined below)
|
||||
platform = espressif32
|
||||
board = mhetesp32minikit
|
||||
framework = arduino
|
||||
build_flags = -Wall -DTSL2561_SCL=22 -DTSL2561_SDA=21
|
||||
|
||||
monitor_speed = 115200
|
||||
|
||||
upload_speed = 921600
|
||||
;upload_port = /dev/ttyUSB[1-9]
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "Joba_Tsl2561",
|
||||
"version": "2.0.7",
|
||||
"version": "2.0.10",
|
||||
"keywords": "twowire, i2c, bus, sensor, luminosity, illuminance, lux",
|
||||
"description": "Arduino Library for ams (taos) luminance chip Tsl2561 with autogain",
|
||||
"description": "Arduino library for ams (taos) luminance chip Tsl2561 with autogain. Tested with Nano, Esp8266 and Esp32.",
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
|
@ -1,9 +1,9 @@
|
|||
name=Joba Tsl2561 Library
|
||||
version=2.0.7
|
||||
version=2.0.10
|
||||
author=joba-1
|
||||
maintainer=joba-1 <joban123.psn@gmail.com>
|
||||
sentence=IoT library for using the Tsl2561 luminosity sensor
|
||||
paragraph=Luminosity measurement in lux with autogain
|
||||
paragraph=Luminosity measurement in lux with autogain. Tested with Nano, Esp8266 and Esp32.
|
||||
category=Sensors
|
||||
url=https://github.com/joba-1/Joba_Tsl2561
|
||||
architectures=*
|
|
@ -18,20 +18,19 @@
|
|||
|
||||
|
||||
[platformio]
|
||||
src_dir = .
|
||||
lib_dir = ../..
|
||||
|
||||
; uncomment one, if you want to build only one
|
||||
; env_default = nodemcuv2
|
||||
; env_default = nano328
|
||||
; env_default = espressif32
|
||||
|
||||
|
||||
[env:nodemcuv2]
|
||||
; TSL <-> ESP8266
|
||||
; ------------
|
||||
; GND <-> GND
|
||||
; VCC <-> 3V
|
||||
; SCL <-> D1
|
||||
; SDA <-> D2
|
||||
; SCL <-> D1 (other pin can be defined below)
|
||||
; SDA <-> D2 (other pin can be defined below)
|
||||
platform = espressif8266
|
||||
board = nodemcuv2
|
||||
framework = arduino
|
||||
|
@ -58,4 +57,21 @@ framework = arduino
|
|||
build_flags = -Wall
|
||||
|
||||
monitor_speed = 115200
|
||||
|
||||
|
||||
[env:espressif32]
|
||||
; TSL <-> ESP32
|
||||
; ------------
|
||||
; GND <-> GND
|
||||
; VCC <-> 3V
|
||||
; SCL <-> IO22 (other pin can be defined below)
|
||||
; SDA <-> IO21 (other pin can be defined below)
|
||||
platform = espressif32
|
||||
board = mhetesp32minikit
|
||||
framework = arduino
|
||||
build_flags = -Wall -DTSL2561_SCL=22 -DTSL2561_SDA=21
|
||||
|
||||
monitor_speed = 115200
|
||||
|
||||
upload_speed = 921600
|
||||
;upload_port = /dev/ttyUSB[1-9]
|
|
@ -23,6 +23,14 @@ This file is part of the Joba_Tsl2561 Library.
|
|||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
|
||||
// To be able to override pin definitions in build flags (used in examples)
|
||||
#ifndef TSL2561_SDA
|
||||
#define TSL2561_SDA SDA
|
||||
#endif
|
||||
#ifndef TSL2561_SCL
|
||||
#define TSL2561_SCL SCL
|
||||
#endif
|
||||
|
||||
class Tsl2561 {
|
||||
|
||||
public:
|
|
@ -22,9 +22,10 @@ This file is part of the Joba_Tsl2561 Library.
|
|||
namespace Tsl2561Util {
|
||||
|
||||
// Tsl2561Util::normalizedLuminosity returncode false can mean:
|
||||
// - saturation: full and/or ir have value ~0 (aka -1)
|
||||
// - saturation: full and/or ir have value ~0 (aka -1) and not shortest exposure
|
||||
// - manual exposure time: full and ir are corrected only for gain
|
||||
// If true, full and ir have values as if exposure was 402 and gain 16.
|
||||
// If true, full and ir have values as if exposure was 402 and gain 16
|
||||
// or ~0 if saturated even at shortest exposure
|
||||
bool normalizedLuminosity( bool gain, Tsl2561::exposure_t exposure, uint32_t &full, uint32_t &ir ) {
|
||||
|
||||
uint16_t scaledFull = (uint16_t)full;
|
||||
|
@ -39,8 +40,8 @@ bool normalizedLuminosity( bool gain, Tsl2561::exposure_t exposure, uint32_t &fu
|
|||
|
||||
switch( exposure ) {
|
||||
case Tsl2561::EXP_14:
|
||||
full = (scaledFull >= 5047/4*3) ? 0xffffffff : ((full + 5) * 322) / 11;
|
||||
ir = (scaledIr >= 5047/4*3) ? 0xffffffff : ((ir + 5) * 322) / 11;
|
||||
full = (scaledFull == 5047) ? 0xffffffff : ((full + 5) * 322) / 11;
|
||||
ir = (scaledIr == 5047) ? 0xffffffff : ((ir + 5) * 322) / 11;
|
||||
break;
|
||||
case Tsl2561::EXP_101:
|
||||
full = (scaledFull >= 37177/4*3) ? 0xffffffff : ((full + 40) * 322) / 81;
|
||||
|
@ -54,7 +55,7 @@ bool normalizedLuminosity( bool gain, Tsl2561::exposure_t exposure, uint32_t &fu
|
|||
return false;
|
||||
}
|
||||
|
||||
return full != 0xffffffff && ir != 0xffffffff;
|
||||
return exposure == Tsl2561::EXP_14 || (full != 0xffffffff && ir != 0xffffffff);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -93,6 +94,8 @@ bool autoGain( Tsl2561 &tsl, bool &gain, Tsl2561::exposure_t &exposure, uint16_t
|
|||
{ true, Tsl2561::EXP_402 } // max
|
||||
};
|
||||
|
||||
// Serial.printf("autoGain start: gain=%u, expo=%u\n", gain, exposure);
|
||||
|
||||
// get current sensitivity
|
||||
if( !tsl.getSensitivity(gain, exposure) ) {
|
||||
return false; // I2C error
|
||||
|
@ -110,9 +113,10 @@ bool autoGain( Tsl2561 &tsl, bool &gain, Tsl2561::exposure_t &exposure, uint16_t
|
|||
return false; // should not happen...
|
||||
}
|
||||
|
||||
// in a loop wait for next sample, get values and adjust sensitivity if needed
|
||||
// sometimes sensor reports high brightness although it is darker.
|
||||
uint8_t retryOnSaturated = 10;
|
||||
|
||||
// in a loop wait for next sample, get values and adjust sensitivity if needed
|
||||
while( true ) {
|
||||
waitNext(exposure);
|
||||
|
||||
|
@ -122,11 +126,14 @@ bool autoGain( Tsl2561 &tsl, bool &gain, Tsl2561::exposure_t &exposure, uint16_t
|
|||
|
||||
uint16_t limit = getLimit(exposure);
|
||||
if( full >= 1000 && full <= limit ) {
|
||||
return true; // new value within limits
|
||||
// Serial.printf("autoGain normal full=%u, limits=1000-%u, curr=%u\n", full, limit, curr);
|
||||
return true; // new value within limits of good accuracy
|
||||
}
|
||||
|
||||
// adjust sensitivity, if possible
|
||||
if( (full < 1000 && ++curr < sizeof(sensitivity)/sizeof(sensitivity[0]))
|
||||
|| (full > limit && curr-- > 0) ) {
|
||||
// Serial.printf("autoGain adjust full=%u, limits=1000-%u, curr=%u\n", full, limit, curr);
|
||||
if( !tsl.setSensitivity(sensitivity[curr].gain, sensitivity[curr].exposure) ) {
|
||||
return false; // I2C error
|
||||
}
|
||||
|
@ -134,7 +141,10 @@ bool autoGain( Tsl2561 &tsl, bool &gain, Tsl2561::exposure_t &exposure, uint16_t
|
|||
exposure = sensitivity[curr].exposure;
|
||||
}
|
||||
else {
|
||||
if( ++curr > 0 && retryOnSaturated-- == 0 ) {
|
||||
// sensitivity already is at minimum or maximum
|
||||
if( ++curr > 0 || retryOnSaturated-- == 0 ) {
|
||||
// Serial.printf("autoGain limit full=%u, ir=%u, limits=1000-%u, curr=%u, retry=%u\n", full, ir, limit, curr, retryOnSaturated);
|
||||
// dark, or repeatedly confirmed high brightness
|
||||
return true; // saturated, but best we can do
|
||||
}
|
||||
}
|
||||
|
@ -176,6 +186,11 @@ bool milliLux( uint32_t full, uint32_t ir, uint32_t &mLux, bool csType, uint8_t
|
|||
return true;
|
||||
}
|
||||
|
||||
if( full == 0xffffffff || ir == 0xffffffff ) {
|
||||
mLux = 99999999; // indicates saturation at shortest exposure
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t milliRatio = ir * 1000 / full;
|
||||
|
||||
if( csType ) {
|
|
@ -100,7 +100,7 @@ TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fal
|
|||
m_buffer = (uint8_t*)malloc(TM_SERIAL_BUFFER_SIZE);
|
||||
if (m_buffer == NULL) return;
|
||||
// Use getCycleCount() loop to get as exact timing as possible
|
||||
m_bit_time = F_CPU / TM_SERIAL_BAUDRATE;
|
||||
m_bit_time = ESP.getCpuFreqMHz() * 1000000 / TM_SERIAL_BAUDRATE;
|
||||
pinMode(m_rx_pin, INPUT);
|
||||
tms_obj_list[m_rx_pin] = this;
|
||||
attachInterrupt(m_rx_pin, ISRList[m_rx_pin], FALLING);
|
||||
|
@ -145,8 +145,8 @@ bool TasmotaSerial::begin(long speed, int stop_bits) {
|
|||
}
|
||||
} else {
|
||||
// Use getCycleCount() loop to get as exact timing as possible
|
||||
m_bit_time = F_CPU / speed;
|
||||
m_high_speed = (speed > 9600);
|
||||
m_bit_time = ESP.getCpuFreqMHz() * 1000000 / speed;
|
||||
m_high_speed = (speed >= 9600);
|
||||
}
|
||||
return m_valid;
|
||||
}
|
|
@ -1,4 +1,10 @@
|
|||
/* 6.5.0.8 20190413
|
||||
/* 6.5.0.9 20190418
|
||||
* Add command SetOption63 0/1 to disable relay state feedback scan at restart (#5594, #5663)
|
||||
* Fix TasmotaSerial at 9600 bps solving DFPlayer comms (#5528)
|
||||
* Fix Shelly 2.5 overtemp
|
||||
*
|
||||
* 6.5.0.8 20190413
|
||||
* Add Tuya Dimmer 10 second heartbeat serial packet required by some Tuya dimmer secondary MCUs
|
||||
* Fix use of SerialDelimiter value 128 (#5634)
|
||||
* Fix lost syslog connection regression from 6.5.0.4
|
||||
* Add Shelly 2.5 Energy Monitoring (#5592)
|
||||
|
|
|
@ -76,7 +76,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
|
|||
uint32_t sleep_normal : 1; // bit 10 (v6.3.0.15) - SetOption60 - Enable normal sleep instead of dynamic sleep
|
||||
uint32_t button_switch_force_local : 1;// bit 11 (v6.3.0.16) - SetOption61 - Force local operation when button/switch topic is set
|
||||
uint32_t no_hold_retain : 1; // bit 12 (v6.4.1.19) - SetOption62 - Don't use retain flag on HOLD messages
|
||||
uint32_t spare13 : 1;
|
||||
uint32_t no_power_feedback : 1; // bit 13 (v6.5.0.9) - SetOption63 - Don't scan relay power state at restart
|
||||
uint32_t spare14 : 1;
|
||||
uint32_t spare15 : 1;
|
||||
uint32_t spare16 : 1;
|
||||
|
|
|
@ -2693,9 +2693,11 @@ void setup(void)
|
|||
|
||||
// Issue #526 and #909
|
||||
for (uint8_t i = 0; i < devices_present; i++) {
|
||||
if (!Settings.flag3.no_power_feedback) { // #5594 and #5663
|
||||
if ((i < MAX_RELAYS) && (pin[GPIO_REL1 +i] < 99)) {
|
||||
bitWrite(power, i, digitalRead(pin[GPIO_REL1 +i]) ^ bitRead(rel_inverted, i));
|
||||
}
|
||||
}
|
||||
if ((i < MAX_PULSETIMERS) && (bitRead(power, i) || (POWER_ALL_OFF_PULSETIME_ON == Settings.poweronstate))) {
|
||||
SetPulseTimer(i, Settings.pulse_timer[i]);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,6 @@
|
|||
#ifndef _SONOFF_VERSION_H_
|
||||
#define _SONOFF_VERSION_H_
|
||||
|
||||
const uint32_t VERSION = 0x06050008;
|
||||
const uint32_t VERSION = 0x06050009;
|
||||
|
||||
#endif // _SONOFF_VERSION_H_
|
||||
|
|
|
@ -584,6 +584,16 @@ float ConvertTemp(float c)
|
|||
return result;
|
||||
}
|
||||
|
||||
float ConvertTempToCelsius(float c)
|
||||
{
|
||||
float result = c;
|
||||
|
||||
if (!isnan(c) && Settings.flag.temperature_conversion) {
|
||||
result = (c - 32) / 1.8; // Celsius
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
char TempUnit(void)
|
||||
{
|
||||
return (Settings.flag.temperature_conversion) ? 'F' : 'C';
|
||||
|
|
|
@ -245,7 +245,7 @@ const char HTTP_HEAD_STYLE1[] PROGMEM =
|
|||
"input[type=checkbox],input[type=radio]{width:1em;margin-right:6px;vertical-align:-1px;}"
|
||||
"select{width:100%%;background:#%06x;color:#%06x;}" // COLOR_INPUT, COLOR_INPUT_TEXT
|
||||
"textarea{resize:none;width:98%%;height:318px;padding:5px;overflow:auto;background:#%06x;color:#%06x;}" // COLOR_CONSOLE, COLOR_CONSOLE_TEXT
|
||||
"body{text-align:center;font-family:verdana;background:#%06x;}" // COLOR_BACKGROUND
|
||||
"body{text-align:center;font-family:verdana,sans-serif;background:#%06x;}" // COLOR_BACKGROUND
|
||||
"td{padding:0px;}";
|
||||
const char HTTP_HEAD_STYLE2[] PROGMEM =
|
||||
"button{border:0;border-radius:0.3rem;background:#%06x;color:#%06x;line-height:2.4rem;font-size:1.2rem;width:100%%;-webkit-transition-duration:0.4s;transition-duration:0.4s;cursor:pointer;}" // COLOR_BUTTON, COLOR_BUTTON_TEXT
|
||||
|
|
|
@ -52,6 +52,7 @@ uint8_t tuya_cmd_status = 0; // Current status of serial-read
|
|||
uint8_t tuya_cmd_checksum = 0; // Checksum of tuya command
|
||||
uint8_t tuya_data_len = 0; // Data lenght of command
|
||||
int8_t tuya_wifi_state = -2; // Keep MCU wifi-status in sync with WifiState()
|
||||
uint8_t tuya_heartbeat_timer = 0; // 10 second heartbeat timer for tuya module
|
||||
|
||||
char *tuya_buffer = nullptr; // Serial receive buffer
|
||||
int tuya_byte_counter = 0; // Index in serial receive buffer
|
||||
|
@ -294,6 +295,7 @@ void TuyaInit(void)
|
|||
TuyaSendCmd(TUYA_CMD_MCU_CONF);
|
||||
}
|
||||
}
|
||||
tuya_heartbeat_timer = 0; // init heartbeat timer when dimmer init is done
|
||||
}
|
||||
|
||||
void TuyaSerialInput(void)
|
||||
|
@ -410,6 +412,11 @@ bool Xdrv16(uint8_t function)
|
|||
break;
|
||||
case FUNC_EVERY_SECOND:
|
||||
if(TuyaSerial && tuya_wifi_state!=WifiState()) { TuyaSetWifiLed(); }
|
||||
tuya_heartbeat_timer++;
|
||||
if (tuya_heartbeat_timer > 10) {
|
||||
tuya_heartbeat_timer = 0;
|
||||
TuyaSendCmd(TUYA_CMD_HEARTBEAT);
|
||||
}
|
||||
break;
|
||||
case FUNC_SET_CHANNELS:
|
||||
result = TuyaSetChannels();
|
||||
|
|
|
@ -162,9 +162,11 @@ void Ade7953EnergyEverySecond()
|
|||
|
||||
void Ade7953EverySecond()
|
||||
{
|
||||
if (power && (global_temperature > ADE7953_OVERTEMP)) { // Device overtemp, turn off relays
|
||||
#ifndef USE_ADC_VCC
|
||||
if (power && (ConvertTempToCelsius(AdcTemperature()) > ADE7953_OVERTEMP)) { // Device overtemp, turn off relays
|
||||
SetAllPower(POWER_ALL_OFF, SRC_OVERTEMP);
|
||||
}
|
||||
#endif // USE_ADC_VCC
|
||||
}
|
||||
|
||||
void Ade7953DrvInit(void)
|
||||
|
@ -190,7 +192,7 @@ bool Ade7953Command(void)
|
|||
{
|
||||
bool serviced = true;
|
||||
|
||||
double value = CharToDouble(XdrvMailbox.data);
|
||||
uint32_t value = (uint32_t)(CharToDouble(XdrvMailbox.data) * 100); // 1.23 = 123
|
||||
|
||||
if (CMND_POWERCAL == energy_command_code) {
|
||||
if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = ADE7953_PREF; }
|
||||
|
@ -206,17 +208,23 @@ bool Ade7953Command(void)
|
|||
}
|
||||
else if (CMND_POWERSET == energy_command_code) {
|
||||
if (XdrvMailbox.data_len && ade7953_active_power) {
|
||||
Settings.energy_power_calibration = (uint32_t)((double)ade7953_active_power / (value / 10)); // W
|
||||
if ((value > 100) && (value < 200000)) { // Between 1W and 2000W
|
||||
Settings.energy_power_calibration = (ade7953_active_power * 1000) / value; // 0.00 W
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (CMND_VOLTAGESET == energy_command_code) {
|
||||
if (XdrvMailbox.data_len && ade7953_voltage_rms) {
|
||||
Settings.energy_voltage_calibration = (uint32_t)((double)ade7953_voltage_rms / value); // V
|
||||
if ((value > 10000) && (value < 26000)) { // Between 100V and 260V
|
||||
Settings.energy_voltage_calibration = (ade7953_voltage_rms * 100) / value; // 0.00 V
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (CMND_CURRENTSET == energy_command_code) {
|
||||
if (XdrvMailbox.data_len && ade7953_current_rms) {
|
||||
Settings.energy_current_calibration = (uint32_t)((double)ade7953_current_rms / (value * 10)); // A
|
||||
if ((value > 2000) && (value < 1000000)) { // Between 20mA and 10A
|
||||
Settings.energy_current_calibration = ((ade7953_current_rms * 100) / value) * 100; // 0.00 mA
|
||||
}
|
||||
}
|
||||
}
|
||||
else serviced = false; // Unknown command
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#define ANALOG_B 3350.0 // Thermistor Beta Coefficient
|
||||
|
||||
uint16_t adc_last_value = 0;
|
||||
float adc_temp = 0;
|
||||
|
||||
uint16_t AdcRead(uint8_t factor)
|
||||
{
|
||||
|
@ -69,6 +70,22 @@ void AdcEvery250ms(void)
|
|||
}
|
||||
#endif // USE_RULES
|
||||
|
||||
void AdcEverySecond(void)
|
||||
{
|
||||
if (my_module_flag.adc0_temp) {
|
||||
int adc = AdcRead(2);
|
||||
// Steinhart-Hart equation for thermistor as temperature sensor
|
||||
double Rt = (adc * ANALOG_R21) / (1024.0 * ANALOG_V33 - (double)adc);
|
||||
double T = ANALOG_B / (ANALOG_B/ANALOG_T0 + log(Rt/ANALOG_R0));
|
||||
adc_temp = ConvertTemp(TO_CELSIUS(T));
|
||||
}
|
||||
}
|
||||
|
||||
float AdcTemperature(void)
|
||||
{
|
||||
return adc_temp;
|
||||
}
|
||||
|
||||
void AdcShow(bool json)
|
||||
{
|
||||
if (my_module_flag.adc0) {
|
||||
|
@ -83,14 +100,8 @@ void AdcShow(bool json)
|
|||
}
|
||||
}
|
||||
if (my_module_flag.adc0_temp) {
|
||||
int adc = AdcRead(2);
|
||||
// Steinhart-Hart equation for thermistor as temperature sensor
|
||||
double Rt = (adc * ANALOG_R21) / (1024.0 * ANALOG_V33 - (double)adc);
|
||||
double T = ANALOG_B / (ANALOG_B/ANALOG_T0 + log(Rt/ANALOG_R0));
|
||||
double temp = ConvertTemp(TO_CELSIUS(T));
|
||||
|
||||
char temperature[33];
|
||||
dtostrfd(temp, Settings.flag2.temperature_resolution, temperature);
|
||||
dtostrfd(adc_temp, Settings.flag2.temperature_resolution, temperature);
|
||||
|
||||
if (json) {
|
||||
ResponseAppend_P(JSON_SNS_TEMP, "ANALOG", temperature);
|
||||
|
@ -127,6 +138,9 @@ bool Xsns02(uint8_t function)
|
|||
AdcEvery250ms();
|
||||
break;
|
||||
#endif // USE_RULES
|
||||
case FUNC_EVERY_SECOND:
|
||||
AdcEverySecond();
|
||||
break;
|
||||
case FUNC_JSON_APPEND:
|
||||
AdcShow(1);
|
||||
break;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
VER = '2.1.0023'
|
||||
VER = '2.1.0024'
|
||||
|
||||
"""
|
||||
decode-config.py - Backup/Restore Sonoff-Tasmota configuration data
|
||||
|
@ -433,7 +433,7 @@ Setting_5_10_0 = {
|
|||
'pwm_control': ('<L', (0x010,1,15), (None, None, ('Main', '"SetOption15 {}".format($)')) ),
|
||||
'ws_clock_reverse': ('<L', (0x010,1,16), (None, None, ('SetOption', '"SetOption16 {}".format($)')) ),
|
||||
'decimal_text': ('<L', (0x010,1,17), (None, None, ('SetOption', '"SetOption17 {}".format($)')) ),
|
||||
}, 0x010, (None, None, ('*', None)), (None, False) ),
|
||||
}, 0x010, (None, None, ('*', None)), (None, None) ),
|
||||
'save_data': ('<h', 0x014, (None, '0 <= $ <= 3600', ('Management', '"SaveData {}".format($)')) ),
|
||||
'timezone': ('b', 0x016, (None, '-13 <= $ <= 13 or $==99', ('Management', '"Timezone {}".format($)')) ),
|
||||
'ota_url': ('101s',0x017, (None, None, ('Main', '"OtaUrl {}".format($)')) ),
|
||||
|
@ -469,7 +469,7 @@ Setting_5_10_0 = {
|
|||
'power6': ('<L', (0x2E8,1,5), (None, None, ('Main', '"Power6 {}".format($)')) ),
|
||||
'power7': ('<L', (0x2E8,1,6), (None, None, ('Main', '"Power7 {}".format($)')) ),
|
||||
'power8': ('<L', (0x2E8,1,7), (None, None, ('Main', '"Power8 {}".format($)')) ),
|
||||
}, 0x2E8, (None, None, ('Main', None)), (None, False) ),
|
||||
}, 0x2E8, (None, None, ('Main', None)), (None, None) ),
|
||||
'pwm_value': ('<H', 0x2EC, ([5], '0 <= $ <= 1023', ('Management', '"Pwm{} {}".format(#,$)')) ),
|
||||
'altitude': ('<h', 0x2F6, (None, '-30000 <= $ <= 30000', ('Sensor', '"Altitude {}".format($)')) ),
|
||||
'tele_period': ('<H', 0x2F8, (None, '0 <= $ <= 1 or 10 <= $ <= 3600',('MQTT', '"TelePeriod {}".format($)')) ),
|
||||
|
@ -483,8 +483,8 @@ Setting_5_10_0 = {
|
|||
'energy_power_calibration': ('<L', 0x364, (None, None, ('Pow', '"PowerSet {}".format($)')) ),
|
||||
'energy_voltage_calibration': ('<L', 0x368, (None, None, ('Pow', '"VoltageSet {}".format($)')) ),
|
||||
'energy_current_calibration': ('<L', 0x36C, (None, None, ('Pow', '"CurrentSet {}".format($)')) ),
|
||||
'energy_kWhtoday': ('<L', 0x370, (None, '0 <= $ <= 42500', ('Pow', '"EnergyReset1 {}".format($)')) ),
|
||||
'energy_kWhyesterday': ('<L', 0x374, (None, '0 <= $ <= 42500', ('Pow', '"EnergyReset2 {}".format($)')) ),
|
||||
'energy_kWhtoday': ('<L', 0x370, (None, '0 <= $ <= 4250000', ('Pow', '"EnergyReset1 {}".format(int(round(float($)/100)))')) ),
|
||||
'energy_kWhyesterday': ('<L', 0x374, (None, '0 <= $ <= 4250000', ('Pow', '"EnergyReset2 {}".format(int(round(float($)/100)))')) ),
|
||||
'energy_kWhdoy': ('<H', 0x378, (None, None, ('Pow', None)) ),
|
||||
'energy_min_power': ('<H', 0x37A, (None, None, ('Pow', '"PowerLow {}".format($)')) ),
|
||||
'energy_max_power': ('<H', 0x37C, (None, None, ('Pow', '"PowerHigh {}".format($)')) ),
|
||||
|
@ -529,9 +529,9 @@ Setting_5_10_0 = {
|
|||
'switchmode': ('B', 0x4CA, ([4], '0 <= $ <= 7', ('Main', '"SwitchMode{} {}".format(#,$)')) ),
|
||||
'ntp_server': ('33s', 0x4CE, ([3], None, ('Wifi', '"NtpServer{} {}".format(#,$)')) ),
|
||||
'ina219_mode': ('B', 0x531, (None, '0 <= $ <= 7', ('Sensor', '"Sensor13 {}".format($)')) ),
|
||||
'pulse_timer': ('<H', 0x532, ([8], '0 <= $ <= 64900', ('Main', '"PulseTime{} {}".format(#,$)')), ("float($)/10 if 1 <= $ <= 111 else $-100 if $ != 0 else 0", "int($*10) if 0.1 <= $ < 12 else $+100 if $ != 0 else 0") ),
|
||||
'pulse_timer': ('<H', 0x532, ([8], '0 <= $ <= 64900', ('Main', '"PulseTime{} {}".format(#,$)')) ),
|
||||
'ip_address': ('<L', 0x544, ([4], None, ('Wifi', '"IPAddress{} {}".format(#,$)')), ("socket.inet_ntoa(struct.pack('<L', $))", "struct.unpack('<L', socket.inet_aton($))[0]")),
|
||||
'energy_kWhtotal': ('<L', 0x554, (None, None, ('Pow', None)) ),
|
||||
'energy_kWhtotal': ('<L', 0x554, (None, '0 <= $ <= 4250000000', ('Pow', '"EnergyReset3 {}".format(int(round(float($)/100)))')) ),
|
||||
'mqtt_fulltopic': ('100s',0x558, (None, None, ('MQTT', '"FullTopic {}".format($)')) ),
|
||||
'flag2': ({
|
||||
'current_resolution': ('<L', (0x5BC,2,15), (None, '0 <= $ <= 3', ('Pow', '"AmpRes {}".format($)')) ),
|
||||
|
@ -542,7 +542,7 @@ Setting_5_10_0 = {
|
|||
'pressure_resolution': ('<L', (0x5BC,2,26), (None, '0 <= $ <= 3', ('Sensor', '"PressRes {}".format($)')) ),
|
||||
'humidity_resolution': ('<L', (0x5BC,2,28), (None, '0 <= $ <= 3', ('Sensor', '"HumRes {}".format($)')) ),
|
||||
'temperature_resolution': ('<L', (0x5BC,2,30), (None, '0 <= $ <= 3', ('Sensor', '"TempRes {}".format($)')) ),
|
||||
}, 0x5BC, (None, None, ('*', None)), (None, False) ),
|
||||
}, 0x5BC, (None, None, ('*', None)), (None, None) ),
|
||||
'pulse_counter': ('<L', 0x5C0, ([4], None, ('Sensor', '"Counter{} {}".format(#,$)')) ),
|
||||
'pulse_counter_type': ('<H', 0x5D0, (None, None, ('Sensor', '"CounterType {}".format($)')) ),
|
||||
'pulse_counter_type': ({
|
||||
|
@ -550,7 +550,7 @@ Setting_5_10_0 = {
|
|||
'pulse_counter_type2': ('<H', (0x5D0,1,1), (None, None, ('Sensor', '"CounterType2 {}".format($)')) ),
|
||||
'pulse_counter_type3': ('<H', (0x5D0,1,2), (None, None, ('Sensor', '"CounterType3 {}".format($)')) ),
|
||||
'pulse_counter_type4': ('<H', (0x5D0,1,3), (None, None, ('Sensor', '"CounterType4 {}".format($)')) ),
|
||||
}, 0x5D0, (None, None, ('Sensor', None)), (None, False) ),
|
||||
}, 0x5D0, (None, None, ('Sensor', None)), (None, None) ),
|
||||
'pulse_counter_debounce': ('<H', 0x5D2, (None, '0 <= $ <= 3200', ('Sensor', '"CounterDebounce {}".format($)')) ),
|
||||
'rf_code': ('B', 0x5D4, ([17,9],None, ('SonoffRF', None)), '"0x{:02x}".format($)'),
|
||||
}
|
||||
|
@ -595,7 +595,7 @@ Setting_5_13_1.update ({
|
|||
'knx_GA_registered': ('B', 0x4A5, (None, None, ('KNX', None)) ),
|
||||
'knx_CB_registered': ('B', 0x4A8, (None, None, ('KNX', None)) ),
|
||||
'timer': ({
|
||||
'value': ('<L', 0x670, (None, None, ('Timers', '"Timer{} {{\\\"Arm\\\":{arm},\\\"Mode\\\":{mode},\\\"Time\\\":\\\"{tsign}{time}\\\",\\\"Window\\\":{window},\\\"Days\\\":\\\"{days}\\\",\\\"Repeat\\\":{repeat},\\\"Output\\\":{device},\\\"Action\\\":{power}}}".format(#, arm=bitsRead($,31),mode=bitsRead($,29,2),tsign="-" if bitsRead($,29,2)>0 and bitsRead($,0,11)>(12*60) else "",time=time.strftime("%H:%M",time.gmtime((bitsRead($,0,11) if bitsRead($,29,2)==0 else bitsRead($,0,11) if bitsRead($,0,11)<=(12*60) else bitsRead($,0,11)-(12*60))*60)),window=bitsRead($,11,4),repeat=bitsRead($,15),days="{:07b}".format(bitsRead($,16,7))[::-1],device=bitsRead($,23,4)+1,power=bitsRead($,27,2) )')), ('"0x{:08x}".format($)', False) ),
|
||||
'_': ('<L', 0x670, (None, None, ('Timers', '"Timer{} {{\\\"Arm\\\":{arm},\\\"Mode\\\":{mode},\\\"Time\\\":\\\"{tsign}{time}\\\",\\\"Window\\\":{window},\\\"Days\\\":\\\"{days}\\\",\\\"Repeat\\\":{repeat},\\\"Output\\\":{device},\\\"Action\\\":{power}}}".format(#, arm=bitsRead($,31),mode=bitsRead($,29,2),tsign="-" if bitsRead($,29,2)>0 and bitsRead($,0,11)>(12*60) else "",time=time.strftime("%H:%M",time.gmtime((bitsRead($,0,11) if bitsRead($,29,2)==0 else bitsRead($,0,11) if bitsRead($,0,11)<=(12*60) else bitsRead($,0,11)-(12*60))*60)),window=bitsRead($,11,4),repeat=bitsRead($,15),days="{:07b}".format(bitsRead($,16,7))[::-1],device=bitsRead($,23,4)+1,power=bitsRead($,27,2) )')), ('"0x{:08x}".format($)', False) ),
|
||||
'time': ('<L', (0x670,11, 0),(None, '0 <= $ < 1440', ('Timers', None)) ),
|
||||
'window': ('<L', (0x670, 4,11),(None, None, ('Timers', None)) ),
|
||||
'repeat': ('<L', (0x670, 1,15),(None, None, ('Timers', None)) ),
|
||||
|
@ -627,7 +627,7 @@ Setting_5_14_0.update ({
|
|||
'month': ('<H', (0x2E2,4, 4), (None, '1 <= $ <= 12', ('Management', None)) ),
|
||||
'dow': ('<H', (0x2E2,3, 8), (None, '1 <= $ <= 7', ('Management', None)) ),
|
||||
'hour': ('<H', (0x2E2,5,11), (None, '0 <= $ <= 23', ('Management', None)) ),
|
||||
}, 0x2E2, ([2], None, ('Management', None)), (None, False) ),
|
||||
}, 0x2E2, ([2], None, ('Management', None)), (None, None) ),
|
||||
'param': ('B', 0x2FC, ([18], None, ('SetOption', '"SetOption{} {}".format(#+31,$)')) ),
|
||||
'toffset': ('<h', 0x30E, ([2], None, ('Management', '"{cmnd} {hemis},{week},{month},{dow},{hour},{toffset}".format(cmnd="TimeSTD" if idx==1 else "TimeDST", hemis=@["tflag"][#-1]["hemis"], week=@["tflag"][#-1]["week"], month=@["tflag"][#-1]["month"], dow=@["tflag"][#-1]["dow"], hour=@["tflag"][#-1]["hour"], toffset=value)')) ),
|
||||
})
|
||||
|
@ -642,12 +642,12 @@ Setting_6_0_0.update({
|
|||
'rule1': ('B', (0x49F,1,0), (None, None, ('Management', '"Rule1 {}".format($)')) ),
|
||||
'rule2': ('B', (0x49F,1,1), (None, None, ('Management', '"Rule2 {}".format($)')) ),
|
||||
'rule3': ('B', (0x49F,1,2), (None, None, ('Management', '"Rule3 {}".format($)')) ),
|
||||
}, 0x49F, (None, None, ('Management', None)), (None, False) ),
|
||||
}, 0x49F, (None, None, ('Management', None)), (None, None) ),
|
||||
'rule_once': ({
|
||||
'rule1': ('B', (0x4A0,1,0), (None, None, ('Management', '"Rule1 {}".format($+4)')) ),
|
||||
'rule2': ('B', (0x4A0,1,1), (None, None, ('Management', '"Rule2 {}".format($+4)')) ),
|
||||
'rule3': ('B', (0x4A0,1,2), (None, None, ('Management', '"Rule3 {}".format($+4)')) ),
|
||||
}, 0x4A0, (None, None, ('Management', None)), (None, False) ),
|
||||
}, 0x4A0, (None, None, ('Management', None)), (None, None) ),
|
||||
'mems': ('10s', 0x7CE, ([5], None, ('Management', '"Mem{} {}".format(#,"\\"" if len($)==0 else $)')) ),
|
||||
'rules': ('512s',0x800, ([3], None, ('Management', '"Rule{} {}".format(#,"\\"" if len($)==0 else $)')) ),
|
||||
})
|
||||
|
@ -660,14 +660,14 @@ Setting_6_1_1.update ({
|
|||
'flag3': ('<L', 0x3A0, (None, None, ('System', None)), '"0x{:08x}".format($)' ),
|
||||
'switchmode': ('B', 0x3A4, ([8], '0 <= $ <= 7', ('Main', '"SwitchMode{} {}".format(#,$)')) ),
|
||||
'mcp230xx_config': ({
|
||||
'value': ('<L', 0x6F6, (None, None, ('MCP230xx', '"Sensor29 {pin},{pinmode},{pullup},{intmode}".format(pin=#-1, pinmode=@["mcp230xx_config"][#-1]["pinmode"], pullup=@["mcp230xx_config"][#-1]["pullup"], intmode=@["mcp230xx_config"][#-1]["int_report_mode"])')), ('"0x{:08x}".format($)', False) ),
|
||||
'_': ('<L', 0x6F6, (None, None, ('MCP230xx', '"Sensor29 {pin},{pinmode},{pullup},{intmode}".format(pin=#-1, pinmode=@["mcp230xx_config"][#-1]["pinmode"], pullup=@["mcp230xx_config"][#-1]["pullup"], intmode=@["mcp230xx_config"][#-1]["int_report_mode"])')), ('"0x{:08x}".format($)', False) ),
|
||||
'pinmode': ('<L', (0x6F6,3, 0), (None, '0 <= $ <= 5', ('MCP230xx', None)) ),
|
||||
'pullup': ('<L', (0x6F6,1, 3), (None, None, ('MCP230xx', None)) ),
|
||||
'saved_state': ('<L', (0x6F6,1, 4), (None, None, ('MCP230xx', None)) ),
|
||||
'int_report_mode': ('<L', (0x6F6,2, 5), (None, None, ('MCP230xx', None)) ),
|
||||
'int_report_defer': ('<L', (0x6F6,4, 7), (None, None, ('MCP230xx', None)) ),
|
||||
'int_count_en': ('<L', (0x6F6,1,11), (None, None, ('MCP230xx', None)) ),
|
||||
}, 0x6F6, ([16], None, ('MCP230xx', None)), (None, False) ),
|
||||
}, 0x6F6, ([16], None, ('MCP230xx', None)), (None, None) ),
|
||||
})
|
||||
Setting_6_1_1['flag'][0].update ({
|
||||
'rf_receive_decimal': ('<L', (0x010,1,28), (None, None, ('SetOption' , '"SetOption28 {}".format($)')) ),
|
||||
|
@ -687,7 +687,7 @@ Setting_6_2_1.update ({
|
|||
'flag3': ({
|
||||
'timers_enable': ('<L', (0x3A0,1, 0), (None, None, ('Timers', '"Timers {}".format($)')) ),
|
||||
'user_esp8285_enable': ('<L', (0x3A0,1,31), (None, None, ('System', None)) ),
|
||||
}, 0x3A0, (None, None, ('*', None)), (None, False) ),
|
||||
}, 0x3A0, (None, None, ('*', None)), (None, None) ),
|
||||
'button_debounce': ('<H', 0x542, (None, '40 <= $ <= 1000', ('Main', '"ButtonDebounce {}".format($)')) ),
|
||||
'switch_debounce': ('<H', 0x66E, (None, '40 <= $ <= 1000', ('Main', '"SwitchDebounce {}".format($)')) ),
|
||||
'mcp230xx_int_prio': ('B', 0x716, (None, None, ('MCP230xx', None)) ),
|
||||
|
@ -834,12 +834,15 @@ Setting_6_4_1_11['flag3'][0].pop('split_interlock',None)
|
|||
Setting_6_4_1_11.update ({
|
||||
'interlock': ('B', 0x4CA, ([4], None, ('Main', None)), '"0x{:02x}".format($)' ),
|
||||
})
|
||||
Setting_6_4_1_11['flag'][0].update ({
|
||||
'interlock': ('<L', (0x010,1,14), (None, None, ('Main', '"Interlock {}".format($)')) ),
|
||||
})
|
||||
# ======================================================================
|
||||
Setting_6_4_1_13 = copy.deepcopy(Setting_6_4_1_11)
|
||||
Setting_6_4_1_13.update ({
|
||||
'SensorBits1': ({
|
||||
'mhz19b_abc_disable': ('B', (0x717,1, 7), (None, None, ('Sensor', '"Sensor15 {}".format($)')) ),
|
||||
}, 0x717, (None, None, ('*', None)), (None, False) ),
|
||||
}, 0x717, (None, None, ('*', None)), (None, None) ),
|
||||
})
|
||||
# ======================================================================
|
||||
Setting_6_4_1_16 = copy.deepcopy(Setting_6_4_1_13)
|
||||
|
@ -861,7 +864,7 @@ Setting_6_4_1_16.update({
|
|||
'gpio15': ('B', 0x73A, (None, None, ('Management', None)) ),
|
||||
'gpio16': ('B', 0x73B, (None, None, ('Management', None)) ),
|
||||
'flag': ({
|
||||
'value': ('B', 0x73C , (None, None, ('Management', '"Template {{\\\"FLAG\\\":{}}}".format($)')) ),
|
||||
'_': ('B', 0x73C , (None, None, ('Management', '"Template {{\\\"FLAG\\\":{}}}".format($)')),(None, False) ),
|
||||
'adc0': ('B', (0x73C,1,0), (None, None, ('Management', None)) ),
|
||||
'pullup': ('B', (0x73C,1,1), (None, None, ('Management', None)) ),
|
||||
}, 0x73C, (None, None, ('Management', None))
|
||||
|
@ -880,10 +883,22 @@ Setting_6_4_1_18['flag3'][0].update ({
|
|||
# ======================================================================
|
||||
Setting_6_5_0_3 = copy.deepcopy(Setting_6_4_1_18)
|
||||
Setting_6_5_0_3.update({
|
||||
'novasds_period': ('B', 0x73D, (None, '0 <= $ <= 255', ('Sensor', '"Sensor20 {}".format($)')) ),
|
||||
'novasds_period': ('B', 0x73D, (None, '1 <= $ <= 255', ('Sensor', '"Sensor20 {}".format($)')) ),
|
||||
})
|
||||
# ======================================================================
|
||||
Setting_6_5_0_6 = copy.deepcopy(Setting_6_5_0_3)
|
||||
Setting_6_5_0_6.update({
|
||||
'web_color': ('3B', 0x73E, ([18], None, ('Wifi', '"WebColor{} {}{:06x}".format(#,chr(35),int($,0))')), '"0x{:06x}".format($)' ),
|
||||
})
|
||||
# ======================================================================
|
||||
Setting_6_5_0_7 = copy.deepcopy(Setting_6_5_0_6)
|
||||
Setting_6_5_0_7.update({
|
||||
'ledmask': ('<H', 0x7BC, (None, None, ('Main', '"LedMask {}".format($)')), '"0x{:04x}".format($)' ),
|
||||
})
|
||||
# ======================================================================
|
||||
Settings = [
|
||||
(0x6050007, 0xe00, Setting_6_5_0_7),
|
||||
(0x6050006, 0xe00, Setting_6_5_0_6),
|
||||
(0x6050003, 0xe00, Setting_6_5_0_3),
|
||||
(0x6040112, 0xe00, Setting_6_4_1_18),
|
||||
(0x6040111, 0xe00, Setting_6_4_1_17),
|
||||
|
@ -1110,11 +1125,11 @@ def GetGroupList(setting):
|
|||
|
||||
for name in setting:
|
||||
dev = setting[name]
|
||||
format, group = GetFieldDef(dev, fields="format, group")
|
||||
format_, group = GetFieldDef(dev, fields="format_, group")
|
||||
if group is not None and len(group) > 0:
|
||||
groups.add(group)
|
||||
if isinstance(format, dict):
|
||||
subgroups = GetGroupList(format)
|
||||
if isinstance(format_, dict):
|
||||
subgroups = GetGroupList(format_)
|
||||
if subgroups is not None and len(subgroups) > 0:
|
||||
for group in subgroups:
|
||||
groups.add(group)
|
||||
|
@ -1478,8 +1493,11 @@ def PushTasmotaConfig(encode_cfg, host, port, username=DEFAULTS['source']['usern
|
|||
# post data
|
||||
c = pycurl.Curl()
|
||||
header = HTTPHeader()
|
||||
from StringIO import StringIO
|
||||
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:
|
||||
|
@ -1506,6 +1524,7 @@ def PushTasmotaConfig(encode_cfg, host, port, username=DEFAULTS['source']['usern
|
|||
responsecode = c.getinfo(c.RESPONSE_CODE)
|
||||
except Exception, e:
|
||||
return e[0], e[1]
|
||||
|
||||
c.close()
|
||||
|
||||
if responsecode >= 400:
|
||||
|
@ -1513,6 +1532,21 @@ def PushTasmotaConfig(encode_cfg, host, port, username=DEFAULTS['source']['usern
|
|||
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")
|
||||
if findUpload < 0:
|
||||
return ExitCode.UPLOAD_CONFIG_ERROR, "Device did not response properly with upload result page"
|
||||
|
||||
body = body[findUpload:]
|
||||
findSuccessful = body.find("Successful")
|
||||
if findSuccessful < 0:
|
||||
errmatch = re.search("<font\s*color='[#0-9a-fA-F]+'>(\S*)</font></b><br/><br/>(.*)<br/>", body)
|
||||
reason = "Unknown error"
|
||||
if errmatch and len(errmatch.groups()) > 1:
|
||||
reason = errmatch.group(2)
|
||||
return ExitCode.UPLOAD_CONFIG_ERROR, reason
|
||||
|
||||
return 0, 'OK'
|
||||
|
||||
|
||||
|
@ -1556,7 +1590,7 @@ def GetSettingsCrc(dobj):
|
|||
return crc & 0xffff
|
||||
|
||||
|
||||
def GetFieldDef(fielddef, fields="format, addrdef, baseaddr, bits, bitshift, datadef, arraydef, validate, cmd, group, tasmotacmnd, converter, readconverter, writeconverter"):
|
||||
def GetFieldDef(fielddef, fields="format_, addrdef, baseaddr, bits, bitshift, datadef, arraydef, validate, cmd, group, tasmotacmnd, converter, readconverter, writeconverter"):
|
||||
|
||||
"""
|
||||
Get field definition items
|
||||
|
@ -1570,7 +1604,7 @@ def GetFieldDef(fielddef, fields="format, addrdef, baseaddr, bits, bitshift, dat
|
|||
@return:
|
||||
set of values defined in <fields>
|
||||
"""
|
||||
format = addrdef = baseaddr = datadef = arraydef = validate = cmd = group = tasmotacmnd = converter = readconverter = writeconverter = None
|
||||
format_ = addrdef = baseaddr = datadef = arraydef = validate = cmd = group = tasmotacmnd = converter = readconverter = writeconverter = None
|
||||
bits = bitshift = 0
|
||||
|
||||
# calling with nothing is wrong
|
||||
|
@ -1581,20 +1615,20 @@ def GetFieldDef(fielddef, fields="format, addrdef, baseaddr, bits, bitshift, dat
|
|||
# get top level items
|
||||
if len(fielddef) == 3:
|
||||
# converter not present
|
||||
format, addrdef, datadef = fielddef
|
||||
format_, addrdef, datadef = fielddef
|
||||
elif len(fielddef) == 4:
|
||||
# converter present
|
||||
format, addrdef, datadef, converter = fielddef
|
||||
format_, addrdef, datadef, converter = fielddef
|
||||
else:
|
||||
print >> sys.stderr, 'wrong <fielddef> {} length ({}) in setting'.format(fielddef, len(fielddef))
|
||||
raise SyntaxError('<fielddef> error')
|
||||
|
||||
# ignore calls with 'root' setting
|
||||
if isinstance(format, dict) and baseaddr is None and datadef is None:
|
||||
if isinstance(format_, dict) and baseaddr is None and datadef is None:
|
||||
return eval(fields)
|
||||
|
||||
if not isinstance(format, (unicode,str,dict)):
|
||||
print >> sys.stderr, 'wrong <format> {} type {} in <fielddef> {}'.format(format, type(format), fielddef)
|
||||
if not isinstance(format_, (unicode,str,dict)):
|
||||
print >> sys.stderr, 'wrong <format> {} type {} in <fielddef> {}'.format(format_, type(format_), fielddef)
|
||||
raise SyntaxError('<fielddef> error')
|
||||
|
||||
# extract addrdef items
|
||||
|
@ -1604,16 +1638,16 @@ def GetFieldDef(fielddef, fields="format, addrdef, baseaddr, bits, bitshift, dat
|
|||
# baseaddr bit definition
|
||||
baseaddr, bits, bitshift = baseaddr
|
||||
if not isinstance(bits, int):
|
||||
print >> sys.stderr, '<bits> must be a integer in <fielddef> {}'.format(bits, fielddef)
|
||||
print >> sys.stderr, '<bits> must be defined as integer in <fielddef> {}'.format(bits, fielddef)
|
||||
raise SyntaxError('<fielddef> error')
|
||||
if not isinstance(bitshift, int):
|
||||
print >> sys.stderr, '<bitshift> must be a integer in <fielddef> {}'.format(bitshift, fielddef)
|
||||
print >> sys.stderr, '<bitshift> must be defined as integer in <fielddef> {}'.format(bitshift, fielddef)
|
||||
raise SyntaxError('<fielddef> error')
|
||||
else:
|
||||
print >> sys.stderr, 'wrong <addrdef> {} length ({}) in <fielddef> {}'.format(addrdef, len(addrdef), fielddef)
|
||||
raise SyntaxError('<fielddef> error')
|
||||
if not isinstance(baseaddr, int):
|
||||
print >> sys.stderr, '<baseaddr> must be a integer in <fielddef> {}'.format(baseaddr, fielddef)
|
||||
print >> sys.stderr, '<baseaddr> must be defined as integer in <fielddef> {}'.format(baseaddr, fielddef)
|
||||
raise SyntaxError('<fielddef> error')
|
||||
|
||||
# extract datadef items
|
||||
|
@ -1742,11 +1776,7 @@ def CmndConverter(valuemapping, value, idx, fielddef):
|
|||
evalstr = tasmotacmnd.replace('$','value').replace('#','idx').replace('@','valuemapping')
|
||||
else:
|
||||
evalstr = tasmotacmnd.replace('$','value').replace('@','valuemapping')
|
||||
# ~ try:
|
||||
result = eval(evalstr)
|
||||
# ~ except:
|
||||
# ~ print evalstr
|
||||
# ~ print value
|
||||
|
||||
elif callable(tasmotacmnd): # use as format function
|
||||
if idx is not None:
|
||||
|
@ -1790,6 +1820,46 @@ def ValidateValue(value, fielddef):
|
|||
return valid
|
||||
|
||||
|
||||
def GetFormatCount(format_):
|
||||
"""
|
||||
Get format prefix count
|
||||
|
||||
@param format_:
|
||||
format specifier
|
||||
|
||||
@return:
|
||||
prefix count or 1 if not specified
|
||||
"""
|
||||
|
||||
if isinstance(format_, str):
|
||||
match = re.search("\s*(\d+)", format_)
|
||||
if match:
|
||||
return int(match.group(0))
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
def GetFormatType(format_):
|
||||
"""
|
||||
Get format type and bitsize without prefix
|
||||
|
||||
@param format_:
|
||||
format specifier
|
||||
|
||||
@return:
|
||||
(format_, 0) or (format without prefix, bitsize)
|
||||
"""
|
||||
|
||||
formattype = format_
|
||||
bitsize = 0
|
||||
if isinstance(format_, str):
|
||||
match = re.search("\s*(\D+)", format_)
|
||||
if match:
|
||||
formattype = match.group(0)
|
||||
bitsize = struct.calcsize(formattype) * 8
|
||||
return formattype, bitsize
|
||||
|
||||
|
||||
def GetFieldMinMax(fielddef):
|
||||
"""
|
||||
Get minimum, maximum of field based on field format definition
|
||||
|
@ -1800,7 +1870,7 @@ def GetFieldMinMax(fielddef):
|
|||
@return:
|
||||
min, max
|
||||
"""
|
||||
minmax = {'c': (0, 1),
|
||||
minmax = {'c': (0, 0xff),
|
||||
'?': (0, 1),
|
||||
'b': (~0x7f, 0x7f),
|
||||
'B': (0, 0xff),
|
||||
|
@ -1815,18 +1885,18 @@ def GetFieldMinMax(fielddef):
|
|||
'f': (sys.float_info.min, sys.float_info.max),
|
||||
'd': (sys.float_info.min, sys.float_info.max),
|
||||
}
|
||||
format = GetFieldDef(fielddef, fields='format')
|
||||
_min = 0
|
||||
_max = 0
|
||||
format_ = GetFieldDef(fielddef, fields='format_')
|
||||
min_ = 0
|
||||
max_ = 0
|
||||
|
||||
if format[-1:] in minmax:
|
||||
_min, _max = minmax[format[-1:]]
|
||||
elif format[-1:] in ['s','p']:
|
||||
if format_[-1:] in minmax:
|
||||
min_, max_ = minmax[format_[-1:]]
|
||||
max_ *= GetFormatCount(format_)
|
||||
elif format_[-1:] in ['s','p']:
|
||||
# s and p may have a prefix as length
|
||||
match = re.search("\s*(\d+)", format)
|
||||
if match:
|
||||
_max=int(match.group(0))
|
||||
return _min,_max
|
||||
max_ = GetFormatCount(format_)
|
||||
|
||||
return min_,max_
|
||||
|
||||
|
||||
def GetFieldLength(fielddef):
|
||||
|
@ -1841,7 +1911,7 @@ def GetFieldLength(fielddef):
|
|||
"""
|
||||
|
||||
length=0
|
||||
format, addrdef, arraydef = GetFieldDef(fielddef, fields='format, addrdef, arraydef')
|
||||
format_, addrdef, arraydef = GetFieldDef(fielddef, fields='format_, addrdef, arraydef')
|
||||
|
||||
# <arraydef> contains a integer list
|
||||
if isinstance(arraydef, list) and len(arraydef) > 0:
|
||||
|
@ -1850,15 +1920,15 @@ def GetFieldLength(fielddef):
|
|||
for i in range(0, arraydef[0]):
|
||||
subfielddef = GetSubfieldDef(fielddef)
|
||||
if len(arraydef) > 1:
|
||||
length += GetFieldLength( (format, addrdef, subfielddef) )
|
||||
length += GetFieldLength( (format_, addrdef, subfielddef) )
|
||||
# single array
|
||||
else:
|
||||
length += GetFieldLength( (format, addrdef, None) )
|
||||
length += GetFieldLength( (format_, addrdef, None) )
|
||||
|
||||
elif isinstance(format, dict):
|
||||
elif isinstance(format_, dict):
|
||||
# -> iterate through format
|
||||
addr = None
|
||||
setting = format
|
||||
setting = format_
|
||||
for name in setting:
|
||||
baseaddr, bits, bitshift = GetFieldDef(setting[name], fields='baseaddr, bits, bitshift')
|
||||
_len = GetFieldLength(setting[name])
|
||||
|
@ -1867,20 +1937,8 @@ def GetFieldLength(fielddef):
|
|||
length += _len
|
||||
|
||||
# a simple value
|
||||
elif isinstance(format, str):
|
||||
if format[-1:] in ['b','B','c','?']:
|
||||
length=1
|
||||
elif format[-1:] in ['h','H']:
|
||||
length=2
|
||||
elif format[-1:] in ['i','I','l','L','f']:
|
||||
length=4
|
||||
elif format[-1:] in ['q','Q','d']:
|
||||
length=8
|
||||
elif format[-1:] in ['s','p']:
|
||||
# s and p may have a prefix as length
|
||||
match = re.search("\s*(\d+)", format)
|
||||
if match:
|
||||
length=int(match.group(0))
|
||||
elif isinstance(format_, str):
|
||||
length = struct.calcsize(format_)
|
||||
|
||||
return length
|
||||
|
||||
|
@ -1896,7 +1954,7 @@ def GetSubfieldDef(fielddef):
|
|||
subfield definition
|
||||
"""
|
||||
|
||||
format, addrdef, datadef, arraydef, validate, cmd, converter = GetFieldDef(fielddef, fields='format, addrdef, datadef, arraydef, validate, cmd, converter')
|
||||
format_, addrdef, datadef, arraydef, validate, cmd, converter = GetFieldDef(fielddef, fields='format_, addrdef, datadef, arraydef, validate, cmd, converter')
|
||||
|
||||
# create new arraydef
|
||||
if len(arraydef) > 1:
|
||||
|
@ -1916,9 +1974,9 @@ def GetSubfieldDef(fielddef):
|
|||
# set new field def
|
||||
subfielddef = None
|
||||
if converter is not None:
|
||||
subfielddef = (format, addrdef, datadef, converter)
|
||||
subfielddef = (format_, addrdef, datadef, converter)
|
||||
else:
|
||||
subfielddef = (format, addrdef, datadef)
|
||||
subfielddef = (format_, addrdef, datadef)
|
||||
|
||||
return subfielddef
|
||||
|
||||
|
@ -1941,6 +1999,79 @@ def IsFilterGroup(group):
|
|||
return True
|
||||
|
||||
|
||||
def GetFieldValue(fielddef, dobj, addr):
|
||||
"""
|
||||
Get single field value from definition
|
||||
|
||||
@param fielddef:
|
||||
see Settings desc
|
||||
@param dobj:
|
||||
decrypted binary config data
|
||||
@param addr
|
||||
addr within dobj
|
||||
|
||||
@return:
|
||||
value read from dobj
|
||||
"""
|
||||
|
||||
format_, bits, bitshift = GetFieldDef(fielddef, fields='format_, bits, bitshift')
|
||||
|
||||
value_ = 0
|
||||
unpackedvalue = struct.unpack_from(format_, dobj, addr)
|
||||
singletype, bitsize = GetFormatType(format_)
|
||||
|
||||
if not format_[-1:].lower() in ['s','p']:
|
||||
for val in unpackedvalue:
|
||||
value_ <<= bitsize
|
||||
value_ = value_ + val
|
||||
value_ = bitsRead(value_, bitshift, bits)
|
||||
else:
|
||||
value_ = unpackedvalue[0]
|
||||
s = str(value_).split('\0')[0] # use left string until \0
|
||||
value_ = unicode(s, errors='ignore') # remove character > 127
|
||||
|
||||
return value_
|
||||
|
||||
|
||||
def SetFieldValue(fielddef, dobj, addr, value):
|
||||
"""
|
||||
Set single field value from definition
|
||||
|
||||
@param fielddef:
|
||||
see Settings desc
|
||||
@param dobj:
|
||||
decrypted binary config data
|
||||
@param addr
|
||||
addr within dobj
|
||||
@param value
|
||||
new value
|
||||
|
||||
@return:
|
||||
new decrypted binary config data
|
||||
"""
|
||||
|
||||
format_, bits, bitshift = GetFieldDef(fielddef, fields='format_, bits, bitshift')
|
||||
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)
|
||||
if not format_[-1:].lower() in ['s','p']:
|
||||
addr += (bitsize / 8) * formatcnt
|
||||
for _ in range(0, formatcnt):
|
||||
addr -= (bitsize / 8)
|
||||
val = value & ((2**bitsize) - 1)
|
||||
if args.debug >= 3:
|
||||
print >> sys.stderr, "SetFieldValue(): Single type - fielddef {}, addr 0x{:04x} value {} singletype {} bitsize {}".format(fielddef,addr,val,singletype,bitsize)
|
||||
struct.pack_into(singletype, dobj, addr, val)
|
||||
value >>= bitsize
|
||||
else:
|
||||
if args.debug >= 3:
|
||||
print >> sys.stderr, "SetFieldValue(): String type - fielddef {}, addr 0x{:04x} value {} format_ {}".format(fielddef,addr,value,format_)
|
||||
struct.pack_into(format_, dobj, addr, value)
|
||||
|
||||
return dobj
|
||||
|
||||
|
||||
def GetField(dobj, fieldname, fielddef, raw=False, addroffset=0):
|
||||
"""
|
||||
Get field value from definition
|
||||
|
@ -1966,7 +2097,7 @@ def GetField(dobj, fieldname, fielddef, raw=False, addroffset=0):
|
|||
valuemapping = None
|
||||
|
||||
# get field definition
|
||||
format, baseaddr, bits, bitshift, arraydef, group, tasmotacmnd = GetFieldDef(fielddef, fields='format, baseaddr, bits, bitshift, arraydef, group, tasmotacmnd')
|
||||
format_, baseaddr, bits, bitshift, arraydef, group, tasmotacmnd = GetFieldDef(fielddef, fields='format_, baseaddr, bits, bitshift, arraydef, group, tasmotacmnd')
|
||||
|
||||
# filter groups
|
||||
if not IsFilterGroup(group):
|
||||
|
@ -1985,36 +2116,24 @@ def GetField(dobj, fieldname, fielddef, raw=False, addroffset=0):
|
|||
offset += length
|
||||
|
||||
# <format> contains a dict
|
||||
elif isinstance(format, dict):
|
||||
elif isinstance(format_, dict):
|
||||
mapping_value = {}
|
||||
# -> iterate through format
|
||||
for name in format:
|
||||
for name in format_:
|
||||
value = None
|
||||
value = GetField(dobj, name, format[name], raw=raw, addroffset=addroffset)
|
||||
value = GetField(dobj, name, format_[name], raw=raw, addroffset=addroffset)
|
||||
if value is not None:
|
||||
mapping_value[name] = value
|
||||
# copy complete returned mapping
|
||||
valuemapping = copy.deepcopy(mapping_value)
|
||||
|
||||
# a simple value
|
||||
elif isinstance(format, (str, bool, int, float, long)):
|
||||
elif isinstance(format_, (str, bool, int, float, long)):
|
||||
if GetFieldLength(fielddef) != 0:
|
||||
valuemapping = struct.unpack_from(format, dobj, baseaddr+addroffset)[0]
|
||||
|
||||
if not format[-1:].lower() in ['s','p']:
|
||||
valuemapping = bitsRead(valuemapping, bitshift, bits)
|
||||
|
||||
# additional processing for strings
|
||||
if format[-1:].lower() in ['s','p']:
|
||||
# use left string until \0
|
||||
s = str(valuemapping).split('\0')[0]
|
||||
# remove character > 127
|
||||
valuemapping = unicode(s, errors='ignore')
|
||||
|
||||
valuemapping = ReadWriteConverter(valuemapping, fielddef, read=True, raw=raw)
|
||||
valuemapping = ReadWriteConverter(GetFieldValue(fielddef, dobj, baseaddr+addroffset), fielddef, read=True, raw=raw)
|
||||
|
||||
else:
|
||||
exit(ExitCode.INTERNAL_ERROR, "Wrong mapping format definition: '{}'".format(format), typ=LogType.WARNING, doexit=not args.ignorewarning, line=inspect.getlineno(inspect.currentframe()))
|
||||
exit(ExitCode.INTERNAL_ERROR, "Wrong mapping format definition: '{}'".format(format_), typ=LogType.WARNING, doexit=not args.ignorewarning, line=inspect.getlineno(inspect.currentframe()))
|
||||
|
||||
return valuemapping
|
||||
|
||||
|
@ -2039,7 +2158,7 @@ def SetField(dobj, fieldname, fielddef, restore, addroffset=0, filename=""):
|
|||
@return:
|
||||
new decrypted binary config data
|
||||
"""
|
||||
format, baseaddr, bits, bitshift, arraydef, group, writeconverter = GetFieldDef(fielddef, fields='format, baseaddr, bits, bitshift, arraydef, group, writeconverter')
|
||||
format_, baseaddr, bits, bitshift, arraydef, group, writeconverter = GetFieldDef(fielddef, fields='format_, baseaddr, bits, bitshift, arraydef, group, writeconverter')
|
||||
# cast unicode
|
||||
fieldname = str(fieldname)
|
||||
|
||||
|
@ -2049,8 +2168,8 @@ def SetField(dobj, fieldname, fielddef, restore, addroffset=0, filename=""):
|
|||
|
||||
# do not write readonly values
|
||||
if writeconverter is False:
|
||||
if args.debug:
|
||||
print >> sys.stderr, "SetField(): Readonly '{}' using '{}'/{}{} @{} skipped".format(fieldname, format, arraydef, bits, hex(baseaddr+addroffset))
|
||||
if args.debug >= 2:
|
||||
print >> sys.stderr, "SetField(): Readonly '{}' using '{}'/{}{} @{} skipped".format(fieldname, format_, arraydef, bits, hex(baseaddr+addroffset))
|
||||
return dobj
|
||||
|
||||
# <arraydef> contains a list
|
||||
|
@ -2069,23 +2188,23 @@ def SetField(dobj, fieldname, fielddef, restore, addroffset=0, filename=""):
|
|||
offset += length
|
||||
|
||||
# <format> contains a dict
|
||||
elif isinstance(format, dict):
|
||||
for name in format: # -> iterate through format
|
||||
elif isinstance(format_, dict):
|
||||
for name in format_: # -> iterate through format
|
||||
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
|
||||
elif isinstance(format, (str, bool, int, float, long)):
|
||||
elif isinstance(format_, (str, bool, int, float, long)):
|
||||
valid = True
|
||||
err = ""
|
||||
errformat = ""
|
||||
|
||||
_min, _max = GetFieldMinMax(fielddef)
|
||||
min_, max_ = GetFieldMinMax(fielddef)
|
||||
value = _value = None
|
||||
skip = False
|
||||
|
||||
# simple char value
|
||||
if format[-1:] in ['c']:
|
||||
if format_[-1:] in ['c']:
|
||||
try:
|
||||
value = ReadWriteConverter(restore.encode(STR_ENCODING)[0], fielddef, read=False)
|
||||
except Exception, e:
|
||||
|
@ -2093,7 +2212,7 @@ def SetField(dobj, fieldname, fielddef, restore, addroffset=0, filename=""):
|
|||
valid = False
|
||||
|
||||
# bool
|
||||
elif format[-1:] in ['?']:
|
||||
elif format_[-1:] in ['?']:
|
||||
try:
|
||||
value = ReadWriteConverter(bool(restore), fielddef, read=False)
|
||||
except Exception, e:
|
||||
|
@ -2101,7 +2220,7 @@ def SetField(dobj, fieldname, fielddef, restore, addroffset=0, filename=""):
|
|||
valid = False
|
||||
|
||||
# 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)
|
||||
if isinstance(value, (str, unicode)):
|
||||
value = int(value, 0)
|
||||
|
@ -2110,16 +2229,17 @@ def SetField(dobj, fieldname, fielddef, restore, addroffset=0, filename=""):
|
|||
# bits
|
||||
if bits != 0:
|
||||
bitvalue = value
|
||||
value = struct.unpack_from(format, dobj, baseaddr+addroffset)[0]
|
||||
value = struct.unpack_from(format_, dobj, baseaddr+addroffset)[0]
|
||||
# validate restore value
|
||||
valid = ValidateValue(bitvalue, fielddef)
|
||||
if not valid:
|
||||
err = "valid bit range exceeding"
|
||||
value = bitvalue
|
||||
else:
|
||||
mask = (1<<bits)-1
|
||||
if bitvalue > mask:
|
||||
_min = 0
|
||||
_max = mask
|
||||
min_ = 0
|
||||
max_ = mask
|
||||
_value = bitvalue
|
||||
valid = False
|
||||
else:
|
||||
|
@ -2142,19 +2262,19 @@ def SetField(dobj, fieldname, fielddef, restore, addroffset=0, filename=""):
|
|||
_value = value
|
||||
|
||||
# float
|
||||
elif format[-1:] in ['f','d']:
|
||||
elif format_[-1:] in ['f','d']:
|
||||
try:
|
||||
value = ReadWriteConverter(float(restore), fielddef, read=False)
|
||||
except:
|
||||
valid = False
|
||||
|
||||
# string
|
||||
elif format[-1:] in ['s','p']:
|
||||
elif format_[-1:] in ['s','p']:
|
||||
value = ReadWriteConverter(restore.encode(STR_ENCODING), fielddef, read=False)
|
||||
err = "string length exceeding"
|
||||
if value is not None:
|
||||
_max -= 1
|
||||
valid = _min <= len(value) <= _max
|
||||
max_ -= 1
|
||||
valid = min_ <= len(value) <= max_
|
||||
else:
|
||||
skip = True
|
||||
valid = True
|
||||
|
@ -2165,7 +2285,7 @@ def SetField(dobj, fieldname, fielddef, restore, addroffset=0, filename=""):
|
|||
|
||||
if valid is None and not skip:
|
||||
# validate against object type size
|
||||
valid = _min <= value <= _max
|
||||
valid = min_ <= value <= max_
|
||||
if not valid:
|
||||
err = "type range exceeding"
|
||||
errformat = " [{smin},{smax}]"
|
||||
|
@ -2179,21 +2299,22 @@ def SetField(dobj, fieldname, fielddef, restore, addroffset=0, filename=""):
|
|||
|
||||
if valid:
|
||||
if not skip:
|
||||
if args.debug:
|
||||
if bits:
|
||||
sbits=" {} bits shift {}".format(bits, bitshift)
|
||||
else:
|
||||
sbits = ""
|
||||
print >> sys.stderr, "SetField(): Set '{}' using '{}'/{}{} @{} to {}".format(fieldname, format, arraydef, sbits, hex(baseaddr+addroffset), _value)
|
||||
if fieldname != 'cfg_crc':
|
||||
prevvalue = struct.unpack_from(format, dobj, baseaddr+addroffset)[0]
|
||||
struct.pack_into(format, dobj, baseaddr+addroffset, value)
|
||||
curvalue = struct.unpack_from(format, dobj, baseaddr+addroffset)[0]
|
||||
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)
|
||||
if fieldname != 'cfg_crc' and fieldname != '_':
|
||||
prevvalue = GetFieldValue(fielddef, dobj, baseaddr+addroffset)
|
||||
dobj = SetFieldValue(fielddef, dobj, baseaddr+addroffset, value)
|
||||
curvalue = GetFieldValue(fielddef, dobj, baseaddr+addroffset)
|
||||
if prevvalue != curvalue and args.verbose:
|
||||
message("Value for '{}' changed from {} to {}".format(fieldname, prevvalue, curvalue), typ=LogType.INFO)
|
||||
else:
|
||||
if args.debug >= 2:
|
||||
print >> sys.stderr, "SetField(): Special field '{}' using '{}'/{}{} @{} skipped".format(fieldname, format_, arraydef, bits, hex(baseaddr+addroffset))
|
||||
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), typ=LogType.WARNING, doexit=not args.ignorewarning)
|
||||
exit(ExitCode.RESTORE_DATA_ERROR, sformat.format(sfile=filename, sname=fieldname, serror=err, svalue=_value, smin=min_, smax=max_), typ=LogType.WARNING, doexit=not args.ignorewarning)
|
||||
|
||||
return dobj
|
||||
|
||||
|
@ -2220,7 +2341,7 @@ def SetCmnd(cmnds, fieldname, fielddef, valuemapping, mappedvalue, addroffset=0,
|
|||
@return:
|
||||
new Tasmota command mapping
|
||||
"""
|
||||
format, baseaddr, bits, bitshift, arraydef, group, tasmotacmnd, writeconverter = GetFieldDef(fielddef, fields='format, baseaddr, bits, bitshift, arraydef, group, tasmotacmnd, writeconverter')
|
||||
format_, baseaddr, bits, bitshift, arraydef, group, tasmotacmnd, writeconverter = GetFieldDef(fielddef, fields='format_, baseaddr, bits, bitshift, arraydef, group, tasmotacmnd, writeconverter')
|
||||
|
||||
# cast unicode
|
||||
fieldname = str(fieldname)
|
||||
|
@ -2245,13 +2366,13 @@ def SetCmnd(cmnds, fieldname, fielddef, valuemapping, mappedvalue, addroffset=0,
|
|||
offset += length
|
||||
|
||||
# <format> contains a dict
|
||||
elif isinstance(format, dict):
|
||||
for name in format: # -> iterate through format
|
||||
elif isinstance(format_, dict):
|
||||
for name in format_: # -> iterate through format
|
||||
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
|
||||
elif isinstance(format, (str, bool, int, float, long)):
|
||||
elif isinstance(format_, (str, bool, int, float, long)):
|
||||
cmnd = CmndConverter(valuemapping, mappedvalue, idx, fielddef)
|
||||
|
||||
if group is not None and cmnd is not None:
|
||||
|
@ -2804,7 +2925,7 @@ def ParseArgs():
|
|||
info = parser.add_argument_group('Info','Extra information')
|
||||
info.add_argument('-D', '--debug',
|
||||
dest='debug',
|
||||
action='store_true',
|
||||
action='count',
|
||||
help=configargparse.SUPPRESS)
|
||||
info.add_argument('-h', '--help',
|
||||
dest='shorthelp',
|
||||
|
@ -2823,7 +2944,7 @@ def ParseArgs():
|
|||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.debug:
|
||||
if args.debug >= 1:
|
||||
print >> sys.stderr, parser.format_values()
|
||||
print >> sys.stderr, "Settings:"
|
||||
for k in args.__dict__:
|
||||
|
|
Loading…
Reference in New Issue