Sync to Tasmota

Sync to Tasmota
This commit is contained in:
Adrian Scillato 2018-05-24 14:40:11 -03:00 committed by GitHub
commit d294ea6033
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 241 additions and 200 deletions

View File

@ -174,7 +174,7 @@ If you like **Sonoff-Tasmota**, give it a star, or fork it and contribute!
### Development
[![Build Status](https://img.shields.io/travis/arendst/Sonoff-Tasmota.svg)](https://travis-ci.org/arendst/Sonoff-Tasmota)
Current version is **5.14.0a** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_releasenotes.ino) for change information.
Current version is **5.14.0b** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_releasenotes.ino) for change information.
### Quick install
Download one of the released binaries from https://github.com/arendst/Sonoff-Tasmota/releases and flash it to your hardware as documented in the wiki.
@ -183,7 +183,7 @@ Download one of the released binaries from https://github.com/arendst/Sonoff-Tas
If you want to compile Sonoff-Tasmota yourself keep in mind the following:
- Only Flash Mode **DOUT** is supported. Do not use Flash Mode DIO / QIO / QOUT as it might seem to brick your device. See [Wiki](https://github.com/arendst/Sonoff-Tasmota/wiki/Theo's-Tasmota-Tips) for background information.
- Sonoff-Tasmota uses a 1M linker script WITHOUT spiffs for optimal code space. If you compile using ESP/Arduino library 2.3.0 then download the provided new linker script to your Arduino IDE or Platformio base folder. Later version of ESP/Arduino library already contain the correct linker script. See [Wiki > Prerequisite](https://github.com/arendst/Sonoff-Tasmota/wiki/Prerequisite).
- Sonoff-Tasmota uses a 1M linker script WITHOUT spiffs **1M (no SPIFFS)** for optimal code space. If you compile using ESP/Arduino library 2.3.0 then download the provided new linker script to your Arduino IDE or Platformio base folder. Later version of ESP/Arduino library already contain the correct linker script. See [Wiki > Prerequisite](https://github.com/arendst/Sonoff-Tasmota/wiki/Prerequisite).
- To make compile time changes to Sonoff-Tasmota it can use the ``user_config_override.h`` file. It assures keeping your settings when you download and compile a new version. To use ``user_config.override.h`` you will have to make a copy of the provided ``user_config.override_sample.h`` file and add your setting overrides. To enable the override file you will need to use a compile define as documented in the ``user_config_override_sample.h`` file.
### Version Information

View File

@ -69,9 +69,6 @@ build_flags_4MB =
; -DUSE_CONFIG_OVERRIDE
-DUSE_KNX_NO_EMULATION
; *** Fix Esp/Arduino core 2.4.x induced Tasmota unused floating point includes
extra_scripts = pio/strip-floats.py
; *** Serial Monitor options
monitor_speed = 115200
@ -79,6 +76,8 @@ monitor_speed = 115200
upload_speed = 115200
upload_resetmethod = nodemcu
upload_port = COM5
; *** Fix Esp/Arduino core 2.4.x induced Tasmota unused floating point includes
extra_scripts = pio/strip-floats.py
;NOTE - command to erase flash from windows console: esptool.py --port COM18 erase_flash

View File

@ -1,4 +1,8 @@
/* 5.14.0a
/* 5.14.0b
* Add two rule sets of 511 characters using commands rule1, rule2 and rule3
* Add rule support for IrReceive and RfReceive (#2758)
*
* 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 by Gennaro Tortone (#2735)
@ -7,7 +11,7 @@
* Add python script fw-server.py in tools folder to create a simple OTA server by Gennaro Tortone (#2759)
* Add rules %mem1% to %mem5% variable names storing data in flash (#2780)
* Add rules test on %varx% or %memx% (#2780)
* Add optional token %id% substituting the unique MAC address for topic names by Michael Graf (#2794)
* Add optional token %id% substituting the unique MAC address to fulltopic by Michael Graf (#2794)
* 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 by David Conran (#2751)

View File

@ -48,8 +48,8 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
uint32_t not_power_linked : 1; // bit 20 (v5.11.1f)
uint32_t no_power_on_check : 1; // bit 21 (v5.11.1i)
uint32_t mqtt_serial : 1; // bit 22 (v5.12.0f)
uint32_t rules_enabled : 1; // bit 23 (v5.12.0j)
uint32_t rules_once : 1; // bit 24 (v5.12.0k)
uint32_t rules_enabled : 1; // bit 23 (v5.12.0j) - free since v5.14.0b
uint32_t rules_once : 1; // bit 24 (v5.12.0k) - free since v5.14.0b
uint32_t knx_enabled : 1; // bit 25 (v5.12.0l) KNX
uint32_t device_index_enable : 1; // bit 26 (v5.13.1a)
uint32_t knx_enable_enhancement : 1; // bit 27 (v5.14.0a) KNX
@ -232,9 +232,8 @@ struct SYSCFG {
uint8_t light_color[5]; // 498
uint8_t light_correction; // 49D
uint8_t light_dimmer; // 49E
byte free_49F[2]; // 49F
uint8_t rule_enabled; // 49F
uint8_t rule_once; // 4A0
uint8_t light_fade; // 4A1
uint8_t light_speed; // 4A2
uint8_t light_scheme; // 4A3
@ -274,9 +273,11 @@ struct SYSCFG {
byte free_6f6[216]; // 6F6
char mems[RULES_MAX_MEMS][10]; // 7CE
char rules[MAX_RULE_SIZE]; // 800 uses 512 bytes in v5.12.0m
// 800 Full - no more free locations
// A00 - FFF free locations
char rules[MAX_RULE_SETS][MAX_RULE_SIZE]; // 800 uses 512 bytes in v5.12.0m, 3 x 512 bytes in v5.14.0b
// E00 - FFF free locations
} Settings;
struct RTCMEM {

View File

@ -143,6 +143,7 @@ extern "C" uint32_t _SPIFFS_end;
uint32_t settings_hash = 0;
uint32_t settings_location = SETTINGS_LOCATION;
uint8_t *settings_buffer = NULL;
/********************************************************************************************/
/*
@ -167,6 +168,24 @@ void SetFlashModeDout()
delete[] _buffer;
}
void SettingsBufferFree()
{
if (settings_buffer != NULL) {
free(settings_buffer);
settings_buffer = NULL;
}
}
bool SettingsBufferAlloc()
{
SettingsBufferFree();
if (!(settings_buffer = (uint8_t *)malloc(sizeof(Settings)))) {
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_UPLOAD_ERR_2)); // Not enough (memory) space
return false;
}
return true;
}
uint32_t GetSettingsHash()
{
uint32_t hash = 0;
@ -870,7 +889,7 @@ void SettingsDelta()
Settings.longitude = (int)((double)LONGITUDE * 1000000);
}
if (Settings.version < 0x050C000B) {
memset(&Settings.rules, 0x00, sizeof(Settings.rules));
Settings.rules[0][0] = '\0';
}
if (Settings.version < 0x050C000D) {
memmove(Settings.rules, Settings.rules -256, sizeof(Settings.rules)); // move rules up by 256 bytes
@ -887,6 +906,13 @@ void SettingsDelta()
if (Settings.version < 0x050D0103) {
SettingsDefaultSet_5_13_1c();
}
if (Settings.version < 0x050E0002) {
for (byte i = 1; i < MAX_RULE_SETS; i++) {
Settings.rules[i][0] = '\0';
}
Settings.rule_enabled = Settings.flag.rules_enabled;
Settings.rule_once = Settings.flag.rules_once;
}
Settings.version = VERSION;
SettingsSave(1);

View File

@ -51,6 +51,7 @@ typedef unsigned long power_t; // Power (Relay) type
#define MAX_KNX_GA 10 // Max number of KNX Group Addresses to read that can be set
#define MAX_KNX_CB 10 // Max number of KNX Group Addresses to write that can be set
#define RULES_MAX_MEMS 5 // Max number of saved vars
#define MAX_RULE_SETS 3 // Max number of rule sets of size 512 characters
#define MAX_RULE_SIZE 512 // Max number of characters in rules
#define MQTT_TOKEN_PREFIX "%prefix%" // To be substituted by mqtt_prefix[x]
@ -88,7 +89,7 @@ typedef unsigned long power_t; // Power (Relay) type
#define SERIALLOG_TIMER 600 // Seconds to disable SerialLog
#define OTA_ATTEMPTS 5 // Number of times to try fetching the new firmware
#define INPUT_BUFFER_SIZE 512 // Max number of characters in (serial and http) command buffer
#define INPUT_BUFFER_SIZE 520 // Max number of characters in (serial and http) command buffer
#define CMDSZ 24 // Max number of characters in command
#define TOPSZ 100 // Max number of characters in topic string
#define LOGSZ 512 // Max number of characters in log
@ -187,7 +188,7 @@ enum LichtSubtypes {LST_NONE, LST_SINGLE, LST_COLDWARM, LST_RGB, LST_RGBW, LST_R
enum LichtSchemes {LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_MAX};
enum XsnsFunctions {FUNC_INIT, FUNC_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_SECOND, FUNC_PREP_BEFORE_TELEPERIOD, FUNC_JSON_APPEND, FUNC_WEB_APPEND, FUNC_SAVE_BEFORE_RESTART,
FUNC_COMMAND, FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_INIT, FUNC_MQTT_DATA, FUNC_SET_POWER, FUNC_SHOW_SENSOR};
FUNC_COMMAND, FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_INIT, FUNC_MQTT_DATA, FUNC_SET_POWER, FUNC_SHOW_SENSOR, FUNC_RULES_PROCESS};
const uint8_t kDefaultRfCode[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 };

View File

@ -25,7 +25,7 @@
- Select IDE Tools - Flash Size: "1M (no SPIFFS)"
====================================================*/
#define VERSION 0x050E0001 // 5.14.0a
#define VERSION 0x050E0002 // 5.14.0b
// Location specific includes
#include <core_version.h> // Arduino_Esp8266 version information (ARDUINO_ESP8266_RELEASE and ARDUINO_ESP8266_RELEASE_2_3_0)
@ -1177,11 +1177,9 @@ boolean SendKey(byte key, byte device, byte state)
MqttPublishDirect(stopic, (key) ? Settings.flag.mqtt_switch_retain : Settings.flag.mqtt_button_retain);
#endif // USE_DOMOTICZ
result = true;
#ifdef USE_RULES
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s%d\":{\"State\":%d}}"), (key) ? "Switch" : "Button", device, state);
result = RulesProcess();
#endif // USE_RULES
result = XdrvRulesProcess();
}
#ifdef USE_KNX
KnxSendButtonPower(key, device, state);
@ -1300,11 +1298,11 @@ void ExecuteCommand(char *cmnd)
void PublishStatus(uint8_t payload)
{
uint8_t option = 1;
uint8_t option = STAT;
char stemp[MAX_FRIENDLYNAMES * (sizeof(Settings.friendlyname[0]) +4)];
// Workaround MQTT - TCP/IP stack queueing when SUB_PREFIX = PUB_PREFIX
if (!strcmp(Settings.mqtt_prefix[0],Settings.mqtt_prefix[1]) && (!payload)) option++;
if (!strcmp(Settings.mqtt_prefix[0],Settings.mqtt_prefix[1]) && (!payload)) option++; // TELE
if ((!Settings.flag.mqtt_enabled) && (6 == payload)) payload = 99;
if (!energy_flg && (9 == payload)) payload = 99;
@ -2168,6 +2166,7 @@ void SerialInput()
serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_SERIALRECEIVED "\":\"%s\"}"), serial_in_buffer);
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_SERIALRECEIVED));
// XdrvRulesProcess();
serial_in_byte_counter = 0;
}
}

View File

@ -482,6 +482,96 @@ int GetStateNumber(char *state_text)
return state_number;
}
boolean GetUsedInModule(byte val, uint8_t *arr)
{
int offset = 0;
if (!val) { return false; } // None
#ifndef USE_I2C
if (GPIO_I2C_SCL == val) { return true; }
if (GPIO_I2C_SDA == val) { return true; }
#endif
#ifndef USE_SR04
if (GPIO_SR04_TRIG == val) { return true; }
if (GPIO_SR04_ECHO == val) { return true; }
#endif
#ifndef USE_WS2812
if (GPIO_WS2812 == val) { return true; }
#endif
#ifndef USE_IR_REMOTE
if (GPIO_IRSEND == val) { return true; }
#ifndef USE_IR_RECEIVE
if (GPIO_IRRECV == val) { return true; }
#endif
#endif
#ifndef USE_MHZ19
if (GPIO_MHZ_TXD == val) { return true; }
if (GPIO_MHZ_RXD == val) { return true; }
#endif
#ifndef USE_PZEM004T
if (GPIO_PZEM_TX == val) { return true; }
if (GPIO_PZEM_RX == val) { return true; }
#endif
#ifndef USE_SENSEAIR
if (GPIO_SAIR_TX == val) { return true; }
if (GPIO_SAIR_RX == val) { return true; }
#endif
#ifndef USE_SPI
if (GPIO_SPI_CS == val) { return true; }
if (GPIO_SPI_DC == val) { return true; }
#endif
#ifndef USE_DISPLAY
if (GPIO_BACKLIGHT == val) { return true; }
#endif
#ifndef USE_PMS5003
if (GPIO_PMS5003 == val) { return true; }
#endif
#ifndef USE_NOVA_SDS
if (GPIO_SDS0X1 == val) { return true; }
#endif
#ifndef USE_SERIAL_BRIDGE
if (GPIO_SBR_TX == val) { return true; }
if (GPIO_SBR_RX == val) { return true; }
#endif
#ifndef USE_SR04
if (GPIO_SR04_TRIG == val) { return true; }
if (GPIO_SR04_ECHO == val) { return true; }
#endif
#ifndef USE_SDM120
if (GPIO_SDM120_TX == val) { return true; }
if (GPIO_SDM120_RX == val) { return true; }
#endif
#ifndef USE_SDM630
if (GPIO_SDM630_TX == val) { return true; }
if (GPIO_SDM630_RX == val) { return true; }
#endif
if ((val >= GPIO_REL1) && (val < GPIO_REL1 + MAX_RELAYS)) {
offset = (GPIO_REL1_INV - GPIO_REL1);
}
if ((val >= GPIO_REL1_INV) && (val < GPIO_REL1_INV + MAX_RELAYS)) {
offset = -(GPIO_REL1_INV - GPIO_REL1);
}
if ((val >= GPIO_LED1) && (val < GPIO_LED1 + MAX_LEDS)) {
offset = (GPIO_LED1_INV - GPIO_LED1);
}
if ((val >= GPIO_LED1_INV) && (val < GPIO_LED1_INV + MAX_LEDS)) {
offset = -(GPIO_LED1_INV - GPIO_LED1);
}
if ((val >= GPIO_PWM1) && (val < GPIO_PWM1 + MAX_PWMS)) {
offset = (GPIO_PWM1_INV - GPIO_PWM1);
}
if ((val >= GPIO_PWM1_INV) && (val < GPIO_PWM1_INV + MAX_PWMS)) {
offset = -(GPIO_PWM1_INV - GPIO_PWM1);
}
for (byte i = 0; i < MAX_GPIO_PIN; i++) {
if (arr[i] == val) { return true; }
if (arr[i] == val + offset) { return true; }
}
return false;
}
void SetSerialBaudrate(int baudrate)
{
Settings.baudrate = baudrate / 1200;
@ -1610,14 +1700,12 @@ void RtcSecond()
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION "(" D_UTC_TIME ") %s, (" D_DST_TIME ") %s, (" D_STD_TIME ") %s"),
GetTime(0).c_str(), GetTime(2).c_str(), GetTime(3).c_str());
AddLog(LOG_LEVEL_DEBUG);
#ifdef USE_RULES
if (local_time < 1451602800) { // 2016-01-01
strncpy_P(mqtt_data, PSTR("{\"Time\":{\"Initialized\":1}}"), sizeof(mqtt_data));
} else {
strncpy_P(mqtt_data, PSTR("{\"Time\":{\"Set\":1}}"), sizeof(mqtt_data));
}
RulesProcess();
#endif // USE_RULES
XdrvRulesProcess();
} else {
ntp_sync_minute++; // Try again in next minute
}
@ -1698,7 +1786,7 @@ void AdcEvery50ms()
adc_last_value = new_value;
uint16_t value = adc_last_value / 10;
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"ANALOG\":{\"A0div10\":%d}}"), (value > 99) ? 100 : value);
RulesProcess();
XdrvRulesProcess();
}
}
}

View File

@ -328,7 +328,6 @@ uint8_t upload_progress_dot_count;
uint8_t config_block_count = 0;
uint8_t config_xor_on = 0;
uint8_t config_xor_on_set = CONFIG_FILE_XOR;
uint8_t *settings_new = NULL;
// Helper function to avoid code duplication (saves 4k Flash)
static void WebGetArg(const char* arg, char* out, size_t max)
@ -639,96 +638,6 @@ void HandleConfiguration()
ShowPage(page);
}
boolean GetUsedInModule(byte val, uint8_t *arr)
{
int offset = 0;
if (!val) { return false; } // None
#ifndef USE_I2C
if (GPIO_I2C_SCL == val) { return true; }
if (GPIO_I2C_SDA == val) { return true; }
#endif
#ifndef USE_SR04
if (GPIO_SR04_TRIG == val) { return true; }
if (GPIO_SR04_ECHO == val) { return true; }
#endif
#ifndef USE_WS2812
if (GPIO_WS2812 == val) { return true; }
#endif
#ifndef USE_IR_REMOTE
if (GPIO_IRSEND == val) { return true; }
#ifndef USE_IR_RECEIVE
if (GPIO_IRRECV == val) { return true; }
#endif
#endif
#ifndef USE_MHZ19
if (GPIO_MHZ_TXD == val) { return true; }
if (GPIO_MHZ_RXD == val) { return true; }
#endif
#ifndef USE_PZEM004T
if (GPIO_PZEM_TX == val) { return true; }
if (GPIO_PZEM_RX == val) { return true; }
#endif
#ifndef USE_SENSEAIR
if (GPIO_SAIR_TX == val) { return true; }
if (GPIO_SAIR_RX == val) { return true; }
#endif
#ifndef USE_SPI
if (GPIO_SPI_CS == val) { return true; }
if (GPIO_SPI_DC == val) { return true; }
#endif
#ifndef USE_DISPLAY
if (GPIO_BACKLIGHT == val) { return true; }
#endif
#ifndef USE_PMS5003
if (GPIO_PMS5003 == val) { return true; }
#endif
#ifndef USE_NOVA_SDS
if (GPIO_SDS0X1 == val) { return true; }
#endif
#ifndef USE_SERIAL_BRIDGE
if (GPIO_SBR_TX == val) { return true; }
if (GPIO_SBR_RX == val) { return true; }
#endif
#ifndef USE_SR04
if (GPIO_SR04_TRIG == val) { return true; }
if (GPIO_SR04_ECHO == val) { return true; }
#endif
#ifndef USE_SDM120
if (GPIO_SDM120_TX == val) { return true; }
if (GPIO_SDM120_RX == val) { return true; }
#endif
#ifndef USE_SDM630
if (GPIO_SDM630_TX == val) { return true; }
if (GPIO_SDM630_RX == val) { return true; }
#endif
if ((val >= GPIO_REL1) && (val < GPIO_REL1 + MAX_RELAYS)) {
offset = (GPIO_REL1_INV - GPIO_REL1);
}
if ((val >= GPIO_REL1_INV) && (val < GPIO_REL1_INV + MAX_RELAYS)) {
offset = -(GPIO_REL1_INV - GPIO_REL1);
}
if ((val >= GPIO_LED1) && (val < GPIO_LED1 + MAX_LEDS)) {
offset = (GPIO_LED1_INV - GPIO_LED1);
}
if ((val >= GPIO_LED1_INV) && (val < GPIO_LED1_INV + MAX_LEDS)) {
offset = -(GPIO_LED1_INV - GPIO_LED1);
}
if ((val >= GPIO_PWM1) && (val < GPIO_PWM1 + MAX_PWMS)) {
offset = (GPIO_PWM1_INV - GPIO_PWM1);
}
if ((val >= GPIO_PWM1_INV) && (val < GPIO_PWM1_INV + MAX_PWMS)) {
offset = -(GPIO_PWM1_INV - GPIO_PWM1);
}
for (byte i = 0; i < MAX_GPIO_PIN; i++) {
if (arr[i] == val) { return true; }
if (arr[i] == val + offset) { return true; }
}
return false;
}
void HandleModuleConfiguration()
{
if (HttpUser()) { return; }
@ -1005,25 +914,36 @@ void HandleBackupConfiguration()
if (HttpUser()) { return; }
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_BACKUP_CONFIGURATION));
uint8_t buffer[sizeof(Settings)];
if (!SettingsBufferAlloc()) { return; }
WiFiClient myClient = WebServer->client();
WebServer->setContentLength(sizeof(buffer));
WebServer->setContentLength(sizeof(Settings));
char attachment[100];
char friendlyname[sizeof(Settings.friendlyname[0])];
snprintf_P(attachment, sizeof(attachment), PSTR("attachment; filename=Config_%s_%s.dmp"), NoAlNumToUnderscore(friendlyname, Settings.friendlyname[0]), my_version);
WebServer->sendHeader(F("Content-Disposition"), attachment);
WebServer->send(200, FPSTR(HDR_CTYPE_STREAM), "");
memcpy(buffer, &Settings, sizeof(buffer));
buffer[0] = CONFIG_FILE_SIGN;
buffer[1] = (!config_xor_on_set) ? 0 : 1;
if (buffer[1]) {
for (uint16_t i = 2; i < sizeof(buffer); i++) {
buffer[i] ^= (config_xor_on_set +i);
memcpy(settings_buffer, &Settings, sizeof(Settings));
settings_buffer[0] = CONFIG_FILE_SIGN;
settings_buffer[1] = (!config_xor_on_set) ? 0 : 1;
if (settings_buffer[1]) {
for (uint16_t i = 2; i < sizeof(Settings); i++) {
settings_buffer[i] ^= (config_xor_on_set +i);
}
}
myClient.write((const char*)buffer, sizeof(buffer));
#ifdef ARDUINO_ESP8266_RELEASE_2_3_0
size_t written = myClient.write((const char*)settings_buffer, sizeof(Settings));
if (written < sizeof(Settings)) { // https://github.com/esp8266/Arduino/issues/3218
myClient.write((const char*)settings_buffer +written, sizeof(Settings) -written);
}
#else
myClient.write((const char*)settings_buffer, sizeof(Settings));
#endif
SettingsBufferFree();
}
void HandleSaveSettings()
@ -1276,14 +1196,6 @@ void HandleUpgradeFirmwareStart()
ExecuteCommand(svalue);
}
void SettingsNewFree()
{
if (settings_new != NULL) {
free(settings_new);
settings_new = NULL;
}
}
void HandleUploadDone()
{
if (HttpUser()) { return; }
@ -1323,7 +1235,7 @@ void HandleUploadDone()
page += FPSTR(HTTP_MSG_RSTRT);
restart_flag = 2;
}
SettingsNewFree();
SettingsBufferFree();
page += F("</div><br/>");
page += FPSTR(HTTP_BTN_MAIN);
ShowPage(page);
@ -1352,8 +1264,7 @@ void HandleUploadLoop()
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD D_FILE " %s ..."), upload.filename.c_str());
AddLog(LOG_LEVEL_INFO);
if (upload_file_type) {
SettingsNewFree();
if (!(settings_new = (uint8_t *)malloc(sizeof(Settings)))) {
if (!SettingsBufferAlloc()) {
upload_error = 2;
return;
}
@ -1401,7 +1312,7 @@ void HandleUploadLoop()
upload_error = 9;
return;
}
memcpy(settings_new + (config_block_count * HTTP_UPLOAD_BUFLEN), upload.buf, upload.currentSize);
memcpy(settings_buffer + (config_block_count * HTTP_UPLOAD_BUFLEN), upload.buf, upload.currentSize);
config_block_count++;
}
} else { // firmware
@ -1422,13 +1333,13 @@ void HandleUploadLoop()
if (upload_file_type) {
if (config_xor_on) {
for (uint16_t i = 2; i < sizeof(Settings); i++) {
settings_new[i] ^= (config_xor_on_set +i);
settings_buffer[i] ^= (config_xor_on_set +i);
}
}
SettingsDefaultSet2();
memcpy((char*)&Settings +16, settings_new +16, sizeof(Settings) -16);
memcpy((char*)&Settings +8, settings_new +8, 4); // Restore version and auto upgrade
SettingsNewFree();
memcpy((char*)&Settings +16, settings_buffer +16, sizeof(Settings) -16);
memcpy((char*)&Settings +8, settings_buffer +8, 4); // Restore version and auto upgrade
SettingsBufferFree();
} else {
if (!Update.end(true)) { // true to set the size to the current progress
if (_serialoutput) { Update.printError(Serial); }

View File

@ -315,10 +315,8 @@ void MqttDisconnected(int state)
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_CONNECT_FAILED_TO " %s:%d, rc %d. " D_RETRY_IN " %d " D_UNIT_SECOND),
Settings.mqtt_host, Settings.mqtt_port, state, mqtt_retry_counter);
AddLog(LOG_LEVEL_INFO);
#ifdef USE_RULES
strncpy_P(mqtt_data, PSTR("{\"MQTT\":{\"Disconnected\":1}}"), sizeof(mqtt_data));
RulesProcess();
#endif // USE_RULES
XdrvRulesProcess();
}
void MqttConnected()
@ -370,17 +368,13 @@ void MqttConnected()
tele_period = Settings.tele_period -9;
}
status_update_timer = 2;
#ifdef USE_RULES
strncpy_P(mqtt_data, PSTR("{\"System\":{\"Boot\":1}}"), sizeof(mqtt_data));
RulesProcess();
#endif // USE_RULES
XdrvRulesProcess();
XdrvCall(FUNC_MQTT_INIT);
}
mqtt_initial_connection_state = 0;
#ifdef USE_RULES
strncpy_P(mqtt_data, PSTR("{\"MQTT\":{\"Connected\":1}}"), sizeof(mqtt_data));
RulesProcess();
#endif // USE_RULES
XdrvRulesProcess();
}
#ifdef USE_MQTT_TLS

View File

@ -110,6 +110,7 @@ void IrReceiveCheck()
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_IRRECEIVED "\":{\"" D_JSON_IR_PROTOCOL "\":\"%s\",\"" D_JSON_IR_BITS "\":%d,\"" D_JSON_IR_DATA "\":\"%lX\"}}"),
GetTextIndexed(sirtype, sizeof(sirtype), iridx, kIrRemoteProtocols), results.bits, (uint32_t)results.value);
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_IRRECEIVED));
XdrvRulesProcess();
#ifdef USE_DOMOTICZ
unsigned long value = results.value | (iridx << 28); // [Protocol:4, Data:28]
DomoticzSensor(DZ_COUNT, value); // Send data as Domoticz Counter value

View File

@ -97,6 +97,7 @@ void SonoffBridgeReceived()
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_RFRECEIVED "\":{\"" D_JSON_SYNC "\":%d,\"" D_JSON_LOW "\":%d,\"" D_JSON_HIGH "\":%d,\"" D_JSON_DATA "\":\"%06X\",\"" D_CMND_RFKEY "\":%s}}"),
sync_time, low_time, high_time, received_id, rfkey);
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_RFRECEIVED));
XdrvRulesProcess();
#ifdef USE_DOMOTICZ
DomoticzSensor(DZ_COUNT, received_id); // Send rid as Domoticz Counter value
#endif // USE_DOMOTICZ

View File

@ -61,6 +61,7 @@ void SerialBridgeInput()
serial_bridge_buffer[serial_bridge_in_byte_counter] = 0; // serial data completed
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_SSERIALRECEIVED "\":\"%s\"}"), serial_bridge_buffer);
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_SSERIALRECEIVED));
// XdrvRulesProcess();
serial_bridge_in_byte_counter = 0;
}
}

View File

@ -287,7 +287,7 @@ void TimerEverySecond()
#ifdef USE_RULES
if (3 == xtimer.power) { // Blink becomes Rule disregarding device and allowing use of Backlog commands
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"Clock\":{\"Timer\":%d}}"), i +1);
RulesProcess();
XdrvRulesProcess();
} else
#endif // USE_RULES
if (devices_present) { ExecuteCommandPower(xtimer.device +1, xtimer.power); }

View File

@ -86,8 +86,8 @@ uint8_t rules_quota = 0;
long rules_new_power = -1;
long rules_old_power = -1;
uint32_t rules_triggers = 0;
uint8_t rules_trigger_count = 0;
uint32_t rules_triggers[MAX_RULE_SETS] = { 0 };
uint8_t rules_trigger_count[MAX_RULE_SETS] = { 0 };
uint8_t rules_teleperiod = 0;
char vars[RULES_MAX_VARS][10] = { 0 };
@ -141,7 +141,7 @@ bool TimeReached(unsigned long timer)
/*******************************************************************************************/
bool RulesRuleMatch(String &event, String &rule)
bool RulesRuleMatch(byte rule_set, String &event, String &rule)
{
// event = {"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089}}
// event = {"System":{"Boot":1}}
@ -179,7 +179,7 @@ bool RulesRuleMatch(String &event, String &rule)
}
}
char tmp_value[CMDSZ] = { 0 };
char rule_svalue[CMDSZ] = { 0 };
double rule_value = 0;
if (pos > 0) {
String rule_param = rule_name.substring(pos + 1);
@ -198,13 +198,13 @@ bool RulesRuleMatch(String &event, String &rule)
}
}
rule_param.toUpperCase();
snprintf(tmp_value, sizeof(tmp_value), rule_param.c_str());
snprintf(rule_svalue, sizeof(rule_svalue), rule_param.c_str());
int temp_value = GetStateNumber(tmp_value);
int temp_value = GetStateNumber(rule_svalue);
if (temp_value > -1) {
rule_value = temp_value;
} else {
rule_value = CharToDouble((char*)tmp_value); // 0.1 - This saves 9k code over toFLoat()!
rule_value = CharToDouble((char*)rule_svalue); // 0.1 - This saves 9k code over toFLoat()!
}
rule_name = rule_name.substring(0, pos); // "CURRENT"
}
@ -218,7 +218,7 @@ bool RulesRuleMatch(String &event, String &rule)
const char* str_value = root[rule_task][rule_name];
//snprintf_P(log_data, sizeof(log_data), PSTR("RUL: Task %s, Name %s, Value |%s|, TrigCnt %d, TrigSt %d, Source %s, Json %s"),
// rule_task.c_str(), rule_name.c_str(), tmp_value, rules_trigger_count, bitRead(rules_triggers, rules_trigger_count), event.c_str(), (str_value) ? str_value : "none");
// rule_task.c_str(), rule_name.c_str(), rule_svalue, rules_trigger_count[rule_set], bitRead(rules_triggers[rule_set], rules_trigger_count[rule_set]), event.c_str(), (str_value) ? str_value : "none");
//AddLog(LOG_LEVEL_DEBUG);
if (!root[rule_task][rule_name].success()) { return false; }
@ -231,13 +231,14 @@ bool RulesRuleMatch(String &event, String &rule)
value = CharToDouble((char*)str_value);
switch (compare) {
case '>':
if (value > rule_value) match = true;
if (value > rule_value) { match = true; }
break;
case '<':
if (value < rule_value) match = true;
if (value < rule_value) { match = true; }
break;
case '=':
if (value == rule_value) match = true;
// if (value == rule_value) { match = true; } // Compare values - only decimals or partly hexadecimals
if (!strcasecmp(str_value, rule_svalue)) { match = true; } // Compare strings - this also works for hexadecimals
break;
case ' ':
match = true; // Json value but not needed
@ -247,13 +248,13 @@ bool RulesRuleMatch(String &event, String &rule)
if (Settings.flag.rules_once) {
if (match) { // Only allow match state changes
if (!bitRead(rules_triggers, rules_trigger_count)) {
bitSet(rules_triggers, rules_trigger_count);
if (!bitRead(rules_triggers[rule_set], rules_trigger_count[rule_set])) {
bitSet(rules_triggers[rule_set], rules_trigger_count[rule_set]);
} else {
match = false;
}
} else {
bitClear(rules_triggers, rules_trigger_count);
bitClear(rules_triggers[rule_set], rules_trigger_count[rule_set]);
}
}
@ -262,24 +263,19 @@ bool RulesRuleMatch(String &event, String &rule)
/*******************************************************************************************/
bool RulesProcess()
bool RuleSetProcess(byte rule_set, String &event_saved)
{
bool serviced = false;
char stemp[10];
delay(0); // Prohibit possible loop software watchdog
//snprintf_P(log_data, sizeof(log_data), PSTR("RUL: Event = %s, Rule = %s"), mqtt_data, Settings.rules);
//snprintf_P(log_data, sizeof(log_data), PSTR("RUL: Event = %s, Rule = %s"), event_saved.c_str(), Settings.rules[rule_set]);
//AddLog(LOG_LEVEL_DEBUG);
if (!Settings.flag.rules_enabled) { return serviced; } // Not enabled
if (!strlen(Settings.rules)) { return serviced; } // No rules
String rules = Settings.rules[rule_set];
String event_saved = mqtt_data;
event_saved.toUpperCase();
String rules = Settings.rules;
rules_trigger_count = 0;
rules_trigger_count[rule_set] = 0;
int plen = 0;
while (true) {
rules = rules.substring(plen); // Select relative to last rule
@ -304,7 +300,7 @@ bool RulesProcess()
//snprintf_P(log_data, sizeof(log_data), PSTR("RUL: Event |%s|, Rule |%s|, Command(s) |%s|"), event.c_str(), event_trigger.c_str(), commands.c_str());
//AddLog(LOG_LEVEL_DEBUG);
if (RulesRuleMatch(event, event_trigger)) {
if (RulesRuleMatch(rule_set, event, event_trigger)) {
commands.trim();
String ucommand = commands;
ucommand.toUpperCase();
@ -331,25 +327,42 @@ bool RulesProcess()
ExecuteCommand(command);
serviced = true;
}
rules_trigger_count++;
rules_trigger_count[rule_set]++;
}
return serviced;
}
/*******************************************************************************************/
bool RulesProcess()
{
bool serviced = false;
String event_saved = mqtt_data;
event_saved.toUpperCase();
for (byte i = 0; i < MAX_RULE_SETS; i++) {
if (strlen(Settings.rules[i]) && bitRead(Settings.rule_enabled, i)) {
if (RuleSetProcess(i, event_saved)) { serviced = true; }
}
}
return serviced;
}
void RulesInit()
{
if (Settings.rules[0] == '\0') {
Settings.flag.rules_enabled = 0;
Settings.flag.rules_once = 0;
for (byte i = 0; i < MAX_RULE_SETS; i++) {
if (Settings.rules[i][0] == '\0') {
bitWrite(Settings.rule_enabled, i, 0);
bitWrite(Settings.rule_once, i, 0);
}
}
rules_teleperiod = 0;
}
void RulesEvery50ms()
{
if (Settings.flag.rules_enabled) {
if (Settings.rule_enabled) { // Any rule enabled
if (rules_new_power != rules_old_power) {
if (rules_old_power != -1) {
for (byte i = 0; i < devices_present; i++) {
@ -381,7 +394,7 @@ void RulesEvery50ms()
void RulesEverySecond()
{
if (Settings.flag.rules_enabled) {
if (Settings.rule_enabled) { // Any rule enabled
for (byte i = 0; i < MAX_RULE_TIMERS; i++) {
if (rules_timer[i] != 0L) { // Timer active?
if (TimeReached(rules_timer[i])) { // Timer finished?
@ -416,39 +429,32 @@ boolean RulesCommand()
if (-1 == command_code) {
serviced = false; // Unknown command
}
else if (CMND_RULE == command_code) {
if ((XdrvMailbox.data_len > 0) && (XdrvMailbox.data_len < sizeof(Settings.rules))) {
else if ((CMND_RULE == command_code) && (index > 0) && (index <= MAX_RULE_SETS)) {
if ((XdrvMailbox.data_len > 0) && (XdrvMailbox.data_len < sizeof(Settings.rules[index -1]))) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6)) {
switch (XdrvMailbox.payload) {
case 0: // Off
case 1: // On
Settings.flag.rules_enabled = XdrvMailbox.payload;
bitWrite(Settings.rule_enabled, index -1, XdrvMailbox.payload);
break;
case 2: // Toggle
Settings.flag.rules_enabled ^= 1;
bitWrite(Settings.rule_enabled, index -1, bitRead(Settings.rule_enabled, index -1) ^1);
break;
case 4: // Off
case 5: // On
Settings.flag.rules_once = XdrvMailbox.payload &1;
bitWrite(Settings.rule_once, index -1, XdrvMailbox.payload &1);
break;
case 6: // Toggle
Settings.flag.rules_once ^= 1;
bitWrite(Settings.rule_once, index -1, bitRead(Settings.rule_once, index -1) ^1);
break;
}
} else {
/*
String uc_data = XdrvMailbox.data; // Do not allow Rule to be used within a rule
uc_data.toUpperCase();
String uc_command = command;
uc_command += " "; // Distuingish from RuleTimer
uc_command.toUpperCase();
if (!uc_data.indexOf(uc_command)) { strlcpy(Settings.rules, XdrvMailbox.data, sizeof(Settings.rules)); }
*/
strlcpy(Settings.rules, XdrvMailbox.data, sizeof(Settings.rules));
strlcpy(Settings.rules[index -1], ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data, sizeof(Settings.rules[index -1]));
}
rules_triggers = 0; // Reset once flag
rules_triggers[index -1] = 0; // Reset once flag
}
snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"%s\",\"Once\":\"%s\",\"Rules\":\"%s\"}"), command, GetStateText(Settings.flag.rules_enabled), GetStateText(Settings.flag.rules_once), Settings.rules);
snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s%d\":\"%s\",\"Once\":\"%s\",\"Free\":%d,\"Rules\":\"%s\"}"),
command, index, GetStateText(bitRead(Settings.rule_enabled, index -1)), GetStateText(bitRead(Settings.rule_once, index -1)), sizeof(Settings.rules[index -1]) - strlen(Settings.rules[index -1]) -1, Settings.rules[index -1]);
}
else if ((CMND_RULETIMER == command_code) && (index > 0) && (index <= MAX_RULE_TIMERS)) {
if (XdrvMailbox.data_len > 0) {
@ -515,6 +521,9 @@ boolean Xdrv10(byte function)
case FUNC_COMMAND:
result = RulesCommand();
break;
case FUNC_RULES_PROCESS:
result = RulesProcess();
break;
}
return result;
}

View File

@ -175,6 +175,11 @@ boolean XdrvMqttData(char *topicBuf, uint16_t stopicBuf, char *dataBuf, uint16_t
return XdrvCall(FUNC_MQTT_DATA);
}
boolean XdrvRulesProcess()
{
return XdrvCall(FUNC_RULES_PROCESS);
}
/*********************************************************************************************\
* Function call to all xdrv
*
@ -188,6 +193,7 @@ boolean XdrvMqttData(char *topicBuf, uint16_t stopicBuf, char *dataBuf, uint16_t
* FUNC_SHOW_SENSOR
* FUNC_EVERY_SECOND
* FUNC_EVERY_50_MSECOND
* FUNC_RULES_PROCESS
\*********************************************************************************************/
boolean XdrvCall(byte Function)