2017-01-28 13:41:01 +00:00
/*
2017-05-13 12:02:10 +01:00
sonoff . ino - Sonoff - Tasmota firmware for iTead Sonoff , Wemos and NodeMCU hardware
2017-12-22 13:55:24 +00:00
Copyright ( C ) 2018 Theo Arends
2017-05-13 12:02:10 +01:00
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2017-05-17 21:49:22 +01:00
/*====================================================
2017-05-13 12:02:10 +01:00
Prerequisites :
- Change libraries / PubSubClient / src / PubSubClient . h
2018-01-18 15:19:28 +00:00
# define MQTT_MAX_PACKET_SIZE 1000
2017-07-15 14:07:30 +01:00
- Select IDE Tools - Flash Mode : " DOUT "
- Select IDE Tools - Flash Size : " 1M (no SPIFFS) "
2017-05-17 21:49:22 +01:00
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
2017-01-28 13:41:01 +00:00
2017-10-18 17:22:34 +01:00
// Location specific includes
2018-01-26 14:21:57 +00:00
# include <core_version.h> // Arduino_Esp8266 version information (ARDUINO_ESP8266_RELEASE and ARDUINO_ESP8266_RELEASE_2_3_0)
2018-08-12 13:05:15 +01:00
# include "sonoff_version.h" // Sonoff-Tasmota version information
2018-10-23 14:51:51 +01:00
# include "sonoff.h" // Enumeration used in my_user_config.h
# include "my_user_config.h" // Fixed user configurable options
2018-04-02 10:24:36 +01:00
# ifdef USE_CONFIG_OVERRIDE
2018-10-23 14:51:51 +01:00
# include "user_config_override.h" // Configuration overrides for my_user_config.h
2018-04-02 10:24:36 +01:00
# endif
2018-04-05 11:49:43 +01:00
# include "sonoff_post.h" // Configuration overrides for all previous includes
2018-10-23 14:51:51 +01:00
# include "i18n.h" // Language support configured by my_user_config.h
2017-10-18 17:22:34 +01:00
# include "sonoff_template.h" // Hardware configuration
2017-03-03 11:35:23 +00:00
2018-02-27 13:59:46 +00:00
# ifdef ARDUINO_ESP8266_RELEASE_2_4_0
# include "lwip/init.h"
# if LWIP_VERSION_MAJOR != 1
# error Please use stable lwIP v1.4
# endif
2017-03-03 11:35:23 +00:00
# endif
2018-01-18 15:19:28 +00:00
2018-02-27 13:59:46 +00:00
// Libraries
2018-11-20 14:00:24 +00:00
# include <ESP8266HTTPClient.h> // Ota
2017-01-28 13:41:01 +00:00
# include <ESP8266httpUpdate.h> // Ota
2017-06-04 16:40:27 +01:00
# include <StreamString.h> // Webserver, Updater
2017-02-17 16:18:41 +00:00
# include <ArduinoJson.h> // WemoHue, IRremote, Domoticz
2018-03-21 16:58:39 +00:00
# ifdef USE_ARDUINO_OTA
# include <ArduinoOTA.h> // Arduino OTA
# ifndef USE_DISCOVERY
# define USE_DISCOVERY
# endif
# endif // USE_ARDUINO_OTA
2017-01-28 13:41:01 +00:00
# ifdef USE_DISCOVERY
2018-03-21 16:58:39 +00:00
# include <ESP8266mDNS.h> // MQTT, Webserver, Arduino OTA
2017-01-28 13:41:01 +00:00
# endif // USE_DISCOVERY
# ifdef USE_I2C
# include <Wire.h> // I2C support library
# endif // USE_I2C
2017-07-15 14:07:30 +01:00
# ifdef USE_SPI
2017-05-10 13:19:36 +01:00
# include <SPI.h> // SPI support, TFT
2017-04-29 13:40:53 +01:00
# endif // USE_SPI
2017-10-18 17:22:34 +01:00
// Structs
2017-02-19 16:49:17 +00:00
# include "settings.h"
2017-01-28 13:41:01 +00:00
2017-10-29 17:18:46 +00:00
enum TasmotaCommands {
2018-06-30 17:50:10 +01:00
CMND_BACKLOG , CMND_DELAY , CMND_POWER , CMND_FANSPEED , CMND_STATUS , CMND_STATE , CMND_POWERONSTATE , CMND_PULSETIME ,
2018-01-24 16:31:20 +00:00
CMND_BLINKTIME , CMND_BLINKCOUNT , CMND_SENSOR , CMND_SAVEDATA , CMND_SETOPTION , CMND_TEMPERATURE_RESOLUTION , CMND_HUMIDITY_RESOLUTION ,
2018-10-08 13:39:36 +01:00
CMND_PRESSURE_RESOLUTION , CMND_POWER_RESOLUTION , CMND_VOLTAGE_RESOLUTION , CMND_FREQUENCY_RESOLUTION , CMND_CURRENT_RESOLUTION , CMND_ENERGY_RESOLUTION , CMND_WEIGHT_RESOLUTION ,
2018-09-07 17:15:47 +01:00
CMND_MODULE , CMND_MODULES , CMND_GPIO , CMND_GPIOS , CMND_PWM , CMND_PWMFREQUENCY , CMND_PWMRANGE , CMND_COUNTER , CMND_COUNTERTYPE ,
2018-08-27 11:01:20 +01:00
CMND_COUNTERDEBOUNCE , CMND_BUTTONDEBOUNCE , CMND_SWITCHDEBOUNCE , CMND_SLEEP , CMND_UPGRADE , CMND_UPLOAD , CMND_OTAURL , CMND_SERIALLOG , CMND_SYSLOG ,
2017-10-29 17:18:46 +00:00
CMND_LOGHOST , CMND_LOGPORT , CMND_IPADDRESS , CMND_NTPSERVER , CMND_AP , CMND_SSID , CMND_PASSWORD , CMND_HOSTNAME ,
2018-11-18 14:02:52 +00:00
CMND_WIFICONFIG , CMND_FRIENDLYNAME , CMND_SWITCHMODE ,
2018-05-14 22:22:29 +01:00
CMND_TELEPERIOD , CMND_RESTART , CMND_RESET , CMND_TIMEZONE , CMND_TIMESTD , CMND_TIMEDST , CMND_ALTITUDE , CMND_LEDPOWER , CMND_LEDSTATE ,
2018-09-20 21:56:07 +01:00
CMND_I2CSCAN , CMND_SERIALSEND , CMND_BAUDRATE , CMND_SERIALDELIMITER , CMND_DRIVER } ;
2017-10-29 17:18:46 +00:00
const char kTasmotaCommands [ ] PROGMEM =
2018-06-30 17:50:10 +01:00
D_CMND_BACKLOG " | " D_CMND_DELAY " | " D_CMND_POWER " | " D_CMND_FANSPEED " | " D_CMND_STATUS " | " D_CMND_STATE " | " D_CMND_POWERONSTATE " | " D_CMND_PULSETIME " | "
2018-01-24 16:31:20 +00:00
D_CMND_BLINKTIME " | " D_CMND_BLINKCOUNT " | " D_CMND_SENSOR " | " D_CMND_SAVEDATA " | " D_CMND_SETOPTION " | " D_CMND_TEMPERATURE_RESOLUTION " | " D_CMND_HUMIDITY_RESOLUTION " | "
2018-10-08 13:39:36 +01:00
D_CMND_PRESSURE_RESOLUTION " | " D_CMND_POWER_RESOLUTION " | " D_CMND_VOLTAGE_RESOLUTION " | " D_CMND_FREQUENCY_RESOLUTION " | " D_CMND_CURRENT_RESOLUTION " | " D_CMND_ENERGY_RESOLUTION " | " D_CMND_WEIGHT_RESOLUTION " | "
2018-09-07 17:15:47 +01:00
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 " | "
2018-08-27 11:01:20 +01:00
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 " | "
2017-10-29 17:18:46 +00:00
D_CMND_LOGHOST " | " D_CMND_LOGPORT " | " D_CMND_IPADDRESS " | " D_CMND_NTPSERVER " | " D_CMND_AP " | " D_CMND_SSID " | " D_CMND_PASSWORD " | " D_CMND_HOSTNAME " | "
2018-11-18 14:02:52 +00:00
D_CMND_WIFICONFIG " | " D_CMND_FRIENDLYNAME " | " D_CMND_SWITCHMODE " | "
2018-05-14 22:22:29 +01:00
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 " | "
2018-09-20 21:56:07 +01:00
D_CMND_I2CSCAN " | " D_CMND_SERIALSEND " | " D_CMND_BAUDRATE " | " D_CMND_SERIALDELIMITER " | " D_CMND_DRIVER ;
2018-05-06 15:18:17 +01:00
2018-06-30 18:09:48 +01:00
const uint8_t kIFan02Speed [ 4 ] [ 3 ] = { { 6 , 6 , 6 } , { 7 , 6 , 6 } , { 7 , 7 , 6 } , { 7 , 6 , 7 } } ;
2018-06-30 17:50:10 +01:00
2017-10-18 17:22:34 +01:00
// Global variables
2018-08-27 15:07:23 +01:00
SerialConfig serial_config = SERIAL_8N1 ; // Serial interface configuration 8 data bits, No parity, 1 stop bit
WiFiUDP PortUdp ; // UDP Syslog and Alexa
2018-05-17 14:36:45 +01:00
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
2018-08-27 11:01:20 +01:00
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
2018-08-27 15:07:23 +01:00
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))
2017-10-18 17:22:34 +01:00
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
2018-09-08 16:18:31 +01:00
int tele_period = 1 ; // Tele period timer
2018-08-27 15:07:23 +01:00
int blinks = 201 ; // Number of LED blinks
uint32_t uptime = 0 ; // Counting every second until 4294967295 = 130 year
2018-11-24 16:16:27 +00:00
uint32_t loop_load_avg = 0 ; // Indicative loop load average
2018-08-27 15:07:23 +01:00
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
2017-10-18 17:22:34 +01:00
uint16_t mqtt_cmnd_publish = 0 ; // ignore flag for publish command
2018-08-27 15:07:23 +01:00
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
2018-09-26 10:56:58 +01:00
uint16_t switch_no_pullup = 0 ; // Switch pull-up bitmask flags
2018-08-27 15:07:23 +01:00
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
2017-10-18 17:22:34 +01:00
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
uint8_t blinkstate = 0 ; // LED state
2018-07-07 16:30:58 +01:00
uint8_t blinkspeed = 1 ; // LED blink rate
2017-10-18 17:22:34 +01:00
uint8_t lastbutton [ MAX_KEYS ] = { NOT_PRESSED , NOT_PRESSED , NOT_PRESSED , NOT_PRESSED } ; // Last button states
2017-10-12 10:29:40 +01:00
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
2017-10-18 17:22:34 +01:00
uint8_t lastwallswitch [ MAX_SWITCHES ] ; // Last wall switch states
2017-10-10 14:40:02 +01:00
uint8_t holdwallswitch [ MAX_SWITCHES ] = { 0 } ; // Timer for wallswitch push button hold
2018-07-12 13:52:35 +01:00
uint8_t virtualswitch [ MAX_SWITCHES ] ; // Virtual switch states
2017-10-18 17:22:34 +01:00
uint8_t pin [ GPIO_MAX ] ; // Possible pin configurations
uint8_t led_inverted = 0 ; // LED inverted flag (1 = (0 = On, 1 = Off))
uint8_t pwm_inverted = 0 ; // PWM inverted flag (1 = inverted)
2018-08-25 12:08:06 +01:00
uint8_t counter_no_pullup = 0 ; // Counter input pullup flag (1 = No pullup)
2017-10-18 17:22:34 +01:00
uint8_t dht_flg = 0 ; // DHT configured
2018-09-04 15:22:34 +01:00
uint8_t energy_flg = 0 ; // Energy monitor configured
2017-10-18 17:22:34 +01:00
uint8_t i2c_flg = 0 ; // I2C configured
uint8_t spi_flg = 0 ; // SPI configured
uint8_t light_type = 0 ; // Light types
2018-05-14 22:22:29 +01:00
uint8_t ntp_force_sync = 0 ; // Force NTP sync
2018-08-27 15:07:23 +01:00
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
2018-10-28 16:57:25 +00:00
byte mdns_delayed_start = 0 ; // mDNS delayed start
2018-08-27 15:07:23 +01:00
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)
2018-01-10 13:10:25 +00:00
char my_version [ 33 ] ; // Composed version string
2018-11-07 14:03:41 +00:00
char my_image [ 33 ] ; // Code image and/or commit
2017-10-18 17:22:34 +01:00
char my_hostname [ 33 ] ; // Composed Wifi hostname
2018-02-08 11:45:26 +00:00
char mqtt_client [ 33 ] ; // Composed MQTT Clientname
2018-02-13 13:30:30 +00:00
char mqtt_topic [ 33 ] ; // Composed MQTT topic
2018-02-08 11:45:26 +00:00
char serial_in_buffer [ INPUT_BUFFER_SIZE ] ; // Receive buffer
2018-01-18 15:19:28 +00:00
char mqtt_data [ MESSZ ] ; // MQTT publish buffer and web page ajax buffer
char log_data [ LOGSZ ] ; // Logging
2018-01-30 13:14:55 +00:00
char web_log [ WEB_LOG_SIZE ] = { ' \0 ' } ; // Web log buffer
2017-10-18 17:22:34 +01:00
String backlog [ MAX_BACKLOG ] ; // Command backlog
2018-11-24 16:16:27 +00:00
2017-09-13 13:19:34 +01:00
2017-01-28 13:41:01 +00:00
/********************************************************************************************/
2018-03-29 12:03:13 +01:00
char * Format ( char * output , const char * input , int size )
2017-01-28 13:41:01 +00:00
{
char * token ;
uint8_t digits = 0 ;
if ( strstr ( input , " % " ) ) {
strlcpy ( output , input , size ) ;
token = strtok ( output , " % " ) ;
if ( strstr ( input , " % " ) = = input ) {
output [ 0 ] = ' \0 ' ;
} else {
token = strtok ( NULL , " " ) ;
}
if ( token ! = NULL ) {
digits = atoi ( token ) ;
if ( digits ) {
2018-02-13 13:30:30 +00:00
if ( strchr ( token , ' d ' ) ) {
snprintf_P ( output , size , PSTR ( " %s%c0%dd " ) , output , ' % ' , digits ) ;
snprintf_P ( output , size , output , ESP . getChipId ( ) & 0x1fff ) ; // %04d - short chip ID in dec, like in hostname
} else {
snprintf_P ( output , size , PSTR ( " %s%c0%dX " ) , output , ' % ' , digits ) ;
snprintf_P ( output , size , output , ESP . getChipId ( ) ) ; // %06X - full chip ID in hex
}
} else {
if ( strchr ( token , ' d ' ) ) {
snprintf_P ( output , size , PSTR ( " %s%d " ) , output , ESP . getChipId ( ) ) ; // %d - full chip ID in dec
digits = 8 ;
}
2017-01-28 13:41:01 +00:00
}
}
}
2018-03-02 14:38:37 +00:00
if ( ! digits ) strlcpy ( output , input , size ) ;
2018-02-13 13:30:30 +00:00
return output ;
}
char * GetOtaUrl ( char * otaurl , size_t otaurl_size )
{
if ( strstr ( Settings . ota_url , " %04d " ) ! = NULL ) { // OTA url contains placeholder for chip ID
snprintf ( otaurl , otaurl_size , Settings . ota_url , ESP . getChipId ( ) & 0x1fff ) ;
}
else if ( strstr ( Settings . ota_url , " %d " ) ! = NULL ) { // OTA url contains placeholder for chip ID
snprintf_P ( otaurl , otaurl_size , Settings . ota_url , ESP . getChipId ( ) ) ;
}
else {
snprintf ( otaurl , otaurl_size , Settings . ota_url ) ;
}
return otaurl ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
void GetTopic_P ( char * stopic , byte prefix , char * topic , const char * subtopic )
2017-05-10 13:19:36 +01:00
{
2018-01-18 15:19:28 +00:00
/* prefix 0 = Cmnd
prefix 1 = Stat
prefix 2 = Tele
*/
2017-05-10 13:19:36 +01:00
char romram [ CMDSZ ] ;
2017-06-30 16:54:19 +01:00
String fulltopic ;
2017-09-02 13:37:02 +01:00
2017-05-10 13:19:36 +01:00
snprintf_P ( romram , sizeof ( romram ) , subtopic ) ;
2017-10-18 17:22:34 +01:00
if ( fallback_topic_flag ) {
fulltopic = FPSTR ( kPrefixes [ prefix ] ) ;
2017-06-30 16:54:19 +01:00
fulltopic + = F ( " / " ) ;
2017-10-18 17:22:34 +01:00
fulltopic + = mqtt_client ;
2017-06-30 16:54:19 +01:00
} else {
2017-10-18 17:22:34 +01:00
fulltopic = Settings . mqtt_fulltopic ;
2017-06-30 16:54:19 +01:00
if ( ( 0 = = prefix ) & & ( - 1 = = fulltopic . indexOf ( F ( MQTT_TOKEN_PREFIX ) ) ) ) {
fulltopic + = F ( " / " MQTT_TOKEN_PREFIX ) ; // Need prefix for commands to handle mqtt topic loops
}
for ( byte i = 0 ; i < 3 ; i + + ) {
2017-10-18 17:22:34 +01:00
if ( ' \0 ' = = Settings . mqtt_prefix [ i ] [ 0 ] ) {
snprintf_P ( Settings . mqtt_prefix [ i ] , sizeof ( Settings . mqtt_prefix [ i ] ) , kPrefixes [ i ] ) ;
2017-06-30 16:54:19 +01:00
}
2017-05-10 13:19:36 +01:00
}
2017-10-18 17:22:34 +01:00
fulltopic . replace ( F ( MQTT_TOKEN_PREFIX ) , Settings . mqtt_prefix [ prefix ] ) ;
2017-06-30 16:54:19 +01:00
fulltopic . replace ( F ( MQTT_TOKEN_TOPIC ) , topic ) ;
2018-10-29 11:38:44 +00:00
fulltopic . replace ( F ( MQTT_TOKEN_HOSTNAME ) , my_hostname ) ;
2018-05-21 16:52:24 +01:00
String token_id = WiFi . macAddress ( ) ;
token_id . replace ( " : " , " " ) ;
fulltopic . replace ( F ( MQTT_TOKEN_ID ) , token_id ) ;
2017-05-10 13:19:36 +01:00
}
fulltopic . replace ( F ( " # " ) , " " ) ;
fulltopic . replace ( F ( " // " ) , " / " ) ;
2018-03-02 14:38:37 +00:00
if ( ! fulltopic . endsWith ( " / " ) ) fulltopic + = " / " ;
2017-05-10 13:19:36 +01:00
snprintf_P ( stopic , TOPSZ , PSTR ( " %s%s " ) , fulltopic . c_str ( ) , romram ) ;
}
2017-10-18 17:22:34 +01:00
char * GetStateText ( byte state )
2017-05-10 13:19:36 +01:00
{
2018-03-02 14:38:37 +00:00
if ( state > 3 ) state = 1 ;
2017-10-18 17:22:34 +01:00
return Settings . state_text [ state ] ;
2017-05-10 13:19:36 +01:00
}
/********************************************************************************************/
2018-09-30 15:52:25 +01:00
void SetLatchingRelay ( power_t lpower , uint8_t state )
2017-02-13 16:25:46 +00:00
{
2018-09-30 15:52:25 +01:00
// power xx00 - toggle REL1 (Off) and REL3 (Off) - device 1 Off, device 2 Off
// power xx01 - toggle REL2 (On) and REL3 (Off) - device 1 On, device 2 Off
// power xx10 - toggle REL1 (Off) and REL4 (On) - device 1 Off, device 2 On
// power xx11 - toggle REL2 (On) and REL4 (On) - device 1 On, device 2 On
if ( state & & ! latching_relay_pulse ) { // Set latching relay to power if previous pulse has finished
latching_power = lpower ;
latching_relay_pulse = 2 ; // max 200mS (initiated by stateloop())
2017-02-13 16:25:46 +00:00
}
2018-09-30 15:52:25 +01:00
for ( byte i = 0 ; i < devices_present ; i + + ) {
uint8_t port = ( i < < 1 ) + ( ( latching_power > > i ) & 1 ) ;
if ( pin [ GPIO_REL1 + port ] < 99 ) {
digitalWrite ( pin [ GPIO_REL1 + port ] , bitRead ( rel_inverted , port ) ? ! state : state ) ;
}
2017-04-25 17:24:42 +01:00
}
2017-02-13 16:25:46 +00:00
}
2018-05-28 14:52:42 +01:00
void SetDevicePower ( power_t rpower , int source )
2017-01-28 13:41:01 +00:00
{
2017-02-13 16:25:46 +00:00
uint8_t state ;
2017-05-05 16:57:05 +01:00
2018-05-28 14:52:42 +01:00
ShowSource ( source ) ;
2018-01-24 16:31:20 +00:00
if ( POWER_ALL_ALWAYS_ON = = Settings . poweronstate ) { // All on and stay on
2017-10-18 17:22:34 +01:00
power = ( 1 < < devices_present ) - 1 ;
2017-05-05 16:57:05 +01:00
rpower = power ;
}
2017-10-18 17:22:34 +01:00
if ( Settings . flag . interlock ) { // Allow only one or no relay set
2017-10-10 14:40:02 +01:00
power_t mask = 1 ;
2017-08-18 11:55:08 +01:00
uint8_t count = 0 ;
2017-10-18 17:22:34 +01:00
for ( byte i = 0 ; i < devices_present ; i + + ) {
2018-03-02 14:38:37 +00:00
if ( rpower & mask ) count + + ;
2017-08-18 11:55:08 +01:00
mask < < = 1 ;
}
if ( count > 1 ) {
power = 0 ;
rpower = 0 ;
}
}
2018-01-05 11:26:19 +00:00
2018-09-22 16:37:49 +01:00
XdrvMailbox . index = rpower ;
2018-10-19 11:53:22 +01:00
XdrvCall ( FUNC_SET_POWER ) ; // Signal power state
2018-01-05 11:26:19 +00:00
2018-10-19 11:53:22 +01:00
XdrvMailbox . index = rpower ;
XdrvMailbox . payload = source ;
if ( XdrvCall ( FUNC_SET_DEVICE_POWER ) ) { // Set power state and stop if serviced
// Serviced
2018-10-18 12:01:31 +01:00
}
else if ( ( SONOFF_DUAL = = Settings . module ) | | ( CH4 = = Settings . module ) ) {
2017-01-28 13:41:01 +00:00
Serial . write ( 0xA0 ) ;
Serial . write ( 0x04 ) ;
2017-10-10 14:40:02 +01:00
Serial . write ( rpower & 0xFF ) ;
2017-01-28 13:41:01 +00:00
Serial . write ( 0xA1 ) ;
Serial . write ( ' \n ' ) ;
Serial . flush ( ) ;
2017-02-13 16:25:46 +00:00
}
2017-10-18 17:22:34 +01:00
else if ( EXS_RELAY = = Settings . module ) {
SetLatchingRelay ( rpower , 1 ) ;
2017-02-13 16:25:46 +00:00
}
else {
2017-10-18 17:22:34 +01:00
for ( byte i = 0 ; i < devices_present ; i + + ) {
2017-10-14 10:26:49 +01:00
state = rpower & 1 ;
if ( ( i < MAX_RELAYS ) & & ( pin [ GPIO_REL1 + i ] < 99 ) ) {
digitalWrite ( pin [ GPIO_REL1 + i ] , bitRead ( rel_inverted , i ) ? ! state : state ) ;
}
rpower > > = 1 ;
}
2017-01-28 13:41:01 +00:00
}
}
2017-10-18 17:22:34 +01:00
void SetLedPower ( uint8_t state )
2017-01-28 13:41:01 +00:00
{
2018-03-02 14:38:37 +00:00
if ( state ) state = 1 ;
2017-10-10 14:40:02 +01:00
digitalWrite ( pin [ GPIO_LED1 ] , ( bitRead ( led_inverted , 0 ) ) ? ! state : state ) ;
2017-01-28 13:41:01 +00:00
}
2018-11-14 13:32:09 +00:00
uint8_t GetFanspeed ( void )
2018-07-01 14:06:44 +01:00
{
uint8_t fanspeed = 0 ;
// if (SONOFF_IFAN02 == Settings.module) {
/* Fanspeed is controlled by relay 2, 3 and 4 as in Sonoff 4CH.
000 x = 0
001 x = 1
011 x = 2
101 x = 3
*/
fanspeed = ( uint8_t ) ( power & 0xF ) > > 1 ;
if ( fanspeed ) { fanspeed = ( fanspeed > > 1 ) + 1 ; }
// }
return fanspeed ;
}
2018-08-20 14:51:46 +01:00
void SetFanspeed ( uint8_t fanspeed )
{
for ( byte i = 0 ; i < 3 ; i + + ) {
uint8_t state = kIFan02Speed [ fanspeed ] [ i ] ;
// uint8_t state = pgm_read_byte(kIFan02Speed +(speed *3) +i);
ExecuteCommandPower ( i + 2 , state , SRC_IGNORE ) ; // Use relay 2, 3 and 4
}
}
2018-08-26 14:42:35 +01:00
void SetPulseTimer ( uint8_t index , uint16_t time )
{
pulse_timer [ index ] = ( time > 111 ) ? millis ( ) + ( 1000 * ( time - 100 ) ) : ( time > 0 ) ? millis ( ) + ( 100 * time ) : 0L ;
}
uint16_t GetPulseTimer ( uint8_t index )
{
uint16_t result = 0 ;
long time = TimePassedSince ( pulse_timer [ index ] ) ;
if ( time < 0 ) {
time * = - 1 ;
result = ( time > 11100 ) ? ( time / 1000 ) + 100 : ( time > 0 ) ? time / 100 : 0 ;
}
return result ;
}
2017-02-18 17:08:55 +00:00
/********************************************************************************************/
2018-02-27 13:59:46 +00:00
void MqttDataHandler ( char * topic , byte * data , unsigned int data_len )
2017-01-28 13:41:01 +00:00
{
char * str ;
2017-10-18 17:22:34 +01:00
if ( ! strcmp ( Settings . mqtt_prefix [ 0 ] , Settings . mqtt_prefix [ 1 ] ) ) {
str = strstr ( topic , Settings . mqtt_prefix [ 0 ] ) ;
2017-01-28 13:41:01 +00:00
if ( ( str = = topic ) & & mqtt_cmnd_publish ) {
2018-08-26 14:42:35 +01:00
if ( mqtt_cmnd_publish > 3 ) {
mqtt_cmnd_publish - = 3 ;
2017-04-25 17:24:42 +01:00
} else {
mqtt_cmnd_publish = 0 ;
}
2017-01-28 13:41:01 +00:00
return ;
}
}
2017-04-25 17:24:42 +01:00
char topicBuf [ TOPSZ ] ;
char dataBuf [ data_len + 1 ] ;
2017-10-29 17:18:46 +00:00
char command [ CMDSZ ] ;
2017-04-25 17:24:42 +01:00
char stemp1 [ TOPSZ ] ;
char * p ;
char * type = NULL ;
2017-09-14 14:35:38 +01:00
byte jsflg = 0 ;
byte lines = 1 ;
2018-02-27 13:59:46 +00:00
uint8_t grpflg = 0 ;
2018-05-13 16:38:44 +01:00
// uint8_t user_append_index = 0;
2017-04-25 17:24:42 +01:00
uint16_t i = 0 ;
uint16_t index ;
2017-03-25 16:24:11 +00:00
uint32_t address ;
2017-01-28 13:41:01 +00:00
2018-06-26 10:48:09 +01:00
ShowFreeMem ( PSTR ( " MqttDataHandler " ) ) ;
2018-09-02 10:52:24 +01:00
strlcpy ( topicBuf , topic , sizeof ( topicBuf ) ) ;
2017-09-08 11:57:08 +01:00
for ( i = 0 ; i < data_len ; i + + ) {
2018-03-02 14:38:37 +00:00
if ( ! isspace ( data [ i ] ) ) break ;
2017-09-08 11:57:08 +01:00
}
data_len - = i ;
memcpy ( dataBuf , data + i , sizeof ( dataBuf ) ) ;
2017-01-28 13:41:01 +00:00
dataBuf [ sizeof ( dataBuf ) - 1 ] = 0 ;
2018-05-28 14:52:42 +01:00
if ( topicBuf [ 0 ] ! = ' / ' ) { ShowSource ( SRC_MQTT ) ; }
2017-09-13 13:19:34 +01:00
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_RESULT D_RECEIVED_TOPIC " %s, " D_DATA_SIZE " %d, " D_DATA " %s " ) ,
2017-09-02 13:37:02 +01:00
topicBuf , data_len , dataBuf ) ;
2017-10-18 17:22:34 +01:00
AddLog ( LOG_LEVEL_DEBUG_MORE ) ;
2017-01-28 13:41:01 +00:00
// if (LOG_LEVEL_DEBUG_MORE <= seriallog_level) Serial.println(dataBuf);
2018-02-27 13:59:46 +00:00
if ( XdrvMqttData ( topicBuf , sizeof ( topicBuf ) , dataBuf , sizeof ( dataBuf ) ) ) return ;
2017-01-28 13:41:01 +00:00
2017-10-18 17:22:34 +01:00
grpflg = ( strstr ( topicBuf , Settings . mqtt_grptopic ) ! = NULL ) ;
fallback_topic_flag = ( strstr ( topicBuf , mqtt_client ) ! = NULL ) ;
2018-09-24 10:44:40 +01:00
type = strrchr ( topicBuf , ' / ' ) ; // Last part of received topic is always the command (type)
2017-01-28 13:41:01 +00:00
index = 1 ;
if ( type ! = NULL ) {
2018-09-24 10:44:40 +01:00
type + + ;
2017-04-25 17:24:42 +01:00
for ( i = 0 ; i < strlen ( type ) ; i + + ) {
type [ i ] = toupper ( type [ i ] ) ;
}
while ( isdigit ( type [ i - 1 ] ) ) {
i - - ;
}
2018-05-13 16:38:44 +01:00
if ( i < strlen ( type ) ) {
index = atoi ( type + i ) ;
// user_append_index = 1;
}
2017-01-28 13:41:01 +00:00
type [ i ] = ' \0 ' ;
}
2017-09-16 16:34:03 +01:00
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_RESULT D_GROUP " %d, " D_INDEX " %d, " D_COMMAND " %s, " D_DATA " %s " ) ,
grpflg , index , type , dataBuf ) ;
2017-10-18 17:22:34 +01:00
AddLog ( LOG_LEVEL_DEBUG ) ;
2017-01-28 13:41:01 +00:00
if ( type ! = NULL ) {
2018-01-06 16:34:42 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { \" " D_JSON_COMMAND " \" : \" " D_JSON_ERROR " \" } " ) ) ;
2018-03-02 14:38:37 +00:00
if ( Settings . ledstate & 0x02 ) blinks + + ;
2017-01-28 13:41:01 +00:00
2018-03-02 14:38:37 +00:00
if ( ! strcmp ( dataBuf , " ? " ) ) data_len = 0 ;
2017-06-25 22:01:41 +01:00
int16_t payload = - 99 ; // No payload
uint16_t payload16 = 0 ;
2018-03-18 12:47:30 +00:00
long payload32 = strtol ( dataBuf , & p , 10 ) ;
2017-06-25 22:01:41 +01:00
if ( p ! = dataBuf ) {
2018-03-18 12:47:30 +00:00
payload = ( int16_t ) payload32 ; // -32766 - 32767
payload16 = ( uint16_t ) payload32 ; // 0 - 65535
} else {
payload32 = 0 ;
2017-06-06 22:23:23 +01:00
}
2018-08-26 14:42:35 +01:00
backlog_delay = millis ( ) + ( 100 * MIN_BACKLOG_DELAY ) ;
2017-06-06 22:23:23 +01:00
2018-05-06 15:07:42 +01:00
int temp_payload = GetStateNumber ( dataBuf ) ;
if ( temp_payload > - 1 ) { payload = temp_payload ; }
2017-01-28 13:41:01 +00:00
2017-09-13 13:19:34 +01:00
// snprintf_P(log_data, sizeof(log_data), PSTR("RSLT: Payload %d, Payload16 %d"), payload, payload16);
2017-10-18 17:22:34 +01:00
// AddLog(LOG_LEVEL_DEBUG);
2017-06-06 22:23:23 +01:00
2017-10-29 17:18:46 +00:00
int command_code = GetCommandCode ( command , sizeof ( command ) , type , kTasmotaCommands ) ;
2018-05-09 09:49:43 +01:00
if ( - 1 = = command_code ) {
if ( ! XdrvCommand ( grpflg , type , index , dataBuf , data_len , payload , payload16 ) ) {
type = NULL ; // Unknown command
}
}
else if ( CMND_BACKLOG = = command_code ) {
2017-07-15 14:07:30 +01:00
if ( data_len ) {
2018-03-31 17:59:37 +01:00
uint8_t bl_pointer = ( ! backlog_pointer ) ? MAX_BACKLOG - 1 : backlog_pointer ;
bl_pointer - - ;
2017-07-15 14:07:30 +01:00
char * blcommand = strtok ( dataBuf , " ; " ) ;
2018-03-31 17:59:37 +01:00
while ( ( blcommand ! = NULL ) & & ( backlog_index ! = bl_pointer ) ) {
2018-05-06 15:07:42 +01:00
while ( true ) {
2018-11-12 11:33:49 +00:00
blcommand = Trim ( blcommand ) ;
2018-05-06 15:07:42 +01:00
if ( ! strncasecmp_P ( blcommand , PSTR ( D_CMND_BACKLOG ) , strlen ( D_CMND_BACKLOG ) ) ) {
blcommand + = strlen ( D_CMND_BACKLOG ) ; // Skip unnecessary command Backlog
} else {
break ;
}
}
if ( * blcommand ! = ' \0 ' ) {
backlog [ backlog_index ] = String ( blcommand ) ;
backlog_index + + ;
if ( backlog_index > = MAX_BACKLOG ) backlog_index = 0 ;
}
2017-07-15 14:07:30 +01:00
blcommand = strtok ( NULL , " ; " ) ;
}
2018-05-06 15:07:42 +01:00
// snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_APPENDED);
mqtt_data [ 0 ] = ' \0 ' ;
2017-07-15 14:07:30 +01:00
} else {
2017-10-18 17:22:34 +01:00
uint8_t blflag = ( backlog_pointer = = backlog_index ) ;
backlog_pointer = backlog_index ;
2018-01-06 16:34:42 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_SVALUE , command , blflag ? D_JSON_EMPTY : D_JSON_ABORTED ) ;
2017-07-15 14:07:30 +01:00
}
}
2017-10-29 17:18:46 +00:00
else if ( CMND_DELAY = = command_code ) {
2018-08-26 14:42:35 +01:00
if ( ( payload > = MIN_BACKLOG_DELAY ) & & ( payload < = 3600 ) ) {
backlog_delay = millis ( ) + ( 100 * payload ) ;
}
uint16_t bl_delay = 0 ;
long bl_delta = TimePassedSince ( backlog_delay ) ;
if ( bl_delta < 0 ) { bl_delay = ( bl_delta * - 1 ) / 100 ; }
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , bl_delay ) ;
2017-07-15 14:07:30 +01:00
}
2017-10-29 17:18:46 +00:00
else if ( ( CMND_POWER = = command_code ) & & ( index > 0 ) & & ( index < = devices_present ) ) {
2018-03-02 14:38:37 +00:00
if ( ( payload < 0 ) | | ( payload > 4 ) ) payload = 9 ;
2018-05-13 16:38:44 +01:00
// Settings.flag.device_index_enable = user_append_index;
2018-05-28 14:52:42 +01:00
ExecuteCommandPower ( index , payload , SRC_IGNORE ) ;
2017-10-18 17:22:34 +01:00
fallback_topic_flag = 0 ;
2017-01-28 13:41:01 +00:00
return ;
}
2018-06-30 17:54:22 +01:00
else if ( ( CMND_FANSPEED = = command_code ) & & ( SONOFF_IFAN02 = = Settings . module ) ) {
2018-08-11 15:12:10 +01:00
if ( data_len > 0 ) {
if ( ' - ' = = dataBuf [ 0 ] ) {
payload = ( int16_t ) GetFanspeed ( ) - 1 ;
if ( payload < 0 ) { payload = 3 ; }
}
else if ( ' + ' = = dataBuf [ 0 ] ) {
payload = GetFanspeed ( ) + 1 ;
if ( payload > 3 ) { payload = 0 ; }
}
}
2018-07-01 14:06:44 +01:00
if ( ( payload > = 0 ) & & ( payload < = 3 ) & & ( payload ! = GetFanspeed ( ) ) ) {
2018-08-20 14:51:46 +01:00
SetFanspeed ( payload ) ;
2018-06-30 17:50:10 +01:00
}
2018-07-01 14:06:44 +01:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , GetFanspeed ( ) ) ;
2018-06-30 17:50:10 +01:00
}
2017-10-29 17:18:46 +00:00
else if ( CMND_STATUS = = command_code ) {
2018-03-02 14:38:37 +00:00
if ( ( payload < 0 ) | | ( payload > MAX_STATUS ) ) payload = 99 ;
2017-10-18 17:22:34 +01:00
PublishStatus ( payload ) ;
fallback_topic_flag = 0 ;
2017-01-28 13:41:01 +00:00
return ;
}
2018-01-20 11:12:39 +00:00
else if ( CMND_STATE = = command_code ) {
mqtt_data [ 0 ] = ' \0 ' ;
MqttShowState ( ) ;
}
2018-07-06 17:00:50 +01:00
else if ( CMND_SLEEP = = command_code ) {
if ( ( payload > = 0 ) & & ( payload < 251 ) ) {
Settings . sleep = payload ;
sleep = payload ;
2018-08-24 15:38:55 +01:00
WiFiSetSleepMode ( ) ;
2018-07-06 17:00:50 +01:00
}
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE_UNIT_NVALUE_UNIT , command , sleep , ( Settings . flag . value_units ) ? " " D_UNIT_MILLISECOND : " " , Settings . sleep , ( Settings . flag . value_units ) ? " " D_UNIT_MILLISECOND : " " ) ;
}
else if ( ( CMND_UPGRADE = = command_code ) | | ( CMND_UPLOAD = = command_code ) ) {
// Check if the payload is numerically 1, and had no trailing chars.
// e.g. "1foo" or "1.2.3" could fool us.
// Check if the version we have been asked to upgrade to is higher than our current version.
// We also need at least 3 chars to make a valid version number string.
if ( ( ( 1 = = data_len ) & & ( 1 = = payload ) ) | | ( ( data_len > = 3 ) & & NewerVersion ( dataBuf ) ) ) {
ota_state_flag = 3 ;
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , " { \" %s \" : \" " D_JSON_VERSION " %s " D_JSON_FROM " %s \" } " , command , my_version , GetOtaUrl ( stemp1 , sizeof ( stemp1 ) ) ) ;
} else {
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , " { \" %s \" : \" " D_JSON_ONE_OR_GT " \" } " , command , my_version ) ;
}
}
else if ( CMND_OTAURL = = command_code ) {
2018-08-27 12:06:22 +01:00
if ( ( data_len > 0 ) & & ( data_len < sizeof ( Settings . ota_url ) ) ) {
2018-08-27 13:53:09 +01:00
strlcpy ( Settings . ota_url , ( SC_DEFAULT = = Shortcut ( dataBuf ) ) ? OTA_URL : dataBuf , sizeof ( Settings . ota_url ) ) ;
2018-08-27 12:06:22 +01:00
}
2018-07-06 17:00:50 +01:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_SVALUE , command , Settings . ota_url ) ;
}
else if ( CMND_SERIALLOG = = command_code ) {
if ( ( payload > = LOG_LEVEL_NONE ) & & ( payload < = LOG_LEVEL_ALL ) ) {
Settings . flag . mqtt_serial = 0 ;
SetSeriallog ( payload ) ;
}
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE_ACTIVE_NVALUE , command , Settings . seriallog_level , seriallog_level ) ;
}
else if ( CMND_RESTART = = command_code ) {
switch ( payload ) {
case 1 :
restart_flag = 2 ;
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_SVALUE , command , D_JSON_RESTARTING ) ;
break ;
case 99 :
AddLog_P ( LOG_LEVEL_INFO , PSTR ( D_LOG_APPLICATION D_RESTARTING ) ) ;
EspRestart ( ) ;
break ;
default :
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_SVALUE , command , D_JSON_ONE_TO_RESTART ) ;
}
}
2017-10-29 17:18:46 +00:00
else if ( ( CMND_POWERONSTATE = = command_code ) & & ( Settings . module ! = MOTOR ) ) {
2017-08-18 11:55:08 +01:00
/* 0 = Keep relays off after power on
2018-01-13 14:53:02 +00:00
* 1 = Turn relays on after power on , if PulseTime set wait for PulseTime seconds , and turn relays off
2017-08-18 11:55:08 +01:00
* 2 = Toggle relays after power on
* 3 = Set relays to last saved state after power on
* 4 = Turn relays on and disable any relay control ( used for Sonoff Pow to always measure power )
2018-01-13 14:53:02 +00:00
* 5 = Keep relays off after power on , if PulseTime set wait for PulseTime seconds , and turn relays on
2017-08-18 11:55:08 +01:00
*/
2018-01-24 16:31:20 +00:00
if ( ( payload > = POWER_ALL_OFF ) & & ( payload < = POWER_ALL_OFF_PULSETIME_ON ) ) {
2017-10-18 17:22:34 +01:00
Settings . poweronstate = payload ;
2018-01-24 16:31:20 +00:00
if ( POWER_ALL_ALWAYS_ON = = Settings . poweronstate ) {
2017-10-18 17:22:34 +01:00
for ( byte i = 1 ; i < = devices_present ; i + + ) {
2018-05-28 14:52:42 +01:00
ExecuteCommandPower ( i , POWER_ON , SRC_IGNORE ) ;
2017-05-05 16:57:05 +01:00
}
}
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . poweronstate ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
else if ( ( CMND_PULSETIME = = command_code ) & & ( index > 0 ) & & ( index < = MAX_PULSETIMERS ) ) {
2017-01-28 13:41:01 +00:00
if ( data_len > 0 ) {
2017-10-18 17:22:34 +01:00
Settings . pulse_timer [ index - 1 ] = payload16 ; // 0 - 65535
2018-08-26 14:42:35 +01:00
SetPulseTimer ( index - 1 , payload16 ) ;
2017-01-28 13:41:01 +00:00
}
2018-08-26 14:42:35 +01:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_INDEX_NVALUE_ACTIVE_NVALUE , command , index , Settings . pulse_timer [ index - 1 ] , GetPulseTimer ( index - 1 ) ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
else if ( CMND_BLINKTIME = = command_code ) {
2018-08-26 16:10:18 +01:00
if ( ( payload > 1 ) & & ( payload < = 3600 ) ) {
2017-10-18 17:22:34 +01:00
Settings . blinktime = payload ;
2018-08-26 16:10:18 +01:00
if ( blink_timer > 0 ) { blink_timer = millis ( ) + ( 100 * payload ) ; }
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . blinktime ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
else if ( CMND_BLINKCOUNT = = command_code ) {
2017-01-28 13:41:01 +00:00
if ( data_len > 0 ) {
2017-10-18 17:22:34 +01:00
Settings . blinkcount = payload16 ; // 0 - 65535
2018-03-02 14:38:37 +00:00
if ( blink_counter ) blink_counter = Settings . blinkcount * 2 ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . blinkcount ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
else if ( CMND_SAVEDATA = = command_code ) {
2017-06-06 22:23:23 +01:00
if ( ( payload > = 0 ) & & ( payload < = 3600 ) ) {
2017-10-18 17:22:34 +01:00
Settings . save_data = payload ;
save_data_counter = Settings . save_data ;
2017-01-28 13:41:01 +00:00
}
2017-11-21 15:06:51 +00:00
SettingsSaveAll ( ) ;
2017-10-18 17:22:34 +01:00
if ( Settings . save_data > 1 ) {
2018-01-06 16:34:42 +00:00
snprintf_P ( stemp1 , sizeof ( stemp1 ) , PSTR ( D_JSON_EVERY " %d " D_UNIT_SECOND ) , Settings . save_data ) ;
2017-04-25 17:24:42 +01:00
}
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_SVALUE , command , ( Settings . save_data > 1 ) ? stemp1 : GetStateText ( Settings . save_data ) ) ;
2017-01-28 13:41:01 +00:00
}
2018-09-21 15:19:31 +01:00
else if ( ( CMND_SENSOR = = command_code ) | | ( CMND_DRIVER = = command_code ) ) {
2018-01-24 16:31:20 +00:00
XdrvMailbox . index = index ;
XdrvMailbox . data_len = data_len ;
2018-03-02 14:38:37 +00:00
XdrvMailbox . payload16 = payload16 ;
XdrvMailbox . payload = payload ;
XdrvMailbox . grpflg = grpflg ;
XdrvMailbox . topic = command ;
2018-01-24 16:31:20 +00:00
XdrvMailbox . data = dataBuf ;
2018-09-21 15:19:31 +01:00
if ( CMND_SENSOR = = command_code ) {
XsnsCall ( FUNC_COMMAND ) ;
} else {
XdrvCall ( FUNC_COMMAND ) ;
}
2018-09-20 21:56:07 +01:00
}
2018-07-03 11:48:56 +01:00
else if ( ( CMND_SETOPTION = = command_code ) & & ( index < 82 ) ) {
byte ptype ;
byte pindex ;
if ( index < = 31 ) { // SetOption0 .. 31 = Settings.flag
ptype = 0 ;
pindex = index ; // 0 .. 31
}
else if ( index < = 49 ) { // SetOption32 .. 49 = Settings.param
ptype = 2 ;
pindex = index - 32 ; // 0 .. 17 (= PARAM8_SIZE -1)
}
else { // SetOption50 .. 81 = Settings.flag3
ptype = 1 ;
pindex = index - 50 ; // 0 .. 31
2017-06-16 13:33:49 +01:00
}
if ( payload > = 0 ) {
2018-07-03 11:48:56 +01:00
if ( 0 = = ptype ) { // SetOption0 .. 31
2017-06-16 13:33:49 +01:00
if ( payload < = 1 ) {
2018-07-03 11:48:56 +01:00
switch ( pindex ) {
case 5 : // mqtt_power_retain (CMND_POWERRETAIN)
case 6 : // mqtt_button_retain (CMND_BUTTONRETAIN)
case 7 : // mqtt_switch_retain (CMND_SWITCHRETAIN)
case 9 : // mqtt_sensor_retain (CMND_SENSORRETAIN)
case 22 : // mqtt_serial (SerialSend and SerialLog)
2018-07-28 14:43:13 +01:00
case 23 : // mqtt_serial_raw (SerialSend)
2018-07-04 17:41:00 +01:00
case 25 : // knx_enabled (Web config)
case 27 : // knx_enable_enhancement (Web config)
2018-07-03 11:48:56 +01:00
ptype = 99 ; // Command Error
break ; // Ignore command SetOption
case 3 : // mqtt
case 15 : // pwm_control
2017-10-18 17:22:34 +01:00
restart_flag = 2 ;
2018-07-03 11:48:56 +01:00
default :
bitWrite ( Settings . flag . data , pindex , payload ) ;
2017-06-16 13:33:49 +01:00
}
2018-07-03 11:48:56 +01:00
if ( 12 = = pindex ) { // stop_flash_rotate
2017-06-25 22:01:41 +01:00
stop_flash_rotate = payload ;
2017-10-18 17:22:34 +01:00
SettingsSave ( 2 ) ;
2017-06-19 21:54:49 +01:00
}
2018-03-29 13:01:38 +01:00
# ifdef USE_HOME_ASSISTANT
2018-07-03 11:48:56 +01:00
if ( ( 19 = = pindex ) | | ( 30 = = pindex ) ) {
HAssDiscovery ( 1 ) ; // hass_discovery or hass_light
2018-03-29 13:01:38 +01:00
}
# endif // USE_HOME_ASSISTANT
2017-06-16 13:33:49 +01:00
}
2017-05-11 16:47:34 +01:00
}
2018-07-03 11:48:56 +01:00
else if ( 1 = = ptype ) { // SetOption50 .. 81
if ( payload < = 1 ) {
bitWrite ( Settings . flag3 . data , pindex , payload ) ;
}
}
else { // SetOption32 .. 49
2018-10-18 12:01:31 +01:00
uint8_t param_low = 0 ;
uint8_t param_high = 255 ;
2018-07-03 11:48:56 +01:00
switch ( pindex ) {
2017-06-16 13:33:49 +01:00
case P_HOLD_TIME :
2017-06-19 21:54:49 +01:00
case P_MAX_POWER_RETRY :
2018-10-18 12:01:31 +01:00
param_low = 1 ;
param_high = 250 ;
2017-06-19 21:54:49 +01:00
break ;
2018-07-03 11:48:56 +01:00
}
2018-10-18 12:01:31 +01:00
if ( ( payload > = param_low ) & & ( payload < = param_high ) ) {
2018-07-03 11:48:56 +01:00
Settings . param [ pindex ] = payload ;
2017-06-16 13:33:49 +01:00
}
}
}
2018-07-03 11:48:56 +01:00
if ( ptype < 99 ) {
if ( 2 = = ptype ) snprintf_P ( stemp1 , sizeof ( stemp1 ) , PSTR ( " %d " ) , Settings . param [ pindex ] ) ;
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_INDEX_SVALUE , command , index , ( 2 = = ptype ) ? stemp1 : ( 1 = = ptype ) ? GetStateText ( bitRead ( Settings . flag3 . data , pindex ) ) : GetStateText ( bitRead ( Settings . flag . data , pindex ) ) ) ;
}
2017-05-11 16:47:34 +01:00
}
2017-10-29 17:18:46 +00:00
else if ( CMND_TEMPERATURE_RESOLUTION = = command_code ) {
2017-06-06 22:23:23 +01:00
if ( ( payload > = 0 ) & & ( payload < = 3 ) ) {
2017-11-11 11:33:30 +00:00
Settings . flag2 . temperature_resolution = payload ;
2017-05-03 17:19:13 +01:00
}
2017-11-11 11:33:30 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . flag2 . temperature_resolution ) ;
2017-05-03 17:19:13 +01:00
}
2017-10-29 17:18:46 +00:00
else if ( CMND_HUMIDITY_RESOLUTION = = command_code ) {
2017-06-06 22:23:23 +01:00
if ( ( payload > = 0 ) & & ( payload < = 3 ) ) {
2017-11-11 11:33:30 +00:00
Settings . flag2 . humidity_resolution = payload ;
2017-05-03 17:19:13 +01:00
}
2017-11-11 11:33:30 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . flag2 . humidity_resolution ) ;
2017-05-03 17:19:13 +01:00
}
2017-10-29 17:18:46 +00:00
else if ( CMND_PRESSURE_RESOLUTION = = command_code ) {
2017-06-06 22:23:23 +01:00
if ( ( payload > = 0 ) & & ( payload < = 3 ) ) {
2017-11-11 11:33:30 +00:00
Settings . flag2 . pressure_resolution = payload ;
2017-05-03 17:19:13 +01:00
}
2017-11-11 11:33:30 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . flag2 . pressure_resolution ) ;
2017-05-03 17:19:13 +01:00
}
2017-10-29 17:18:46 +00:00
else if ( CMND_POWER_RESOLUTION = = command_code ) {
2017-11-11 11:33:30 +00:00
if ( ( payload > = 0 ) & & ( payload < = 3 ) ) {
Settings . flag2 . wattage_resolution = payload ;
2017-08-20 10:40:50 +01:00
}
2017-11-11 11:33:30 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . flag2 . wattage_resolution ) ;
2017-08-20 10:40:50 +01:00
}
2017-10-29 17:18:46 +00:00
else if ( CMND_VOLTAGE_RESOLUTION = = command_code ) {
2017-11-11 11:33:30 +00:00
if ( ( payload > = 0 ) & & ( payload < = 3 ) ) {
Settings . flag2 . voltage_resolution = payload ;
}
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . flag2 . voltage_resolution ) ;
}
2018-09-07 17:15:47 +01:00
else if ( CMND_FREQUENCY_RESOLUTION = = command_code ) {
if ( ( payload > = 0 ) & & ( payload < = 3 ) ) {
Settings . flag2 . frequency_resolution = payload ;
}
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . flag2 . frequency_resolution ) ;
}
2017-11-11 11:33:30 +00:00
else if ( CMND_CURRENT_RESOLUTION = = command_code ) {
if ( ( payload > = 0 ) & & ( payload < = 3 ) ) {
Settings . flag2 . current_resolution = payload ;
2017-08-05 14:11:50 +01:00
}
2017-11-11 11:33:30 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . flag2 . current_resolution ) ;
2017-08-05 14:11:50 +01:00
}
2017-10-29 17:18:46 +00:00
else if ( CMND_ENERGY_RESOLUTION = = command_code ) {
2017-06-06 22:23:23 +01:00
if ( ( payload > = 0 ) & & ( payload < = 5 ) ) {
2017-11-11 11:33:30 +00:00
Settings . flag2 . energy_resolution = payload ;
2017-05-03 17:19:13 +01:00
}
2017-11-11 11:33:30 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . flag2 . energy_resolution ) ;
2017-03-08 15:20:45 +00:00
}
2018-10-08 13:39:36 +01:00
else if ( CMND_WEIGHT_RESOLUTION = = command_code ) {
if ( ( payload > = 0 ) & & ( payload < = 3 ) ) {
Settings . flag2 . weight_resolution = payload ;
}
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . flag2 . weight_resolution ) ;
}
2017-10-29 17:18:46 +00:00
else if ( CMND_MODULE = = command_code ) {
2017-06-06 22:23:23 +01:00
if ( ( payload > 0 ) & & ( payload < = MAXMODULE ) ) {
2017-03-19 17:19:08 +00:00
payload - - ;
2017-11-15 22:07:45 +00:00
Settings . last_module = Settings . module ;
2017-10-18 17:22:34 +01:00
Settings . module = payload ;
2017-11-15 22:07:45 +00:00
if ( Settings . last_module ! = payload ) {
2017-04-25 17:24:42 +01:00
for ( byte i = 0 ; i < MAX_GPIO_PIN ; i + + ) {
2017-10-18 17:22:34 +01:00
Settings . my_gp . io [ i ] = 0 ;
2017-04-25 17:24:42 +01:00
}
2017-04-03 15:38:15 +01:00
}
2017-10-18 17:22:34 +01:00
restart_flag = 2 ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
snprintf_P ( stemp1 , sizeof ( stemp1 ) , kModules [ Settings . module ] . name ) ;
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE_SVALUE , command , Settings . module + 1 , stemp1 ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
else if ( CMND_MODULES = = command_code ) {
2017-09-14 14:35:38 +01:00
for ( byte i = 0 ; i < MAXMODULE ; i + + ) {
if ( ! jsflg ) {
2017-12-18 17:20:28 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { \" " D_CMND_MODULES " %d \" :[ " ) , lines ) ;
2017-09-14 14:35:38 +01:00
} else {
2017-11-11 11:33:30 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s, " ) , mqtt_data ) ;
2017-04-25 17:24:42 +01:00
}
2017-01-28 13:41:01 +00:00
jsflg = 1 ;
2017-10-18 17:22:34 +01:00
snprintf_P ( stemp1 , sizeof ( stemp1 ) , kModules [ i ] . name ) ;
2017-12-18 17:20:28 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s \" %d (%s) \" " ) , mqtt_data , i + 1 , stemp1 ) ;
2018-01-18 15:19:28 +00:00
if ( ( strlen ( mqtt_data ) > ( LOGSZ - TOPSZ ) ) | | ( i = = MAXMODULE - 1 ) ) {
2017-12-18 17:20:28 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s]} " ) , mqtt_data ) ;
2018-01-18 15:19:28 +00:00
MqttPublishPrefixTopic_P ( RESULT_OR_STAT , type ) ;
2017-09-14 14:35:38 +01:00
jsflg = 0 ;
lines + + ;
2017-04-25 17:24:42 +01:00
}
2017-01-28 13:41:01 +00:00
}
2017-09-14 14:35:38 +01:00
mqtt_data [ 0 ] = ' \0 ' ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
else if ( ( CMND_GPIO = = command_code ) & & ( index < MAX_GPIO_PIN ) ) {
2017-01-28 13:41:01 +00:00
mytmplt cmodule ;
2017-10-18 17:22:34 +01:00
memcpy_P ( & cmodule , & kModules [ Settings . module ] , sizeof ( cmodule ) ) ;
2018-09-06 09:42:22 +01:00
if ( ( GPIO_USER = = ValidGPIO ( index , cmodule . gp . io [ index ] ) ) & & ( payload > = 0 ) & & ( payload < GPIO_SENSOR_END ) ) {
2018-11-05 16:27:02 +00:00
bool present = false ;
for ( byte i = 0 ; i < sizeof ( kGpioNiceList ) ; i + + ) {
uint8_t midx = pgm_read_byte ( kGpioNiceList + i ) ;
if ( midx = = payload ) { present = true ; }
}
if ( present ) {
for ( byte i = 0 ; i < MAX_GPIO_PIN ; i + + ) {
if ( ( GPIO_USER = = ValidGPIO ( i , cmodule . gp . io [ i ] ) ) & & ( Settings . my_gp . io [ i ] = = payload ) ) {
Settings . my_gp . io [ i ] = 0 ;
}
2017-04-25 17:24:42 +01:00
}
2018-11-05 16:27:02 +00:00
Settings . my_gp . io [ index ] = payload ;
restart_flag = 2 ;
2017-01-28 13:41:01 +00:00
}
}
2017-09-13 13:19:34 +01:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { " ) ) ;
2017-01-28 13:41:01 +00:00
for ( byte i = 0 ; i < MAX_GPIO_PIN ; i + + ) {
2018-09-06 09:42:22 +01:00
if ( GPIO_USER = = ValidGPIO ( i , cmodule . gp . io [ i ] ) ) {
2018-03-02 14:38:37 +00:00
if ( jsflg ) snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s, " ) , mqtt_data ) ;
2017-01-28 13:41:01 +00:00
jsflg = 1 ;
2018-02-01 15:18:00 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s \" " D_CMND_GPIO " %d \" : \" %d (%s) \" " ) ,
mqtt_data , i , Settings . my_gp . io [ i ] , GetTextIndexed ( stemp1 , sizeof ( stemp1 ) , Settings . my_gp . io [ i ] , kSensorNames ) ) ;
2017-01-28 13:41:01 +00:00
}
}
if ( jsflg ) {
2017-09-13 13:19:34 +01:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s} " ) , mqtt_data ) ;
2017-01-28 13:41:01 +00:00
} else {
2018-01-06 16:34:42 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_SVALUE , command , D_JSON_NOT_SUPPORTED ) ;
2017-01-28 13:41:01 +00:00
}
}
2017-10-29 17:18:46 +00:00
else if ( CMND_GPIOS = = command_code ) {
2018-06-03 16:09:10 +01:00
mytmplt cmodule ;
memcpy_P ( & cmodule , & kModules [ Settings . module ] , sizeof ( cmodule ) ) ;
2018-11-05 16:27:02 +00:00
uint8_t midx ;
for ( byte i = 0 ; i < sizeof ( kGpioNiceList ) ; i + + ) {
midx = pgm_read_byte ( kGpioNiceList + i ) ;
if ( ! GetUsedInModule ( midx , cmodule . gp . io ) ) {
2018-08-23 15:05:51 +01:00
if ( ! jsflg ) {
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { \" " D_CMND_GPIOS " %d \" :[ " ) , lines ) ;
} else {
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s, " ) , mqtt_data ) ;
}
jsflg = 1 ;
2018-11-05 16:27:02 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s \" %d (%s) \" " ) , mqtt_data , midx , GetTextIndexed ( stemp1 , sizeof ( stemp1 ) , midx , kSensorNames ) ) ;
if ( ( strlen ( mqtt_data ) > ( LOGSZ - TOPSZ ) ) | | ( i = = sizeof ( kGpioNiceList ) - 1 ) ) {
2018-06-03 16:09:10 +01:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s]} " ) , mqtt_data ) ;
MqttPublishPrefixTopic_P ( RESULT_OR_STAT , type ) ;
jsflg = 0 ;
lines + + ;
}
2017-04-25 17:24:42 +01:00
}
2017-01-28 13:41:01 +00:00
}
2018-11-05 16:27:02 +00:00
2017-09-14 14:35:38 +01:00
mqtt_data [ 0 ] = ' \0 ' ;
2017-01-28 13:41:01 +00:00
}
2018-02-06 09:06:22 +00:00
else if ( ( CMND_PWM = = command_code ) & & pwm_present & & ( index > 0 ) & & ( index < = MAX_PWMS ) ) {
2017-10-18 17:22:34 +01:00
if ( ( payload > = 0 ) & & ( payload < = Settings . pwm_range ) & & ( pin [ GPIO_PWM1 + index - 1 ] < 99 ) ) {
Settings . pwm_value [ index - 1 ] = payload ;
analogWrite ( pin [ GPIO_PWM1 + index - 1 ] , bitRead ( pwm_inverted , index - 1 ) ? Settings . pwm_range - payload : payload ) ;
2017-03-19 17:19:08 +00:00
}
2018-03-20 15:28:18 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { " ) ) ;
MqttShowPWMState ( ) ; // Render the PWM status to MQTT
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s} " ) , mqtt_data ) ;
2017-03-19 17:19:08 +00:00
}
2017-10-29 17:18:46 +00:00
else if ( CMND_PWMFREQUENCY = = command_code ) {
2018-10-07 18:27:09 +01:00
if ( ( 1 = = payload ) | | ( ( payload > = PWM_MIN ) & & ( payload < = PWM_MAX ) ) ) {
2017-10-18 17:22:34 +01:00
Settings . pwm_frequency = ( 1 = = payload ) ? PWM_FREQ : payload ;
analogWriteFreq ( Settings . pwm_frequency ) ; // Default is 1000 (core_esp8266_wiring_pwm.c)
}
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . pwm_frequency ) ;
2017-10-18 17:22:34 +01:00
}
2017-10-29 17:18:46 +00:00
else if ( CMND_PWMRANGE = = command_code ) {
2017-10-18 17:22:34 +01:00
if ( ( 1 = = payload ) | | ( ( payload > 254 ) & & ( payload < 1024 ) ) ) {
Settings . pwm_range = ( 1 = = payload ) ? PWM_RANGE : payload ;
2018-02-03 22:25:05 +00:00
for ( byte i = 0 ; i < MAX_PWMS ; i + + ) {
2017-10-18 17:22:34 +01:00
if ( Settings . pwm_value [ i ] > Settings . pwm_range ) {
Settings . pwm_value [ i ] = Settings . pwm_range ;
}
}
analogWriteRange ( Settings . pwm_range ) ; // Default is 1023 (Arduino.h)
}
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . pwm_range ) ;
2017-10-18 17:22:34 +01:00
}
2017-10-29 17:18:46 +00:00
else if ( ( CMND_COUNTER = = command_code ) & & ( index > 0 ) & & ( index < = MAX_COUNTERS ) ) {
2018-08-25 12:08:06 +01:00
if ( ( data_len > 0 ) & & ( pin [ GPIO_CNTR1 + index - 1 ] < 99 ) ) {
2018-06-26 16:17:23 +01:00
if ( ( dataBuf [ 0 ] = = ' - ' ) | | ( dataBuf [ 0 ] = = ' + ' ) ) {
RtcSettings . pulse_counter [ index - 1 ] + = payload32 ;
Settings . pulse_counter [ index - 1 ] + = payload32 ;
} else {
RtcSettings . pulse_counter [ index - 1 ] = payload32 ;
Settings . pulse_counter [ index - 1 ] = payload32 ;
}
2017-05-17 21:49:22 +01:00
}
2018-02-03 22:25:05 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_INDEX_LVALUE , command , index , RtcSettings . pulse_counter [ index - 1 ] ) ;
2017-05-17 21:49:22 +01:00
}
2017-10-29 17:18:46 +00:00
else if ( ( CMND_COUNTERTYPE = = command_code ) & & ( index > 0 ) & & ( index < = MAX_COUNTERS ) ) {
2018-08-25 12:08:06 +01:00
if ( ( payload > = 0 ) & & ( payload < = 1 ) & & ( pin [ GPIO_CNTR1 + index - 1 ] < 99 ) ) {
2017-10-18 17:22:34 +01:00
bitWrite ( Settings . pulse_counter_type , index - 1 , payload & 1 ) ;
RtcSettings . pulse_counter [ index - 1 ] = 0 ;
Settings . pulse_counter [ index - 1 ] = 0 ;
2017-05-17 21:49:22 +01:00
}
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_INDEX_NVALUE , command , index , bitRead ( Settings . pulse_counter_type , index - 1 ) ) ;
2017-05-17 21:49:22 +01:00
}
2017-10-29 17:18:46 +00:00
else if ( CMND_COUNTERDEBOUNCE = = command_code ) {
2017-06-19 21:54:49 +01:00
if ( ( data_len > 0 ) & & ( payload16 < 32001 ) ) {
2017-10-18 17:22:34 +01:00
Settings . pulse_counter_debounce = payload16 ;
2017-05-17 21:49:22 +01:00
}
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . pulse_counter_debounce ) ;
2017-05-17 21:49:22 +01:00
}
2018-08-27 11:01:20 +01:00
else if ( CMND_BUTTONDEBOUNCE = = command_code ) {
if ( ( payload > 39 ) & & ( payload < 1001 ) ) {
2018-08-27 12:06:22 +01:00
Settings . button_debounce = payload ;
2018-08-27 11:01:20 +01:00
}
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 ) ) {
2018-08-27 12:06:22 +01:00
Settings . switch_debounce = payload ;
2018-08-27 11:01:20 +01:00
}
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . switch_debounce ) ;
}
2018-03-18 12:47:30 +00:00
else if ( CMND_BAUDRATE = = command_code ) {
if ( payload32 > 0 ) {
payload32 / = 1200 ; // Make it a valid baudrate
baudrate = ( 1 = = payload ) ? APP_BAUDRATE : payload32 * 1200 ;
SetSerialBaudrate ( baudrate ) ;
}
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . baudrate * 1200 ) ;
}
2018-09-16 15:09:00 +01:00
else if ( ( CMND_SERIALSEND = = command_code ) & & ( index > 0 ) & & ( index < = 5 ) ) {
2018-03-18 12:47:30 +00:00
SetSeriallog ( LOG_LEVEL_NONE ) ;
Settings . flag . mqtt_serial = 1 ;
2018-09-16 15:09:00 +01:00
Settings . flag . mqtt_serial_raw = ( index > 3 ) ? 1 : 0 ;
2018-03-18 12:47:30 +00:00
if ( data_len > 0 ) {
2018-03-20 13:31:11 +00:00
if ( 1 = = index ) {
2018-09-16 15:09:00 +01:00
Serial . printf ( " %s \n " , dataBuf ) ; // "Hello Tiger\n"
2018-03-20 13:31:11 +00:00
}
2018-07-27 11:17:34 +01:00
else if ( 2 = = index | | 4 = = index ) {
2018-07-28 14:43:13 +01:00
for ( int i = 0 ; i < data_len ; i + + ) {
2018-09-16 15:09:00 +01:00
Serial . write ( dataBuf [ i ] ) ; // "Hello Tiger" or "A0"
2018-07-27 11:17:34 +01:00
}
2018-03-20 13:31:11 +00:00
}
else if ( 3 = = index ) {
uint16_t dat_len = data_len ;
2018-09-16 15:09:00 +01:00
Serial . printf ( " %s " , Unescape ( dataBuf , & dat_len ) ) ; // "Hello\f"
}
else if ( 5 = = index ) {
2018-10-16 10:21:44 +01:00
SerialSendRaw ( RemoveSpace ( dataBuf ) ) ; // "AA004566"
2018-03-20 13:31:11 +00:00
}
2018-03-18 12:47:30 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_SVALUE , command , D_JSON_DONE ) ;
}
}
2018-03-20 13:31:11 +00:00
else if ( CMND_SERIALDELIMITER = = command_code ) {
if ( ( data_len > 0 ) & & ( payload < 256 ) ) {
if ( payload > 0 ) {
Settings . serial_delimiter = payload ;
} else {
uint16_t dat_len = data_len ;
Unescape ( dataBuf , & dat_len ) ;
Settings . serial_delimiter = dataBuf [ 0 ] ;
}
}
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . serial_delimiter ) ;
}
2017-10-29 17:18:46 +00:00
else if ( CMND_SYSLOG = = command_code ) {
2017-06-06 22:23:23 +01:00
if ( ( payload > = LOG_LEVEL_NONE ) & & ( payload < = LOG_LEVEL_ALL ) ) {
2017-10-18 17:22:34 +01:00
Settings . syslog_level = payload ;
2018-09-12 23:00:35 +01:00
syslog_level = payload ;
2017-01-28 13:41:01 +00:00
syslog_timer = 0 ;
}
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE_ACTIVE_NVALUE , command , Settings . syslog_level , syslog_level ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
else if ( CMND_LOGHOST = = command_code ) {
2017-10-18 17:22:34 +01:00
if ( ( data_len > 0 ) & & ( data_len < sizeof ( Settings . syslog_host ) ) ) {
2018-08-27 13:53:09 +01:00
strlcpy ( Settings . syslog_host , ( SC_DEFAULT = = Shortcut ( dataBuf ) ) ? SYS_LOG_HOST : dataBuf , sizeof ( Settings . syslog_host ) ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_SVALUE , command , Settings . syslog_host ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
else if ( CMND_LOGPORT = = command_code ) {
2018-08-27 12:06:22 +01:00
if ( payload16 > 0 ) {
Settings . syslog_port = ( 1 = = payload16 ) ? SYS_LOG_PORT : payload16 ;
}
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . syslog_port ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
else if ( ( CMND_IPADDRESS = = command_code ) & & ( index > 0 ) & & ( index < = 4 ) ) {
2017-10-18 17:22:34 +01:00
if ( ParseIp ( & address , dataBuf ) ) {
Settings . ip_address [ index - 1 ] = address ;
// restart_flag = 2;
2017-03-25 16:24:11 +00:00
}
2017-03-29 17:42:05 +01:00
snprintf_P ( stemp1 , sizeof ( stemp1 ) , PSTR ( " (%s) " ) , WiFi . localIP ( ) . toString ( ) . c_str ( ) ) ;
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_INDEX_SVALUE_SVALUE , command , index , IPAddress ( Settings . ip_address [ index - 1 ] ) . toString ( ) . c_str ( ) , ( 1 = = index ) ? stemp1 : " " ) ;
2017-03-25 16:24:11 +00:00
}
2017-10-29 17:18:46 +00:00
else if ( ( CMND_NTPSERVER = = command_code ) & & ( index > 0 ) & & ( index < = 3 ) ) {
2017-10-18 17:22:34 +01:00
if ( ( data_len > 0 ) & & ( data_len < sizeof ( Settings . ntp_server [ 0 ] ) ) ) {
2018-08-27 13:53:09 +01:00
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 ] ) ) ;
2017-10-18 17:22:34 +01:00
for ( i = 0 ; i < strlen ( Settings . ntp_server [ index - 1 ] ) ; i + + ) {
2018-03-02 14:38:37 +00:00
if ( Settings . ntp_server [ index - 1 ] [ i ] = = ' , ' ) Settings . ntp_server [ index - 1 ] [ i ] = ' . ' ;
2017-04-25 17:24:42 +01:00
}
2018-09-25 10:35:37 +01:00
// restart_flag = 2; // Issue #3890
ntp_force_sync = 1 ;
2017-03-12 17:36:33 +00:00
}
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_INDEX_SVALUE , command , index , Settings . ntp_server [ index - 1 ] ) ;
2017-03-12 17:36:33 +00:00
}
2017-10-29 17:18:46 +00:00
else if ( CMND_AP = = command_code ) {
2017-06-06 22:23:23 +01:00
if ( ( payload > = 0 ) & & ( payload < = 2 ) ) {
2017-01-28 13:41:01 +00:00
switch ( payload ) {
case 0 : // Toggle
2017-10-18 17:22:34 +01:00
Settings . sta_active ^ = 1 ;
2017-01-28 13:41:01 +00:00
break ;
case 1 : // AP1
case 2 : // AP2
2017-10-18 17:22:34 +01:00
Settings . sta_active = payload - 1 ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
restart_flag = 2 ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE_SVALUE , command , Settings . sta_active + 1 , Settings . sta_ssid [ Settings . sta_active ] ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
else if ( ( CMND_SSID = = command_code ) & & ( index > 0 ) & & ( index < = 2 ) ) {
2017-10-18 17:22:34 +01:00
if ( ( data_len > 0 ) & & ( data_len < sizeof ( Settings . sta_ssid [ 0 ] ) ) ) {
2018-08-27 13:53:09 +01:00
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 ] ) ) ;
2017-10-18 17:22:34 +01:00
Settings . sta_active = index - 1 ;
restart_flag = 2 ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_INDEX_SVALUE , command , index , Settings . sta_ssid [ index - 1 ] ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
else if ( ( CMND_PASSWORD = = command_code ) & & ( index > 0 ) & & ( index < = 2 ) ) {
2017-10-18 17:22:34 +01:00
if ( ( data_len > 0 ) & & ( data_len < sizeof ( Settings . sta_pwd [ 0 ] ) ) ) {
2018-08-27 13:53:09 +01:00
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 ] ) ) ;
2017-10-18 17:22:34 +01:00
Settings . sta_active = index - 1 ;
restart_flag = 2 ;
2018-04-21 17:17:24 +01:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_INDEX_SVALUE , command , index , Settings . sta_pwd [ index - 1 ] ) ;
} else {
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_INDEX_ASTERIX , command , index ) ;
2017-01-28 13:41:01 +00:00
}
}
2017-10-29 17:18:46 +00:00
else if ( ( CMND_HOSTNAME = = command_code ) & & ! grpflg ) {
2017-10-18 17:22:34 +01:00
if ( ( data_len > 0 ) & & ( data_len < sizeof ( Settings . hostname ) ) ) {
2018-08-27 13:53:09 +01:00
strlcpy ( Settings . hostname , ( SC_DEFAULT = = Shortcut ( dataBuf ) ) ? WIFI_HOSTNAME : dataBuf , sizeof ( Settings . hostname ) ) ;
2017-10-18 17:22:34 +01:00
if ( strstr ( Settings . hostname , " % " ) ) {
strlcpy ( Settings . hostname , WIFI_HOSTNAME , sizeof ( Settings . hostname ) ) ;
2017-04-25 17:24:42 +01:00
}
2017-10-18 17:22:34 +01:00
restart_flag = 2 ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_SVALUE , command , Settings . hostname ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
else if ( CMND_WIFICONFIG = = command_code ) {
2017-06-06 22:23:23 +01:00
if ( ( payload > = WIFI_RESTART ) & & ( payload < MAX_WIFI_OPTION ) ) {
2017-10-18 17:22:34 +01:00
Settings . sta_config = payload ;
wifi_state_flag = Settings . sta_config ;
snprintf_P ( stemp1 , sizeof ( stemp1 ) , kWifiConfig [ Settings . sta_config ] ) ;
2018-01-06 16:34:42 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { \" " D_CMND_WIFICONFIG " \" : \" %s " D_JSON_SELECTED " \" } " ) , stemp1 ) ;
2018-10-30 14:34:31 +00:00
if ( WifiState ( ) > WIFI_RESTART ) {
2017-09-13 13:19:34 +01:00
// snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s after restart"), mqtt_data);
2017-10-18 17:22:34 +01:00
restart_flag = 2 ;
2017-01-28 13:41:01 +00:00
}
} else {
2017-10-18 17:22:34 +01:00
snprintf_P ( stemp1 , sizeof ( stemp1 ) , kWifiConfig [ Settings . sta_config ] ) ;
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE_SVALUE , command , Settings . sta_config , stemp1 ) ;
2017-01-28 13:41:01 +00:00
}
}
2018-06-30 13:17:26 +01:00
else if ( ( CMND_FRIENDLYNAME = = command_code ) & & ( index > 0 ) & & ( index < = MAX_FRIENDLYNAMES ) ) {
2017-10-18 17:22:34 +01:00
if ( ( data_len > 0 ) & & ( data_len < sizeof ( Settings . friendlyname [ 0 ] ) ) ) {
2017-04-25 17:24:42 +01:00
if ( 1 = = index ) {
2017-01-29 20:36:12 +00:00
snprintf_P ( stemp1 , sizeof ( stemp1 ) , PSTR ( FRIENDLY_NAME ) ) ;
} else {
snprintf_P ( stemp1 , sizeof ( stemp1 ) , PSTR ( FRIENDLY_NAME " %d " ) , index ) ;
}
2018-08-27 13:53:09 +01:00
strlcpy ( Settings . friendlyname [ index - 1 ] , ( SC_DEFAULT = = Shortcut ( dataBuf ) ) ? stemp1 : dataBuf , sizeof ( Settings . friendlyname [ index - 1 ] ) ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_INDEX_SVALUE , command , index , Settings . friendlyname [ index - 1 ] ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
else if ( ( CMND_SWITCHMODE = = command_code ) & & ( index > 0 ) & & ( index < = MAX_SWITCHES ) ) {
2018-08-27 12:06:22 +01:00
if ( ( payload > = 0 ) & & ( payload < MAX_SWITCH_OPTION ) ) {
Settings . switchmode [ index - 1 ] = payload ;
2018-09-26 10:56:58 +01:00
GpioSwitchPinMode ( index - 1 ) ;
2018-08-27 12:06:22 +01:00
}
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_INDEX_NVALUE , command , index , Settings . switchmode [ index - 1 ] ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
else if ( CMND_TELEPERIOD = = command_code ) {
2017-06-06 22:23:23 +01:00
if ( ( payload > = 0 ) & & ( payload < 3601 ) ) {
2017-10-18 17:22:34 +01:00
Settings . tele_period = ( 1 = = payload ) ? TELE_PERIOD : payload ;
2018-03-02 14:38:37 +00:00
if ( ( Settings . tele_period > 0 ) & & ( Settings . tele_period < 10 ) ) Settings . tele_period = 10 ; // Do not allow periods < 10 seconds
2017-10-18 17:22:34 +01:00
tele_period = Settings . tele_period ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE_UNIT , command , Settings . tele_period , ( Settings . flag . value_units ) ? " " D_UNIT_SECOND : " " ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
else if ( CMND_RESET = = command_code ) {
2017-01-28 13:41:01 +00:00
switch ( payload ) {
case 1 :
2017-10-18 17:22:34 +01:00
restart_flag = 211 ;
2018-01-06 16:34:42 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_SVALUE , command , D_JSON_RESET_AND_RESTARTING ) ;
2017-01-28 13:41:01 +00:00
break ;
case 2 :
2018-02-24 15:37:33 +00:00
case 3 :
2018-10-14 19:00:41 +01:00
case 4 :
2018-10-14 23:10:02 +01:00
case 5 :
2018-10-15 13:43:47 +01:00
restart_flag = 210 + payload ;
2018-10-14 23:10:02 +01:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { \" " D_CMND_RESET " \" : \" " D_JSON_ERASE " , " D_JSON_RESET_AND_RESTARTING " \" } " ) ) ;
break ;
2017-01-28 13:41:01 +00:00
default :
2018-01-06 16:34:42 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_SVALUE , command , D_JSON_ONE_TO_RESET ) ;
2017-01-28 13:41:01 +00:00
}
}
2017-10-29 17:18:46 +00:00
else if ( CMND_TIMEZONE = = command_code ) {
2018-11-01 12:00:05 +00:00
if ( ( data_len > 0 ) & & ( payload > = - 13 ) ) {
2018-08-27 12:06:22 +01:00
Settings . timezone = payload ;
2018-11-01 12:00:05 +00:00
Settings . timezone_minutes = 0 ;
if ( payload < 15 ) {
p = strtok ( dataBuf , " : " ) ;
if ( p ) {
p = strtok ( NULL , " : " ) ;
if ( p ) {
Settings . timezone_minutes = strtol ( p , NULL , 10 ) ;
if ( Settings . timezone_minutes > 59 ) { Settings . timezone_minutes = 59 ; }
}
}
} else {
Settings . timezone = 99 ;
}
ntp_force_sync = 1 ;
}
if ( 99 = = Settings . timezone ) {
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . timezone ) ;
} else {
snprintf_P ( stemp1 , sizeof ( stemp1 ) , PSTR ( " %+03d:%02d " ) , Settings . timezone , Settings . timezone_minutes ) ;
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_SVALUE , command , stemp1 ) ;
2018-08-27 12:06:22 +01:00
}
2017-01-28 13:41:01 +00:00
}
2018-05-14 22:22:29 +01:00
else if ( ( CMND_TIMESTD = = command_code ) | | ( CMND_TIMEDST = = command_code ) ) {
// TimeStd 0/1, 0/1/2/3/4, 1..12, 1..7, 0..23, +/-780
uint8_t ts = 0 ;
if ( CMND_TIMEDST = = command_code ) { ts = 1 ; }
if ( data_len > 0 ) {
2018-05-15 11:32:53 +01:00
if ( strstr ( dataBuf , " , " ) ) { // Process parameter entry
uint8_t tpos = 0 ; // Parameter index
int value = 0 ;
p = dataBuf ; // Parameters like "1, 2,3 , 4 ,5, -120" or ",,,,,+240"
char * q = p ; // Value entered flag
2018-05-14 22:22:29 +01:00
while ( p & & ( tpos < 7 ) ) {
2018-05-15 11:32:53 +01:00
if ( p > q ) { // Any value entered
if ( 1 = = tpos ) { Settings . tflag [ ts ] . hemis = value & 1 ; }
if ( 2 = = tpos ) { Settings . tflag [ ts ] . week = ( value < 0 ) ? 0 : ( value > 4 ) ? 4 : value ; }
if ( 3 = = tpos ) { Settings . tflag [ ts ] . month = ( value < 1 ) ? 1 : ( value > 12 ) ? 12 : value ; }
if ( 4 = = tpos ) { Settings . tflag [ ts ] . dow = ( value < 1 ) ? 1 : ( value > 7 ) ? 7 : value ; }
if ( 5 = = tpos ) { Settings . tflag [ ts ] . hour = ( value < 0 ) ? 0 : ( value > 23 ) ? 23 : value ; }
if ( 6 = = tpos ) { Settings . toffset [ ts ] = ( value < - 900 ) ? - 900 : ( value > 900 ) ? 900 : value ; }
}
2018-11-12 14:54:18 +00:00
p = Trim ( p ) ; // Skip spaces
2018-05-15 11:32:53 +01:00
if ( tpos & & ( * p = = ' , ' ) ) { p + + ; } // Skip separator
2018-11-12 14:54:18 +00:00
p = Trim ( p ) ; // Skip spaces
2018-05-15 11:32:53 +01:00
q = p ; // Reset any value entered flag
2018-05-14 22:22:29 +01:00
value = strtol ( p , & p , 10 ) ;
2018-05-15 11:32:53 +01:00
tpos + + ; // Next parameter
2018-05-14 22:22:29 +01:00
}
ntp_force_sync = 1 ;
} else {
if ( 0 = = payload ) {
if ( 0 = = ts ) {
SettingsResetStd ( ) ;
} else {
SettingsResetDst ( ) ;
}
}
ntp_force_sync = 1 ;
}
}
2018-07-25 09:04:35 +01:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { \" %s \" :{ \" Hemisphere \" :%d, \" Week \" :%d, \" Month \" :%d, \" Day \" :%d, \" Hour \" :%d, \" Offset \" :%d}} " ) ,
2018-05-14 22:22:29 +01:00
command , Settings . tflag [ ts ] . hemis , Settings . tflag [ ts ] . week , Settings . tflag [ ts ] . month , Settings . tflag [ ts ] . dow , Settings . tflag [ ts ] . hour , Settings . toffset [ ts ] ) ;
}
2017-10-29 17:18:46 +00:00
else if ( CMND_ALTITUDE = = command_code ) {
2018-08-27 12:06:22 +01:00
if ( ( data_len > 0 ) & & ( ( payload > = - 30000 ) & & ( payload < = 30000 ) ) ) {
Settings . altitude = payload ;
}
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . altitude ) ;
2017-10-08 15:51:05 +01:00
}
2017-10-29 17:18:46 +00:00
else if ( CMND_LEDPOWER = = command_code ) {
2017-06-06 22:23:23 +01:00
if ( ( payload > = 0 ) & & ( payload < = 2 ) ) {
2017-10-18 17:22:34 +01:00
Settings . ledstate & = 8 ;
2017-01-28 13:41:01 +00:00
switch ( payload ) {
case 0 : // Off
case 1 : // On
2017-10-18 17:22:34 +01:00
Settings . ledstate = payload < < 3 ;
2017-01-28 13:41:01 +00:00
break ;
case 2 : // Toggle
2017-10-18 17:22:34 +01:00
Settings . ledstate ^ = 8 ;
2017-01-28 13:41:01 +00:00
break ;
}
blinks = 0 ;
2017-10-18 17:22:34 +01:00
SetLedPower ( Settings . ledstate & 8 ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_SVALUE , command , GetStateText ( bitRead ( Settings . ledstate , 3 ) ) ) ;
2017-01-28 13:41:01 +00:00
}
2018-03-18 12:47:30 +00:00
else if ( CMND_LEDSTATE = = command_code ) {
2017-06-06 22:23:23 +01:00
if ( ( payload > = 0 ) & & ( payload < MAX_LED_OPTION ) ) {
2017-10-18 17:22:34 +01:00
Settings . ledstate = payload ;
2018-03-02 14:38:37 +00:00
if ( ! Settings . ledstate ) SetLedPower ( 0 ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . ledstate ) ;
2017-01-28 13:41:01 +00:00
}
2017-11-11 11:33:30 +00:00
# ifdef USE_I2C
else if ( ( CMND_I2CSCAN = = command_code ) & & i2c_flg ) {
I2cScan ( mqtt_data , sizeof ( mqtt_data ) ) ;
}
# endif // USE_I2C
2018-05-09 09:49:43 +01:00
else type = NULL ; // Unknown command
2017-01-28 13:41:01 +00:00
}
if ( type = = NULL ) {
blinks = 201 ;
2018-01-06 16:34:42 +00:00
snprintf_P ( topicBuf , sizeof ( topicBuf ) , PSTR ( D_JSON_COMMAND ) ) ;
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { \" " D_JSON_COMMAND " \" : \" " D_JSON_UNKNOWN " \" } " ) ) ;
2017-04-03 15:38:15 +01:00
type = ( char * ) topicBuf ;
2017-01-28 13:41:01 +00:00
}
2018-03-02 14:38:37 +00:00
if ( mqtt_data [ 0 ] ! = ' \0 ' ) MqttPublishPrefixTopic_P ( RESULT_OR_STAT , type ) ;
2017-10-18 17:22:34 +01:00
fallback_topic_flag = 0 ;
2017-01-28 13:41:01 +00:00
}
/********************************************************************************************/
2018-04-13 16:42:11 +01:00
boolean SendKey ( byte key , byte device , byte state )
2017-01-28 13:41:01 +00:00
{
// key 0 = button_topic
// key 1 = switch_topic
2017-06-06 22:23:23 +01:00
// state 0 = off
// state 1 = on
// state 2 = toggle
// state 3 = hold
// state 9 = clear retain flag
2017-01-28 13:41:01 +00:00
2017-04-25 17:24:42 +01:00
char stopic [ TOPSZ ] ;
2017-05-08 12:21:45 +01:00
char scommand [ CMDSZ ] ;
2018-03-29 12:03:13 +01:00
char key_topic [ sizeof ( Settings . button_topic ) ] ;
2017-06-06 22:23:23 +01:00
boolean result = false ;
2017-01-28 13:41:01 +00:00
2018-03-29 12:03:13 +01:00
char * tmp = ( key ) ? Settings . switch_topic : Settings . button_topic ;
Format ( key_topic , tmp , sizeof ( key_topic ) ) ;
2018-02-27 13:59:46 +00:00
if ( Settings . flag . mqtt_enabled & & MqttIsConnected ( ) & & ( strlen ( key_topic ) ! = 0 ) & & strcmp ( key_topic , " 0 " ) ) {
2018-06-28 11:25:50 +01:00
if ( ! key & & ( device > devices_present ) ) device = 1 ; // Only allow number of buttons up to number of devices
GetTopic_P ( stopic , CMND , key_topic , GetPowerDevice ( scommand , device , sizeof ( scommand ) , key ) ) ; // cmnd/switchtopic/POWERx
2017-06-06 22:23:23 +01:00
if ( 9 = = state ) {
2017-09-13 13:19:34 +01:00
mqtt_data [ 0 ] = ' \0 ' ;
2017-06-06 22:23:23 +01:00
} else {
2018-02-13 13:30:30 +00:00
if ( ( ! strcmp ( mqtt_topic , key_topic ) | | ! strcmp ( Settings . mqtt_grptopic , key_topic ) ) & & ( 2 = = state ) ) {
2017-10-10 14:40:02 +01:00
state = ~ ( power > > ( device - 1 ) ) & 1 ;
2017-06-06 22:23:23 +01:00
}
2017-10-18 17:22:34 +01:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , GetStateText ( state ) ) ;
2017-01-28 13:41:01 +00:00
}
# ifdef USE_DOMOTICZ
2018-04-13 16:42:11 +01:00
if ( ! ( DomoticzSendKey ( key , device , state , strlen ( mqtt_data ) ) ) ) {
2017-10-18 17:22:34 +01:00
MqttPublishDirect ( stopic , ( key ) ? Settings . flag . mqtt_switch_retain : Settings . flag . mqtt_button_retain ) ;
2017-06-06 22:23:23 +01:00
}
2017-01-28 13:41:01 +00:00
# else
2017-10-18 17:22:34 +01:00
MqttPublishDirect ( stopic , ( key ) ? Settings . flag . mqtt_switch_retain : Settings . flag . mqtt_button_retain ) ;
2017-01-28 13:41:01 +00:00
# endif // USE_DOMOTICZ
2017-06-06 22:23:23 +01:00
result = true ;
2018-04-13 16:42:11 +01:00
} else {
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { \" %s%d \" :{ \" State \" :%d}} " ) , ( key ) ? " Switch " : " Button " , device , state ) ;
2018-05-24 15:23:20 +01:00
result = XdrvRulesProcess ( ) ;
2017-06-06 22:23:23 +01:00
}
2018-04-17 14:34:18 +01:00
# ifdef USE_KNX
KnxSendButtonPower ( key , device , state ) ;
# endif // USE_KNX
2017-06-06 22:23:23 +01:00
return result ;
2017-01-28 13:41:01 +00:00
}
2018-05-28 14:52:42 +01:00
void ExecuteCommandPower ( byte device , byte state , int source )
2017-01-28 13:41:01 +00:00
{
// device = Relay number 1 and up
// state 0 = Relay Off
2017-10-18 17:22:34 +01:00
// state 1 = Relay On (turn off after Settings.pulse_timer * 100 mSec if enabled)
2017-01-28 13:41:01 +00:00
// state 2 = Toggle relay
// state 3 = Blink relay
// state 4 = Stop blinking relay
2017-07-15 14:07:30 +01:00
// state 6 = Relay Off and no publishPowerState
// state 7 = Relay On and no publishPowerState
2017-01-28 13:41:01 +00:00
// state 9 = Show power state
2018-05-28 14:52:42 +01:00
// ShowSource(source);
2018-06-30 17:50:10 +01:00
if ( SONOFF_IFAN02 = = Settings . module ) {
2018-07-01 14:06:44 +01:00
blink_mask & = 1 ; // No blinking on the fan relays
Settings . flag . interlock = 0 ; // No interlock mode as it is already done by the microcontroller
Settings . pulse_timer [ 1 ] = 0 ; // No pulsetimers on the fan relays
Settings . pulse_timer [ 2 ] = 0 ;
Settings . pulse_timer [ 3 ] = 0 ;
2018-06-30 17:50:10 +01:00
}
2018-07-01 14:06:44 +01:00
2017-10-18 17:22:34 +01:00
uint8_t publish_power = 1 ;
2018-01-24 16:31:20 +00:00
if ( ( POWER_OFF_NO_STATE = = state ) | | ( POWER_ON_NO_STATE = = state ) ) {
2017-07-15 14:07:30 +01:00
state & = 1 ;
2017-10-18 17:22:34 +01:00
publish_power = 0 ;
2017-07-15 14:07:30 +01:00
}
2018-03-02 14:38:37 +00:00
if ( ( device < 1 ) | | ( device > devices_present ) ) device = 1 ;
2018-08-26 14:42:35 +01:00
if ( device < = MAX_PULSETIMERS ) { SetPulseTimer ( device - 1 , 0 ) ; }
2017-10-10 14:40:02 +01:00
power_t mask = 1 < < ( device - 1 ) ;
2018-01-24 16:31:20 +00:00
if ( state < = POWER_TOGGLE ) {
2017-01-28 13:41:01 +00:00
if ( ( blink_mask & mask ) ) {
2017-10-10 14:40:02 +01:00
blink_mask & = ( POWER_MASK ^ mask ) ; // Clear device mask
2017-10-18 17:22:34 +01:00
MqttPublishPowerBlinkState ( device ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
if ( Settings . flag . interlock & & ! interlock_mutex ) { // Clear all but masked relay
interlock_mutex = 1 ;
for ( byte i = 0 ; i < devices_present ; i + + ) {
2017-10-10 14:40:02 +01:00
power_t imask = 1 < < i ;
2018-05-28 14:52:42 +01:00
if ( ( power & imask ) & & ( mask ! = imask ) ) ExecuteCommandPower ( i + 1 , POWER_OFF , SRC_IGNORE ) ;
2017-08-18 11:55:08 +01:00
}
2017-10-18 17:22:34 +01:00
interlock_mutex = 0 ;
2017-08-18 11:55:08 +01:00
}
2017-01-28 13:41:01 +00:00
switch ( state ) {
2018-01-24 16:31:20 +00:00
case POWER_OFF : {
2017-10-10 14:40:02 +01:00
power & = ( POWER_MASK ^ mask ) ;
2017-01-28 13:41:01 +00:00
break ; }
2018-01-24 16:31:20 +00:00
case POWER_ON :
2017-01-28 13:41:01 +00:00
power | = mask ;
break ;
2018-01-24 16:31:20 +00:00
case POWER_TOGGLE :
2017-01-28 13:41:01 +00:00
power ^ = mask ;
}
2018-05-28 14:52:42 +01:00
SetDevicePower ( power , source ) ;
2017-01-28 13:41:01 +00:00
# ifdef USE_DOMOTICZ
2017-10-18 17:22:34 +01:00
DomoticzUpdatePowerState ( device ) ;
2017-01-28 13:41:01 +00:00
# endif // USE_DOMOTICZ
2018-04-17 14:34:18 +01:00
# ifdef USE_KNX
KnxUpdatePowerState ( device , power ) ;
# endif // USE_KNX
2018-08-26 14:42:35 +01:00
if ( device < = MAX_PULSETIMERS ) { // Restart PulseTime if powered On
SetPulseTimer ( device - 1 , ( ( ( POWER_ALL_OFF_PULSETIME_ON = = Settings . poweronstate ) ? ~ power : power ) & mask ) ? Settings . pulse_timer [ device - 1 ] : 0 ) ;
2017-10-10 14:40:02 +01:00
}
2017-01-28 13:41:01 +00:00
}
2018-01-24 16:31:20 +00:00
else if ( POWER_BLINK = = state ) {
2017-01-28 13:41:01 +00:00
if ( ! ( blink_mask & mask ) ) {
2017-10-10 14:40:02 +01:00
blink_powersave = ( blink_powersave & ( POWER_MASK ^ mask ) ) | ( power & mask ) ; // Save state
2017-01-28 13:41:01 +00:00
blink_power = ( power > > ( device - 1 ) ) & 1 ; // Prep to Toggle
}
2018-08-26 16:10:18 +01:00
blink_timer = millis ( ) + 100 ;
2017-10-18 17:22:34 +01:00
blink_counter = ( ( ! Settings . blinkcount ) ? 64000 : ( Settings . blinkcount * 2 ) ) + 1 ;
2017-01-28 13:41:01 +00:00
blink_mask | = mask ; // Set device mask
2017-10-18 17:22:34 +01:00
MqttPublishPowerBlinkState ( device ) ;
2017-01-28 13:41:01 +00:00
return ;
}
2018-01-24 16:31:20 +00:00
else if ( POWER_BLINK_STOP = = state ) {
2017-01-28 13:41:01 +00:00
byte flag = ( blink_mask & mask ) ;
2017-10-10 14:40:02 +01:00
blink_mask & = ( POWER_MASK ^ mask ) ; // Clear device mask
2017-10-18 17:22:34 +01:00
MqttPublishPowerBlinkState ( device ) ;
2018-05-28 14:52:42 +01:00
if ( flag ) ExecuteCommandPower ( device , ( blink_powersave > > ( device - 1 ) ) & 1 , SRC_IGNORE ) ; // Restore state
2017-01-28 13:41:01 +00:00
return ;
}
2018-03-02 14:38:37 +00:00
if ( publish_power ) MqttPublishPowerState ( device ) ;
2017-01-28 13:41:01 +00:00
}
2018-11-14 13:32:09 +00:00
void StopAllPowerBlink ( void )
2017-01-28 13:41:01 +00:00
{
2017-10-10 14:40:02 +01:00
power_t mask ;
2017-01-28 13:41:01 +00:00
2017-10-18 17:22:34 +01:00
for ( byte i = 1 ; i < = devices_present ; i + + ) {
2017-10-10 14:40:02 +01:00
mask = 1 < < ( i - 1 ) ;
2017-01-28 13:41:01 +00:00
if ( blink_mask & mask ) {
2017-10-10 14:40:02 +01:00
blink_mask & = ( POWER_MASK ^ mask ) ; // Clear device mask
2017-10-18 17:22:34 +01:00
MqttPublishPowerBlinkState ( i ) ;
2018-05-28 14:52:42 +01:00
ExecuteCommandPower ( i , ( blink_powersave > > ( i - 1 ) ) & 1 , SRC_IGNORE ) ; // Restore state
2017-01-28 13:41:01 +00:00
}
}
}
2018-05-28 14:52:42 +01:00
void ExecuteCommand ( char * cmnd , int source )
2017-01-28 13:41:01 +00:00
{
2017-05-08 12:21:45 +01:00
char stopic [ CMDSZ ] ;
2017-07-15 14:07:30 +01:00
char svalue [ INPUT_BUFFER_SIZE ] ;
2017-01-28 13:41:01 +00:00
char * start ;
char * token ;
2018-06-26 10:48:09 +01:00
ShowFreeMem ( PSTR ( " ExecuteCommand " ) ) ;
2018-05-28 14:52:42 +01:00
ShowSource ( source ) ;
2017-01-28 13:41:01 +00:00
token = strtok ( cmnd , " " ) ;
if ( token ! = NULL ) {
start = strrchr ( token , ' / ' ) ; // Skip possible cmnd/sonoff/ preamble
2018-03-02 14:38:37 +00:00
if ( start ) token = start + 1 ;
2017-01-28 13:41:01 +00:00
}
2017-05-11 16:47:34 +01:00
snprintf_P ( stopic , sizeof ( stopic ) , PSTR ( " /%s " ) , ( token = = NULL ) ? " " : token ) ;
2017-01-28 13:41:01 +00:00
token = strtok ( NULL , " " ) ;
2017-09-26 14:10:58 +01:00
// snprintf_P(svalue, sizeof(svalue), (token == NULL) ? "" : token); // Fails with command FullTopic home/%prefix%/%topic% as it processes %p of %prefix%
strlcpy ( svalue , ( token = = NULL ) ? " " : token , sizeof ( svalue ) ) ; // Fixed 5.8.0b
2018-02-27 13:59:46 +00:00
MqttDataHandler ( stopic , ( byte * ) svalue , strlen ( svalue ) ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
void PublishStatus ( uint8_t payload )
2017-01-28 13:41:01 +00:00
{
2018-05-24 15:23:20 +01:00
uint8_t option = STAT ;
2018-06-30 13:17:26 +01:00
char stemp [ MAX_FRIENDLYNAMES * ( sizeof ( Settings . friendlyname [ 0 ] ) + MAX_FRIENDLYNAMES ) ] ;
2018-09-26 09:13:44 +01:00
char stemp2 [ MAX_SWITCHES * 3 ] ;
2017-01-28 13:41:01 +00:00
// Workaround MQTT - TCP/IP stack queueing when SUB_PREFIX = PUB_PREFIX
2018-05-24 15:23:20 +01:00
if ( ! strcmp ( Settings . mqtt_prefix [ 0 ] , Settings . mqtt_prefix [ 1 ] ) & & ( ! payload ) ) option + + ; // TELE
2017-01-28 13:41:01 +00:00
2018-03-02 14:38:37 +00:00
if ( ( ! Settings . flag . mqtt_enabled ) & & ( 6 = = payload ) ) payload = 99 ;
if ( ! energy_flg & & ( 9 = = payload ) ) payload = 99 ;
2017-01-28 13:41:01 +00:00
2017-04-25 17:24:42 +01:00
if ( ( 0 = = payload ) | | ( 99 = = payload ) ) {
2018-04-11 16:56:18 +01:00
uint8_t maxfn = ( devices_present > MAX_FRIENDLYNAMES ) ? MAX_FRIENDLYNAMES : ( ! devices_present ) ? 1 : devices_present ;
2018-07-01 14:18:50 +01:00
if ( SONOFF_IFAN02 = = Settings . module ) { maxfn = 1 ; }
2018-03-21 09:42:56 +00:00
stemp [ 0 ] = ' \0 ' ;
for ( byte i = 0 ; i < maxfn ; i + + ) {
snprintf_P ( stemp , sizeof ( stemp ) , PSTR ( " %s%s \" %s \" " ) , stemp , ( i > 0 ? " , " : " " ) , Settings . friendlyname [ i ] ) ;
}
2018-09-26 09:13:44 +01:00
stemp2 [ 0 ] = ' \0 ' ;
for ( byte i = 0 ; i < MAX_SWITCHES ; i + + ) {
snprintf_P ( stemp2 , sizeof ( stemp2 ) , PSTR ( " %s%s%d " ) , stemp2 , ( i > 0 ? " , " : " " ) , Settings . switchmode [ i ] ) ;
}
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { \" " D_CMND_STATUS " \" :{ \" " D_CMND_MODULE " \" :%d, \" " D_CMND_FRIENDLYNAME " \" :[%s], \" " D_CMND_TOPIC " \" : \" %s \" , \" " D_CMND_BUTTONTOPIC " \" : \" %s \" , \" " D_CMND_POWER " \" :%d, \" " D_CMND_POWERONSTATE " \" :%d, \" " D_CMND_LEDSTATE " \" :%d, \" " D_CMND_SAVEDATA " \" :%d, \" " D_JSON_SAVESTATE " \" :%d, \" " D_CMND_SWITCHTOPIC " \" : \" %s \" , \" " D_CMND_SWITCHMODE " \" :[%s], \" " D_CMND_BUTTONRETAIN " \" :%d, \" " D_CMND_SWITCHRETAIN " \" :%d, \" " D_CMND_SENSORRETAIN " \" :%d, \" " D_CMND_POWERRETAIN " \" :%d}} " ) ,
Settings . module + 1 , stemp , mqtt_topic , Settings . button_topic , power , Settings . poweronstate , Settings . ledstate , Settings . save_data , Settings . flag . save_state , Settings . switch_topic , stemp2 , Settings . flag . mqtt_button_retain , Settings . flag . mqtt_switch_retain , Settings . flag . mqtt_sensor_retain , Settings . flag . mqtt_power_retain ) ;
2017-10-18 17:22:34 +01:00
MqttPublishPrefixTopic_P ( option , PSTR ( D_CMND_STATUS ) ) ;
2017-01-28 13:41:01 +00:00
}
2017-04-25 17:24:42 +01:00
if ( ( 0 = = payload ) | | ( 1 = = payload ) ) {
2018-03-14 16:28:30 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { \" " D_CMND_STATUS D_STATUS1_PARAMETER " \" :{ \" " D_JSON_BAUDRATE " \" :%d, \" " D_CMND_GROUPTOPIC " \" : \" %s \" , \" " D_CMND_OTAURL " \" : \" %s \" , \" " D_JSON_RESTARTREASON " \" : \" %s \" , \" " D_JSON_UPTIME " \" : \" %s \" , \" " D_JSON_STARTUPUTC " \" : \" %s \" , \" " D_CMND_SLEEP " \" :%d, \" " D_JSON_BOOTCOUNT " \" :%d, \" " D_JSON_SAVECOUNT " \" :%d, \" " D_JSON_SAVEADDRESS " \" : \" %X \" }} " ) ,
2018-09-02 09:42:52 +01:00
baudrate , Settings . mqtt_grptopic , Settings . ota_url , GetResetReason ( ) . c_str ( ) , GetUptime ( ) . c_str ( ) , GetDateAndTime ( DT_RESTART ) . c_str ( ) , Settings . sleep , Settings . bootcount , Settings . save_flag , GetSettingsAddress ( ) ) ;
2017-10-18 17:22:34 +01:00
MqttPublishPrefixTopic_P ( option , PSTR ( D_CMND_STATUS " 1 " ) ) ;
2017-01-28 13:41:01 +00:00
}
2017-04-25 17:24:42 +01:00
if ( ( 0 = = payload ) | | ( 2 = = payload ) ) {
2018-11-07 14:03:41 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { \" " D_CMND_STATUS D_STATUS2_FIRMWARE " \" :{ \" " D_JSON_VERSION " \" : \" %s%s \" , \" " D_JSON_BUILDDATETIME " \" : \" %s \" , \" " D_JSON_BOOTVERSION " \" :%d, \" " D_JSON_COREVERSION " \" : \" " ARDUINO_ESP8266_RELEASE " \" , \" " D_JSON_SDKVERSION " \" : \" %s \" }} " ) ,
my_version , my_image , GetBuildDateAndTime ( ) . c_str ( ) , ESP . getBootVersion ( ) , ESP . getSdkVersion ( ) ) ;
2017-10-18 17:22:34 +01:00
MqttPublishPrefixTopic_P ( option , PSTR ( D_CMND_STATUS " 2 " ) ) ;
2017-01-28 13:41:01 +00:00
}
2017-04-25 17:24:42 +01:00
if ( ( 0 = = payload ) | | ( 3 = = payload ) ) {
2018-07-25 11:42:53 +01:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { \" " D_CMND_STATUS D_STATUS3_LOGGING " \" :{ \" " D_CMND_SERIALLOG " \" :%d, \" " D_CMND_WEBLOG " \" :%d, \" " D_CMND_SYSLOG " \" :%d, \" " D_CMND_LOGHOST " \" : \" %s \" , \" " D_CMND_LOGPORT " \" :%d, \" " D_CMND_SSID " \" :[ \" %s \" , \" %s \" ], \" " D_CMND_TELEPERIOD " \" :%d, \" " D_CMND_SETOPTION " \" :[ \" %08X \" , \" %08X \" , \" %08X \" ]}} " ) ,
Settings . seriallog_level , Settings . weblog_level , Settings . syslog_level , Settings . syslog_host , Settings . syslog_port , Settings . sta_ssid [ 0 ] , Settings . sta_ssid [ 1 ] , Settings . tele_period , Settings . flag . data , Settings . flag2 . data , Settings . flag3 . data ) ;
2017-10-18 17:22:34 +01:00
MqttPublishPrefixTopic_P ( option , PSTR ( D_CMND_STATUS " 3 " ) ) ;
2017-01-28 13:41:01 +00:00
}
2017-04-25 17:24:42 +01:00
if ( ( 0 = = payload ) | | ( 4 = = payload ) ) {
2018-11-08 09:40:19 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { \" " D_CMND_STATUS D_STATUS4_MEMORY " \" :{ \" " D_JSON_PROGRAMSIZE " \" :%d, \" " D_JSON_FREEMEMORY " \" :%d, \" " D_JSON_HEAPSIZE " \" :%d, \" " D_JSON_PROGRAMFLASHSIZE " \" :%d, \" " D_JSON_FLASHSIZE " \" :%d, \" " D_JSON_FLASHCHIPID " \" : \" %06X \" , \" " D_JSON_FLASHMODE " \" :%d, \" " D_JSON_FEATURES " \" :[ \" %08X \" , \" %08X \" , \" %08X \" , \" %08X \" , \" %08X \" ]}} " ) ,
ESP . getSketchSize ( ) / 1024 , ESP . getFreeSketchSpace ( ) / 1024 , ESP . getFreeHeap ( ) / 1024 , ESP . getFlashChipSize ( ) / 1024 , ESP . getFlashChipRealSize ( ) / 1024 , ESP . getFlashChipId ( ) , ESP . getFlashChipMode ( ) , LANGUAGE_LCID , feature_drv1 , feature_drv2 , feature_sns1 , feature_sns2 ) ;
2017-10-18 17:22:34 +01:00
MqttPublishPrefixTopic_P ( option , PSTR ( D_CMND_STATUS " 4 " ) ) ;
2017-01-28 13:41:01 +00:00
}
2017-04-25 17:24:42 +01:00
if ( ( 0 = = payload ) | | ( 5 = = payload ) ) {
2018-01-06 16:34:42 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { \" " D_CMND_STATUS D_STATUS5_NETWORK " \" :{ \" " D_CMND_HOSTNAME " \" : \" %s \" , \" " D_CMND_IPADDRESS " \" : \" %s \" , \" " D_JSON_GATEWAY " \" : \" %s \" , \" " D_JSON_SUBNETMASK " \" : \" %s \" , \" " D_JSON_DNSSERVER " \" : \" %s \" , \" " D_JSON_MAC " \" : \" %s \" , \" " D_CMND_WEBSERVER " \" :%d, \" " D_CMND_WIFICONFIG " \" :%d}} " ) ,
2017-10-18 17:22:34 +01:00
my_hostname , WiFi . localIP ( ) . toString ( ) . c_str ( ) , IPAddress ( Settings . ip_address [ 1 ] ) . toString ( ) . c_str ( ) , IPAddress ( Settings . ip_address [ 2 ] ) . toString ( ) . c_str ( ) , IPAddress ( Settings . ip_address [ 3 ] ) . toString ( ) . c_str ( ) ,
WiFi . macAddress ( ) . c_str ( ) , Settings . webserver , Settings . sta_config ) ;
MqttPublishPrefixTopic_P ( option , PSTR ( D_CMND_STATUS " 5 " ) ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
if ( ( ( 0 = = payload ) | | ( 6 = = payload ) ) & & Settings . flag . mqtt_enabled ) {
2018-03-02 14:38:37 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { \" " D_CMND_STATUS D_STATUS6_MQTT " \" :{ \" " D_CMND_MQTTHOST " \" : \" %s \" , \" " D_CMND_MQTTPORT " \" :%d, \" " D_CMND_MQTTCLIENT D_JSON_MASK " \" : \" %s \" , \" " D_CMND_MQTTCLIENT " \" : \" %s \" , \" " D_CMND_MQTTUSER " \" : \" %s \" , \" MqttType \" :%d, \" MAX_PACKET_SIZE \" :%d, \" KEEPALIVE \" :%d}} " ) ,
Settings . mqtt_host , Settings . mqtt_port , Settings . mqtt_client , mqtt_client , Settings . mqtt_user , MqttLibraryType ( ) , MQTT_MAX_PACKET_SIZE , MQTT_KEEPALIVE ) ;
2017-10-18 17:22:34 +01:00
MqttPublishPrefixTopic_P ( option , PSTR ( D_CMND_STATUS " 6 " ) ) ;
2017-01-28 13:41:01 +00:00
}
2017-04-25 17:24:42 +01:00
if ( ( 0 = = payload ) | | ( 7 = = payload ) ) {
2018-11-01 12:00:05 +00:00
if ( 99 = = Settings . timezone ) {
snprintf_P ( stemp , sizeof ( stemp ) , PSTR ( " %d " ) , Settings . timezone ) ;
} else {
snprintf_P ( stemp , sizeof ( stemp ) , PSTR ( " \" %s \" " ) , GetTimeZone ( ) . c_str ( ) ) ;
}
2018-04-10 10:45:53 +01:00
# if defined(USE_TIMERS) && defined(USE_SUNRISE)
2018-11-01 12:00:05 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { \" " D_CMND_STATUS D_STATUS7_TIME " \" :{ \" " D_JSON_UTC_TIME " \" : \" %s \" , \" " D_JSON_LOCAL_TIME " \" : \" %s \" , \" " D_JSON_STARTDST " \" : \" %s \" , \" " D_JSON_ENDDST " \" : \" %s \" , \" " D_CMND_TIMEZONE " \" :%s, \" " D_JSON_SUNRISE " \" : \" %s \" , \" " D_JSON_SUNSET " \" : \" %s \" }} " ) ,
GetTime ( 0 ) . c_str ( ) , GetTime ( 1 ) . c_str ( ) , GetTime ( 2 ) . c_str ( ) , GetTime ( 3 ) . c_str ( ) , stemp , GetSun ( 0 ) . c_str ( ) , GetSun ( 1 ) . c_str ( ) ) ;
2018-04-05 11:49:43 +01:00
# else
2018-11-01 12:00:05 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { \" " D_CMND_STATUS D_STATUS7_TIME " \" :{ \" " D_JSON_UTC_TIME " \" : \" %s \" , \" " D_JSON_LOCAL_TIME " \" : \" %s \" , \" " D_JSON_STARTDST " \" : \" %s \" , \" " D_JSON_ENDDST " \" : \" %s \" , \" " D_CMND_TIMEZONE " \" :%s}} " ) ,
GetTime ( 0 ) . c_str ( ) , GetTime ( 1 ) . c_str ( ) , GetTime ( 2 ) . c_str ( ) , GetTime ( 3 ) . c_str ( ) , stemp ) ;
2018-04-10 10:45:53 +01:00
# endif // USE_TIMERS and USE_SUNRISE
2017-10-18 17:22:34 +01:00
MqttPublishPrefixTopic_P ( option , PSTR ( D_CMND_STATUS " 7 " ) ) ;
2017-02-04 16:09:54 +00:00
}
2017-12-16 14:51:45 +00:00
if ( energy_flg ) {
2017-04-25 17:24:42 +01:00
if ( ( 0 = = payload ) | | ( 9 = = payload ) ) {
2018-03-14 16:28:30 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { \" " D_CMND_STATUS D_STATUS9_MARGIN " \" :{ \" " D_CMND_POWERDELTA " \" :%d, \" " D_CMND_POWERLOW " \" :%d, \" " D_CMND_POWERHIGH " \" :%d, \" " D_CMND_VOLTAGELOW " \" :%d, \" " D_CMND_VOLTAGEHIGH " \" :%d, \" " D_CMND_CURRENTLOW " \" :%d, \" " D_CMND_CURRENTHIGH " \" :%d}} " ) ,
Settings . energy_power_delta , Settings . energy_min_power , Settings . energy_max_power , Settings . energy_min_voltage , Settings . energy_max_voltage , Settings . energy_min_current , Settings . energy_max_current ) ;
2017-10-18 17:22:34 +01:00
MqttPublishPrefixTopic_P ( option , PSTR ( D_CMND_STATUS " 9 " ) ) ;
2017-02-04 16:09:54 +00:00
}
}
2017-12-16 14:51:45 +00:00
if ( ( 0 = = payload ) | | ( 8 = = payload ) | | ( 10 = = payload ) ) {
2017-09-13 13:19:34 +01:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { \" " D_CMND_STATUS D_STATUS10_SENSOR " \" : " ) ) ;
2017-11-03 17:07:25 +00:00
MqttShowSensor ( ) ;
2017-09-13 13:19:34 +01:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s} " ) , mqtt_data ) ;
2017-12-16 14:51:45 +00:00
if ( 8 = = payload ) {
MqttPublishPrefixTopic_P ( option , PSTR ( D_CMND_STATUS " 8 " ) ) ;
} else {
MqttPublishPrefixTopic_P ( option , PSTR ( D_CMND_STATUS " 10 " ) ) ;
}
2017-01-28 13:41:01 +00:00
}
2017-03-14 17:03:25 +00:00
2017-04-25 17:24:42 +01:00
if ( ( 0 = = payload ) | | ( 11 = = payload ) ) {
2017-09-13 13:19:34 +01:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { \" " D_CMND_STATUS D_STATUS11_STATUS " \" : " ) ) ;
2017-10-18 17:22:34 +01:00
MqttShowState ( ) ;
2017-09-13 13:19:34 +01:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s} " ) , mqtt_data ) ;
2017-10-18 17:22:34 +01:00
MqttPublishPrefixTopic_P ( option , PSTR ( D_CMND_STATUS " 11 " ) ) ;
2017-03-14 17:03:25 +00:00
}
2017-09-02 13:37:02 +01:00
2017-03-14 17:03:25 +00:00
}
2018-11-14 13:32:09 +00:00
void MqttShowPWMState ( void )
2018-03-20 15:28:18 +00:00
{
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s \" " D_CMND_PWM " \" :{ " ) , mqtt_data ) ;
bool first = true ;
for ( byte i = 0 ; i < MAX_PWMS ; i + + ) {
if ( pin [ GPIO_PWM1 + i ] < 99 ) {
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s%s \" " D_CMND_PWM " %d \" :%d " ) , mqtt_data , first ? " " : " , " , i + 1 , Settings . pwm_value [ i ] ) ;
first = false ;
}
}
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s} " ) , mqtt_data ) ;
}
2018-11-14 13:32:09 +00:00
void MqttShowState ( void )
2017-03-14 17:03:25 +00:00
{
2018-01-13 14:53:02 +00:00
char stemp1 [ 33 ] ;
2017-09-02 13:37:02 +01:00
2018-09-02 09:42:52 +01:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s{ \" " D_JSON_TIME " \" : \" %s \" , \" " D_JSON_UPTIME " \" : \" %s \" " ) , mqtt_data , GetDateAndTime ( DT_LOCAL ) . c_str ( ) , GetUptime ( ) . c_str ( ) ) ;
2017-03-14 17:03:25 +00:00
# ifdef USE_ADC_VCC
2017-09-02 13:37:02 +01:00
dtostrfd ( ( double ) ESP . getVcc ( ) / 1000 , 3 , stemp1 ) ;
2018-01-06 16:34:42 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s, \" " D_JSON_VCC " \" :%s " ) , mqtt_data , stemp1 ) ;
2017-09-02 13:37:02 +01:00
# endif
2018-01-20 11:12:39 +00:00
2018-11-25 12:29:53 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s, \" LoopSet \" :%u " ) , mqtt_data , ( uint32_t ) Settings . param [ P_LOOP_SLEEP_DELAY ] ) ; // Add current loop delay target to telemetry
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s, \" LoadAvg \" :%u " ) , mqtt_data , loop_load_avg ) ; // Add LoadAvg to telemetry data
2018-11-24 16:12:49 +00:00
2017-10-18 17:22:34 +01:00
for ( byte i = 0 ; i < devices_present ; i + + ) {
2018-01-20 11:12:39 +00:00
if ( i = = light_device - 1 ) {
LightState ( 1 ) ;
} else {
2018-05-13 16:38:44 +01:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s, \" %s \" : \" %s \" " ) , mqtt_data , GetPowerDevice ( stemp1 , i + 1 , sizeof ( stemp1 ) , Settings . flag . device_index_enable ) , GetStateText ( bitRead ( power , i ) ) ) ;
2018-07-01 14:06:44 +01:00
if ( SONOFF_IFAN02 = = Settings . module ) {
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s, \" " D_CMND_FANSPEED " \" :%d " ) , mqtt_data , GetFanspeed ( ) ) ;
break ;
}
2018-01-20 11:12:39 +00:00
}
2017-03-14 17:03:25 +00:00
}
2018-01-20 11:12:39 +00:00
2018-03-20 15:28:18 +00:00
if ( pwm_present ) {
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s, " ) , mqtt_data ) ;
MqttShowPWMState ( ) ;
}
2018-09-02 14:54:26 +01:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s, \" " D_JSON_WIFI " \" :{ \" " D_JSON_AP " \" :%d, \" " D_JSON_SSID " \" : \" %s \" , \" " D_JSON_BSSID " \" : \" %s \" , \" " D_JSON_CHANNEL " \" :%d, \" " D_JSON_RSSI " \" :%d}} " ) ,
mqtt_data , Settings . sta_active + 1 , Settings . sta_ssid [ Settings . sta_active ] , WiFi . BSSIDstr ( ) . c_str ( ) , WiFi . channel ( ) , WifiGetRssiAsQuality ( WiFi . RSSI ( ) ) ) ;
2017-02-04 16:09:54 +00:00
}
2018-11-14 13:32:09 +00:00
boolean MqttShowSensor ( void )
2017-02-04 16:09:54 +00:00
{
2018-02-17 13:09:39 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s{ \" " D_JSON_TIME " \" : \" %s \" " ) , mqtt_data , GetDateAndTime ( DT_LOCAL ) . c_str ( ) ) ;
2017-11-04 15:36:51 +00:00
int json_data_start = strlen ( mqtt_data ) ;
2017-10-12 13:09:19 +01:00
for ( byte i = 0 ; i < MAX_SWITCHES ; i + + ) {
2018-06-28 16:40:37 +01:00
# ifdef USE_TM1638
2018-08-25 12:08:06 +01:00
if ( ( pin [ GPIO_SWT1 + i ] < 99 ) | | ( ( pin [ GPIO_TM16CLK ] < 99 ) & & ( pin [ GPIO_TM16DIO ] < 99 ) & & ( pin [ GPIO_TM16STB ] < 99 ) ) ) {
2018-06-28 16:40:37 +01:00
# else
2018-08-25 12:08:06 +01:00
if ( pin [ GPIO_SWT1 + i ] < 99 ) {
2018-06-28 16:40:37 +01:00
# endif // USE_TM1638
2017-10-18 17:22:34 +01:00
boolean swm = ( ( FOLLOW_INV = = Settings . switchmode [ i ] ) | | ( PUSHBUTTON_INV = = Settings . switchmode [ i ] ) | | ( PUSHBUTTONHOLD_INV = = Settings . switchmode [ i ] ) ) ;
2018-01-06 16:34:42 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s, \" " D_JSON_SWITCH " %d \" : \" %s \" " ) , mqtt_data , i + 1 , GetStateText ( swm ^ lastwallswitch [ i ] ) ) ;
2017-03-19 17:19:08 +00:00
}
}
2017-12-25 16:41:12 +00:00
XsnsCall ( FUNC_JSON_APPEND ) ;
2017-11-04 15:36:51 +00:00
boolean json_data_available = ( strlen ( mqtt_data ) - json_data_start ) ;
2018-11-04 15:55:12 +00:00
if ( strstr_P ( mqtt_data , PSTR ( D_JSON_PRESSURE ) ) ) {
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s, \" " D_JSON_PRESSURE_UNIT " \" : \" %s \" " ) , mqtt_data , PressureUnit ( ) . c_str ( ) ) ;
}
2018-01-24 16:31:20 +00:00
if ( strstr_P ( mqtt_data , PSTR ( D_JSON_TEMPERATURE ) ) ) {
2018-01-06 16:34:42 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s, \" " D_JSON_TEMPERATURE_UNIT " \" : \" %c \" " ) , mqtt_data , TempUnit ( ) ) ;
2017-05-03 17:19:13 +01:00
}
2017-09-13 13:19:34 +01:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s} " ) , mqtt_data ) ;
2018-01-05 11:26:19 +00:00
2018-03-02 14:38:37 +00:00
if ( json_data_available ) XdrvCall ( FUNC_SHOW_SENSOR ) ;
2017-11-03 17:07:25 +00:00
return json_data_available ;
2017-01-28 13:41:01 +00:00
}
/********************************************************************************************/
2018-11-14 13:32:09 +00:00
void PerformEverySecond ( void )
2017-01-28 13:41:01 +00:00
{
2018-02-07 16:50:02 +00:00
uptime + + ;
2018-08-30 13:27:33 +01:00
if ( BOOT_LOOP_TIME = = uptime ) {
2018-09-04 15:22:34 +01:00
RtcReboot . fast_reboot_count = 0 ;
RtcRebootSave ( ) ;
2018-11-16 08:36:41 +00:00
Settings . bootcount + + ; // Moved to here to stop flash writes during start-up
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_APPLICATION D_BOOT_COUNT " %d " ) , Settings . bootcount ) ;
AddLog ( LOG_LEVEL_DEBUG ) ;
2018-08-30 13:27:33 +01:00
}
2018-08-20 14:51:46 +01:00
if ( ( 4 = = uptime ) & & ( SONOFF_IFAN02 = = Settings . module ) ) { // Microcontroller needs 3 seconds before accepting commands
SetDevicePower ( 1 , SRC_RETRY ) ; // Sync with default power on state microcontroller being Light ON and Fan OFF
SetDevicePower ( power , SRC_RETRY ) ; // Set required power on state
}
2017-01-28 13:41:01 +00:00
if ( seriallog_timer ) {
seriallog_timer - - ;
if ( ! seriallog_timer ) {
if ( seriallog_level ) {
2017-10-18 17:22:34 +01:00
AddLog_P ( LOG_LEVEL_INFO , PSTR ( D_LOG_APPLICATION D_SERIAL_LOGGING_DISABLED ) ) ;
2017-01-28 13:41:01 +00:00
}
seriallog_level = 0 ;
}
}
if ( syslog_timer ) { // Restore syslog level
syslog_timer - - ;
if ( ! syslog_timer ) {
2018-09-12 23:00:35 +01:00
syslog_level = Settings . syslog_level ;
2017-10-18 17:22:34 +01:00
if ( Settings . syslog_level ) {
AddLog_P ( LOG_LEVEL_INFO , PSTR ( D_LOG_APPLICATION D_SYSLOG_LOGGING_REENABLED ) ) ; // Might trigger disable again (on purpose)
2017-01-28 13:41:01 +00:00
}
}
}
2018-07-24 17:41:50 +01:00
ResetGlobalValues ( ) ;
2017-10-18 17:22:34 +01:00
if ( Settings . tele_period ) {
2017-01-28 13:41:01 +00:00
tele_period + + ;
2017-10-18 17:22:34 +01:00
if ( tele_period = = Settings . tele_period - 1 ) {
2017-12-25 16:41:12 +00:00
XsnsCall ( FUNC_PREP_BEFORE_TELEPERIOD ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
if ( tele_period > = Settings . tele_period ) {
2017-01-28 13:41:01 +00:00
tele_period = 0 ;
2017-09-13 13:19:34 +01:00
mqtt_data [ 0 ] = ' \0 ' ;
2017-10-18 17:22:34 +01:00
MqttShowState ( ) ;
2018-11-25 20:27:19 +00:00
if ( Settings . flag3 . hass_tele_as_result ) {
MqttPublishPrefixTopic_P ( STAT , S_RSLT_RESULT , MQTT_TELE_RETAIN ) ;
} else {
MqttPublishPrefixTopic_P ( TELE , PSTR ( D_RSLT_STATE ) , MQTT_TELE_RETAIN ) ;
}
2017-01-28 13:41:01 +00:00
2017-09-13 13:19:34 +01:00
mqtt_data [ 0 ] = ' \0 ' ;
2018-04-27 17:06:19 +01:00
if ( MqttShowSensor ( ) ) {
MqttPublishPrefixTopic_P ( TELE , PSTR ( D_RSLT_SENSOR ) , Settings . flag . mqtt_sensor_retain ) ;
# ifdef USE_RULES
RulesTeleperiod ( ) ; // Allow rule based HA messages
# endif // USE_RULES
}
2017-01-28 13:41:01 +00:00
}
}
2018-01-05 11:26:19 +00:00
XdrvCall ( FUNC_EVERY_SECOND ) ;
2017-12-25 16:41:12 +00:00
XsnsCall ( FUNC_EVERY_SECOND ) ;
2017-01-28 13:41:01 +00:00
2017-10-18 17:22:34 +01:00
if ( ( 2 = = RtcTime . minute ) & & latest_uptime_flag ) {
latest_uptime_flag = false ;
2018-09-02 09:42:52 +01:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { \" " D_JSON_TIME " \" : \" %s \" , \" " D_JSON_UPTIME " \" : \" %s \" } " ) , GetDateAndTime ( DT_LOCAL ) . c_str ( ) , GetUptime ( ) . c_str ( ) ) ;
2018-01-18 15:19:28 +00:00
MqttPublishPrefixTopic_P ( TELE , PSTR ( D_RSLT_UPTIME ) ) ;
2017-01-28 13:41:01 +00:00
}
2018-03-02 14:38:37 +00:00
if ( ( 3 = = RtcTime . minute ) & & ! latest_uptime_flag ) latest_uptime_flag = true ;
2017-01-28 13:41:01 +00:00
}
2017-07-25 17:05:47 +01:00
/*********************************************************************************************\
* Button handler with single press only or multi - press and hold on all buttons
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2018-11-14 13:32:09 +00:00
void ButtonHandler ( void )
2017-01-28 13:41:01 +00:00
{
2017-04-25 17:24:42 +01:00
uint8_t button = NOT_PRESSED ;
2017-10-18 17:22:34 +01:00
uint8_t button_present = 0 ;
2018-08-27 11:01:20 +01:00
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 ;
2017-04-25 17:24:42 +01:00
char scmnd [ 20 ] ;
2017-02-13 16:25:46 +00:00
2017-10-18 17:22:34 +01:00
uint8_t maxdev = ( devices_present > MAX_KEYS ) ? MAX_KEYS : devices_present ;
2018-02-04 21:44:15 +00:00
for ( byte button_index = 0 ; button_index < maxdev ; button_index + + ) {
2017-07-30 16:55:37 +01:00
button = NOT_PRESSED ;
2017-10-18 17:22:34 +01:00
button_present = 0 ;
2017-07-25 17:05:47 +01:00
2018-02-04 21:44:15 +00:00
if ( ! button_index & & ( ( SONOFF_DUAL = = Settings . module ) | | ( CH4 = = Settings . module ) ) ) {
2017-10-18 17:22:34 +01:00
button_present = 1 ;
if ( dual_button_code ) {
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_APPLICATION D_BUTTON " " D_CODE " %04X " ) , dual_button_code ) ;
AddLog ( LOG_LEVEL_DEBUG ) ;
2017-07-25 17:05:47 +01:00
button = PRESSED ;
2018-08-27 11:01:20 +01:00
if ( 0xF500 = = dual_button_code ) { // Button hold
holdbutton [ button_index ] = ( loops_per_second * Settings . param [ P_HOLD_TIME ] / 10 ) - 1 ;
2018-03-29 16:23:47 +01:00
hold_time_extent = 1 ;
2017-07-25 17:05:47 +01:00
}
2017-10-18 17:22:34 +01:00
dual_button_code = 0 ;
2017-04-25 17:24:42 +01:00
}
2017-01-28 13:41:01 +00:00
} else {
2018-08-27 15:07:23 +01:00
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 ] ) ;
}
2017-06-06 22:23:23 +01:00
}
2017-01-28 13:41:01 +00:00
}
2017-07-25 17:05:47 +01:00
2017-10-18 17:22:34 +01:00
if ( button_present ) {
2018-10-19 11:53:22 +01:00
XdrvMailbox . index = button_index ;
XdrvMailbox . payload = button ;
if ( XdrvCall ( FUNC_BUTTON_PRESSED ) ) {
// Serviced
}
else if ( SONOFF_4CHPRO = = Settings . module ) {
2018-08-27 11:01:20 +01:00
if ( holdbutton [ button_index ] ) { holdbutton [ button_index ] - - ; }
2018-02-04 21:44:15 +00:00
2017-10-18 17:22:34 +01:00
boolean button_pressed = false ;
2018-02-04 21:44:15 +00:00
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 ) ;
2017-10-18 17:22:34 +01:00
AddLog ( LOG_LEVEL_DEBUG ) ;
2018-08-27 11:01:20 +01:00
holdbutton [ button_index ] = loops_per_second ;
2017-10-18 17:22:34 +01:00
button_pressed = true ;
2017-07-25 17:05:47 +01:00
}
2018-02-04 21:44:15 +00:00
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 ) ;
2017-10-18 17:22:34 +01:00
AddLog ( LOG_LEVEL_DEBUG ) ;
2018-08-27 11:01:20 +01:00
if ( ! holdbutton [ button_index ] ) { button_pressed = true ; } // Do not allow within 1 second
2017-07-25 17:05:47 +01:00
}
2017-10-18 17:22:34 +01:00
if ( button_pressed ) {
2018-08-27 11:01:20 +01:00
if ( ! SendKey ( 0 , button_index + 1 , POWER_TOGGLE ) ) { // Execute Toggle command via MQTT if ButtonTopic is set
2018-05-28 14:52:42 +01:00
ExecuteCommandPower ( button_index + 1 , POWER_TOGGLE , SRC_BUTTON ) ; // Execute Toggle command internally
2017-07-25 17:05:47 +01:00
}
}
2018-10-18 15:02:40 +01:00
}
else {
2018-02-04 21:44:15 +00:00
if ( ( PRESSED = = button ) & & ( NOT_PRESSED = = lastbutton [ button_index ] ) ) {
2018-08-27 11:01:20 +01:00
if ( Settings . flag . button_single ) { // Allow only single button press for immediate action
2018-02-04 21:44:15 +00:00
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_APPLICATION D_BUTTON " %d " D_IMMEDIATE ) , button_index + 1 ) ;
2017-10-18 17:22:34 +01:00
AddLog ( LOG_LEVEL_DEBUG ) ;
2018-04-13 16:42:11 +01:00
if ( ! SendKey ( 0 , button_index + 1 , POWER_TOGGLE ) ) { // Execute Toggle command via MQTT if ButtonTopic is set
2018-05-28 14:52:42 +01:00
ExecuteCommandPower ( button_index + 1 , POWER_TOGGLE , SRC_BUTTON ) ; // Execute Toggle command internally
2017-07-25 17:05:47 +01:00
}
2017-01-28 13:41:01 +00:00
} else {
2018-02-04 21:44:15 +00:00
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 ] ) ;
2017-10-18 17:22:34 +01:00
AddLog ( LOG_LEVEL_DEBUG ) ;
2018-08-27 11:01:20 +01:00
multiwindow [ button_index ] = loops_per_second / 2 ; // 0.5 second multi press window
2017-01-28 13:41:01 +00:00
}
2017-07-25 17:05:47 +01:00
blinks = 201 ;
}
2017-09-02 13:37:02 +01:00
2017-07-25 17:05:47 +01:00
if ( NOT_PRESSED = = button ) {
2018-02-04 21:44:15 +00:00
holdbutton [ button_index ] = 0 ;
2017-01-28 13:41:01 +00:00
} else {
2018-02-04 21:44:15 +00:00
holdbutton [ button_index ] + + ;
2018-08-27 11:01:20 +01:00
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
2017-10-18 17:22:34 +01:00
// Settings.flag.button_single = 0;
2017-09-02 13:37:02 +01:00
snprintf_P ( scmnd , sizeof ( scmnd ) , PSTR ( D_CMND_SETOPTION " 13 0 " ) ) ; // Disable single press only
2018-05-28 14:52:42 +01:00
ExecuteCommand ( scmnd , SRC_BUTTON ) ;
2017-07-25 17:05:47 +01:00
}
} else {
2018-08-27 11:01:20 +01:00
if ( Settings . flag . button_restrict ) { // Button restriction
if ( holdbutton [ button_index ] = = loops_per_second * Settings . param [ P_HOLD_TIME ] / 10 ) { // Button hold
2018-03-29 16:21:03 +01:00
multipress [ button_index ] = 0 ;
2018-08-27 11:01:20 +01:00
SendKey ( 0 , button_index + 1 , 3 ) ; // Execute Hold command via MQTT if ButtonTopic is set
2018-03-29 16:21:03 +01:00
}
} else {
2018-08-27 11:01:20 +01:00
if ( holdbutton [ button_index ] = = loops_per_second * hold_time_extent * Settings . param [ P_HOLD_TIME ] / 10 ) { // Button held for factor times longer
2018-03-29 16:21:03 +01:00
multipress [ button_index ] = 0 ;
2017-09-02 13:37:02 +01:00
snprintf_P ( scmnd , sizeof ( scmnd ) , PSTR ( D_CMND_RESET " 1 " ) ) ;
2018-05-28 14:52:42 +01:00
ExecuteCommand ( scmnd , SRC_BUTTON ) ;
2017-07-25 17:05:47 +01:00
}
}
2017-03-08 15:20:45 +00:00
}
2017-01-28 13:41:01 +00:00
}
2018-08-27 11:01:20 +01:00
if ( ! Settings . flag . button_single ) { // Allow multi-press
2018-02-04 21:44:15 +00:00
if ( multiwindow [ button_index ] ) {
multiwindow [ button_index ] - - ;
2017-07-25 17:05:47 +01:00
} else {
2018-02-04 21:44:15 +00:00
if ( ! restart_flag & & ! holdbutton [ button_index ] & & ( multipress [ button_index ] > 0 ) & & ( multipress [ button_index ] < MAX_BUTTON_COMMANDS + 3 ) ) {
2017-10-18 17:22:34 +01:00
boolean single_press = false ;
2018-08-27 11:01:20 +01:00
if ( multipress [ button_index ] < 3 ) { // Single or Double press
2017-12-02 11:40:33 +00:00
if ( ( SONOFF_DUAL_R2 = = Settings . module ) | | ( SONOFF_DUAL = = Settings . module ) | | ( CH4 = = Settings . module ) ) {
2017-10-18 17:22:34 +01:00
single_press = true ;
2017-07-25 17:05:47 +01:00
} else {
2018-02-04 21:44:15 +00:00
single_press = ( Settings . flag . button_swap + 1 = = multipress [ button_index ] ) ;
multipress [ button_index ] = 1 ;
2017-07-25 17:05:47 +01:00
}
}
2018-04-13 16:42:11 +01:00
if ( single_press & & SendKey ( 0 , button_index + multipress [ button_index ] , POWER_TOGGLE ) ) { // Execute Toggle command via MQTT if ButtonTopic is set
2017-07-25 17:05:47 +01:00
// Success
} else {
2018-08-27 11:01:20 +01:00
if ( multipress [ button_index ] < 3 ) { // Single or Double press
2018-10-30 14:34:31 +00:00
if ( WifiState ( ) > WIFI_RESTART ) { // WPSconfig, Smartconfig or Wifimanager active
2017-10-18 17:22:34 +01:00
restart_flag = 1 ;
2017-07-25 17:05:47 +01:00
} else {
2018-05-28 14:52:42 +01:00
ExecuteCommandPower ( button_index + multipress [ button_index ] , POWER_TOGGLE , SRC_BUTTON ) ; // Execute Toggle command internally
2017-07-25 17:05:47 +01:00
}
2018-08-27 11:01:20 +01:00
} else { // 3 - 7 press
2017-10-18 17:22:34 +01:00
if ( ! Settings . flag . button_restrict ) {
2018-02-04 21:44:15 +00:00
snprintf_P ( scmnd , sizeof ( scmnd ) , kCommands [ multipress [ button_index ] - 3 ] ) ;
2018-05-28 14:52:42 +01:00
ExecuteCommand ( scmnd , SRC_BUTTON ) ;
2017-07-25 17:05:47 +01:00
}
}
}
2018-02-04 21:44:15 +00:00
multipress [ button_index ] = 0 ;
2017-07-25 17:05:47 +01:00
}
}
2017-04-25 17:24:42 +01:00
}
2017-01-28 13:41:01 +00:00
}
}
2018-02-04 21:44:15 +00:00
lastbutton [ button_index ] = button ;
2017-01-28 13:41:01 +00:00
}
2017-07-25 17:05:47 +01:00
}
/*********************************************************************************************\
* Switch handler
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2018-06-28 16:40:37 +01:00
void SwitchHandler ( byte mode )
2017-07-25 17:05:47 +01:00
{
uint8_t button = NOT_PRESSED ;
uint8_t switchflag ;
2018-08-27 11:01:20 +01:00
uint16_t loops_per_second = 1000 / Settings . switch_debounce ;
2017-01-28 13:41:01 +00:00
2017-10-10 14:40:02 +01:00
for ( byte i = 0 ; i < MAX_SWITCHES ; i + + ) {
2018-08-25 12:08:06 +01:00
if ( ( pin [ GPIO_SWT1 + i ] < 99 ) | | ( mode ) ) {
2017-06-06 22:23:23 +01:00
2017-06-16 13:33:49 +01:00
if ( holdwallswitch [ i ] ) {
holdwallswitch [ i ] - - ;
if ( 0 = = holdwallswitch [ i ] ) {
2018-08-27 11:01:20 +01:00
SendKey ( 1 , i + 1 , 3 ) ; // Execute command via MQTT
2017-06-06 22:23:23 +01:00
}
}
2017-09-02 13:37:02 +01:00
2018-06-28 16:40:37 +01:00
if ( mode ) {
button = virtualswitch [ i ] ;
} else {
2018-08-27 15:07:23 +01:00
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 ] ) ;
}
2018-06-28 16:40:37 +01:00
}
2017-04-25 17:24:42 +01:00
if ( button ! = lastwallswitch [ i ] ) {
switchflag = 3 ;
2017-10-18 17:22:34 +01:00
switch ( Settings . switchmode [ i ] ) {
2017-04-25 17:24:42 +01:00
case TOGGLE :
2017-10-10 14:40:02 +01:00
switchflag = 2 ; // Toggle
2017-04-25 17:24:42 +01:00
break ;
case FOLLOW :
2017-10-10 14:40:02 +01:00
switchflag = button & 1 ; // Follow wall switch state
2017-04-25 17:24:42 +01:00
break ;
case FOLLOW_INV :
2017-10-10 14:40:02 +01:00
switchflag = ~ button & 1 ; // Follow inverted wall switch state
2017-04-25 17:24:42 +01:00
break ;
case PUSHBUTTON :
if ( ( PRESSED = = button ) & & ( NOT_PRESSED = = lastwallswitch [ i ] ) ) {
2017-06-16 13:33:49 +01:00
switchflag = 2 ; // Toggle with pushbutton to Gnd
2017-04-25 17:24:42 +01:00
}
break ;
case PUSHBUTTON_INV :
if ( ( NOT_PRESSED = = button ) & & ( PRESSED = = lastwallswitch [ i ] ) ) {
2017-06-16 13:33:49 +01:00
switchflag = 2 ; // Toggle with releasing pushbutton from Gnd
2017-04-25 17:24:42 +01:00
}
2017-06-06 22:23:23 +01:00
break ;
2017-11-22 14:34:07 +00:00
case PUSHBUTTON_TOGGLE :
if ( button ! = lastwallswitch [ i ] ) {
switchflag = 2 ; // Toggle with any pushbutton change
}
break ;
2017-06-06 22:23:23 +01:00
case PUSHBUTTONHOLD :
if ( ( PRESSED = = button ) & & ( NOT_PRESSED = = lastwallswitch [ i ] ) ) {
2018-08-27 11:01:20 +01:00
holdwallswitch [ i ] = loops_per_second * Settings . param [ P_HOLD_TIME ] / 10 ;
2017-06-06 22:23:23 +01:00
}
2017-06-16 13:33:49 +01:00
if ( ( NOT_PRESSED = = button ) & & ( PRESSED = = lastwallswitch [ i ] ) & & ( holdwallswitch [ i ] ) ) {
holdwallswitch [ i ] = 0 ;
switchflag = 2 ; // Toggle with pushbutton to Gnd
2017-06-06 22:23:23 +01:00
}
break ;
case PUSHBUTTONHOLD_INV :
if ( ( NOT_PRESSED = = button ) & & ( PRESSED = = lastwallswitch [ i ] ) ) {
2018-08-27 11:01:20 +01:00
holdwallswitch [ i ] = loops_per_second * Settings . param [ P_HOLD_TIME ] / 10 ;
2017-06-06 22:23:23 +01:00
}
2017-06-16 13:33:49 +01:00
if ( ( PRESSED = = button ) & & ( NOT_PRESSED = = lastwallswitch [ i ] ) & & ( holdwallswitch [ i ] ) ) {
holdwallswitch [ i ] = 0 ;
2018-08-27 11:01:20 +01:00
switchflag = 2 ; // Toggle with pushbutton to Gnd
2017-06-06 22:23:23 +01:00
}
break ;
2017-01-28 13:41:01 +00:00
}
2017-09-02 13:37:02 +01:00
2017-04-25 17:24:42 +01:00
if ( switchflag < 3 ) {
2018-04-13 16:42:11 +01:00
if ( ! SendKey ( 1 , i + 1 , switchflag ) ) { // Execute command via MQTT
2018-08-27 11:01:20 +01:00
ExecuteCommandPower ( i + 1 , switchflag , SRC_SWITCH ) ; // Execute command internally (if i < devices_present)
2017-04-25 17:24:42 +01:00
}
}
2017-09-02 13:37:02 +01:00
2017-04-25 17:24:42 +01:00
lastwallswitch [ i ] = button ;
2017-01-28 13:41:01 +00:00
}
}
}
2017-07-25 17:05:47 +01:00
}
/*********************************************************************************************\
2018-08-26 14:42:35 +01:00
* State loops
2017-07-25 17:05:47 +01:00
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*-------------------------------------------------------------------------------------------*\
* Every 0.1 second
\ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2018-11-14 13:32:09 +00:00
void Every100mSeconds ( void )
2018-08-26 14:42:35 +01:00
{
// As the max amount of sleep = 250 mSec this loop will shift in time...
power_t power_now ;
2017-09-02 13:37:02 +01:00
2018-08-26 14:42:35 +01:00
if ( latching_relay_pulse ) {
latching_relay_pulse - - ;
if ( ! latching_relay_pulse ) SetLatchingRelay ( 0 , 0 ) ;
}
2017-07-25 17:05:47 +01:00
2018-08-26 14:42:35 +01:00
for ( byte i = 0 ; i < MAX_PULSETIMERS ; i + + ) {
if ( pulse_timer [ i ] ! = 0L ) { // Timer active?
if ( TimeReached ( pulse_timer [ i ] ) ) { // Timer finished?
pulse_timer [ i ] = 0L ; // Turn off this timer
ExecuteCommandPower ( i + 1 , ( POWER_ALL_OFF_PULSETIME_ON = = Settings . poweronstate ) ? POWER_ON : POWER_OFF , SRC_PULSETIMER ) ;
2017-07-25 17:05:47 +01:00
}
}
2018-08-26 14:42:35 +01:00
}
2017-07-25 17:05:47 +01:00
2018-08-26 14:42:35 +01:00
if ( blink_mask ) {
2018-08-26 16:10:18 +01:00
if ( TimeReached ( blink_timer ) ) {
SetNextTimeInterval ( blink_timer , 100 * Settings . blinktime ) ;
2018-08-26 14:42:35 +01:00
blink_counter - - ;
if ( ! blink_counter ) {
StopAllPowerBlink ( ) ;
} else {
blink_power ^ = 1 ;
power_now = ( power & ( POWER_MASK ^ blink_mask ) ) | ( ( blink_power ) ? blink_mask : 0 ) ;
SetDevicePower ( power_now , SRC_IGNORE ) ;
2017-07-25 17:05:47 +01:00
}
}
2018-08-26 14:42:35 +01:00
}
2017-07-25 17:05:47 +01:00
2018-08-26 14:42:35 +01:00
// Backlog
if ( TimeReached ( backlog_delay ) ) {
if ( ( backlog_pointer ! = backlog_index ) & & ! backlog_mutex ) {
2017-10-18 17:22:34 +01:00
backlog_mutex = 1 ;
2018-05-28 14:52:42 +01:00
ExecuteCommand ( ( char * ) backlog [ backlog_pointer ] . c_str ( ) , SRC_BACKLOG ) ;
2017-10-18 17:22:34 +01:00
backlog_mutex = 0 ;
backlog_pointer + + ;
2018-08-26 14:42:35 +01:00
if ( backlog_pointer > = MAX_BACKLOG ) { backlog_pointer = 0 ; }
2017-07-25 17:05:47 +01:00
}
}
2018-08-26 14:42:35 +01:00
}
2017-07-25 17:05:47 +01:00
/*-------------------------------------------------------------------------------------------*\
2018-08-26 14:42:35 +01:00
* Every 0.25 second
2017-07-25 17:05:47 +01:00
\ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2018-11-14 13:32:09 +00:00
void Every250mSeconds ( void )
2018-08-26 14:42:35 +01:00
{
// As the max amount of sleep = 250 mSec this loop should always be taken...
2017-07-25 17:05:47 +01:00
2018-08-26 14:42:35 +01:00
uint8_t blinkinterval = 1 ;
2017-12-25 16:41:12 +00:00
2018-08-26 14:42:35 +01:00
state_250mS + + ;
state_250mS & = 0x3 ;
2017-01-28 13:41:01 +00:00
2018-08-26 14:42:35 +01:00
if ( mqtt_cmnd_publish ) mqtt_cmnd_publish - - ; // Clean up
if ( ! Settings . flag . global_state ) { // Problem blinkyblinky enabled
if ( global_state . data ) { // Any problem
if ( global_state . mqtt_down ) { blinkinterval = 7 ; } // MQTT problem so blink every 2 seconds (slowest)
if ( global_state . wifi_down ) { blinkinterval = 3 ; } // Wifi problem so blink every second (slow)
blinks = 201 ; // Allow only a single blink in case the problem is solved
2018-07-07 16:30:58 +01:00
}
2018-08-26 14:42:35 +01:00
}
if ( blinks | | restart_flag | | ota_state_flag ) {
if ( restart_flag | | ota_state_flag ) { // Overrule blinks and keep led lit
blinkstate = 1 ; // Stay lit
} else {
blinkspeed - - ;
if ( ! blinkspeed ) {
blinkspeed = blinkinterval ; // Set interval to 0.2 (default), 1 or 2 seconds
blinkstate ^ = 1 ; // Blink
2017-01-28 13:41:01 +00:00
}
2018-07-07 16:30:58 +01:00
}
2018-08-26 14:42:35 +01:00
if ( ( ! ( Settings . ledstate & 0x08 ) ) & & ( ( Settings . ledstate & 0x06 ) | | ( blinks > 200 ) | | ( blinkstate ) ) ) {
// if ( (!Settings.flag.global_state && global_state.data) || ((!(Settings.ledstate &0x08)) && ((Settings.ledstate &0x06) || (blinks > 200) || (blinkstate))) ) {
SetLedPower ( blinkstate ) ; // Set led on or off
}
if ( ! blinkstate ) {
blinks - - ;
if ( 200 = = blinks ) blinks = 0 ; // Disable blink
}
}
else if ( Settings . ledstate & 1 ) {
boolean tstate = power ;
if ( ( SONOFF_TOUCH = = Settings . module ) | | ( SONOFF_T11 = = Settings . module ) | | ( SONOFF_T12 = = Settings . module ) | | ( SONOFF_T13 = = Settings . module ) ) {
tstate = ( ! power ) ? 1 : 0 ; // As requested invert signal for Touch devices to find them in the dark
2017-01-28 13:41:01 +00:00
}
2018-08-26 14:42:35 +01:00
SetLedPower ( tstate ) ;
2017-01-28 13:41:01 +00:00
}
2017-07-25 17:05:47 +01:00
/*-------------------------------------------------------------------------------------------*\
2018-08-26 14:42:35 +01:00
* Every second at 0.25 second interval
2017-07-25 17:05:47 +01:00
\ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2017-07-15 14:07:30 +01:00
2018-08-26 14:42:35 +01:00
switch ( state_250mS ) {
case 0 : // Every x.0 second
PerformEverySecond ( ) ;
2017-10-18 17:22:34 +01:00
if ( ota_state_flag & & ( backlog_pointer = = backlog_index ) ) {
ota_state_flag - - ;
if ( 2 = = ota_state_flag ) {
2018-01-10 13:10:25 +00:00
ota_url = Settings . ota_url ;
RtcSettings . ota_loader = 0 ; // Try requested image first
2017-10-18 17:22:34 +01:00
ota_retry_counter = OTA_ATTEMPTS ;
2017-01-28 13:41:01 +00:00
ESPhttpUpdate . rebootOnUpdate ( false ) ;
2017-10-18 17:22:34 +01:00
SettingsSave ( 1 ) ; // Free flash for OTA update
2017-02-24 17:17:48 +00:00
}
2017-10-18 17:22:34 +01:00
if ( ota_state_flag < = 0 ) {
2017-02-24 17:17:48 +00:00
# ifdef USE_WEBSERVER
2018-03-02 14:38:37 +00:00
if ( Settings . webserver ) StopWebserver ( ) ;
2017-02-24 17:17:48 +00:00
# endif // USE_WEBSERVER
2017-11-24 16:26:20 +00:00
# ifdef USE_ARILUX_RF
AriluxRfDisable ( ) ; // Prevent restart exception on Arilux Interrupt routine
# endif // USE_ARILUX_RF
2017-10-18 17:22:34 +01:00
ota_state_flag = 92 ;
ota_result = 0 ;
ota_retry_counter - - ;
if ( ota_retry_counter ) {
2018-02-13 13:30:30 +00:00
strlcpy ( mqtt_data , GetOtaUrl ( log_data , sizeof ( log_data ) ) , sizeof ( mqtt_data ) ) ;
2018-01-10 13:10:25 +00:00
# ifndef BE_MINIMAL
if ( RtcSettings . ota_loader ) {
2018-08-23 15:05:51 +01:00
char * bch = strrchr ( mqtt_data , ' / ' ) ; // Only consider filename after last backslash prevent change of urls having "-" in it
char * pch = strrchr ( ( bch ! = NULL ) ? bch : mqtt_data , ' - ' ) ; // Change from filename-DE.bin into filename-minimal.bin
char * ech = strrchr ( ( bch ! = NULL ) ? bch : mqtt_data , ' . ' ) ; // Change from filename.bin into filename-minimal.bin
2018-03-02 14:38:37 +00:00
if ( ! pch ) pch = ech ;
2018-01-10 13:10:25 +00:00
if ( pch ) {
2018-02-13 13:30:30 +00:00
mqtt_data [ pch - mqtt_data ] = ' \0 ' ;
char * ech = strrchr ( Settings . ota_url , ' . ' ) ; // Change from filename.bin into filename-minimal.bin
2018-01-10 13:10:25 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s- " D_JSON_MINIMAL " %s " ) , mqtt_data , ech ) ; // Minimal filename must be filename-minimal
}
}
# endif // BE_MINIMAL
2018-02-13 13:30:30 +00:00
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_UPLOAD " %s " ) , mqtt_data ) ;
2018-01-10 13:10:25 +00:00
AddLog ( LOG_LEVEL_DEBUG ) ;
2018-10-11 14:54:34 +01:00
# if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2)
2018-02-13 13:30:30 +00:00
ota_result = ( HTTP_UPDATE_FAILED ! = ESPhttpUpdate . update ( mqtt_data ) ) ;
2018-10-11 14:54:34 +01:00
# else
// If using core stage or 2.5.0+ the syntax has changed
2018-10-16 10:21:44 +01:00
WiFiClient OTAclient ;
2018-10-16 03:27:43 +01:00
ota_result = ( HTTP_UPDATE_FAILED ! = ESPhttpUpdate . update ( OTAclient , mqtt_data ) ) ;
2018-10-11 14:54:34 +01:00
# endif
2017-10-18 17:22:34 +01:00
if ( ! ota_result ) {
2018-01-10 13:10:25 +00:00
# ifndef BE_MINIMAL
int ota_error = ESPhttpUpdate . getLastError ( ) ;
// snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD "Ota error %d"), ota_error);
// AddLog(LOG_LEVEL_DEBUG);
if ( ( HTTP_UE_TOO_LESS_SPACE = = ota_error ) | | ( HTTP_UE_BIN_FOR_WRONG_FLASH = = ota_error ) ) {
RtcSettings . ota_loader = 1 ; // Try minimal image next
}
# endif // BE_MINIMAL
2017-11-24 16:26:20 +00:00
ota_state_flag = 2 ; // Upgrade failed - retry
2017-04-25 17:24:42 +01:00
}
2017-01-28 13:41:01 +00:00
}
}
2017-11-24 16:26:20 +00:00
if ( 90 = = ota_state_flag ) { // Allow MQTT to reconnect
2017-10-18 17:22:34 +01:00
ota_state_flag = 0 ;
if ( ota_result ) {
2018-11-15 13:55:45 +00:00
// SetFlashModeDout(); // Force DOUT for both ESP8266 and ESP8285
2018-01-06 16:34:42 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( D_JSON_SUCCESSFUL " . " D_JSON_RESTARTING ) ) ;
2017-01-28 13:41:01 +00:00
} else {
2018-01-06 16:34:42 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( D_JSON_FAILED " %s " ) , ESPhttpUpdate . getLastErrorString ( ) . c_str ( ) ) ;
2017-01-28 13:41:01 +00:00
}
2017-11-24 16:26:20 +00:00
restart_flag = 2 ; // Restart anyway to keep memory clean webserver
2018-01-18 15:19:28 +00:00
MqttPublishPrefixTopic_P ( STAT , PSTR ( D_CMND_UPGRADE ) ) ;
2017-01-28 13:41:01 +00:00
}
}
break ;
2018-08-26 14:42:35 +01:00
case 1 : // Every x.25 second
if ( MidnightNow ( ) ) { CounterSaveState ( ) ; }
2017-10-18 17:22:34 +01:00
if ( save_data_counter & & ( backlog_pointer = = backlog_index ) ) {
save_data_counter - - ;
if ( save_data_counter < = 0 ) {
if ( Settings . flag . save_state ) {
2017-10-10 14:40:02 +01:00
power_t mask = POWER_MASK ;
2017-04-25 17:24:42 +01:00
for ( byte i = 0 ; i < MAX_PULSETIMERS ; i + + ) {
2017-10-18 17:22:34 +01:00
if ( ( Settings . pulse_timer [ i ] > 0 ) & & ( Settings . pulse_timer [ i ] < 30 ) ) { // 3 seconds
2017-04-25 17:24:42 +01:00
mask & = ~ ( 1 < < i ) ;
}
}
2017-10-18 17:22:34 +01:00
if ( ! ( ( Settings . power & mask ) = = ( power & mask ) ) ) {
Settings . power = power ;
2017-04-25 17:24:42 +01:00
}
2017-10-04 16:29:49 +01:00
} else {
2017-10-18 17:22:34 +01:00
Settings . power = 0 ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
SettingsSave ( 0 ) ;
save_data_counter = Settings . save_data ;
2017-01-28 13:41:01 +00:00
}
}
2017-10-18 17:22:34 +01:00
if ( restart_flag & & ( backlog_pointer = = backlog_index ) ) {
2018-10-15 13:43:47 +01:00
if ( ( 214 = = restart_flag ) | | ( 215 = = restart_flag ) ) {
char storage [ sizeof ( Settings . sta_ssid ) + sizeof ( Settings . sta_pwd ) ] ;
memcpy ( storage , Settings . sta_ssid , sizeof ( storage ) ) ; // Backup current SSIDs and Passwords
if ( 215 = = restart_flag ) {
SettingsErase ( 0 ) ; // Erase all flash from program end to end of physical flash
}
SettingsDefault ( ) ;
memcpy ( Settings . sta_ssid , storage , sizeof ( storage ) ) ; // Restore current SSIDs and Passwords
restart_flag = 2 ;
}
else if ( 213 = = restart_flag ) {
2018-02-24 15:37:33 +00:00
SettingsSdkErase ( ) ; // Erase flash SDK parameters
restart_flag = 2 ;
2018-10-15 13:43:47 +01:00
}
else if ( 212 = = restart_flag ) {
2018-02-24 15:37:33 +00:00
SettingsErase ( 0 ) ; // Erase all flash from program end to end of physical flash
restart_flag = 211 ;
2017-11-21 15:06:51 +00:00
}
if ( 211 = = restart_flag ) {
2017-10-18 17:22:34 +01:00
SettingsDefault ( ) ;
restart_flag = 2 ;
2017-01-28 13:41:01 +00:00
}
2017-11-21 15:06:51 +00:00
SettingsSaveAll ( ) ;
2017-10-18 17:22:34 +01:00
restart_flag - - ;
if ( restart_flag < = 0 ) {
AddLog_P ( LOG_LEVEL_INFO , PSTR ( D_LOG_APPLICATION D_RESTARTING ) ) ;
2018-06-03 16:09:10 +01:00
EspRestart ( ) ;
2017-01-28 13:41:01 +00:00
}
}
break ;
2018-08-26 14:42:35 +01:00
case 2 : // Every x.5 second
2017-10-18 17:22:34 +01:00
WifiCheck ( wifi_state_flag ) ;
wifi_state_flag = WIFI_RESTART ;
2017-01-28 13:41:01 +00:00
break ;
2018-08-26 14:42:35 +01:00
case 3 : // Every x.75 second
2018-11-04 17:00:07 +00:00
if ( ! global_state . wifi_down ) { MqttCheck ( ) ; }
2018-03-02 14:38:37 +00:00
break ;
2017-01-28 13:41:01 +00:00
}
}
2018-03-21 16:58:39 +00:00
# ifdef USE_ARDUINO_OTA
/*********************************************************************************************\
* Allow updating via the Arduino OTA - protocol .
*
* - Once started disables current wifi clients and udp
* - Perform restart when done to re - init wifi clients
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool arduino_ota_triggered = false ;
uint16_t arduino_ota_progress_dot_count = 0 ;
2018-11-14 13:32:09 +00:00
void ArduinoOTAInit ( void )
2018-03-21 16:58:39 +00:00
{
ArduinoOTA . setPort ( 8266 ) ;
ArduinoOTA . setHostname ( Settings . hostname ) ;
if ( Settings . web_password [ 0 ] ! = 0 ) ArduinoOTA . setPassword ( Settings . web_password ) ;
ArduinoOTA . onStart ( [ ] ( )
{
SettingsSave ( 1 ) ; // Free flash for OTA update
# ifdef USE_WEBSERVER
if ( Settings . webserver ) StopWebserver ( ) ;
# endif // USE_WEBSERVER
# ifdef USE_ARILUX_RF
AriluxRfDisable ( ) ; // Prevent restart exception on Arilux Interrupt routine
# endif // USE_ARILUX_RF
if ( Settings . flag . mqtt_enabled ) MqttDisconnect ( ) ;
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_UPLOAD " Arduino OTA " D_UPLOAD_STARTED ) ) ;
AddLog ( LOG_LEVEL_INFO ) ;
arduino_ota_triggered = true ;
arduino_ota_progress_dot_count = 0 ;
delay ( 100 ) ; // Allow time for message xfer
} ) ;
ArduinoOTA . onProgress ( [ ] ( unsigned int progress , unsigned int total )
{
if ( ( LOG_LEVEL_DEBUG < = seriallog_level ) ) {
arduino_ota_progress_dot_count + + ;
Serial . printf ( " . " ) ;
if ( ! ( arduino_ota_progress_dot_count % 80 ) ) Serial . println ( ) ;
}
} ) ;
ArduinoOTA . onError ( [ ] ( ota_error_t error )
{
/*
From ArduinoOTA . h :
typedef enum { OTA_AUTH_ERROR , OTA_BEGIN_ERROR , OTA_CONNECT_ERROR , OTA_RECEIVE_ERROR , OTA_END_ERROR } ota_error_t ;
*/
char error_str [ 100 ] ;
if ( ( LOG_LEVEL_DEBUG < = seriallog_level ) & & arduino_ota_progress_dot_count ) Serial . println ( ) ;
switch ( error ) {
case OTA_BEGIN_ERROR : strncpy_P ( error_str , PSTR ( D_UPLOAD_ERR_2 ) , sizeof ( error_str ) ) ; break ;
case OTA_RECEIVE_ERROR : strncpy_P ( error_str , PSTR ( D_UPLOAD_ERR_5 ) , sizeof ( error_str ) ) ; break ;
case OTA_END_ERROR : strncpy_P ( error_str , PSTR ( D_UPLOAD_ERR_7 ) , sizeof ( error_str ) ) ; break ;
default :
snprintf_P ( error_str , sizeof ( error_str ) , PSTR ( D_UPLOAD_ERROR_CODE " %d " ) , error ) ;
}
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_UPLOAD " Arduino OTA %s. " D_RESTARTING ) , error_str ) ;
AddLog ( LOG_LEVEL_INFO ) ;
2018-06-03 16:09:10 +01:00
EspRestart ( ) ;
2018-03-21 16:58:39 +00:00
} ) ;
ArduinoOTA . onEnd ( [ ] ( )
{
if ( ( LOG_LEVEL_DEBUG < = seriallog_level ) ) Serial . println ( ) ;
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_UPLOAD " Arduino OTA " D_SUCCESSFUL " . " D_RESTARTING ) ) ;
AddLog ( LOG_LEVEL_INFO ) ;
2018-06-03 16:09:10 +01:00
EspRestart ( ) ;
2018-03-21 16:58:39 +00:00
} ) ;
ArduinoOTA . begin ( ) ;
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_UPLOAD " Arduino OTA " D_ENABLED " " D_PORT " 8266 " ) ) ;
AddLog ( LOG_LEVEL_INFO ) ;
}
# endif // USE_ARDUINO_OTA
2017-04-10 16:25:31 +01:00
/********************************************************************************************/
2018-11-14 13:32:09 +00:00
void SerialInput ( void )
2017-01-28 13:41:01 +00:00
{
while ( Serial . available ( ) ) {
yield ( ) ;
2017-10-18 17:22:34 +01:00
serial_in_byte = Serial . read ( ) ;
2017-01-28 13:41:01 +00:00
2017-07-30 16:55:37 +01:00
/*-------------------------------------------------------------------------------------------*\
2017-12-03 13:06:15 +00:00
* Sonoff dual and ch4 19200 baud serial interface
2017-07-30 16:55:37 +01:00
\ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2017-12-03 13:06:15 +00:00
if ( ( SONOFF_DUAL = = Settings . module ) | | ( CH4 = = Settings . module ) ) {
2017-10-18 17:22:34 +01:00
if ( dual_hex_code ) {
2017-12-03 13:06:15 +00:00
dual_hex_code - - ;
if ( dual_hex_code ) {
dual_button_code = ( dual_button_code < < 8 ) | serial_in_byte ;
serial_in_byte = 0 ;
} else {
if ( serial_in_byte ! = 0xA1 ) {
dual_button_code = 0 ; // 0xA1 - End of Sonoff dual button code
}
2017-04-25 17:24:42 +01:00
}
2017-01-28 13:41:01 +00:00
}
2017-12-03 13:06:15 +00:00
if ( 0xA0 = = serial_in_byte ) { // 0xA0 - Start of Sonoff dual button code
serial_in_byte = 0 ;
dual_button_code = 0 ;
dual_hex_code = 3 ;
}
2017-01-28 13:41:01 +00:00
}
2018-09-04 15:22:34 +01:00
/*-------------------------------------------------------------------------------------------*/
2017-07-30 16:55:37 +01:00
2018-09-04 15:22:34 +01:00
if ( XdrvCall ( FUNC_SERIAL ) ) {
serial_in_byte_counter = 0 ;
Serial . flush ( ) ;
return ;
2018-02-03 22:25:05 +00:00
}
2018-09-04 15:22:34 +01:00
2017-07-30 16:55:37 +01:00
/*-------------------------------------------------------------------------------------------*/
2018-10-18 12:01:31 +01:00
if ( serial_in_byte > 127 & & ! Settings . flag . mqtt_serial_raw ) { // binary data...
serial_in_byte_counter = 0 ;
Serial . flush ( ) ;
return ;
}
if ( ! Settings . flag . mqtt_serial ) {
if ( isprint ( serial_in_byte ) ) {
if ( serial_in_byte_counter < INPUT_BUFFER_SIZE - 1 ) { // add char to string if it still fits
serial_in_buffer [ serial_in_byte_counter + + ] = serial_in_byte ;
} else {
serial_in_byte_counter = 0 ;
2018-10-16 00:32:14 +01:00
}
2018-10-18 12:01:31 +01:00
}
} else {
if ( serial_in_byte | | Settings . flag . mqtt_serial_raw ) {
if ( ( serial_in_byte_counter < INPUT_BUFFER_SIZE - 1 ) & &
( ( serial_in_byte ! = Settings . serial_delimiter ) | | Settings . flag . mqtt_serial_raw ) ) { // add char to string if it still fits
serial_in_buffer [ serial_in_byte_counter + + ] = serial_in_byte ;
serial_polling_window = millis ( ) ;
} else {
serial_polling_window = 0 ;
break ;
2018-03-20 13:31:11 +00:00
}
2017-01-28 13:41:01 +00:00
}
}
2018-10-18 12:01:31 +01:00
2017-09-16 16:34:03 +01:00
/*-------------------------------------------------------------------------------------------*\
* Sonoff SC 19200 baud serial interface
\ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2018-03-18 12:47:30 +00:00
if ( SONOFF_SC = = Settings . module ) {
if ( serial_in_byte = = ' \x1B ' ) { // Sonoff SC status from ATMEGA328P
serial_in_buffer [ serial_in_byte_counter ] = 0 ; // serial data completed
SonoffScSerialInput ( serial_in_buffer ) ;
serial_in_byte_counter = 0 ;
Serial . flush ( ) ;
return ;
}
}
/*-------------------------------------------------------------------------------------------*/
2018-03-20 13:31:11 +00:00
2018-03-18 12:47:30 +00:00
else if ( ! Settings . flag . mqtt_serial & & ( serial_in_byte = = ' \n ' ) ) {
2017-10-18 17:22:34 +01:00
serial_in_buffer [ serial_in_byte_counter ] = 0 ; // serial data completed
2018-02-03 22:25:05 +00:00
seriallog_level = ( Settings . seriallog_level < LOG_LEVEL_INFO ) ? ( byte ) LOG_LEVEL_INFO : Settings . seriallog_level ;
2017-10-18 17:22:34 +01:00
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_COMMAND " %s " ) , serial_in_buffer ) ;
AddLog ( LOG_LEVEL_INFO ) ;
2018-05-28 14:52:42 +01:00
ExecuteCommand ( serial_in_buffer , SRC_SERIAL ) ;
2017-10-18 17:22:34 +01:00
serial_in_byte_counter = 0 ;
2018-03-18 12:47:30 +00:00
serial_polling_window = 0 ;
2017-01-28 13:41:01 +00:00
Serial . flush ( ) ;
return ;
}
}
2018-03-18 12:47:30 +00:00
2018-10-18 12:01:31 +01:00
if ( Settings . flag . mqtt_serial & & serial_in_byte_counter & & ( millis ( ) > ( serial_polling_window + SERIAL_POLLING ) ) ) {
2018-03-18 12:47:30 +00:00
serial_in_buffer [ serial_in_byte_counter ] = 0 ; // serial data completed
2018-10-18 12:01:31 +01:00
if ( ! Settings . flag . mqtt_serial_raw ) {
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { \" " D_JSON_SERIALRECEIVED " \" : \" %s \" } " ) , serial_in_buffer ) ;
} else {
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " { \" " D_JSON_SERIALRECEIVED " \" : \" " ) ) ;
for ( int i = 0 ; i < serial_in_byte_counter ; i + + ) {
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s%02x " ) , mqtt_data , serial_in_buffer [ i ] ) ;
2018-07-27 11:17:34 +01:00
}
2018-10-18 12:01:31 +01:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s \" } " ) , mqtt_data ) ;
2018-07-27 11:17:34 +01:00
}
2018-10-18 12:01:31 +01:00
MqttPublishPrefixTopic_P ( RESULT_OR_TELE , PSTR ( D_JSON_SERIALRECEIVED ) ) ;
// XdrvRulesProcess();
serial_in_byte_counter = 0 ;
2018-03-18 12:47:30 +00:00
}
2017-01-28 13:41:01 +00:00
}
/********************************************************************************************/
2018-09-26 10:56:58 +01:00
void GpioSwitchPinMode ( uint8_t index )
{
if ( pin [ GPIO_SWT1 + index ] < 99 ) {
2018-11-10 09:48:28 +00:00
pinMode ( pin [ GPIO_SWT1 + index ] , ( 16 = = pin [ GPIO_SWT1 + index ] ) ? INPUT_PULLDOWN_16 : bitRead ( switch_no_pullup , index ) ? INPUT : INPUT_PULLUP ) ;
/*
// Re-enable pull-up on Shelly2 as of 20181110 (#4255)
2018-11-07 17:43:44 +00:00
uint8_t no_pullup = bitRead ( switch_no_pullup , index ) ; // 0 = INPUT_PULLUP, 1 = INPUT
2018-10-07 11:37:03 +01:00
if ( no_pullup ) {
if ( SHELLY2 = = Settings . module ) {
2018-11-07 17:43:44 +00:00
// Switchmodes : TOGGLE, FOLLOW, FOLLOW_INV, PUSHBUTTON, PUSHBUTTON_INV, PUSHBUTTONHOLD, PUSHBUTTONHOLD_INV, PUSHBUTTON_TOGGLE, MAX_SWITCH_OPTION
no_pullup = ( Settings . switchmode [ index ] < PUSHBUTTON ) ; // INPUT on TOGGLE, FOLLOW and FOLLOW_INV. INPUT_PULLUP on anything else
2018-10-07 11:37:03 +01:00
}
2018-09-26 10:56:58 +01:00
}
pinMode ( pin [ GPIO_SWT1 + index ] , ( 16 = = pin [ GPIO_SWT1 + index ] ) ? INPUT_PULLDOWN_16 : ( no_pullup ) ? INPUT : INPUT_PULLUP ) ;
2018-11-10 09:48:28 +00:00
*/
2018-09-26 10:56:58 +01:00
}
}
2018-11-14 13:32:09 +00:00
void GpioInit ( void )
2017-01-28 13:41:01 +00:00
{
uint8_t mpin ;
2018-08-25 12:08:06 +01:00
uint8_t key_no_pullup = 0 ;
2017-01-28 13:41:01 +00:00
mytmplt def_module ;
2018-11-06 10:48:04 +00:00
if ( Settings . module > = MAXMODULE ) {
2017-10-18 17:22:34 +01:00
Settings . module = MODULE ;
2017-11-15 22:07:45 +00:00
Settings . last_module = MODULE ;
2017-04-25 17:24:42 +01:00
}
2018-11-06 10:48:04 +00:00
if ( Settings . module ! = Settings . last_module ) {
baudrate = APP_BAUDRATE ;
}
2017-01-28 13:41:01 +00:00
2017-10-18 17:22:34 +01:00
memcpy_P ( & def_module , & kModules [ Settings . module ] , sizeof ( def_module ) ) ;
2017-01-28 13:41:01 +00:00
strlcpy ( my_module . name , def_module . name , sizeof ( my_module . name ) ) ;
for ( byte i = 0 ; i < MAX_GPIO_PIN ; i + + ) {
2017-10-18 17:22:34 +01:00
if ( Settings . my_gp . io [ i ] > GPIO_NONE ) {
my_module . gp . io [ i ] = Settings . my_gp . io [ i ] ;
2017-04-25 17:24:42 +01:00
}
if ( ( def_module . gp . io [ i ] > GPIO_NONE ) & & ( def_module . gp . io [ i ] < GPIO_USER ) ) {
my_module . gp . io [ i ] = def_module . gp . io [ i ] ;
}
2017-01-28 13:41:01 +00:00
}
2017-02-11 14:06:23 +00:00
2017-04-25 17:24:42 +01:00
for ( byte i = 0 ; i < GPIO_MAX ; i + + ) {
pin [ i ] = 99 ;
}
2017-01-28 13:41:01 +00:00
for ( byte i = 0 ; i < MAX_GPIO_PIN ; i + + ) {
2018-08-30 13:27:33 +01:00
mpin = ValidGPIO ( i , my_module . gp . io [ i ] ) ;
2017-01-28 13:41:01 +00:00
2017-09-13 13:19:34 +01:00
// snprintf_P(log_data, sizeof(log_data), PSTR("DBG: gpio pin %d, mpin %d"), i, mpin);
2017-10-18 17:22:34 +01:00
// AddLog(LOG_LEVEL_DEBUG);
2017-09-02 13:37:02 +01:00
2017-01-28 13:41:01 +00:00
if ( mpin ) {
2018-08-25 12:08:06 +01:00
if ( ( mpin > = GPIO_SWT1_NP ) & & ( mpin < ( GPIO_SWT1_NP + MAX_SWITCHES ) ) ) {
bitSet ( switch_no_pullup , mpin - GPIO_SWT1_NP ) ;
mpin - = ( GPIO_SWT1_NP - GPIO_SWT1 ) ;
}
2018-08-30 13:27:33 +01:00
else if ( ( mpin > = GPIO_KEY1_NP ) & & ( mpin < ( GPIO_KEY1_NP + MAX_KEYS ) ) ) {
2018-08-25 12:08:06 +01:00
bitSet ( key_no_pullup , mpin - GPIO_KEY1_NP ) ;
mpin - = ( GPIO_KEY1_NP - GPIO_KEY1 ) ;
}
else if ( ( mpin > = GPIO_REL1_INV ) & & ( mpin < ( GPIO_REL1_INV + MAX_RELAYS ) ) ) {
2017-10-10 14:40:02 +01:00
bitSet ( rel_inverted , mpin - GPIO_REL1_INV ) ;
2017-10-05 12:28:31 +01:00
mpin - = ( GPIO_REL1_INV - GPIO_REL1 ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-10 14:40:02 +01:00
else if ( ( mpin > = GPIO_LED1_INV ) & & ( mpin < ( GPIO_LED1_INV + MAX_LEDS ) ) ) {
bitSet ( led_inverted , mpin - GPIO_LED1_INV ) ;
2017-10-05 12:28:31 +01:00
mpin - = ( GPIO_LED1_INV - GPIO_LED1 ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-10 14:40:02 +01:00
else if ( ( mpin > = GPIO_PWM1_INV ) & & ( mpin < ( GPIO_PWM1_INV + MAX_PWMS ) ) ) {
bitSet ( pwm_inverted , mpin - GPIO_PWM1_INV ) ;
2017-10-05 12:28:31 +01:00
mpin - = ( GPIO_PWM1_INV - GPIO_PWM1 ) ;
2017-10-04 16:29:49 +01:00
}
2018-08-25 12:08:06 +01:00
else if ( ( mpin > = GPIO_CNTR1_NP ) & & ( mpin < ( GPIO_CNTR1_NP + MAX_COUNTERS ) ) ) {
bitSet ( counter_no_pullup , mpin - GPIO_CNTR1_NP ) ;
mpin - = ( GPIO_CNTR1_NP - GPIO_CNTR1 ) ;
}
2017-09-02 13:37:02 +01:00
# ifdef USE_DHT
2017-12-03 13:06:15 +00:00
else if ( ( mpin > = GPIO_DHT11 ) & & ( mpin < = GPIO_SI7021 ) ) {
2017-10-18 17:22:34 +01:00
if ( DhtSetup ( i , mpin ) ) {
2017-05-03 17:19:13 +01:00
dht_flg = 1 ;
mpin = GPIO_DHT11 ;
} else {
mpin = 0 ;
}
2017-01-28 13:41:01 +00:00
}
2017-09-02 13:37:02 +01:00
# endif // USE_DHT
2017-05-03 17:19:13 +01:00
}
2018-03-02 14:38:37 +00:00
if ( mpin ) pin [ mpin ] = i ;
2017-01-28 13:41:01 +00:00
}
2018-09-05 17:01:15 +01:00
if ( ( 2 = = pin [ GPIO_TXD ] ) | | ( H801 = = Settings . module ) ) { Serial . set_tx ( 2 ) ; }
2017-03-25 16:24:11 +00:00
2017-10-18 17:22:34 +01:00
analogWriteRange ( Settings . pwm_range ) ; // Default is 1023 (Arduino.h)
analogWriteFreq ( Settings . pwm_frequency ) ; // Default is 1000 (core_esp8266_wiring_pwm.c)
2017-03-19 17:19:08 +00:00
2018-01-05 11:26:19 +00:00
# ifdef USE_SPI
spi_flg = ( ( ( ( pin [ GPIO_SPI_CS ] < 99 ) & & ( pin [ GPIO_SPI_CS ] > 14 ) ) | | ( pin [ GPIO_SPI_CS ] < 12 ) ) | | ( ( ( pin [ GPIO_SPI_DC ] < 99 ) & & ( pin [ GPIO_SPI_DC ] > 14 ) ) | | ( pin [ GPIO_SPI_DC ] < 12 ) ) ) ;
if ( spi_flg ) {
for ( byte i = 0 ; i < GPIO_MAX ; i + + ) {
2018-03-02 14:38:37 +00:00
if ( ( pin [ i ] > = 12 ) & & ( pin [ i ] < = 14 ) ) pin [ i ] = 99 ;
2018-01-05 11:26:19 +00:00
}
my_module . gp . io [ 12 ] = GPIO_SPI_MISO ;
pin [ GPIO_SPI_MISO ] = 12 ;
my_module . gp . io [ 13 ] = GPIO_SPI_MOSI ;
pin [ GPIO_SPI_MOSI ] = 13 ;
my_module . gp . io [ 14 ] = GPIO_SPI_CLK ;
pin [ GPIO_SPI_CLK ] = 14 ;
}
# endif // USE_SPI
2017-10-10 14:40:02 +01:00
# ifdef USE_I2C
i2c_flg = ( ( pin [ GPIO_I2C_SCL ] < 99 ) & & ( pin [ GPIO_I2C_SDA ] < 99 ) ) ;
2018-03-02 14:38:37 +00:00
if ( i2c_flg ) Wire . begin ( pin [ GPIO_I2C_SDA ] , pin [ GPIO_I2C_SCL ] ) ;
2017-10-10 14:40:02 +01:00
# endif // USE_I2C
2017-10-18 17:22:34 +01:00
devices_present = 1 ;
2017-12-25 16:41:12 +00:00
light_type = LT_BASIC ; // Use basic PWM control if SetOption15 = 0
2017-10-18 17:22:34 +01:00
if ( Settings . flag . pwm_control ) {
2017-10-10 14:40:02 +01:00
for ( byte i = 0 ; i < MAX_PWMS ; i + + ) {
2018-03-02 14:38:37 +00:00
if ( pin [ GPIO_PWM1 + i ] < 99 ) light_type + + ; // Use Dimmer/Color control for all PWM as SetOption15 = 1
2017-10-01 13:32:36 +01:00
}
}
2017-12-25 16:41:12 +00:00
2017-10-18 17:22:34 +01:00
if ( SONOFF_BRIDGE = = Settings . module ) {
2018-03-18 12:47:30 +00:00
Settings . flag . mqtt_serial = 0 ;
2017-10-18 17:22:34 +01:00
baudrate = 19200 ;
2017-07-30 16:55:37 +01:00
}
2017-12-25 16:41:12 +00:00
2018-10-18 12:01:31 +01:00
if ( XdrvCall ( FUNC_MODULE_INIT ) ) {
2018-10-19 11:53:22 +01:00
// Serviced
2018-10-18 12:01:31 +01:00
}
else if ( SONOFF_DUAL = = Settings . module ) {
2018-03-18 12:47:30 +00:00
Settings . flag . mqtt_serial = 0 ;
2017-10-18 17:22:34 +01:00
devices_present = 2 ;
baudrate = 19200 ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
else if ( CH4 = = Settings . module ) {
2018-03-18 12:47:30 +00:00
Settings . flag . mqtt_serial = 0 ;
2017-10-18 17:22:34 +01:00
devices_present = 4 ;
baudrate = 19200 ;
2017-02-13 16:25:46 +00:00
}
2017-10-18 17:22:34 +01:00
else if ( SONOFF_SC = = Settings . module ) {
2018-03-18 12:47:30 +00:00
Settings . flag . mqtt_serial = 0 ;
2017-10-18 17:22:34 +01:00
devices_present = 0 ;
baudrate = 19200 ;
2017-04-10 16:25:31 +01:00
}
2017-10-18 17:22:34 +01:00
else if ( SONOFF_BN = = Settings . module ) { // PWM Single color led (White)
2017-10-25 13:27:30 +01:00
light_type = LT_PWM1 ;
2017-07-03 10:45:15 +01:00
}
2017-10-18 17:22:34 +01:00
else if ( SONOFF_LED = = Settings . module ) { // PWM Dual color led (White warm and cold)
2017-10-25 13:27:30 +01:00
light_type = LT_PWM2 ;
2017-02-13 16:25:46 +00:00
}
2017-10-18 17:22:34 +01:00
else if ( AILIGHT = = Settings . module ) { // RGBW led
2017-10-25 13:27:30 +01:00
light_type = LT_RGBW ;
2017-08-13 14:31:49 +01:00
}
2017-10-18 17:22:34 +01:00
else if ( SONOFF_B1 = = Settings . module ) { // RGBWC led
2017-10-25 13:27:30 +01:00
light_type = LT_RGBWC ;
2017-08-12 16:55:20 +01:00
}
2017-02-13 16:25:46 +00:00
else {
2018-03-02 14:38:37 +00:00
if ( ! light_type ) devices_present = 0 ;
2017-10-10 14:40:02 +01:00
for ( byte i = 0 ; i < MAX_RELAYS ; i + + ) {
2017-02-28 15:01:48 +00:00
if ( pin [ GPIO_REL1 + i ] < 99 ) {
pinMode ( pin [ GPIO_REL1 + i ] , OUTPUT ) ;
2017-10-18 17:22:34 +01:00
devices_present + + ;
2018-09-30 15:52:25 +01:00
if ( EXS_RELAY = = Settings . module ) {
digitalWrite ( pin [ GPIO_REL1 + i ] , bitRead ( rel_inverted , i ) ? 1 : 0 ) ;
if ( i & 1 ) { devices_present - - ; }
}
2017-02-28 15:01:48 +00:00
}
2017-01-28 13:41:01 +00:00
}
}
2017-12-25 16:41:12 +00:00
2017-10-12 10:29:40 +01:00
for ( byte i = 0 ; i < MAX_KEYS ; i + + ) {
2017-07-30 16:55:37 +01:00
if ( pin [ GPIO_KEY1 + i ] < 99 ) {
2018-08-25 12:08:06 +01:00
pinMode ( pin [ GPIO_KEY1 + i ] , ( 16 = = pin [ GPIO_KEY1 + i ] ) ? INPUT_PULLDOWN_16 : bitRead ( key_no_pullup , i ) ? INPUT : INPUT_PULLUP ) ;
2018-08-23 15:05:51 +01:00
}
2017-10-10 14:40:02 +01:00
}
for ( byte i = 0 ; i < MAX_LEDS ; i + + ) {
2017-01-28 13:41:01 +00:00
if ( pin [ GPIO_LED1 + i ] < 99 ) {
pinMode ( pin [ GPIO_LED1 + i ] , OUTPUT ) ;
2017-10-10 14:40:02 +01:00
digitalWrite ( pin [ GPIO_LED1 + i ] , bitRead ( led_inverted , i ) ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-10 14:40:02 +01:00
}
for ( byte i = 0 ; i < MAX_SWITCHES ; i + + ) {
2018-07-12 13:52:35 +01:00
lastwallswitch [ i ] = 1 ; // Init global to virtual switch state;
2017-01-28 13:41:01 +00:00
if ( pin [ GPIO_SWT1 + i ] < 99 ) {
2018-09-26 10:56:58 +01:00
GpioSwitchPinMode ( i ) ;
2018-07-12 13:52:35 +01:00
lastwallswitch [ i ] = digitalRead ( pin [ GPIO_SWT1 + i ] ) ; // Set global now so doesn't change the saved power state on first switch check
2018-08-23 15:05:51 +01:00
}
2018-07-12 13:52:35 +01:00
virtualswitch [ i ] = lastwallswitch [ i ] ;
2017-01-28 13:41:01 +00:00
}
2017-09-02 13:37:02 +01:00
2017-09-16 16:34:03 +01:00
# ifdef USE_WS2812
2017-10-18 17:22:34 +01:00
if ( ! light_type & & ( pin [ GPIO_WS2812 ] < 99 ) ) { // RGB led
devices_present + + ;
2017-10-25 13:27:30 +01:00
light_type = LT_WS2812 ;
2017-09-16 16:34:03 +01:00
}
# endif // USE_WS2812
2018-01-05 11:26:19 +00:00
if ( ! light_type ) {
2017-12-25 16:41:12 +00:00
for ( byte i = 0 ; i < MAX_PWMS ; i + + ) { // Basic PWM control only
2017-10-05 12:28:31 +01:00
if ( pin [ GPIO_PWM1 + i ] < 99 ) {
2018-02-06 09:06:22 +00:00
pwm_present = true ;
2017-10-05 12:28:31 +01:00
pinMode ( pin [ GPIO_PWM1 + i ] , OUTPUT ) ;
2017-10-18 17:22:34 +01:00
analogWrite ( pin [ GPIO_PWM1 + i ] , bitRead ( pwm_inverted , i ) ? Settings . pwm_range - Settings . pwm_value [ i ] : Settings . pwm_value [ i ] ) ;
2017-10-05 12:28:31 +01:00
}
2017-03-19 17:19:08 +00:00
}
}
2017-05-17 21:49:22 +01:00
2017-10-18 17:22:34 +01:00
SetLedPower ( Settings . ledstate & 8 ) ;
2017-01-28 13:41:01 +00:00
2018-06-04 17:10:38 +01:00
XdrvCall ( FUNC_PRE_INIT ) ;
2017-01-28 13:41:01 +00:00
}
2018-11-24 16:43:18 +00:00
2017-04-29 13:40:53 +01:00
extern " C " {
extern struct rst_info resetInfo ;
}
2018-11-14 13:32:09 +00:00
void setup ( void )
2017-01-28 13:41:01 +00:00
{
byte idx ;
2018-09-04 15:22:34 +01:00
RtcRebootLoad ( ) ;
if ( ! RtcRebootValid ( ) ) { RtcReboot . fast_reboot_count = 0 ; }
RtcReboot . fast_reboot_count + + ;
RtcRebootSave ( ) ;
2018-08-30 13:27:33 +01:00
2017-10-18 17:22:34 +01:00
Serial . begin ( baudrate ) ;
2017-01-28 13:41:01 +00:00
delay ( 10 ) ;
Serial . println ( ) ;
seriallog_level = LOG_LEVEL_INFO ; // Allow specific serial messages until config loaded
2018-11-07 14:03:41 +00:00
snprintf_P ( my_version , sizeof ( my_version ) , PSTR ( " %d.%d.%d " ) , VERSION > > 24 & 0xff , VERSION > > 16 & 0xff , VERSION > > 8 & 0xff ) ; // Release version 6.3.0
if ( VERSION & 0xff ) { // Development or patched version 6.3.0.10
2018-08-17 10:10:21 +01:00
snprintf_P ( my_version , sizeof ( my_version ) , PSTR ( " %s.%d " ) , my_version , VERSION & 0xff ) ;
}
2018-11-07 14:03:41 +00:00
char code_image [ 20 ] ;
snprintf_P ( my_image , sizeof ( my_image ) , PSTR ( " (%s) " ) , GetTextIndexed ( code_image , sizeof ( code_image ) , CODE_IMAGE , kCodeImage ) ) ;
2018-01-10 13:10:25 +00:00
2017-10-18 17:22:34 +01:00
SettingsLoad ( ) ;
SettingsDelta ( ) ;
2017-01-28 13:41:01 +00:00
2017-10-18 17:22:34 +01:00
OsWatchInit ( ) ;
2017-02-28 15:01:48 +00:00
2018-05-17 14:36:45 +01:00
GetFeatures ( ) ;
2018-10-23 14:51:51 +01:00
if ( 1 = = RtcReboot . fast_reboot_count ) { // Allow setting override only when all is well
XdrvCall ( FUNC_SETTINGS_OVERRIDE ) ;
}
2018-03-18 12:47:30 +00:00
baudrate = Settings . baudrate * 1200 ;
2018-10-28 16:57:25 +00:00
mdns_delayed_start = Settings . param [ P_MDNS_DELAYED_START ] ;
2017-10-18 17:22:34 +01:00
seriallog_level = Settings . seriallog_level ;
2017-08-24 10:09:52 +01:00
seriallog_timer = SERIALLOG_TIMER ;
2018-09-12 23:00:35 +01:00
syslog_level = Settings . syslog_level ;
2017-10-18 17:22:34 +01:00
stop_flash_rotate = Settings . flag . stop_flash_rotate ;
save_data_counter = Settings . save_data ;
sleep = Settings . sleep ;
2018-11-16 08:36:41 +00:00
# ifndef USE_EMULATION
Settings . flag2 . emulation = 0 ;
# endif // USE_EMULATION
2017-01-28 13:41:01 +00:00
2018-08-30 13:47:48 +01:00
// Disable functionality as possible cause of fast restart within BOOT_LOOP_TIME seconds (Exception, WDT or restarts)
2018-10-23 14:51:51 +01:00
if ( RtcReboot . fast_reboot_count > 1 ) { // Restart twice
2018-08-30 13:27:33 +01:00
Settings . flag3 . user_esp8285_enable = 0 ; // Disable ESP8285 Generic GPIOs interfering with flash SPI
2018-10-23 14:51:51 +01:00
if ( RtcReboot . fast_reboot_count > 2 ) { // Restart 3 times
2018-08-30 13:27:33 +01:00
for ( byte i = 0 ; i < MAX_RULE_SETS ; i + + ) {
if ( bitRead ( Settings . rule_stop , i ) ) {
bitWrite ( Settings . rule_enabled , i , 0 ) ; // Disable rules causing boot loop
}
}
}
2018-10-23 14:51:51 +01:00
if ( RtcReboot . fast_reboot_count > 3 ) { // Restarted 4 times
2018-08-30 13:27:33 +01:00
Settings . rule_enabled = 0 ; // Disable all rules
}
2018-10-23 14:51:51 +01:00
if ( RtcReboot . fast_reboot_count > 4 ) { // Restarted 5 times
2018-08-30 13:47:48 +01:00
Settings . module = SONOFF_BASIC ; // Reset module to Sonoff Basic
2018-11-06 10:48:04 +00:00
// Settings.last_module = SONOFF_BASIC;
2018-08-30 13:47:48 +01:00
for ( byte i = 0 ; i < MAX_GPIO_PIN ; i + + ) {
Settings . my_gp . io [ i ] = GPIO_NONE ; // Reset user defined GPIO disabling sensors
}
2018-08-28 09:26:33 +01:00
}
2018-09-04 15:22:34 +01:00
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_APPLICATION D_LOG_SOME_SETTINGS_RESET " (%d) " ) , RtcReboot . fast_reboot_count ) ;
2018-08-30 13:27:33 +01:00
AddLog ( LOG_LEVEL_DEBUG ) ;
2018-08-28 09:26:33 +01:00
}
2018-03-29 12:03:13 +01:00
Format ( mqtt_client , Settings . mqtt_client , sizeof ( mqtt_client ) ) ;
Format ( mqtt_topic , Settings . mqtt_topic , sizeof ( mqtt_topic ) ) ;
2017-10-18 17:22:34 +01:00
if ( strstr ( Settings . hostname , " % " ) ) {
strlcpy ( Settings . hostname , WIFI_HOSTNAME , sizeof ( Settings . hostname ) ) ;
2018-02-13 13:30:30 +00:00
snprintf_P ( my_hostname , sizeof ( my_hostname ) - 1 , Settings . hostname , mqtt_topic , ESP . getChipId ( ) & 0x1FFF ) ;
2017-01-28 13:41:01 +00:00
} else {
2017-10-18 17:22:34 +01:00
snprintf_P ( my_hostname , sizeof ( my_hostname ) - 1 , Settings . hostname ) ;
2017-01-28 13:41:01 +00:00
}
2018-09-05 14:38:48 +01:00
GpioInit ( ) ;
SetSerialBaudrate ( baudrate ) ;
2017-10-18 17:22:34 +01:00
WifiConnect ( ) ;
2017-01-28 13:41:01 +00:00
2018-03-02 14:38:37 +00:00
if ( MOTOR = = Settings . module ) Settings . poweronstate = POWER_ALL_ON ; // Needs always on else in limbo!
2018-01-24 16:31:20 +00:00
if ( POWER_ALL_ALWAYS_ON = = Settings . poweronstate ) {
2018-05-28 14:52:42 +01:00
SetDevicePower ( 1 , SRC_RESTART ) ;
2017-05-05 16:57:05 +01:00
} else {
if ( ( resetInfo . reason = = REASON_DEFAULT_RST ) | | ( resetInfo . reason = = REASON_EXT_SYS_RST ) ) {
2017-10-18 17:22:34 +01:00
switch ( Settings . poweronstate ) {
2018-01-24 16:31:20 +00:00
case POWER_ALL_OFF :
case POWER_ALL_OFF_PULSETIME_ON :
2017-05-05 16:57:05 +01:00
power = 0 ;
2018-05-28 14:52:42 +01:00
SetDevicePower ( power , SRC_RESTART ) ;
2017-05-05 16:57:05 +01:00
break ;
2018-01-24 16:31:20 +00:00
case POWER_ALL_ON : // All on
2017-10-18 17:22:34 +01:00
power = ( 1 < < devices_present ) - 1 ;
2018-05-28 14:52:42 +01:00
SetDevicePower ( power , SRC_RESTART ) ;
2017-05-05 16:57:05 +01:00
break ;
2018-01-24 16:31:20 +00:00
case POWER_ALL_SAVED_TOGGLE :
2018-02-03 22:25:05 +00:00
power = ( Settings . power & ( ( 1 < < devices_present ) - 1 ) ) ^ POWER_MASK ;
2017-10-18 17:22:34 +01:00
if ( Settings . flag . save_state ) {
2018-05-28 14:52:42 +01:00
SetDevicePower ( power , SRC_RESTART ) ;
2017-05-05 16:57:05 +01:00
}
break ;
2018-01-24 16:31:20 +00:00
case POWER_ALL_SAVED :
2017-10-18 17:22:34 +01:00
power = Settings . power & ( ( 1 < < devices_present ) - 1 ) ;
if ( Settings . flag . save_state ) {
2018-05-28 14:52:42 +01:00
SetDevicePower ( power , SRC_RESTART ) ;
2017-05-05 16:57:05 +01:00
}
break ;
2017-04-25 17:24:42 +01:00
}
2017-05-05 16:57:05 +01:00
} else {
2017-10-18 17:22:34 +01:00
power = Settings . power & ( ( 1 < < devices_present ) - 1 ) ;
if ( Settings . flag . save_state ) {
2018-05-28 14:52:42 +01:00
SetDevicePower ( power , SRC_RESTART ) ;
2017-04-25 17:24:42 +01:00
}
2017-01-28 13:41:01 +00:00
}
}
2017-08-29 15:35:45 +01:00
2017-10-14 10:26:49 +01:00
// Issue #526 and #909
2017-10-18 17:22:34 +01:00
for ( byte i = 0 ; i < devices_present ; i + + ) {
2017-10-14 10:26:49 +01:00
if ( ( i < MAX_RELAYS ) & & ( pin [ GPIO_REL1 + i ] < 99 ) ) {
bitWrite ( power , i , digitalRead ( pin [ GPIO_REL1 + i ] ) ^ bitRead ( rel_inverted , i ) ) ;
2017-08-29 15:35:45 +01:00
}
2018-01-24 16:31:20 +00:00
if ( ( i < MAX_PULSETIMERS ) & & ( bitRead ( power , i ) | | ( POWER_ALL_OFF_PULSETIME_ON = = Settings . poweronstate ) ) ) {
2018-08-26 14:42:35 +01:00
SetPulseTimer ( i , Settings . pulse_timer [ i ] ) ;
2017-10-12 13:09:19 +01:00
}
}
2017-01-28 13:41:01 +00:00
blink_powersave = power ;
2018-11-07 14:03:41 +00:00
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_PROJECT " %s %s ( " D_CMND_TOPIC " %s, " D_FALLBACK " %s, " D_CMND_GROUPTOPIC " %s) " D_VERSION " %s%s- " ARDUINO_ESP8266_RELEASE ) ,
PROJECT , Settings . friendlyname [ 0 ] , mqtt_topic , mqtt_client , Settings . mqtt_grptopic , my_version , my_image ) ;
2018-01-10 13:10:25 +00:00
AddLog ( LOG_LEVEL_INFO ) ;
# ifdef BE_MINIMAL
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_WARNING_MINIMAL_VERSION ) ) ;
2017-10-18 17:22:34 +01:00
AddLog ( LOG_LEVEL_INFO ) ;
2018-01-10 13:10:25 +00:00
# endif // BE_MINIMAL
2017-12-01 14:59:53 +00:00
RtcInit ( ) ;
2018-03-21 16:58:39 +00:00
# ifdef USE_ARDUINO_OTA
ArduinoOTAInit ( ) ;
# endif // USE_ARDUINO_OTA
2018-06-04 17:10:38 +01:00
XdrvCall ( FUNC_INIT ) ;
2018-01-24 16:31:20 +00:00
XsnsCall ( FUNC_INIT ) ;
2017-01-28 13:41:01 +00:00
}
2018-11-14 13:32:09 +00:00
void loop ( void )
2017-01-28 13:41:01 +00:00
{
2018-11-18 14:02:52 +00:00
uint32_t my_sleep = millis ( ) ;
2018-02-27 13:59:46 +00:00
XdrvCall ( FUNC_LOOP ) ;
2017-10-18 17:22:34 +01:00
OsWatchLoop ( ) ;
2017-09-02 13:37:02 +01:00
2018-08-27 11:01:20 +01:00
if ( TimeReached ( button_debounce ) ) {
SetNextTimeInterval ( button_debounce , Settings . button_debounce ) ;
ButtonHandler ( ) ;
}
if ( TimeReached ( switch_debounce ) ) {
SetNextTimeInterval ( switch_debounce , Settings . switch_debounce ) ;
SwitchHandler ( 0 ) ;
}
2018-08-26 14:42:35 +01:00
if ( TimeReached ( state_50msecond ) ) {
SetNextTimeInterval ( state_50msecond , 50 ) ;
2018-08-26 16:10:18 +01:00
XdrvCall ( FUNC_EVERY_50_MSECOND ) ;
XsnsCall ( FUNC_EVERY_50_MSECOND ) ;
2018-08-26 14:42:35 +01:00
}
if ( TimeReached ( state_100msecond ) ) {
SetNextTimeInterval ( state_100msecond , 100 ) ;
Every100mSeconds ( ) ;
2018-08-26 16:10:18 +01:00
XdrvCall ( FUNC_EVERY_100_MSECOND ) ;
XsnsCall ( FUNC_EVERY_100_MSECOND ) ;
2018-08-26 14:42:35 +01:00
}
if ( TimeReached ( state_250msecond ) ) {
SetNextTimeInterval ( state_250msecond , 250 ) ;
Every250mSeconds ( ) ;
2018-08-26 16:10:18 +01:00
XdrvCall ( FUNC_EVERY_250_MSECOND ) ;
XsnsCall ( FUNC_EVERY_250_MSECOND ) ;
2018-08-26 14:42:35 +01:00
}
2018-02-27 13:59:46 +00:00
2018-05-09 12:43:22 +01:00
if ( ! serial_local ) SerialInput ( ) ;
2017-01-28 13:41:01 +00:00
2018-03-21 16:58:39 +00:00
# ifdef USE_ARDUINO_OTA
ArduinoOTA . handle ( ) ;
// Once OTA is triggered, only handle that and dont do other stuff. (otherwise it fails)
while ( arduino_ota_triggered ) ArduinoOTA . handle ( ) ;
# endif // USE_ARDUINO_OTA
2018-11-18 14:02:52 +00:00
// yield(); // yield == delay(0), delay contains yield, auto yield in loop
2017-01-29 13:52:31 +00:00
delay ( sleep ) ; // https://github.com/esp8266/Arduino/issues/2021
2018-11-18 14:02:52 +00:00
uint32_t my_activity = millis ( ) - my_sleep ;
2018-11-22 15:13:55 +00:00
if ( my_activity < ( uint32_t ) Settings . param [ P_LOOP_SLEEP_DELAY ] ) {
delay ( ( uint32_t ) Settings . param [ P_LOOP_SLEEP_DELAY ] - my_activity ) ; // Provide time for background tasks like wifi
2018-11-22 11:25:18 +00:00
} else {
2018-11-22 15:13:55 +00:00
if ( global_state . wifi_down ) {
delay ( my_activity / 2 ) ; // If wifi down and my_activity > setoption36 then force loop delay to 1/3 of my_activity period
2018-11-22 11:25:18 +00:00
}
}
2018-11-25 16:31:53 +00:00
if ( ! my_activity ) { my_activity + + ; } // We cannot divide by 0
uint32_t loop_delay = Settings . param [ P_LOOP_SLEEP_DELAY ] ;
if ( ! loop_delay ) { loop_delay + + ; } // We cannot divide by 0
uint32_t loops_per_second = 1000 / loop_delay ; // We need to keep track of this many loops per second
uint32_t this_cycle_ratio = 100 * my_activity / loop_delay ;
2018-11-26 09:37:15 +00:00
loop_load_avg = loop_load_avg - ( loop_load_avg / loops_per_second ) + ( this_cycle_ratio / loops_per_second ) ; // Take away one loop average away and add the new one
2017-08-08 15:08:08 +01:00
}