diff --git a/lib/ESPAsyncUDP-master/src/AsyncUDP.cpp b/lib/ESPAsyncUDP-master/src/AsyncUDP.cpp index 2a538c4c6..9e433b1f4 100644 --- a/lib/ESPAsyncUDP-master/src/AsyncUDP.cpp +++ b/lib/ESPAsyncUDP-master/src/AsyncUDP.cpp @@ -1,3 +1,6 @@ +#include // Arduino_Esp8266 version information (ARDUINO_ESP8266_RELEASE and ARDUINO_ESP8266_RELEASE_2_3_0) +#ifndef ARDUINO_ESP8266_RELEASE_2_3_0 // This Library will only work with ARDUINO_ESP8266_RELEASE_2_4_0 and up + #include "Arduino.h" #include "ESPAsyncUDP.h" @@ -425,3 +428,5 @@ size_t AsyncUDP::broadcast(AsyncUDPMessage &message) } return broadcast(message.data(), message.length()); } + +#endif diff --git a/lib/esp-knx-ip-0.5.1/esp-knx-ip.h b/lib/esp-knx-ip-0.5.1/esp-knx-ip.h index d8fde1dc9..515a5d843 100644 --- a/lib/esp-knx-ip-0.5.1/esp-knx-ip.h +++ b/lib/esp-knx-ip-0.5.1/esp-knx-ip.h @@ -7,14 +7,6 @@ #ifndef ESP_KNX_IP_H #define ESP_KNX_IP_H -//#define USE_ASYNC_UDP // UDP WIFI Library Selection for Multicast - // If commented out, the esp-knx-ip library will use WIFI_UDP Library that is compatible with ESP8266 Library Version 2.3.0 and up - // If not commented out, the esp-knx-ip library will use ESPAsyncUDP Library that is compatible with ESP8266 Library Version 2.4.0 and up - // The ESPAsyncUDP Library have a more reliable multicast communication - // Please Use it with Patch (https://github.com/me-no-dev/ESPAsyncUDP/pull/21) ) - // check line 57 on esp-knx-ip.h file is uncommented: #include - // Comment out that line when using UDP WIFI to avoid compiling issues on PlatformIO with ESP8266 Library Version 2.3.0 - /** * CONFIG * All MAX_ values must not exceed 255 (1 byte, except MAC_CONFIG_SPACE which can go up to 2 bytes, so 0xffff in theory) and must not be negative! @@ -54,8 +46,13 @@ #include #include +#include // Arduino_Esp8266 version information (ARDUINO_ESP8266_RELEASE and ARDUINO_ESP8266_RELEASE_2_3_0) +#ifndef ARDUINO_ESP8266_RELEASE_2_3_0 +#define USE_ASYNC_UDP // UDP WIFI Library Selection for Multicast +#endif + #ifdef USE_ASYNC_UDP -//#include +#include #else #include #endif diff --git a/platformio.ini b/platformio.ini index 4551a164d..d385873f4 100644 --- a/platformio.ini +++ b/platformio.ini @@ -52,14 +52,28 @@ framework = arduino board = esp01_1m board_build.flash_mode = dout +; set CPU frequency to 80MHz (default) or 160MHz +board_build.f_cpu = 80000000L +;board_build.f_cpu = 160000000L + ; *** Fix espressif8266@1.7.0 induced undesired all warnings build_unflags = -Wall build_flags = -Wl,-Tesp8266.flash.1m0.ld - -DVTABLES_IN_FLASH +; -DUSE_CONFIG_OVERRIDE +; lwIP 1.4 (Default) -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH -; -DUSE_CONFIG_OVERRIDE +; lwIP 2 - Low Memory +; -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY +; lwIP 2 - Higher Bandwitdh +; -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH +; VTABLES in Flash (default) + -DVTABLES_IN_FLASH +; VTABLES in Heap +; -DVTABLES_IN_DRAM +; VTABLES in IRAM +; -DVTABLES_IN_IRAM ; *** Serial Monitor options monitor_speed = 115200 @@ -68,6 +82,7 @@ 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 @@ -86,6 +101,7 @@ platform = ${common.platform} framework = ${common.framework} board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} monitor_speed = ${common.monitor_speed} @@ -99,6 +115,7 @@ platform = ${common.platform} framework = ${common.framework} board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} -DBE_MINIMAL monitor_speed = ${common.monitor_speed} @@ -112,6 +129,7 @@ platform = ${common.platform} framework = ${common.framework} board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} -DUSE_CLASSIC monitor_speed = ${common.monitor_speed} @@ -125,6 +143,7 @@ platform = ${common.platform} framework = ${common.framework} board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} -DUSE_KNX_NO_EMULATION monitor_speed = ${common.monitor_speed} @@ -138,6 +157,7 @@ platform = ${common.platform} framework = ${common.framework} board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} -DUSE_ALL_SENSORS monitor_speed = ${common.monitor_speed} @@ -151,6 +171,7 @@ platform = ${common.platform} framework = ${common.framework} board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} -DMY_LANGUAGE=bg-BG monitor_speed = ${common.monitor_speed} @@ -164,6 +185,7 @@ platform = ${common.platform} framework = ${common.framework} board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} -DMY_LANGUAGE=pt-BR monitor_speed = ${common.monitor_speed} @@ -177,6 +199,7 @@ platform = ${common.platform} framework = ${common.framework} board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} -DMY_LANGUAGE=zh-CN monitor_speed = ${common.monitor_speed} @@ -190,6 +213,7 @@ platform = ${common.platform} framework = ${common.framework} board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} -DMY_LANGUAGE=cs-CZ monitor_speed = ${common.monitor_speed} @@ -203,6 +227,7 @@ platform = ${common.platform} framework = ${common.framework} board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} -DMY_LANGUAGE=de-DE monitor_speed = ${common.monitor_speed} @@ -216,6 +241,7 @@ platform = ${common.platform} framework = ${common.framework} board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} -DMY_LANGUAGE=es-AR monitor_speed = ${common.monitor_speed} @@ -229,6 +255,7 @@ platform = ${common.platform} framework = ${common.framework} board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} -DMY_LANGUAGE=fr-FR monitor_speed = ${common.monitor_speed} @@ -242,6 +269,7 @@ platform = ${common.platform} framework = ${common.framework} board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} -DMY_LANGUAGE=el-GR monitor_speed = ${common.monitor_speed} @@ -255,6 +283,7 @@ platform = ${common.platform} framework = ${common.framework} board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} -DMY_LANGUAGE=hu-HU monitor_speed = ${common.monitor_speed} @@ -268,6 +297,7 @@ platform = ${common.platform} framework = ${common.framework} board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} -DMY_LANGUAGE=it-IT monitor_speed = ${common.monitor_speed} @@ -281,6 +311,7 @@ platform = ${common.platform} framework = ${common.framework} board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} -DMY_LANGUAGE=nl-NL monitor_speed = ${common.monitor_speed} @@ -294,6 +325,7 @@ platform = ${common.platform} framework = ${common.framework} board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} -DMY_LANGUAGE=pl-PL monitor_speed = ${common.monitor_speed} @@ -307,6 +339,7 @@ platform = ${common.platform} framework = ${common.framework} board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} -DMY_LANGUAGE=pt-PT monitor_speed = ${common.monitor_speed} @@ -320,6 +353,7 @@ platform = ${common.platform} framework = ${common.framework} board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} -DMY_LANGUAGE=ru-RU monitor_speed = ${common.monitor_speed} @@ -333,6 +367,7 @@ platform = ${common.platform} framework = ${common.framework} board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} -DMY_LANGUAGE=tr-TR monitor_speed = ${common.monitor_speed} @@ -346,6 +381,7 @@ platform = ${common.platform} framework = ${common.framework} board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} -DMY_LANGUAGE=zh-TW monitor_speed = ${common.monitor_speed} @@ -359,6 +395,7 @@ platform = ${common.platform} framework = ${common.framework} board = ${common.board} board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} -DMY_LANGUAGE=uk-UK monitor_speed = ${common.monitor_speed} diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index e12138049..97822dec0 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,10 @@ -/* 6.1.1.11 20180826 +/* 6.1.1.12 20180827 + * Add commands ButtonDebounce 40..1000 and SwitchDebounce 40..1000 to have user control over debounce timing. Default is 50mS (#3594) + * Add rule variables %sunrise%, %sunset%, %uptime% and %time% (#3608) + * Fix handling use of default names when using names starting with shortcut character (#3392, #3600) + * Fix Sonoff Bridge data reception when using Portisch EFM8 firmware and in data buffer length (#3605) + * + * 6.1.1.11 20180826 * Change scheduler phase 1/3 - Fixed when sleep is enabled: Uptime, Delay, PulseTime and TelePeriod (#3581) * Change scheduler phase 2/3 - Fixed when sleep is enabled: Blinktime (#3581) * Change scheduler phase 3/3 - Some sensor update timings: AdcEvery 200 -> 250, Senseair 300 -> 250, SDM120 300 -> 250, SDM630 300 -> 250 diff --git a/sonoff/i18n.h b/sonoff/i18n.h index 235f0cc04..3d63f73f5 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -192,6 +192,8 @@ #define D_CMND_COUNTER "Counter" #define D_CMND_COUNTERTYPE "CounterType" #define D_CMND_COUNTERDEBOUNCE "CounterDebounce" +#define D_CMND_BUTTONDEBOUNCE "ButtonDebounce" +#define D_CMND_SWITCHDEBOUNCE "SwitchDebounce" #define D_CMND_SLEEP "Sleep" #define D_CMND_UPLOAD "Upload" #define D_CMND_UPGRADE "Upgrade" diff --git a/sonoff/settings.h b/sonoff/settings.h index bb3c7711b..b918b67ee 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -297,9 +297,7 @@ struct SYSCFG { char ntp_server[3][33]; // 4CE byte ina219_mode; // 531 uint16_t pulse_timer[MAX_PULSETIMERS]; // 532 - - byte free542[2]; // 542 - + uint16_t button_debounce; // 542 uint32_t ip_address[4]; // 544 unsigned long energy_kWhtotal; // 554 char mqtt_fulltopic[100]; // 558 @@ -309,8 +307,9 @@ struct SYSCFG { uint16_t pulse_counter_debounce; // 5D2 uint8_t rf_code[17][9]; // 5D4 - byte free_66d[3]; // 66D + byte free_66d[1]; // 66D + uint16_t switch_debounce; // 66E Timer timer[MAX_TIMERS]; // 670 int latitude; // 6B0 int longitude; // 6B4 @@ -321,7 +320,9 @@ struct SYSCFG { byte knx_CB_param[MAX_KNX_CB]; // 6EC Type of Output (set relay, toggle relay, reply sensor value) Mcp230xxCfg mcp230xx_config[16]; // 6F6 uint8_t mcp230xx_int_prio; // 716 - byte free_717; // 717 + + byte free_717[1]; // 717 + uint16_t mcp230xx_int_timer; // 718 byte free_71A[180]; // 71A diff --git a/sonoff/settings.ino b/sonoff/settings.ino index 7ba1b53f8..e0a40a17c 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -588,6 +588,9 @@ void SettingsDefaultSet2() Settings.latitude = (int)((double)LATITUDE * 1000000); Settings.longitude = (int)((double)LONGITUDE * 1000000); SettingsDefaultSet_5_13_1c(); // Time STD/DST settings + + Settings.button_debounce = KEY_DEBOUNCE_TIME; + Settings.switch_debounce = SWITCH_DEBOUNCE_TIME; } /********************************************************************************************/ @@ -787,6 +790,10 @@ void SettingsDelta() if (Settings.version < 0x06010103) { Settings.flag3.timers_enable = 1; } + if (Settings.version < 0x0601010C) { + Settings.button_debounce = KEY_DEBOUNCE_TIME; + Settings.switch_debounce = SWITCH_DEBOUNCE_TIME; + } Settings.version = VERSION; SettingsSave(1); diff --git a/sonoff/sonoff.h b/sonoff/sonoff.h index cea1b6f98..f93df0059 100644 --- a/sonoff/sonoff.h +++ b/sonoff/sonoff.h @@ -83,7 +83,7 @@ typedef unsigned long power_t; // Power (Relay) type #define SAFE_POWER_WINDOW 30 // Time in MINUTES to disable allow max unit safe power #define MAX_POWER_RETRY 5 // Retry count allowing agreed power limit overflow -#define STATES 20 // State loops per second +#define STATES 20 // Number of states per second using 50 mSec interval #define IMMINENT_RESET_FACTOR 10 // Factor to extent button hold time for imminent Reset to default 40 seconds using KEY_HOLD_TIME of 40 #define SYSLOG_TIMER 600 // Seconds to restore syslog_level #define SERIALLOG_TIMER 600 // Seconds to disable SerialLog @@ -187,7 +187,9 @@ enum ExecuteCommandPowerOptions { POWER_OFF, POWER_ON, POWER_TOGGLE, POWER_BLINK enum PowerOnStateOptions { POWER_ALL_OFF, POWER_ALL_ON, POWER_ALL_SAVED_TOGGLE, POWER_ALL_SAVED, POWER_ALL_ALWAYS_ON, POWER_ALL_OFF_PULSETIME_ON }; -enum ButtonStates {PRESSED, NOT_PRESSED}; +enum ButtonStates { PRESSED, NOT_PRESSED }; + +enum Shortcuts { SC_CLEAR, SC_DEFAULT, SC_USER }; enum SettingsParmaIndex {P_HOLD_TIME, P_MAX_POWER_RETRY, P_MAX_PARAM8}; diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 6281dabaf..a006c1b0a 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -79,7 +79,7 @@ enum TasmotaCommands { CMND_BLINKTIME, CMND_BLINKCOUNT, CMND_SENSOR, CMND_SAVEDATA, CMND_SETOPTION, CMND_TEMPERATURE_RESOLUTION, CMND_HUMIDITY_RESOLUTION, CMND_PRESSURE_RESOLUTION, CMND_POWER_RESOLUTION, CMND_VOLTAGE_RESOLUTION, CMND_CURRENT_RESOLUTION, CMND_ENERGY_RESOLUTION, CMND_MODULE, CMND_MODULES, CMND_GPIO, CMND_GPIOS, CMND_PWM, CMND_PWMFREQUENCY, CMND_PWMRANGE, CMND_COUNTER, CMND_COUNTERTYPE, - CMND_COUNTERDEBOUNCE, CMND_SLEEP, CMND_UPGRADE, CMND_UPLOAD, CMND_OTAURL, CMND_SERIALLOG, CMND_SYSLOG, + CMND_COUNTERDEBOUNCE, CMND_BUTTONDEBOUNCE, CMND_SWITCHDEBOUNCE, CMND_SLEEP, CMND_UPGRADE, CMND_UPLOAD, CMND_OTAURL, CMND_SERIALLOG, CMND_SYSLOG, CMND_LOGHOST, CMND_LOGPORT, CMND_IPADDRESS, CMND_NTPSERVER, CMND_AP, CMND_SSID, CMND_PASSWORD, CMND_HOSTNAME, CMND_WIFICONFIG, CMND_FRIENDLYNAME, CMND_SWITCHMODE, CMND_TELEPERIOD, CMND_RESTART, CMND_RESET, CMND_TIMEZONE, CMND_TIMESTD, CMND_TIMEDST, CMND_ALTITUDE, CMND_LEDPOWER, CMND_LEDSTATE, @@ -89,7 +89,7 @@ const char kTasmotaCommands[] PROGMEM = D_CMND_BLINKTIME "|" D_CMND_BLINKCOUNT "|" D_CMND_SENSOR "|" D_CMND_SAVEDATA "|" D_CMND_SETOPTION "|" D_CMND_TEMPERATURE_RESOLUTION "|" D_CMND_HUMIDITY_RESOLUTION "|" D_CMND_PRESSURE_RESOLUTION "|" D_CMND_POWER_RESOLUTION "|" D_CMND_VOLTAGE_RESOLUTION "|" D_CMND_CURRENT_RESOLUTION "|" D_CMND_ENERGY_RESOLUTION "|" D_CMND_MODULE "|" D_CMND_MODULES "|" D_CMND_GPIO "|" D_CMND_GPIOS "|" D_CMND_PWM "|" D_CMND_PWMFREQUENCY "|" D_CMND_PWMRANGE "|" D_CMND_COUNTER "|" D_CMND_COUNTERTYPE "|" - D_CMND_COUNTERDEBOUNCE "|" D_CMND_SLEEP "|" D_CMND_UPGRADE "|" D_CMND_UPLOAD "|" D_CMND_OTAURL "|" D_CMND_SERIALLOG "|" D_CMND_SYSLOG "|" + D_CMND_COUNTERDEBOUNCE "|" D_CMND_BUTTONDEBOUNCE "|" D_CMND_SWITCHDEBOUNCE "|" D_CMND_SLEEP "|" D_CMND_UPGRADE "|" D_CMND_UPLOAD "|" D_CMND_OTAURL "|" D_CMND_SERIALLOG "|" D_CMND_SYSLOG "|" D_CMND_LOGHOST "|" D_CMND_LOGPORT "|" D_CMND_IPADDRESS "|" D_CMND_NTPSERVER "|" D_CMND_AP "|" D_CMND_SSID "|" D_CMND_PASSWORD "|" D_CMND_HOSTNAME "|" D_CMND_WIFICONFIG "|" D_CMND_FRIENDLYNAME "|" D_CMND_SWITCHMODE "|" D_CMND_TELEPERIOD "|" D_CMND_RESTART "|" D_CMND_RESET "|" D_CMND_TIMEZONE "|" D_CMND_TIMESTD "|" D_CMND_TIMEDST "|" D_CMND_ALTITUDE "|" D_CMND_LEDPOWER "|" D_CMND_LEDSTATE "|" @@ -98,52 +98,7 @@ const char kTasmotaCommands[] PROGMEM = const uint8_t kIFan02Speed[4][3] = {{6,6,6}, {7,6,6}, {7,7,6}, {7,6,7}}; // Global variables -unsigned long feature_drv1; // Compiled driver feature map -unsigned long feature_drv2; // Compiled driver feature map -unsigned long feature_sns1; // Compiled sensor feature map -unsigned long feature_sns2; // Compiled sensor feature map -int baudrate = APP_BAUDRATE; // Serial interface baud rate SerialConfig serial_config = SERIAL_8N1; // Serial interface configuration 8 data bits, No parity, 1 stop bit -byte serial_in_byte; // Received byte -uint8_t serial_local = 0; // Handle serial locally; -unsigned long serial_polling_window = 0; // Serial polling window -int serial_in_byte_counter = 0; // Index in receive buffer -byte dual_hex_code = 0; // Sonoff dual input flag -uint16_t dual_button_code = 0; // Sonoff dual received code -int16_t save_data_counter; // Counter and flag for config save to Flash -uint8_t fallback_topic_flag = 0; // Use Topic or FallbackTopic -unsigned long state_second = 0; // State second timer -unsigned long state_50msecond = 0; // State 50msecond timer -unsigned long state_100msecond = 0; // State 100msecond timer -unsigned long state_250msecond = 0; // State 250msecond timer -uint8_t state_250mS = 0; // State 250msecond per second flag -int ota_state_flag = 0; // OTA state flag -int ota_result = 0; // OTA result -byte ota_retry_counter = OTA_ATTEMPTS; // OTA retry counter -char *ota_url; // OTA url string -int restart_flag = 0; // Sonoff restart flag -int wifi_state_flag = WIFI_RESTART; // Wifi state flag -uint32_t uptime = 0; // Counting every second until 4294967295 = 130 year -boolean latest_uptime_flag = true; // Signal latest uptime -int tele_period = 0; // Tele period timer -byte web_log_index = 1; // Index in Web log buffer (should never be 0) -byte reset_web_log_flag = 0; // Reset web console log -byte devices_present = 0; // Max number of devices supported -int status_update_timer = 0; // Refresh initial status -unsigned long pulse_timer[MAX_PULSETIMERS] = { 0 }; // Power off timer -unsigned long blink_timer = 0; // Power cycle timer -uint16_t blink_counter = 0; // Number of blink cycles -power_t blink_power; // Blink power state -power_t blink_mask = 0; // Blink relay active mask -power_t blink_powersave; // Blink start power save state -uint16_t mqtt_cmnd_publish = 0; // ignore flag for publish command -power_t latching_power = 0; // Power state at latching start -uint8_t latching_relay_pulse = 0; // Latching relay pulse timer -uint8_t backlog_index = 0; // Command backlog index -uint8_t backlog_pointer = 0; // Command backlog pointer -uint8_t backlog_mutex = 0; // Command backlog pending -unsigned long backlog_delay = 0; // Command backlog delay -uint8_t interlock_mutex = 0; // Interlock power command pending #ifdef USE_MQTT_TLS WiFiClientSecure EspClient; // Wifi Secure Client @@ -153,30 +108,67 @@ uint8_t interlock_mutex = 0; // Interlock power command pending WiFiUDP PortUdp; // UDP Syslog and Alexa +unsigned long feature_drv1; // Compiled driver feature map +unsigned long feature_drv2; // Compiled driver feature map +unsigned long feature_sns1; // Compiled sensor feature map +unsigned long feature_sns2; // Compiled sensor feature map +unsigned long serial_polling_window = 0; // Serial polling window +unsigned long state_second = 0; // State second timer +unsigned long state_50msecond = 0; // State 50msecond timer +unsigned long state_100msecond = 0; // State 100msecond timer +unsigned long state_250msecond = 0; // State 250msecond timer +unsigned long pulse_timer[MAX_PULSETIMERS] = { 0 }; // Power off timer +unsigned long blink_timer = 0; // Power cycle timer +unsigned long backlog_delay = 0; // Command backlog delay +unsigned long button_debounce = 0; // Button debounce timer +unsigned long switch_debounce = 0; // Switch debounce timer power_t power = 0; // Current copy of Settings.power -byte syslog_level; // Current copy of Settings.syslog_level -uint16_t syslog_timer = 0; // Timer to re-enable syslog_level -byte seriallog_level; // Current copy of Settings.seriallog_level +power_t blink_power; // Blink power state +power_t blink_mask = 0; // Blink relay active mask +power_t blink_powersave; // Blink start power save state +power_t latching_power = 0; // Power state at latching start +power_t rel_inverted = 0; // Relay inverted flag (1 = (0 = On, 1 = Off)) +int baudrate = APP_BAUDRATE; // Serial interface baud rate +int serial_in_byte_counter = 0; // Index in receive buffer +int ota_state_flag = 0; // OTA state flag +int ota_result = 0; // OTA result +int restart_flag = 0; // Sonoff restart flag +int wifi_state_flag = WIFI_RESTART; // Wifi state flag +int tele_period = 0; // Tele period timer +int status_update_timer = 0; // Refresh initial status +int blinks = 201; // Number of LED blinks +uint32_t uptime = 0; // Counting every second until 4294967295 = 130 year +uint32_t global_update = 0; // Timestamp of last global temperature and humidity update +float global_temperature = 0; // Provide a global temperature to be used by some sensors +float global_humidity = 0; // Provide a global humidity to be used by some sensors +char *ota_url; // OTA url string pointer +uint16_t dual_button_code = 0; // Sonoff dual received code +uint16_t mqtt_cmnd_publish = 0; // ignore flag for publish command +uint16_t blink_counter = 0; // Number of blink cycles uint16_t seriallog_timer = 0; // Timer to disable Seriallog +uint16_t syslog_timer = 0; // Timer to re-enable syslog_level +uint16_t holdbutton[MAX_KEYS] = { 0 }; // Timer for button hold +int16_t save_data_counter; // Counter and flag for config save to Flash +RulesBitfield rules_flag; // Rule state flags (16 bits) +uint8_t serial_local = 0; // Handle serial locally; +uint8_t fallback_topic_flag = 0; // Use Topic or FallbackTopic +uint8_t state_250mS = 0; // State 250msecond per second flag +uint8_t latching_relay_pulse = 0; // Latching relay pulse timer +uint8_t backlog_index = 0; // Command backlog index +uint8_t backlog_pointer = 0; // Command backlog pointer +uint8_t backlog_mutex = 0; // Command backlog pending +uint8_t interlock_mutex = 0; // Interlock power command pending uint8_t sleep; // Current copy of Settings.sleep uint8_t stop_flash_rotate = 0; // Allow flash configuration rotation - -int blinks = 201; // Number of LED blinks uint8_t blinkstate = 0; // LED state uint8_t blinkspeed = 1; // LED blink rate - -uint8_t blockgpio0 = 4; // Block GPIO0 for 4 seconds after poweron to workaround Wemos D1 RTS circuit uint8_t lastbutton[MAX_KEYS] = { NOT_PRESSED, NOT_PRESSED, NOT_PRESSED, NOT_PRESSED }; // Last button states -uint16_t holdbutton[MAX_KEYS] = { 0 }; // Timer for button hold uint8_t multiwindow[MAX_KEYS] = { 0 }; // Max time between button presses to record press count uint8_t multipress[MAX_KEYS] = { 0 }; // Number of button presses within multiwindow uint8_t lastwallswitch[MAX_SWITCHES]; // Last wall switch states uint8_t holdwallswitch[MAX_SWITCHES] = { 0 }; // Timer for wallswitch push button hold uint8_t virtualswitch[MAX_SWITCHES]; // Virtual switch states - -mytmplt my_module; // Active copy of Module name and GPIOs uint8_t pin[GPIO_MAX]; // Possible pin configurations -power_t rel_inverted = 0; // Relay inverted flag (1 = (0 = On, 1 = Off)) uint8_t led_inverted = 0; // LED inverted flag (1 = (0 = On, 1 = Off)) uint8_t pwm_inverted = 0; // PWM inverted flag (1 = inverted) uint8_t counter_no_pullup = 0; // Counter input pullup flag (1 = No pullup) @@ -185,16 +177,20 @@ uint8_t energy_flg = 1; // Energy monitor configured uint8_t i2c_flg = 0; // I2C configured uint8_t spi_flg = 0; // SPI configured uint8_t light_type = 0; // Light types -bool pwm_present = false; // Any PWM channel configured with SetOption15 0 -boolean mdns_begun = false; uint8_t ntp_force_sync = 0; // Force NTP sync -StateBitfield global_state; -RulesBitfield rules_flag; - -uint32_t global_update = 0; -float global_temperature = 0; -float global_humidity = 0; - +byte serial_in_byte; // Received byte +byte dual_hex_code = 0; // Sonoff dual input flag +byte ota_retry_counter = OTA_ATTEMPTS; // OTA retry counter +byte web_log_index = 1; // Index in Web log buffer (should never be 0) +byte reset_web_log_flag = 0; // Reset web console log +byte devices_present = 0; // Max number of devices supported +byte seriallog_level; // Current copy of Settings.seriallog_level +byte syslog_level; // Current copy of Settings.syslog_level +boolean latest_uptime_flag = true; // Signal latest uptime +boolean pwm_present = false; // Any PWM channel configured with SetOption15 0 +boolean mdns_begun = false; // mDNS active +mytmplt my_module; // Active copy of Module name and GPIOs (23 x 8 bits) +StateBitfield global_state; // Global states (currently Wifi and Mqtt) (8 bits) char my_version[33]; // Composed version string char my_hostname[33]; // Composed Wifi hostname char mqtt_client[33]; // Composed MQTT Clientname @@ -608,8 +604,9 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) } } else if (CMND_OTAURL == command_code) { - if ((data_len > 0) && (data_len < sizeof(Settings.ota_url))) - strlcpy(Settings.ota_url, (1 == payload) ? OTA_URL : dataBuf, sizeof(Settings.ota_url)); + if ((data_len > 0) && (data_len < sizeof(Settings.ota_url))) { + strlcpy(Settings.ota_url, (SC_DEFAULT == Shortcut(dataBuf)) ? OTA_URL : dataBuf, sizeof(Settings.ota_url)); + } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.ota_url); } else if (CMND_SERIALLOG == command_code) { @@ -947,6 +944,18 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.pulse_counter_debounce); } + else if (CMND_BUTTONDEBOUNCE == command_code) { + if ((payload > 39) && (payload < 1001)) { + Settings.button_debounce = payload; + } + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.button_debounce); + } + else if (CMND_SWITCHDEBOUNCE == command_code) { + if ((payload > 39) && (payload < 1001)) { + Settings.switch_debounce = payload; + } + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.switch_debounce); + } else if (CMND_BAUDRATE == command_code) { if (payload32 > 0) { payload32 /= 1200; // Make it a valid baudrate @@ -997,12 +1006,14 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) } else if (CMND_LOGHOST == command_code) { if ((data_len > 0) && (data_len < sizeof(Settings.syslog_host))) { - strlcpy(Settings.syslog_host, (1 == payload) ? SYS_LOG_HOST : dataBuf, sizeof(Settings.syslog_host)); + strlcpy(Settings.syslog_host, (SC_DEFAULT == Shortcut(dataBuf)) ? SYS_LOG_HOST : dataBuf, sizeof(Settings.syslog_host)); } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.syslog_host); } else if (CMND_LOGPORT == command_code) { - if (payload16 > 0) Settings.syslog_port = (1 == payload16) ? SYS_LOG_PORT : payload16; + if (payload16 > 0) { + Settings.syslog_port = (1 == payload16) ? SYS_LOG_PORT : payload16; + } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.syslog_port); } else if ((CMND_IPADDRESS == command_code) && (index > 0) && (index <= 4)) { @@ -1015,7 +1026,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) } else if ((CMND_NTPSERVER == command_code) && (index > 0) && (index <= 3)) { if ((data_len > 0) && (data_len < sizeof(Settings.ntp_server[0]))) { - strlcpy(Settings.ntp_server[index -1], (!strcmp(dataBuf,"0")) ? "" : (1 == payload) ? (1==index)?NTP_SERVER1:(2==index)?NTP_SERVER2:NTP_SERVER3 : dataBuf, sizeof(Settings.ntp_server[0])); + strlcpy(Settings.ntp_server[index -1], (SC_CLEAR == Shortcut(dataBuf)) ? "" : (SC_DEFAULT == Shortcut(dataBuf)) ? (1==index)?NTP_SERVER1:(2==index)?NTP_SERVER2:NTP_SERVER3 : dataBuf, sizeof(Settings.ntp_server[0])); for (i = 0; i < strlen(Settings.ntp_server[index -1]); i++) { if (Settings.ntp_server[index -1][i] == ',') Settings.ntp_server[index -1][i] = '.'; } @@ -1039,7 +1050,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) } else if ((CMND_SSID == command_code) && (index > 0) && (index <= 2)) { if ((data_len > 0) && (data_len < sizeof(Settings.sta_ssid[0]))) { - strlcpy(Settings.sta_ssid[index -1], (!strcmp(dataBuf,"0")) ? "" : (1 == payload) ? (1 == index) ? STA_SSID1 : STA_SSID2 : dataBuf, sizeof(Settings.sta_ssid[0])); + strlcpy(Settings.sta_ssid[index -1], (SC_CLEAR == Shortcut(dataBuf)) ? "" : (SC_DEFAULT == Shortcut(dataBuf)) ? (1 == index) ? STA_SSID1 : STA_SSID2 : dataBuf, sizeof(Settings.sta_ssid[0])); Settings.sta_active = index -1; restart_flag = 2; } @@ -1047,7 +1058,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) } else if ((CMND_PASSWORD == command_code) && (index > 0) && (index <= 2)) { if ((data_len > 0) && (data_len < sizeof(Settings.sta_pwd[0]))) { - strlcpy(Settings.sta_pwd[index -1], (!strcmp(dataBuf,"0")) ? "" : (1 == payload) ? (1 == index) ? STA_PASS1 : STA_PASS2 : dataBuf, sizeof(Settings.sta_pwd[0])); + strlcpy(Settings.sta_pwd[index -1], (SC_CLEAR == Shortcut(dataBuf)) ? "" : (SC_DEFAULT == Shortcut(dataBuf)) ? (1 == index) ? STA_PASS1 : STA_PASS2 : dataBuf, sizeof(Settings.sta_pwd[0])); Settings.sta_active = index -1; restart_flag = 2; snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.sta_pwd[index -1]); @@ -1057,7 +1068,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) } else if ((CMND_HOSTNAME == command_code) && !grpflg) { if ((data_len > 0) && (data_len < sizeof(Settings.hostname))) { - strlcpy(Settings.hostname, (1 == payload) ? WIFI_HOSTNAME : dataBuf, sizeof(Settings.hostname)); + strlcpy(Settings.hostname, (SC_DEFAULT == Shortcut(dataBuf)) ? WIFI_HOSTNAME : dataBuf, sizeof(Settings.hostname)); if (strstr(Settings.hostname,"%")) { strlcpy(Settings.hostname, WIFI_HOSTNAME, sizeof(Settings.hostname)); } @@ -1087,12 +1098,14 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) } else { snprintf_P(stemp1, sizeof(stemp1), PSTR(FRIENDLY_NAME "%d"), index); } - strlcpy(Settings.friendlyname[index -1], (1 == payload) ? stemp1 : dataBuf, sizeof(Settings.friendlyname[index -1])); + strlcpy(Settings.friendlyname[index -1], (SC_DEFAULT == Shortcut(dataBuf)) ? stemp1 : dataBuf, sizeof(Settings.friendlyname[index -1])); } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.friendlyname[index -1]); } else if ((CMND_SWITCHMODE == command_code) && (index > 0) && (index <= MAX_SWITCHES)) { - if ((payload >= 0) && (payload < MAX_SWITCH_OPTION)) Settings.switchmode[index -1] = payload; + if ((payload >= 0) && (payload < MAX_SWITCH_OPTION)) { + Settings.switchmode[index -1] = payload; + } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_NVALUE, command, index, Settings.switchmode[index-1]); } else if (CMND_TELEPERIOD == command_code) { @@ -1119,7 +1132,9 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) } } else if (CMND_TIMEZONE == command_code) { - if ((data_len > 0) && (((payload >= -13) && (payload <= 14)) || (99 == payload))) Settings.timezone = payload; + if ((data_len > 0) && (((payload >= -13) && (payload <= 14)) || (99 == payload))) { + Settings.timezone = payload; + } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.timezone); } else if ((CMND_TIMESTD == command_code) || (CMND_TIMEDST == command_code)) { @@ -1164,7 +1179,9 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) command, Settings.tflag[ts].hemis, Settings.tflag[ts].week, Settings.tflag[ts].month, Settings.tflag[ts].dow, Settings.tflag[ts].hour, Settings.toffset[ts]); } else if (CMND_ALTITUDE == command_code) { - if ((data_len > 0) && ((payload >= -30000) && (payload <= 30000))) Settings.altitude = payload; + if ((data_len > 0) && ((payload >= -30000) && (payload <= 30000))) { + Settings.altitude = payload; + } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.altitude); } else if (CMND_LEDPOWER == command_code) { @@ -1556,8 +1573,6 @@ void PerformEverySecond() SetDevicePower(power, SRC_RETRY); // Set required power on state } - if (blockgpio0) blockgpio0--; - if (seriallog_timer) { seriallog_timer--; if (!seriallog_timer) { @@ -1631,7 +1646,8 @@ void ButtonHandler() { uint8_t button = NOT_PRESSED; uint8_t button_present = 0; - uint8_t hold_time_extent = IMMINENT_RESET_FACTOR; // Extent hold time factor in case of iminnent Reset command + uint8_t hold_time_extent = IMMINENT_RESET_FACTOR; // Extent hold time factor in case of iminnent Reset command + uint16_t loops_per_second = 1000 / Settings.button_debounce; char scmnd[20]; uint8_t maxdev = (devices_present > MAX_KEYS) ? MAX_KEYS : devices_present; @@ -1645,43 +1661,45 @@ void ButtonHandler() snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON " " D_CODE " %04X"), dual_button_code); AddLog(LOG_LEVEL_DEBUG); button = PRESSED; - if (0xF500 == dual_button_code) { // Button hold - holdbutton[button_index] = (Settings.param[P_HOLD_TIME] * (STATES / 10)) -1; + if (0xF500 == dual_button_code) { // Button hold + holdbutton[button_index] = (loops_per_second * Settings.param[P_HOLD_TIME] / 10) -1; hold_time_extent = 1; } dual_button_code = 0; } } else { - if ((pin[GPIO_KEY1 +button_index] < 99) && !blockgpio0) { - button_present = 1; - button = digitalRead(pin[GPIO_KEY1 +button_index]); + if (pin[GPIO_KEY1 +button_index] < 99) { + if (!((uptime < 4) && (0 == pin[GPIO_KEY1 +button_index]))) { // Block GPIO0 for 4 seconds after poweron to workaround Wemos D1 RTS circuit + button_present = 1; + button = digitalRead(pin[GPIO_KEY1 +button_index]); + } } } if (button_present) { if (SONOFF_4CHPRO == Settings.module) { - if (holdbutton[button_index]) holdbutton[button_index]--; + if (holdbutton[button_index]) { holdbutton[button_index]--; } boolean button_pressed = false; if ((PRESSED == button) && (NOT_PRESSED == lastbutton[button_index])) { snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_LEVEL_10), button_index +1); AddLog(LOG_LEVEL_DEBUG); - holdbutton[button_index] = STATES; + holdbutton[button_index] = loops_per_second; button_pressed = true; } if ((NOT_PRESSED == button) && (PRESSED == lastbutton[button_index])) { snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_LEVEL_01), button_index +1); AddLog(LOG_LEVEL_DEBUG); - if (!holdbutton[button_index]) button_pressed = true; // Do not allow within 1 second + if (!holdbutton[button_index]) { button_pressed = true; } // Do not allow within 1 second } if (button_pressed) { - if (!SendKey(0, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set + if (!SendKey(0, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally } } } else { if ((PRESSED == button) && (NOT_PRESSED == lastbutton[button_index])) { - if (Settings.flag.button_single) { // Allow only single button press for immediate action + if (Settings.flag.button_single) { // Allow only single button press for immediate action snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_IMMEDIATE), button_index +1); AddLog(LOG_LEVEL_DEBUG); if (!SendKey(0, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set @@ -1691,7 +1709,7 @@ void ButtonHandler() multipress[button_index] = (multiwindow[button_index]) ? multipress[button_index] +1 : 1; snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_MULTI_PRESS " %d"), button_index +1, multipress[button_index]); AddLog(LOG_LEVEL_DEBUG); - multiwindow[button_index] = STATES /2; // 0.5 second multi press window + multiwindow[button_index] = loops_per_second / 2; // 0.5 second multi press window } blinks = 201; } @@ -1700,20 +1718,20 @@ void ButtonHandler() holdbutton[button_index] = 0; } else { holdbutton[button_index]++; - if (Settings.flag.button_single) { // Allow only single button press for immediate action - if (holdbutton[button_index] == Settings.param[P_HOLD_TIME] * (STATES / 10) * hold_time_extent) { // Button held for factor times longer + if (Settings.flag.button_single) { // Allow only single button press for immediate action + if (holdbutton[button_index] == loops_per_second * hold_time_extent * Settings.param[P_HOLD_TIME] / 10) { // Button held for factor times longer // Settings.flag.button_single = 0; snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_SETOPTION "13 0")); // Disable single press only ExecuteCommand(scmnd, SRC_BUTTON); } } else { - if (Settings.flag.button_restrict) { // Button restriction - if (holdbutton[button_index] == Settings.param[P_HOLD_TIME] * (STATES / 10)) { // Button hold + if (Settings.flag.button_restrict) { // Button restriction + if (holdbutton[button_index] == loops_per_second * Settings.param[P_HOLD_TIME] / 10) { // Button hold multipress[button_index] = 0; - SendKey(0, button_index +1, 3); // Execute Hold command via MQTT if ButtonTopic is set + SendKey(0, button_index +1, 3); // Execute Hold command via MQTT if ButtonTopic is set } } else { - if (holdbutton[button_index] == (Settings.param[P_HOLD_TIME] * (STATES / 10)) * hold_time_extent) { // Button held for factor times longer + if (holdbutton[button_index] == loops_per_second * hold_time_extent * Settings.param[P_HOLD_TIME] / 10) { // Button held for factor times longer multipress[button_index] = 0; snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_RESET " 1")); ExecuteCommand(scmnd, SRC_BUTTON); @@ -1722,13 +1740,13 @@ void ButtonHandler() } } - if (!Settings.flag.button_single) { // Allow multi-press + if (!Settings.flag.button_single) { // Allow multi-press if (multiwindow[button_index]) { multiwindow[button_index]--; } else { if (!restart_flag && !holdbutton[button_index] && (multipress[button_index] > 0) && (multipress[button_index] < MAX_BUTTON_COMMANDS +3)) { boolean single_press = false; - if (multipress[button_index] < 3) { // Single or Double press + if (multipress[button_index] < 3) { // Single or Double press if ((SONOFF_DUAL_R2 == Settings.module) || (SONOFF_DUAL == Settings.module) || (CH4 == Settings.module)) { single_press = true; } else { @@ -1739,13 +1757,13 @@ void ButtonHandler() if (single_press && SendKey(0, button_index + multipress[button_index], POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set // Success } else { - if (multipress[button_index] < 3) { // Single or Double press - if (WifiState()) { // WPSconfig, Smartconfig or Wifimanager active + if (multipress[button_index] < 3) { // Single or Double press + if (WifiState()) { // WPSconfig, Smartconfig or Wifimanager active restart_flag = 1; } else { ExecuteCommandPower(button_index + multipress[button_index], POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally } - } else { // 3 - 7 press + } else { // 3 - 7 press if (!Settings.flag.button_restrict) { snprintf_P(scmnd, sizeof(scmnd), kCommands[multipress[button_index] -3]); ExecuteCommand(scmnd, SRC_BUTTON); @@ -1770,6 +1788,7 @@ void SwitchHandler(byte mode) { uint8_t button = NOT_PRESSED; uint8_t switchflag; + uint16_t loops_per_second = 1000 / Settings.switch_debounce; for (byte i = 0; i < MAX_SWITCHES; i++) { if ((pin[GPIO_SWT1 +i] < 99) || (mode)) { @@ -1777,14 +1796,16 @@ void SwitchHandler(byte mode) if (holdwallswitch[i]) { holdwallswitch[i]--; if (0 == holdwallswitch[i]) { - SendKey(1, i +1, 3); // Execute command via MQTT + SendKey(1, i +1, 3); // Execute command via MQTT } } if (mode) { button = virtualswitch[i]; } else { - button = digitalRead(pin[GPIO_SWT1 +i]); + if (!((uptime < 4) && (0 == pin[GPIO_SWT1 +i]))) { // Block GPIO0 for 4 seconds after poweron to workaround Wemos D1 RTS circuit + button = digitalRead(pin[GPIO_SWT1 +i]); + } } if (button != lastwallswitch[i]) { @@ -1816,7 +1837,7 @@ void SwitchHandler(byte mode) break; case PUSHBUTTONHOLD: if ((PRESSED == button) && (NOT_PRESSED == lastwallswitch[i])) { - holdwallswitch[i] = Settings.param[P_HOLD_TIME] * (STATES / 10); + holdwallswitch[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 10; } if ((NOT_PRESSED == button) && (PRESSED == lastwallswitch[i]) && (holdwallswitch[i])) { holdwallswitch[i] = 0; @@ -1825,18 +1846,18 @@ void SwitchHandler(byte mode) break; case PUSHBUTTONHOLD_INV: if ((NOT_PRESSED == button) && (PRESSED == lastwallswitch[i])) { - holdwallswitch[i] = Settings.param[P_HOLD_TIME] * (STATES / 10); + holdwallswitch[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 10; } if ((PRESSED == button) && (NOT_PRESSED == lastwallswitch[i]) && (holdwallswitch[i])) { holdwallswitch[i] = 0; - switchflag = 2; // Toggle with pushbutton to Gnd + switchflag = 2; // Toggle with pushbutton to Gnd } break; } if (switchflag < 3) { if (!SendKey(1, i +1, switchflag)) { // Execute command via MQTT - ExecuteCommandPower(i +1, switchflag, SRC_SWITCH); // Execute command internally (if i < devices_present) + ExecuteCommandPower(i +1, switchflag, SRC_SWITCH); // Execute command internally (if i < devices_present) } } @@ -1849,15 +1870,6 @@ void SwitchHandler(byte mode) /*********************************************************************************************\ * State loops \*********************************************************************************************/ - -void Every50mSeconds() -{ - // As the max amount of sleep = 250 mSec this loop will shift in time... - - ButtonHandler(); - SwitchHandler(0); -} - /*-------------------------------------------------------------------------------------------*\ * Every 0.1 second \*-------------------------------------------------------------------------------------------*/ @@ -2607,20 +2619,25 @@ void loop() OsWatchLoop(); + if (TimeReached(button_debounce)) { + SetNextTimeInterval(button_debounce, Settings.button_debounce); + ButtonHandler(); + } + if (TimeReached(switch_debounce)) { + SetNextTimeInterval(switch_debounce, Settings.switch_debounce); + SwitchHandler(0); + } if (TimeReached(state_50msecond)) { SetNextTimeInterval(state_50msecond, 50); - Every50mSeconds(); XdrvCall(FUNC_EVERY_50_MSECOND); XsnsCall(FUNC_EVERY_50_MSECOND); } - if (TimeReached(state_100msecond)) { SetNextTimeInterval(state_100msecond, 100); Every100mSeconds(); XdrvCall(FUNC_EVERY_100_MSECOND); XsnsCall(FUNC_EVERY_100_MSECOND); } - if (TimeReached(state_250msecond)) { SetNextTimeInterval(state_250msecond, 250); Every250mSeconds(); diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h index 47c6bb893..c498dccec 100644 --- a/sonoff/sonoff_version.h +++ b/sonoff/sonoff_version.h @@ -20,7 +20,7 @@ #ifndef _SONOFF_VERSION_H_ #define _SONOFF_VERSION_H_ -#define VERSION 0x0601010B +#define VERSION 0x0601010C #define D_PROGRAMNAME "Sonoff-Tasmota" #define D_AUTHOR "Theo Arends" diff --git a/sonoff/support.ino b/sonoff/support.ino index 90e31ce9c..654c998b8 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -309,6 +309,31 @@ char* NoAlNumToUnderscore(char* dest, const char* source) return dest; } +void SetShortcut(char* str, uint8_t action) +{ + if ('\0' != str[0]) { // There must be at least one character in the buffer + str[0] = '0' + action; // SC_CLEAR, SC_DEFAULT, SC_USER + str[1] = '\0'; + } +} + +uint8_t Shortcut(const char* str) +{ + uint8_t result = 10; + + if ('\0' == str[1]) { // Only allow single character input for shortcut + if (('"' == str[0]) || ('0' == str[0])) { + result = SC_CLEAR; + } else { + result = atoi(str); // 1 = SC_DEFAULT, 2 = SC_USER + if (0 == result) { + result = 10; + } + } + } + return result; +} + boolean ParseIp(uint32_t* addr, const char* str) { uint8_t *part = (uint8_t*)addr; @@ -1186,6 +1211,7 @@ void WiFiSetSleepMode() * See https://github.com/arendst/Sonoff-Tasmota/issues/2559 */ +//#ifdef ARDUINO_ESP8266_RELEASE_2_4_1 #if defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2) #else // Enabled in 2.3.0, 2.4.0 and stage if (sleep) { diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 86761b663..3988bd8be 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -167,7 +167,9 @@ #define APP_BLINKCOUNT 10 // [BlinkCount] Number of blinks (0 = 32000) #define APP_SLEEP 0 // [Sleep] Sleep time to lower energy consumption (0 = Off, 1 - 250 mSec) +#define KEY_DEBOUNCE_TIME 50 // [ButtonDebounce] Number of mSeconds button press debounce time #define KEY_HOLD_TIME 40 // [SetOption32] Number of 0.1 seconds to hold Button or external Pushbutton before sending HOLD message +#define SWITCH_DEBOUNCE_TIME 50 // [SwitchDebounce] Number of mSeconds switch press debounce time #define SWITCH_MODE TOGGLE // [SwitchMode] TOGGLE, FOLLOW, FOLLOW_INV, PUSHBUTTON, PUSHBUTTON_INV, PUSHBUTTONHOLD, PUSHBUTTONHOLD_INV, PUSHBUTTON_TOGGLE (the wall switch state) #define WS2812_LEDS 30 // [Pixels] Number of WS2812 LEDs to start with (max is 512) @@ -292,8 +294,8 @@ // #define USE_SI1145 // Enable SI1145/46/47 sensor (I2C address 0x60) (+1k code) #define USE_LM75AD // Enable LM75AD sensor (I2C addresses 0x48 - 0x4F) (+0k5 code) // #define USE_APDS9960 // Enable APDS9960 Proximity Sensor (I2C address 0x39). Disables SHT and VEML6070 (+4k7 code) -// #define USE_MCP230xx // Enable MCP23008/MCP23017 for GP INPUT ONLY (I2C addresses 0x20 - 0x27) providing command Sensor29 for configuration (+2k2 code) -// #define USE_MCP230xx_OUTPUT // Enable MCP23008/MCP23017 OUTPUT support through sensor29 commands (+1k code) +// #define USE_MCP230xx // Enable MCP23008/MCP23017 for GP INPUT ONLY (I2C addresses 0x20 - 0x27) providing command Sensor29 for configuration (+4k7 code) +// #define USE_MCP230xx_OUTPUT // Enable MCP23008/MCP23017 OUTPUT support through sensor29 commands (+1k5 code) // #define USE_MCP230xx_DISPLAYOUTPUT // Enable MCP23008/MCP23017 to display state of OUTPUT pins on Web UI (+0k2 code) // #define USE_MPR121 // Enable MPR121 controller (I2C addresses 0x5A, 0x5B, 0x5C and 0x5D) in input mode for touch buttons (+1k3 code) // #define USE_CCS811 // Enable CCS811 sensor (I2C address 0x5A) (+2k2 code) diff --git a/sonoff/xdrv_01_mqtt.ino b/sonoff/xdrv_01_mqtt.ino index f03a75c19..de0df8f9f 100644 --- a/sonoff/xdrv_01_mqtt.ino +++ b/sonoff/xdrv_01_mqtt.ino @@ -555,7 +555,7 @@ bool MqttCommand() } else if (CMND_MQTTHOST == command_code) { if ((data_len > 0) && (data_len < sizeof(Settings.mqtt_host))) { - strlcpy(Settings.mqtt_host, (!strcmp(dataBuf,"0")) ? "" : (1 == payload) ? MQTT_HOST : dataBuf, sizeof(Settings.mqtt_host)); + strlcpy(Settings.mqtt_host, (SC_CLEAR == Shortcut(dataBuf)) ? "" : (SC_DEFAULT == Shortcut(dataBuf)) ? MQTT_HOST : dataBuf, sizeof(Settings.mqtt_host)); restart_flag = 2; } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.mqtt_host); @@ -587,14 +587,13 @@ bool MqttCommand() else if ((CMND_MQTTFINGERPRINT == command_code) && (index > 0) && (index <= 2)) { char fingerprint[60]; if ((data_len > 0) && (data_len < sizeof(fingerprint))) { - strlcpy(fingerprint, (!strcmp(dataBuf,"0")) ? "" : (1 == payload) ? (1 == index) ? MQTT_FINGERPRINT1 : MQTT_FINGERPRINT2 : dataBuf, sizeof(fingerprint)); + strlcpy(fingerprint, (SC_CLEAR == Shortcut(dataBuf)) ? "" : (SC_DEFAULT == Shortcut(dataBuf)) ? (1 == index) ? MQTT_FINGERPRINT1 : MQTT_FINGERPRINT2 : dataBuf, sizeof(fingerprint)); char *p = fingerprint; for (byte i = 0; i < 20; i++) { Settings.mqtt_fingerprint[index -1][i] = strtol(p, &p, 16); } restart_flag = 2; } - fingerprint[0] = '\0'; for (byte i = 0; i < sizeof(Settings.mqtt_fingerprint[index -1]); i++) { snprintf_P(fingerprint, sizeof(fingerprint), PSTR("%s%s%02X"), fingerprint, (i) ? " " : "", Settings.mqtt_fingerprint[index -1][i]); @@ -604,21 +603,21 @@ bool MqttCommand() #endif else if ((CMND_MQTTCLIENT == command_code) && !grpflg) { if ((data_len > 0) && (data_len < sizeof(Settings.mqtt_client))) { - strlcpy(Settings.mqtt_client, (1 == payload) ? MQTT_CLIENT_ID : dataBuf, sizeof(Settings.mqtt_client)); + strlcpy(Settings.mqtt_client, (SC_DEFAULT == Shortcut(dataBuf)) ? MQTT_CLIENT_ID : dataBuf, sizeof(Settings.mqtt_client)); restart_flag = 2; } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.mqtt_client); } else if (CMND_MQTTUSER == command_code) { if ((data_len > 0) && (data_len < sizeof(Settings.mqtt_user))) { - strlcpy(Settings.mqtt_user, (!strcmp(dataBuf,"0")) ? "" : (1 == payload) ? MQTT_USER : dataBuf, sizeof(Settings.mqtt_user)); + strlcpy(Settings.mqtt_user, (SC_CLEAR == Shortcut(dataBuf)) ? "" : (SC_DEFAULT == Shortcut(dataBuf)) ? MQTT_USER : dataBuf, sizeof(Settings.mqtt_user)); restart_flag = 2; } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.mqtt_user); } else if (CMND_MQTTPASSWORD == command_code) { if ((data_len > 0) && (data_len < sizeof(Settings.mqtt_pwd))) { - strlcpy(Settings.mqtt_pwd, (!strcmp(dataBuf,"0")) ? "" : (1 == payload) ? MQTT_PASS : dataBuf, sizeof(Settings.mqtt_pwd)); + strlcpy(Settings.mqtt_pwd, (SC_CLEAR == Shortcut(dataBuf)) ? "" : (SC_DEFAULT == Shortcut(dataBuf)) ? MQTT_PASS : dataBuf, sizeof(Settings.mqtt_pwd)); snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.mqtt_pwd); restart_flag = 2; } else { @@ -628,8 +627,8 @@ bool MqttCommand() else if (CMND_FULLTOPIC == command_code) { if ((data_len > 0) && (data_len < sizeof(Settings.mqtt_fulltopic))) { MakeValidMqtt(1, dataBuf); - if (!strcmp(dataBuf, mqtt_client)) payload = 1; - strlcpy(stemp1, (1 == payload) ? MQTT_FULLTOPIC : dataBuf, sizeof(stemp1)); + if (!strcmp(dataBuf, mqtt_client)) SetShortcut(dataBuf, SC_DEFAULT); + strlcpy(stemp1, (SC_DEFAULT == Shortcut(dataBuf)) ? MQTT_FULLTOPIC : dataBuf, sizeof(stemp1)); if (strcmp(stemp1, Settings.mqtt_fulltopic)) { snprintf_P(mqtt_data, sizeof(mqtt_data), (Settings.flag.mqtt_offline) ? S_OFFLINE : ""); MqttPublishPrefixTopic_P(TELE, PSTR(D_LWT), true); // Offline or remove previous retained topic @@ -642,7 +641,7 @@ bool MqttCommand() else if ((CMND_PREFIX == command_code) && (index > 0) && (index <= 3)) { if ((data_len > 0) && (data_len < sizeof(Settings.mqtt_prefix[0]))) { MakeValidMqtt(0, dataBuf); - strlcpy(Settings.mqtt_prefix[index -1], (1 == payload) ? (1==index)?SUB_PREFIX:(2==index)?PUB_PREFIX:PUB_PREFIX2 : dataBuf, sizeof(Settings.mqtt_prefix[0])); + strlcpy(Settings.mqtt_prefix[index -1], (SC_DEFAULT == Shortcut(dataBuf)) ? (1==index)?SUB_PREFIX:(2==index)?PUB_PREFIX:PUB_PREFIX2 : dataBuf, sizeof(Settings.mqtt_prefix[0])); // if (Settings.mqtt_prefix[index -1][strlen(Settings.mqtt_prefix[index -1])] == '/') Settings.mqtt_prefix[index -1][strlen(Settings.mqtt_prefix[index -1])] = 0; restart_flag = 2; } @@ -668,8 +667,8 @@ bool MqttCommand() else if (CMND_GROUPTOPIC == command_code) { if ((data_len > 0) && (data_len < sizeof(Settings.mqtt_grptopic))) { MakeValidMqtt(0, dataBuf); - if (!strcmp(dataBuf, mqtt_client)) payload = 1; - strlcpy(Settings.mqtt_grptopic, (1 == payload) ? MQTT_GRPTOPIC : dataBuf, sizeof(Settings.mqtt_grptopic)); + if (!strcmp(dataBuf, mqtt_client)) SetShortcut(dataBuf, SC_DEFAULT); + strlcpy(Settings.mqtt_grptopic, (SC_DEFAULT == Shortcut(dataBuf)) ? MQTT_GRPTOPIC : dataBuf, sizeof(Settings.mqtt_grptopic)); restart_flag = 2; } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.mqtt_grptopic); @@ -677,8 +676,8 @@ bool MqttCommand() else if ((CMND_TOPIC == command_code) && !grpflg) { if ((data_len > 0) && (data_len < sizeof(Settings.mqtt_topic))) { MakeValidMqtt(0, dataBuf); - if (!strcmp(dataBuf, mqtt_client)) payload = 1; - strlcpy(stemp1, (1 == payload) ? MQTT_TOPIC : dataBuf, sizeof(stemp1)); + if (!strcmp(dataBuf, mqtt_client)) SetShortcut(dataBuf, SC_DEFAULT); + strlcpy(stemp1, (SC_DEFAULT == Shortcut(dataBuf)) ? MQTT_TOPIC : dataBuf, sizeof(stemp1)); if (strcmp(stemp1, Settings.mqtt_topic)) { snprintf_P(mqtt_data, sizeof(mqtt_data), (Settings.flag.mqtt_offline) ? S_OFFLINE : ""); MqttPublishPrefixTopic_P(TELE, PSTR(D_LWT), true); // Offline or remove previous retained topic @@ -691,22 +690,26 @@ bool MqttCommand() else if ((CMND_BUTTONTOPIC == command_code) && !grpflg) { if ((data_len > 0) && (data_len < sizeof(Settings.button_topic))) { MakeValidMqtt(0, dataBuf); - if (!strcmp(dataBuf, mqtt_client)) payload = 1; - if (!strcmp(dataBuf,"0")) strlcpy(Settings.button_topic, "", sizeof(Settings.button_topic)); - else if (1 == payload) strlcpy(Settings.button_topic, mqtt_topic, sizeof(Settings.button_topic)); - else if (2 == payload) strlcpy(Settings.button_topic, MQTT_BUTTON_TOPIC, sizeof(Settings.button_topic)); - else strlcpy(Settings.button_topic, dataBuf, sizeof(Settings.button_topic)); + if (!strcmp(dataBuf, mqtt_client)) SetShortcut(dataBuf, SC_DEFAULT); + switch (Shortcut(dataBuf)) { + case SC_CLEAR: strlcpy(Settings.button_topic, "", sizeof(Settings.button_topic)); break; + case SC_DEFAULT: strlcpy(Settings.button_topic, mqtt_topic, sizeof(Settings.button_topic)); break; + case SC_USER: strlcpy(Settings.button_topic, MQTT_BUTTON_TOPIC, sizeof(Settings.button_topic)); break; + default: strlcpy(Settings.button_topic, dataBuf, sizeof(Settings.button_topic)); + } } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.button_topic); } else if (CMND_SWITCHTOPIC == command_code) { if ((data_len > 0) && (data_len < sizeof(Settings.switch_topic))) { MakeValidMqtt(0, dataBuf); - if (!strcmp(dataBuf, mqtt_client)) payload = 1; - if (!strcmp(dataBuf,"0")) strlcpy(Settings.switch_topic, "", sizeof(Settings.switch_topic)); - else if (1 == payload) strlcpy(Settings.switch_topic, mqtt_topic, sizeof(Settings.switch_topic)); - else if (2 == payload) strlcpy(Settings.switch_topic, MQTT_SWITCH_TOPIC, sizeof(Settings.switch_topic)); - else strlcpy(Settings.switch_topic, dataBuf, sizeof(Settings.switch_topic)); + if (!strcmp(dataBuf, mqtt_client)) SetShortcut(dataBuf, SC_DEFAULT); + switch (Shortcut(dataBuf)) { + case SC_CLEAR: strlcpy(Settings.switch_topic, "", sizeof(Settings.switch_topic)); break; + case SC_DEFAULT: strlcpy(Settings.switch_topic, mqtt_topic, sizeof(Settings.switch_topic)); break; + case SC_USER: strlcpy(Settings.switch_topic, MQTT_SWITCH_TOPIC, sizeof(Settings.switch_topic)); break; + default: strlcpy(Settings.switch_topic, dataBuf, sizeof(Settings.switch_topic)); + } } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.switch_topic); } diff --git a/sonoff/xdrv_02_webserver.ino b/sonoff/xdrv_02_webserver.ino index caa002aa4..b7ca9ecd8 100644 --- a/sonoff/xdrv_02_webserver.ino +++ b/sonoff/xdrv_02_webserver.ino @@ -2019,7 +2019,7 @@ bool WebCommand() } else if (CMND_WEBPASSWORD == command_code) { if ((XdrvMailbox.data_len > 0) && (XdrvMailbox.data_len < sizeof(Settings.web_password))) { - strlcpy(Settings.web_password, (!strcmp(XdrvMailbox.data,"0")) ? "" : (1 == XdrvMailbox.payload) ? WEB_PASSWORD : XdrvMailbox.data, sizeof(Settings.web_password)); + strlcpy(Settings.web_password, (SC_CLEAR == Shortcut(XdrvMailbox.data)) ? "" : (SC_DEFAULT == Shortcut(XdrvMailbox.data)) ? WEB_PASSWORD : XdrvMailbox.data, sizeof(Settings.web_password)); snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.web_password); } else { snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_ASTERIX, command); diff --git a/sonoff/xdrv_06_snfbridge.ino b/sonoff/xdrv_06_snfbridge.ino index 729cd51dc..73c93d374 100644 --- a/sonoff/xdrv_06_snfbridge.ino +++ b/sonoff/xdrv_06_snfbridge.ino @@ -316,13 +316,20 @@ void SonoffBridgeReceived() boolean SonoffBridgeSerialInput() { // iTead Rf Universal Transceiver Module Serial Protocol Version 1.0 (20170420) + int8_t receive_len = 0; + if (sonoff_bridge_receive_flag) { if (sonoff_bridge_receive_raw_flag) { if (!serial_in_byte_counter) { serial_in_buffer[serial_in_byte_counter++] = 0xAA; } serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; - if (0x55 == serial_in_byte) { // 0x55 - End of text + if (serial_in_byte_counter > 2) { + if ((0xA6 == serial_in_buffer[1]) || (0xAB == serial_in_buffer[1])) { // AA A6 06 023908010155 55 - 06 is receive_len + receive_len = serial_in_buffer[2] + 3 - serial_in_byte_counter; // Get at least receive_len bytes + } + } + if ((0 == receive_len) && (0x55 == serial_in_byte)) { // 0x55 - End of text SonoffBridgeReceivedRaw(); sonoff_bridge_receive_flag = 0; return 1; diff --git a/sonoff/xdrv_10_rules.ino b/sonoff/xdrv_10_rules.ino index 4139d0273..f0b8611f6 100644 --- a/sonoff/xdrv_10_rules.ino +++ b/sonoff/xdrv_10_rules.ino @@ -155,6 +155,24 @@ bool RulesRuleMatch(byte rule_set, String &event, String &rule) break; } } + snprintf_P(stemp, sizeof(stemp), PSTR("%%TIME%%")); + if (rule_param.startsWith(stemp)) { + rule_param = String(GetMinutesPastMidnight()); + } + snprintf_P(stemp, sizeof(stemp), PSTR("%%UPTIME%%")); + if (rule_param.startsWith(stemp)) { + rule_param = String(GetMinutesUptime()); + } +#if defined(USE_TIMERS) && defined(USE_SUNRISE) + snprintf_P(stemp, sizeof(stemp), PSTR("%%SUNRISE%%")); + if (rule_param.startsWith(stemp)) { + rule_param = String(GetSunMinutes(0)); + } + snprintf_P(stemp, sizeof(stemp), PSTR("%%SUNSET%%")); + if (rule_param.startsWith(stemp)) { + rule_param = String(GetSunMinutes(1)); + } +#endif // USE_TIMERS and USE_SUNRISE rule_param.toUpperCase(); snprintf(rule_svalue, sizeof(rule_svalue), rule_param.c_str()); @@ -522,13 +540,13 @@ boolean RulesCommand() } else if ((CMND_VAR == command_code) && (index > 0) && (index <= MAX_RULE_VARS)) { if (XdrvMailbox.data_len > 0) { - strlcpy(vars[index -1], ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data, sizeof(vars[index -1])); + strlcpy(vars[index -1], (SC_CLEAR == Shortcut(XdrvMailbox.data)) ? "" : XdrvMailbox.data, sizeof(vars[index -1])); } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, vars[index -1]); } else if ((CMND_MEM == command_code) && (index > 0) && (index <= MAX_RULE_MEMS)) { if (XdrvMailbox.data_len > 0) { - strlcpy(Settings.mems[index -1], ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data, sizeof(Settings.mems[index -1])); + strlcpy(Settings.mems[index -1], (SC_CLEAR == Shortcut(XdrvMailbox.data)) ? "" : XdrvMailbox.data, sizeof(Settings.mems[index -1])); } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.mems[index -1]); } diff --git a/tools/fw_efm8bb1/RF_Bridge_00.hex b/tools/fw_efm8bb1/RF-Bridge-EFM8BB1-20180320.hex similarity index 100% rename from tools/fw_efm8bb1/RF_Bridge_00.hex rename to tools/fw_efm8bb1/RF-Bridge-EFM8BB1-20180320.hex diff --git a/tools/fw_efm8bb1/RF-Bridge-EFM8BB1-20180816.hex b/tools/fw_efm8bb1/RF-Bridge-EFM8BB1-20180816.hex new file mode 100644 index 000000000..b51bb158c --- /dev/null +++ b/tools/fw_efm8bb1/RF-Bridge-EFM8BB1-20180816.hex @@ -0,0 +1,451 @@ +:020000040000FA +:10000000021197ED24F8FEEFD39E4015ED2408FD74 +:10001000E433FCC3EF9DEC6480F874809850028058 +:1000200001C322021078E4F5A922220215927EFF74 +:10003000EFD394004022EF9480501DE4FDED75F065 +:1000400005A42486F582E4341BF583E493B5070404 +:10005000AE0580040DBD06E5AF06220212AE121AEF +:10006000BB53D87853DBFE121A7CE4900085F02253 +:10007000D2DE220215E5D201121883C290C296D2B6 +:1000800080E4FBFD7F10121A6312061E74A4F0D2E6 +:10009000AFE4F537F538D2960538E5387002053704 +:1000A000B410F3E537B427EEC2963001091217C534 +:1000B0008E3A8F3B8006753A01753B00E53B700434 +:1000C000E53A640170409000CCE07007F537F538F0 +:1000D0000202870538E53870020537D39410E537FA +:1000E00094274002D296D3E5389430E53794755082 +:1000F00003020287E4F537F5389000CCF09000CB8E +:10010000F0C296020287E4F537F5389000CCE0148F +:10011000602A14700302025914700302021E147044 +:100120000302023424046003020287E53B64AA60F0 +:10013000030202879000CC04F0020287E53B9000A6 +:10014000CBF0A37402F0E53B120BE00206A00170B5 +:10015000A10182A501A6A601BAA701C3A801DFA932 +:1001600001C6B001CFB10197C00287FF00000215A0 +:100170001205D79000A87401F0E4900075F07FA1FB +:10018000806E12005E9000CC7404F0753908E4F5BE +:100190003D753C090202879000CC7404F0E4F53D03 +:1001A000753C02020287E49000A8F0900075F07F91 +:1001B000A612064F74A6F002028712061E74A4F05F +:1001C0000202877539089000CC7403F00202879010 +:1001D00000757401F07FB112064FEFF00202871232 +:1001E00005D79000A8E0F536E4F0900075F07FA9FF +:1001F00012174D90007CEFF07D307C757F017E0002 +:100200001218D602028712063290007CEFF0E490BA +:1002100000CCF08072E49000CBF0A3F08069E4F5AC +:100220003DE53BF53CE53CD394009000CC40257483 +:1002300004F080537404253DF582E43400F583E531 +:100240003BF0053DE53D653C6007E53DC3947040EE +:10025000369000CC7402F0802EE53B6455702890F7 +:1002600000CCF0C2019000CBE02460601824FC6058 +:100270000F24FE600B14600824F66004241070073D +:100280007FA0121A30D2019000CBE0120BE002B036 +:10029000A102DAA402ECA503B5A603D1A804F1A932 +:1002A000052EB005A1B1037DC003A3FF000000AA85 +:1002B000900084E030E70F7DC87C001206077FA322 +:1002C00012168102050B121A7440030200AA7DE87F +:1002D0007C031206077FA2020526900084E020E737 +:1002E000030200AA7FA41216810203C99000CCE089 +:1002F00060030200AA900085E024FC6049240460A9 +:10030000030200AA1539900008E0FEA3E0FF1215D1 +:100310002C8F46900006E0FEA3E0FF8E47F54812C2 +:10032000152C8F49754A18900008E0FAA3E0FB905D +:100330000004E0FCA3E0FDA3E0FEA3E0FF120656EC +:100340007406F00204BD7F0112002EEF12157C60CE +:10035000030200AAE539601D1205B812158CD3946A +:100360000050030204E21205B812158C12063B126B +:100370001AAD0204E21206327FA00205269000CCDC +:10038000E060030200AA900004E0FCA3E0FD7F010E +:100390007E001218D6D296121AADC2967FA0121AFB +:1003A00030800AE4FF121A30E49000CCF0D201123F +:1003B00006460200AA900084E020E7030200AA5447 +:1003C0007FF53FFD7FA61214B4E4900084F0020094 +:1003D000AA9000CCE060030200AA900085E024FC13 +:1003E00070030204C3240460030200AA12157A6099 +:1003F000030200AA153912005E900004E0647F70C9 +:1004000036A3E0FCA3E0FFAE04900009E0FCA3E00B +:10041000FBAA04A3E0F546A3E0F547A3E0F548A353 +:10042000E0F549A3E0F54A900007E0FCA3E0FD12E7 +:100430000656740CF0807D900004E0FF12002E8FB1 +:100440003EE53EF46069EF121561120A60FFAEF0FE +:10045000C006C00712155F900002120A8BFFAEF0B3 +:10046000C006C007900005120A8BFDACF0C004C0A6 +:1004700005900009120984FF900007120A8BFDAC59 +:10048000F090000A120984FE90000B120984F54ACC +:100490008E498C478D488F46D003D002D005D004BA +:1004A000D007D00612143A9000747401F08005E46D +:1004B0009000CBF09000CBE070030200AA1219AAC2 +:1004C0000200AA12157A60030200AAE539601B1225 +:1004D000155F12158CFFD394004007EF12063B12F4 +:1004E0001AADE4900085F00200AA1206467FA080B3 +:1004F00035900084E0FF30E71C547FF53F7DC87CD9 +:10050000001205EAAD3F7FAB1214B4E4900084F012 +:10051000D2010200AA121A7440030200AA7DE87CEC +:10052000031205EA7FAA121A30D2010200AA900033 +:1005300004E025E0F53F9000CCE060030200AA90C3 +:100540000085E0700512005E800B900085E0640479 +:1005500060030200AAE53F6007E53CC3940450082D +:10056000E49000CBF00200AA7406253FF9E43400C1 +:10057000754301F5448945C3E53C953F24FEF546A6 +:10058000900005E0F5477B017A0079061213337F6E +:10059000A0121A3090007CE0FF12174DD201020029 +:1005A000AA900084E020E7030200AA7FB11213B8EA +:1005B000E4900084F00200AA7F0112002EEF75F093 +:1005C00005A4241CF582E4341BF583E493FB740139 +:1005D00093FA740293F9227D327C007F017E00122F +:1005E00018D6D296121AADC296227F017E0012183A +:1005F000D6D296121AADC2969000A8E536F09000B9 +:100600007CE0FF12174D227F017E001218D6D29691 +:10061000121AADC29690007CE0FF12174D22900096 +:10062000A87401F0E4900075F07FA412174D9000BB +:100630007C2290007CE0FF12174D22FD7C007F01A0 +:100640007E001218D62290007CE0FF12174D221275 +:10065000174D90007C2212143A90007422AFE9AE3C +:10066000EA7C007D0A1209C38E088F0920930302D9 +:1006700008EE85080A85090BC3E509950DF511E516 +:1006800008950CF510900075E01470030208E8045A +:10069000600302090F900085E014606504600302A6 +:1006A000090F900084E0600302090F9000A8E0FFAA +:1006B000AB11AA10AD0FAC0E120FCA8F12E5126467 +:1006C00080700302090F90007F120FA5900002E5D1 +:1006D00010F0A3E511120F0AE4900074F090007777 +:1006E000F090007EF0F513F514FE7F70FD7B017A2B +:1006F000007904120C33E490007DF090008504F042 +:1007000022E512120F2F700302082A046003020967 +:100710000FE512120E3F900004120984FFD39400DB +:10072000400B90007EE09F5004E004F022120F483E +:10073000AE10AF11AB07AA06E50F2BFFE50E3AFE90 +:10074000E433FDE433FCC004A905AA06AB07AE0EF2 +:10075000AF0F120FADD000120B4E8F22E512120E0A +:100760003F900009120984FD120003401BE512129C +:100770000E3F90000A12097A400EE512120E3F1247 +:100780000EE16F60030208A3E512120E3F9000090C +:1007900012097A500CE512120E3F120EE1C39F406F +:1007A00016D3E50F9514E50E9513402EE512120EA3 +:1007B0003F120EE16F7023900086120FA5120E58A3 +:1007C000C083C082120F407401A806088002C333A0 +:1007D000D8FC4FD082D083F0801790007A120FA5FA +:1007E000C290D39514E50E95134006850E13850F20 +:1007F00014900088E0700D120E5A120EF0FF1219BC +:10080000C5120F06E512120E3F120EE16F600302D1 +:10081000090F121A6C5005E4900083F0120EED706F +:10082000030208E012095C0208E0E512120E3F9094 +:10083000000B120984FF7E00900004120A8BFDACAD +:10084000F01209C3120F198E238F24120F48E512DC +:10085000120E3F9000061209105011E512120E3FC1 +:100860009000071209365004C2908041E512120E22 +:100870003F900008120910502AE512120E3F900016 +:1008800009120936501D120E58C083C082120F4043 +:100890007401A806088002C333D8FC4FD082D083ED +:1008A000F0800AE4900084F0C290A3F022900088C7 +:1008B000E0700D120E5A120EF0FF1219C5120F063B +:1008C000E512120E3F90000A120EE46F7041121AE8 +:1008D0006C5005E4900083F0120EED600312095C89 +:1008E000C290E4900085F022AF11AE10801E850802 +:1008F0000C85090DC3E509950BF50FE508950AF57B +:100900000E900075E0147007AF0FAE0E120C5F2250 +:10091000120984FD7C00900004120A8BFFAEF012D5 +:1009200009C3C3E50F9FFFE50E9EFE121A24C3EF15 +:100930009524EE952322120984FD7C009000041278 +:100940000A8BFFAEF01209C3C3E5119FFFE5109EAD +:10095000FE121A24C3EF9524EE952322121A7C7DF1 +:10096000207C037F017E001218AD90007DE0900096 +:1009700083F0A3E512F04480F022120984FDAF2237 +:1009800012000322BB010CE58229F582E5833AF5CA +:1009900083E0225006E92582F8E622BBFE06E9251F +:1009A00082F8E222E58229F582E5833AF583E49331 +:1009B00022BB010689828A83F0225002F722BBFE05 +:1009C00001F322EF8DF0A4A8F0CF8CF0A428CE8DF7 +:1009D000F0A42EFE22BC000BBE0029EF8DF084FF98 +:1009E000ADF022E4CCF875F008EF2FFFEE33FEEC0B +:1009F00033FCEE9DEC984005FCEE9DFE0FD5F0E932 +:100A0000E4CEFD22EDF8F5F0EE8420D21CFEADF030 +:100A100075F008EF2FFFED33FD4007985006D5F035 +:100A2000F222C398FD0FD5F0EA22C2D5EC30E709D7 +:100A3000B2D5E4C39DFDE49CFCEE30E715B2D5E4ED +:100A4000C39FFFE49EFE1209D5C3E49DFDE49CFC18 +:100A500080031209D530D507C3E49FFFE49EFE2230 +:100A6000BB010A89828A83E0F5F0A3E02250068761 +:100A7000F009E71922BBFE07E3F5F009E319228923 +:100A8000828A83E493F5F074019322BB0110E5821E +:100A900029F582E5833AF583E0F5F0A3E0225009D9 +:100AA000E92582F886F008E622BBFE0AE92582F8ED +:100AB000E2F5F008E222E5832AF583E993F5F0A355 +:100AC000E99322E88FF0A4CC8BF0A42CFCE98EF003 +:100AD000A42CFC8AF0EDA42CFCEA8EF0A4CDA8F0A6 +:100AE0008BF0A42DCC3825F0FDE98FF0A42CCD356A +:100AF000F0FCEB8EF0A4FEA9F0EB8FF0A4CFC5F0D4 +:100B00002ECD39FEE43CFCEAA42DCE35F0FDE43CCC +:100B1000FC2275F008758200EF2FFFEE33FECD3317 +:100B2000CDCC33CCC58233C5829BED9AEC99E5825E +:100B300098400CF582EE9BFEED9AFDEC99FC0FD5EA +:100B4000F0D6E4CEFBE4CDFAE4CCF9A88222B800DA +:100B5000C1B90059BA002DEC8BF084CFCECDFCE5A5 +:100B6000F0CBF97818EF2FFFEE33FEED33FDEC33C9 +:100B7000FCEB33FB10D703994004EB99FB0FD8E54E +:100B8000E4F9FA227818EF2FFFEE33FEED33FDEC97 +:100B900033FCC933C910D7059BE99A4007EC9BFC8D +:100BA000E99AF90FD8E0E4C9FAE4CCFB2275F01019 +:100BB000EF2FFFEE33FEED33FDCC33CCC833C8103E +:100BC000D7079BEC9AE899400AED9BFDEC9AFCE86C +:100BD00099F80FD5F0DAE4CDFBE4CCFAE4C8F922B9 +:100BE000D083D082F8E4937012740193700DA3A3A4 +:100BF00093F8740193F5828883E4737402936860B8 +:100C0000EFA3A3A380DFEC8EF0A4CCC5F0CCCDF88D +:100C1000EFA4CEC5F02DFDE43CFCE8A42EC8C5F041 +:100C20003DFDE43CFCEFA4FFE5F028FEE43DFDE4DF +:100C30003CFC22EF4E6012EF60010EEDBB010B8910 +:100C4000828A83F0A3DFFCDEFA2289F05007F709DD +:100C5000DFFCA9F022BBFEFCF309DFFCA9F0228E29 +:100C6000258F26900085E0146035147003020D3D39 +:100C700024026003020E0EC290900084E060030222 +:100C80000E0EAF26AE251219F24003020E0EE490AE +:100C90000001F0120F8E9000857401F0D290229026 +:100CA0000078E0FCA3E0FDAE047802CEC313CE13BF +:100CB000D8F92DFFEC3EFED3E5269FE5259E4009A1 +:100CC000120F8EE4900001F022AF26AE2512178A93 +:100CD000501F900001E094004017E4900074F090E1 +:100CE00000887404F0E490007DF09000857402F0B8 +:100CF00022C3E5269464E52594005003020DA31257 +:100D00000E0F501C120EF8E0FEA3E02526FFE5258D +:100D10003EC313FEEF13FF120EF8EEF0A3EFF02226 +:100D2000900001E0120EFA120F91900001E004F021 +:100D3000E0D3941E5003020E0EE4020DFFB290AFFA +:100D400026AE2512178A505E121A6C5005E49000E8 +:100D500083F0120EED604A121A7C7DF47C017F0153 +:100D60007E001218AD90007DE0900083F090008826 +:100D7000E07019120E78C083C082E0FF900001E09D +:100D8000540FFEEF4ED082D083F0800E900001E031 +:100D9000C454F0440F120E77EFF0900084E04480CA +:100DA000F0C290E48064120E0F5057900088E0B4B7 +:100DB0000410E527C454F0120E77EFF0E490008899 +:100DC000F022900074E0FF120E7CE0FEE527540F45 +:100DD000FDEE4DF074042F120E7E120EF0FF12196C +:100DE000C5EFF0900074E004F09000887404F09077 +:100DF0000074E0D394704016121A7CE4900001F065 +:100E00008008121A7CE4900001F0900085F0227BAB +:100E1000007A007927AF26AE2512122622E52B751F +:100E2000F005A42488F582E4341BF583E493FB7475 +:100E30000193FA740293F9120A60FFAEF0E52B7584 +:100E4000F005A42488F582E4341BF583E493FB7455 +:100E50000193FA740293F922D290900077E024FF74 +:100E6000FFE434FFFE7C007D08120A2A74042FF58B +:100E70008274003EF58322FF900074E02404F58222 +:100E8000E43400F58322120B4EAB07AA06E4F9F80E +:100E90007F407E427D0FFC120B4EE47BFFFAF9F897 +:100EA000120AC3A804A905AA06AB077F207ED77D36 +:100EB000757C01120B4EEFF40422AE28AF297C00A2 +:100EC0007D1F1209D58E2C8F2D7C007D051209D532 +:100ED000C3E52D9FFDE52C9EFCD3E5279DE5269CD3 +:100EE0002290000B120984FF900077E0229000838B +:100EF000E0FF90007DE06F22E52725E0248AF5825F +:100F0000E43400F5832290007DEFF09000887408AF +:100F1000F02275F0FFA4FFAEF07C007D640209D5DD +:100F2000E53524C8FFE43534FEC3ED9FEC9E227501 +:100F3000F005A42487F582E4341BF583E49314229E +:100F4000E0FF900088E0FE22900088E014F090001E +:100F500077E004F022E5352438FFE53434FFFED392 +:100F6000ED9FEC9E22E52D2FFFE52C3EFEC3E527ED +:100F70009FE5269E2253DAFE53F7DF53F7BF22ABDD +:100F800043AA44A9458548827583000209849000DC +:100F900078E525F0A3E526F022900081E0FF90009F +:100FA00077E0D39F22E50EF0A3E50FF0227C007DD1 +:100FB00064020C06540F75F002A4F58285F08322BA +:100FC000D3E5299494E5289411228F258C268D272A +:100FD0008A288B29752A80E5257052E4F52B7F013C +:100FE00012002EEF652B701B120FC04035E52994BF +:100FF00050E5289446502B120EBA4026120F655029 +:10100000218054E52B120F2F600D047015120E1D58 +:1010100012105D500D8008120E1D12105D500385D8 +:101020002B2A052BE52BC3940640B3802DAF251248 +:10103000002E8F2B7F0112002EEF652B701C120FDC +:10104000C04017E5299450E5289446500D120EBA79 +:101050004008120F655003852B2AAF2A2290000208 +:10106000120A8BF53585F034AB07AA06AD29AC28FA +:10107000AF27AE2612163822C0E0C0F0C083C0826F +:10108000C0D075D000C000C001C002C003C004C001 +:1010900005C006C007E5985403F54FF45298E54F94 +:1010A00030E017121AC49000C0121742EFF09000FF +:1010B000C0E004F0E0B41402E4F0E54F30E12E901B +:1010C00000C2E0D39400401A9000BFE02450F8E63C +:1010D000FF121AC19000BFE004F09000C2E014F0CB +:1010E0008002D2029000BFE0B42002E4F0D007D02A +:1010F00006D005D004D003D002D001D000D0D0D08B +:1011000082D083D0F0D0E0324200C700004200C35A +:1011100000004200C900004200C500004100CC00B0 +:101120004100CB0041008400410085004100A8003F +:101130004100750041007C0041007656410089ABBA +:10114000410000004100820042007F000042000296 +:101150000000420086000042007A00004100810049 +:10116000410088004100770041007E00410074008A +:101170004100830041007D00410001004100C000AA +:101180004100C1004100BE004100BF004100C2005B +:101190004100BD00C1020012002A787FE4F6D8FDAC +:1011A00075816F0211E1020076E493A3F8E493A342 +:1011B0004003F68001F208DFF48029E493A3F85499 +:1011C00007240CC8C333C4540F4420C8834004F41C +:1011D00056800146F6DFE4800B010204081020402F +:1011E00080901108E47E019360BCA3FF543F30E57A +:1011F00009541FFEE493A360010ECF54C025E060A4 +:10120000A840B8E493A3FAE493A3F8E493A3C8C571 +:1012100082C8CAC583CAF0A3C8C582C8CAC583CA62 +:10122000DFE9DEE780BE8E288F298B2A8A2B892C66 +:10123000C200E4F52D900001E0FFE52DC39F506B47 +:10124000E529AE287803CEC313CE13D8F9FDAC063A +:10125000E529AE287802CEC313CE13D8F92DF52F89 +:10126000EE3CF52EE52D120EFAE0FEA3E0FFC3954D +:101270002FFDEE952EFCC3ED9529EC95285028E521 +:101280002F2FFFE52E3EFEC3E5299FE5289E501730 +:10129000E52C452B452A600BAB2AAA2BA92CE52D62 +:1012A0001209B1D2008004052D808AA20022C0E07C +:1012B000C0F0C083C082C0D075D000C000C001C0E3 +:1012C00002C003C004C005C006C007E5D85487F5B6 +:1012D00021F452D8E5F730E508E5F730E6031217B8 +:1012E000FB53F7DFE52130E708E5D930E003121AB8 +:1012F000CAE52130E008E5DA30E0031218FFE52105 +:1013000030E108E5DB30E00312065DE52130E2085C +:10131000E5DC30E003121ACBD007D006D005D004AC +:10132000D003D002D001D000D0D0D082D083D0F072 +:10133000D0E0328B408A41894253DBFE120F755355 +:10134000E2FDE4F548E548C39546504FAB40AA415D +:10135000A942C003C002C001120F7FC4120FB4D053 +:1013600001D002D003120A8BF54A85F049D28012CF +:1013700013AAAB40AA41A942C003C002C001120F88 +:101380007F120FB4D001D002D003120A8BF54A8528 +:10139000F049C2801213AA054880AAB290AF47153F +:1013A00047EF709E43E202C29022FDAC497F0A7E65 +:1013B0000012182C121AAD22AE07E4F54012194B98 +:1013C000900001E004FF121952121433900001E062 +:1013D000FFE540C39F501212173612172912173615 +:1013E000F583121730054080E3900078E0FF121972 +:1013F00052900078121730121433E4F540900074C4 +:10140000E02401FFE433FEC3E5409FEE6480F874FE +:1014100080985017740425401217240540E5405465 +:101420001F70DA121ABE121AB780D27F55121952E3 +:10143000021ABE121ABE121AB7228E408F418C4277 +:101440008D43AE02AF03120FADC007AF46AB07E44A +:10145000FAF9F8D007120E86900000F0AE47AF48B8 +:10146000120FADC007AF49AB07E4FAF9F8D0071285 +:101470000E86900082F0E546120F12900076EFF093 +:10148000E549120F12900089EFF090007FE540F0DF +:10149000A3E541F0900002E542F0A3E543F090009F +:1014A00081E54AF043DA0153F7DF43F74053DBFEAF +:1014B00075F9FF22AC05AB07E4FEFDFA7FAA12190D +:1014C00052AF03121952EC75F005A424F3F582E42F +:1014D000341BF583E49314600B04701212170A9006 +:1014E000000B800612170A90000A120984FAEEC354 +:1014F0009A500774082EFE0D80F4ED04FF12195265 +:10150000EC75F005A424F2F582E4341BF583E49332 +:10151000FF121952E4FEEEC39D500974042E1217F7 +:10152000240E80F27F55121952021ABE7C007D648F +:10153000120C06A804A905AA06AB07900006E0FE57 +:10154000A3E0FFA3E0FCA3E02FFDEC3EAF05FEE42B +:10155000FDC8FCEDC9FDEECAFEEFCBFF020B4EE568 +:101560003E75F005A4241CF582E4341BF583E49356 +:10157000FB740193FA740293F922E53E75F005A419 +:10158000241BF582E4341BF583E4932290000C02C3 +:101590000984C0E0C083C082C0D075D000C004C040 +:1015A00005C006C00753C87F9000C7E0FEA3E0FF58 +:1015B0004E700353C8FB9000C31216FF50099000F1 +:1015C000C7E4F0A3F0800DC39000C8E09DF0900048 +:1015D000C7E09CF0D007D006D005D004D0D0D08290 +:1015E000D083D0E032C0E0C083C082C0D075D000CC +:1015F000C004C005C006C00753917F9000C9E0FE3B +:10160000A3E0FF4E70035391FB9000C51216FF50EC +:10161000099000C9E4F0A3F0800DC39000CAE09DDA +:10162000F09000C9E09CF0D007D006D005D004D0DF +:10163000D0D082D083D0E032C200D3EB9400EA94C1 +:1016400000402FEB2438F582EA34FFF583D3EF9581 +:1016500082EE95834028EB24C8FBE43AFAC3EF9B63 +:10166000EE9A501A120F554015120F205010D2004A +:10167000800C120F554007120F205002D200A2001A +:1016800022AE07E4FDF54012194B900002E0FF1274 +:10169000195290000212173090007AE0FF1219528E +:1016A00090007A121730900086E0FF1219529000D5 +:1016B0008612173074042D1217240DBD03F67F55C2 +:1016C000121952021ABEAB07AA06E4F9F87F407E4F +:1016D000427D0FFC120B4EA804A905AA06AB077F9A +:1016E000207ED77D757C01120B4EC3E49FFFE49EE4 +:1016F000FE22AB07AA06E4F9F87FE87E03FD22E0AC +:10170000FCA3E0FDC3EF9DEE9C22EC75F005A42444 +:10171000F4F582E4341BF583E493FB740193FA74CB +:101720000293F922F582E43400F583E0FF021952B6 +:10173000A3E0FF021952E54025E0248AF582E43453 +:101740000022E024A9F582E43400F583228F409042 +:10175000007CE0F5417F0B121AC743DB01120F75C5 +:101760001200707D0A7C007F017E001218D6121ACA +:10177000AD43E202E4900085F0900084F09000CB4D +:10178000E540F090007CF0AF4122AD07AC06900040 +:1017900078E0FEA3E07802CEC313CE13D8F9FFC3DE +:1017A000900079E09FFB900078E09EFAC3EB9DEA01 +:1017B0009C5010A3E02FFF900078E03E120F2850BD +:1017C000028001C3229000C0E0FF9000BEE0B50798 +:1017D000057E017F00229000BE121742E0FD7C00D2 +:1017E0009000BEE004F0E0B41402E4F09000BDE02C +:1017F000FEEE4204E4F0AE04AF0522120F9940035E +:1018000002198C120E78120F40EFA806088002C34E +:1018100013D8FC30E00B900000E0FF121AC7D29002 +:1018200022900082E0FF121AC7C290228E4B8F4C8A +:101830008C4D8D4E1216C6121A0CE54E24BF900028 +:10184000CAF0E54D34FF9000C9F09000C5E54BF0BB +:10185000A3E54CF043910422D29053E2FDD2809054 +:10186000007F121873C290C2809000021218734356 +:10187000E20222E0FCA3E0FD7F0A7E0012182C1297 +:101880001AAD22121A83121A8A121A91121A3B12D4 +:1018900000261219DC121A59121A45121A4F121A7E +:1018A00018121A98121A9F121AB3021AA68E288FAB +:1018B000298C2A8D2B1216F21216D3121A009000C0 +:1018C000C7E52AF0A3E52BF09000C3E528F0A3E5D7 +:1018D00029F043C804228E428F438C448D45121652 +:1018E000F21216D3121A0C9000C9E544F0A3E54594 +:1018F000F09000C5E542F0A3E543F0439104229047 +:101900000088E07008900074E004120F0A120F4E75 +:10191000900088E014F0120F99500302192453E24A +:10192000FDC28022120E78120F40EFA80608800236 +:10193000C313D8FC30E0059000768003900089E066 +:101940007D00FCE4FF12196E22AE077FAA12195225 +:10195000AF06C2029000C1E0B42002E4F09000C1E2 +:10196000E02450F8A607E004F0A3E004F022AB075F +:10197000AF04EB14600C14600E2402700E8DFB8F0C +:10198000FC228DE98FEA228DEB8FEC22E4FDFCFF37 +:1019900012196E120F75121ABB53D87853E2FDC29A +:1019A00080C2909000857404F022120F0BE014F0B6 +:1019B0009000777401F09000857403F012192412DE +:1019C00018580200707E1DE4FDEF30E70625E06E3A +:1019D000FF8004EF25E0FF0DBD08EE22AF8853889D +:1019E000AF758CA0758DCBEF5440FEEF54104E4276 +:1019F0008822C3EF94ACEE940D4003D38001C32240 +:101A0000AD07AC06ECF5CBAF058FCA22AD07AC062F +:101A1000ECF593AF058F9222C2DE75D90575F9FFFB +:101A200075960122EE30E707C3E49FFFE49EFE2295 +:101A30001219497F55121952021ABE75E34075E119 +:101A40000175E20222E59154045391FB4291227503 +:101A50008E5475892243885022E5C8540453C8FB2C +:101A600042C82253984FEB4F4DF59822E5C8C3204A +:101A7000E201D322E591C320E201D32253C8FB53F4 +:101A8000C87F227597DE7597AD2275A41175D4CEE7 +:101A90002275A54175D5772253F77F75DA4A22530F +:101AA000F77F75DB302275E69075A8B022E59120AE +:101AB000E2FB22439810223002FD22C2DE22D2999C +:101AC000228F9922AF99228F8C222222019030708E +:101AD00000064001904B19180012C005DC0002BC42 +:101AE000012C461E28080BB8232800044C01904BFB +:101AF000191800251C0BB80003840140461E18006D +:101B0000000072D80702BC012C264040000BB81C14 +:101B1000520190010303011846000100FF1ACC0294 +:101B200000FF1AD90300FF1AE60400FF1AF30500AC +:101B3000FF1B000601FF1B0D0190307000064001E5 +:101B4000904B19180012C005DC0002BC012C461E87 +:101B500028080BB8232800044C01904B19180025C5 +:101B60001C0BB80003840140461E1800000072D808 +:101B70000702BC012C264040000BB81C520190010A +:101B80000303011846000100FF1B380200FF1B453C +:101B90000300FF1B520400FF1B5F0500FF1B6C06C8 +:101BA00001FF1B790190307000064001904B19181D +:101BB0000012C005DC0002BC012C461E28080BB830 +:101BC000232800044C01904B191800251C0BB80069 +:101BD00003840140461E1800000072D80702BC01B1 +:101BE0002C264040000BB81C520190010303011841 +:101BF00046000100FF1BA40200FF1BB10300FF1BF6 +:101C0000BE0400FF1BCB0500FF1BD80601FF1BE530 +:00000001FF