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
2019-01-01 12:55:01 +00:00
Copyright ( C ) 2019 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
2019-02-17 09:42:55 +00:00
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 ,
2019-02-11 18:21:49 +00:00
CMND_WIFICONFIG , CMND_FRIENDLYNAME , CMND_SWITCHMODE , CMND_INTERLOCK , CMND_TEMPLATE ,
2019-04-10 13:26:36 +01:00
CMND_TELEPERIOD , CMND_RESTART , CMND_RESET , CMND_TIMEZONE , CMND_TIMESTD , CMND_TIMEDST , CMND_ALTITUDE , CMND_LEDPOWER , CMND_LEDSTATE , CMND_LEDMASK ,
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 " | "
2019-02-11 18:21:49 +00:00
D_CMND_WIFICONFIG " | " D_CMND_FRIENDLYNAME " | " D_CMND_SWITCHMODE " | " D_CMND_INTERLOCK " | " D_CMND_TEMPLATE " | "
2019-04-10 13:26:36 +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 " | " D_CMND_LEDMASK " | "
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-12-01 17:53:42 +00:00
const char kSleepMode [ ] PROGMEM = " Dynamic|Normal " ;
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
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
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
int16_t save_data_counter ; // Counter and flag for config save to Flash
RulesBitfield rules_flag ; // Rule state flags (16 bits)
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 sleep ; // Current copy of Settings.sleep
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 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)
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 light_type = 0 ; // Light types
2019-01-28 13:08:33 +00:00
uint8_t serial_in_byte ; // Received byte
uint8_t ota_retry_counter = OTA_ATTEMPTS ; // OTA retry counter
uint8_t web_log_index = 1 ; // Index in Web log buffer (should never be 0)
uint8_t devices_present = 0 ; // Max number of devices supported
uint8_t seriallog_level ; // Current copy of Settings.seriallog_level
uint8_t syslog_level ; // Current copy of Settings.syslog_level
2019-02-11 18:21:49 +00:00
uint8_t my_module_type ; // Current copy of Settings.module or user template type
2019-01-28 13:08:33 +00:00
//uint8_t mdns_delayed_start = 0; // mDNS delayed start
bool serial_local = false ; // Handle serial locally;
bool fallback_topic_flag = false ; // Use Topic or FallbackTopic
bool backlog_mutex = false ; // Command backlog pending
bool interlock_mutex = false ; // Interlock power command pending
bool stop_flash_rotate = false ; // Allow flash configuration rotation
bool blinkstate = false ; // LED state
bool latest_uptime_flag = true ; // Signal latest uptime
bool pwm_present = false ; // Any PWM channel configured with SetOption15 0
bool dht_flg = false ; // DHT configured
bool i2c_flg = false ; // I2C configured
bool spi_flg = false ; // SPI configured
bool soft_spi_flg = false ; // Software SPI configured
bool ntp_force_sync = false ; // Force NTP sync
2019-01-07 15:33:18 +00:00
myio my_module ; // Active copy of Module GPIOs (17 x 8 bits)
gpio_flag my_module_flag ; // Active copy of Module GPIO flags
2018-08-27 15:07:23 +01:00
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-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 ;
2019-03-26 17:26:50 +00:00
if ( strstr ( input , " % " ) ! = nullptr ) {
2017-01-28 13:41:01 +00:00
strlcpy ( output , input , size ) ;
token = strtok ( output , " % " ) ;
if ( strstr ( input , " % " ) = = input ) {
output [ 0 ] = ' \0 ' ;
} else {
2019-03-26 17:26:50 +00:00
token = strtok ( nullptr , " " ) ;
2017-01-28 13:41:01 +00:00
}
2019-03-26 17:26:50 +00:00
if ( token ! = nullptr ) {
2017-01-28 13:41:01 +00:00
digits = atoi ( token ) ;
if ( digits ) {
2019-03-08 15:28:46 +00:00
char tmp [ size ] ;
2018-02-13 13:30:30 +00:00
if ( strchr ( token , ' d ' ) ) {
2019-03-08 15:28:46 +00:00
snprintf_P ( tmp , size , PSTR ( " %s%c0%dd " ) , output , ' % ' , digits ) ;
2019-03-08 16:42:21 +00:00
snprintf_P ( output , size , tmp , ESP . getChipId ( ) & 0x1fff ) ; // %04d - short chip ID in dec, like in hostname
2018-02-13 13:30:30 +00:00
} else {
2019-03-08 15:28:46 +00:00
snprintf_P ( tmp , size , PSTR ( " %s%c0%dX " ) , output , ' % ' , digits ) ;
snprintf_P ( output , size , tmp , ESP . getChipId ( ) ) ; // %06X - full chip ID in hex
2018-02-13 13:30:30 +00:00
}
} 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
}
}
}
2019-01-28 13:08:33 +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 )
{
2019-03-26 17:26:50 +00:00
if ( strstr ( Settings . ota_url , " %04d " ) ! = nullptr ) { // OTA url contains placeholder for chip ID
2018-02-13 13:30:30 +00:00
snprintf ( otaurl , otaurl_size , Settings . ota_url , ESP . getChipId ( ) & 0x1fff ) ;
}
2019-03-26 17:26:50 +00:00
else if ( strstr ( Settings . ota_url , " %d " ) ! = nullptr ) { // OTA url contains placeholder for chip ID
2018-02-13 13:30:30 +00:00
snprintf_P ( otaurl , otaurl_size , Settings . ota_url , ESP . getChipId ( ) ) ;
}
else {
2019-03-08 18:24:02 +00:00
strlcpy ( otaurl , Settings . ota_url , otaurl_size ) ;
2018-02-13 13:30:30 +00:00
}
return otaurl ;
2017-01-28 13:41:01 +00:00
}
2019-01-28 13:08:33 +00:00
char * GetTopic_P ( char * stopic , uint8_t 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
2018-12-23 13:48:57 +00:00
prefix 4 = Cmnd fallback
prefix 5 = Stat fallback
prefix 6 = Tele fallback
2018-01-18 15:19:28 +00:00
*/
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 ) ;
2018-12-23 13:48:57 +00:00
if ( fallback_topic_flag | | ( prefix > 3 ) ) {
prefix & = 3 ;
2017-10-18 17:22:34 +01:00
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 ;
2018-12-23 13:48:57 +00:00
fulltopic + = F ( " _fb " ) ; // cmnd/<mqttclient>_fb
2017-06-30 16:54:19 +01:00
} else {
2017-10-18 17:22:34 +01:00
fulltopic = Settings . mqtt_fulltopic ;
2019-03-30 15:29:27 +00:00
if ( ( 0 = = prefix ) & & ( - 1 = = fulltopic . indexOf ( FPSTR ( MQTT_TOKEN_PREFIX ) ) ) ) {
fulltopic + = F ( " / " ) ;
fulltopic + = FPSTR ( MQTT_TOKEN_PREFIX ) ; // Need prefix for commands to handle mqtt topic loops
2017-06-30 16:54:19 +01:00
}
2019-01-28 13:08:33 +00:00
for ( uint8_t 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
}
2019-03-30 15:29:27 +00:00
fulltopic . replace ( FPSTR ( MQTT_TOKEN_PREFIX ) , Settings . mqtt_prefix [ prefix ] ) ;
fulltopic . replace ( FPSTR ( MQTT_TOKEN_TOPIC ) , topic ) ;
fulltopic . replace ( F ( " %hostname% " ) , my_hostname ) ;
2018-05-21 16:52:24 +01:00
String token_id = WiFi . macAddress ( ) ;
token_id . replace ( " : " , " " ) ;
2019-03-30 15:29:27 +00:00
fulltopic . replace ( F ( " %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 ) ;
2018-12-23 13:48:57 +00:00
return stopic ;
}
2019-01-28 13:08:33 +00:00
char * GetFallbackTopic_P ( char * stopic , uint8_t prefix , const char * subtopic )
2018-12-23 13:48:57 +00:00
{
2019-03-26 17:26:50 +00:00
return GetTopic_P ( stopic , prefix + 4 , nullptr , subtopic ) ;
2017-05-10 13:19:36 +01:00
}
2019-01-28 13:08:33 +00:00
char * GetStateText ( uint8_t state )
2017-05-10 13:19:36 +01:00
{
2019-01-28 13:08:33 +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
2019-01-28 13:08:33 +00:00
for ( uint8_t i = 0 ; i < devices_present ; i + + ) {
2018-09-30 15:52:25 +01:00
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 ;
}
2019-01-25 16:46:27 +00:00
if ( Settings . flag . interlock ) { // Allow only one or no relay set
2019-01-28 13:08:33 +00:00
for ( uint8_t i = 0 ; i < MAX_INTERLOCKS ; i + + ) {
2019-01-22 11:46:55 +00:00
power_t mask = 1 ;
uint8_t count = 0 ;
2019-01-28 13:08:33 +00:00
for ( uint8_t j = 0 ; j < devices_present ; j + + ) {
2019-01-25 16:46:27 +00:00
if ( ( Settings . interlock [ i ] & mask ) & & ( rpower & mask ) ) { count + + ; }
2019-01-22 11:46:55 +00:00
mask < < = 1 ;
}
if ( count > 1 ) {
2019-01-25 16:46:27 +00:00
mask = ~ Settings . interlock [ i ] ; // Turn interlocked group off as there would be multiple relays on
power & = mask ;
rpower & = mask ;
2019-01-22 11:46:55 +00:00
}
2017-08-18 11:55:08 +01:00
}
}
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
}
2019-02-11 18:21:49 +00:00
else if ( ( SONOFF_DUAL = = my_module_type ) | | ( CH4 = = my_module_type ) ) {
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
}
2019-02-11 18:21:49 +00:00
else if ( EXS_RELAY = = my_module_type ) {
2017-10-18 17:22:34 +01:00
SetLatchingRelay ( rpower , 1 ) ;
2017-02-13 16:25:46 +00:00
}
else {
2019-01-28 13:08:33 +00:00
for ( uint8_t 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 )
2019-01-06 17:02:21 +00:00
{
2019-01-28 13:08:33 +00:00
if ( state ) { state = 1 ; }
2019-01-06 17:02:21 +00:00
uint8_t led_pin = 0 ;
if ( pin [ GPIO_LED2 ] < 99 ) { led_pin = 1 ; }
digitalWrite ( pin [ GPIO_LED1 + led_pin ] , ( bitRead ( led_inverted , led_pin ) ) ? ! state : state ) ;
}
2019-01-08 10:44:45 +00:00
void SetLedLink ( uint8_t state )
2017-01-28 13:41:01 +00:00
{
2019-01-28 13:08:33 +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 ;
2019-02-11 18:21:49 +00:00
// if (SONOFF_IFAN02 == my_module_type) {
2018-07-01 14:06:44 +01:00
/* 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 )
{
2019-01-28 13:08:33 +00:00
for ( uint8_t i = 0 ; i < MAX_FAN_SPEED - 1 ; i + + ) {
2018-08-20 14:51:46 +01:00
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-12-06 14:03:42 +00:00
# ifdef USE_DOMOTICZ
DomoticzUpdateFanState ( ) ; // Command FanSpeed feedback
# endif // USE_DOMOTICZ
2018-08-20 14:51:46 +01:00
}
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
/********************************************************************************************/
2019-01-28 13:08:33 +00:00
void MqttDataHandler ( char * topic , uint8_t * data , unsigned int data_len )
2017-01-28 13:41:01 +00:00
{
2019-02-23 18:19:31 +00:00
if ( data_len > MQTT_MAX_PACKET_SIZE ) { return ; } // Do not allow more data than would be feasable within stack space
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 ;
2019-03-26 17:26:50 +00:00
char * type = nullptr ;
2019-01-28 13:08:33 +00:00
uint8_t lines = 1 ;
bool jsflg = false ;
bool grpflg = false ;
// bool user_append_index = false;
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
2019-03-11 09:38:41 +00:00
# ifdef USE_DEBUG_DRIVER
2018-06-26 10:48:09 +01:00
ShowFreeMem ( PSTR ( " MqttDataHandler " ) ) ;
2019-03-11 09:38:41 +00:00
# endif
2018-06-26 10:48:09 +01:00
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 + + ) {
2019-01-28 13:08:33 +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 ) ; }
2019-03-08 14:15:42 +00:00
AddLog_P2 ( LOG_LEVEL_DEBUG_MORE , PSTR ( D_LOG_RESULT D_RECEIVED_TOPIC " %s, " D_DATA_SIZE " %d, " D_DATA " %s " ) , topicBuf , data_len , dataBuf ) ;
2019-01-28 13:08:33 +00:00
// if (LOG_LEVEL_DEBUG_MORE <= seriallog_level) { Serial.println(dataBuf); }
2017-01-28 13:41:01 +00:00
2019-01-28 13:08:33 +00:00
if ( XdrvMqttData ( topicBuf , sizeof ( topicBuf ) , dataBuf , sizeof ( dataBuf ) ) ) { return ; }
2017-01-28 13:41:01 +00:00
2019-03-26 17:26:50 +00:00
grpflg = ( strstr ( topicBuf , Settings . mqtt_grptopic ) ! = nullptr ) ;
2018-12-23 13:48:57 +00:00
GetFallbackTopic_P ( stemp1 , CMND , " " ) ; // Full Fallback topic = cmnd/DVES_xxxxxxxx_fb/
2018-12-22 15:13:07 +00:00
fallback_topic_flag = ( ! strncmp ( topicBuf , stemp1 , strlen ( stemp1 ) ) ) ;
2018-12-23 13:48:57 +00:00
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 ;
2019-03-26 17:26:50 +00:00
if ( type ! = nullptr ) {
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 ) ;
2019-01-28 13:08:33 +00:00
// user_append_index = true;
2018-05-13 16:38:44 +01:00
}
2017-01-28 13:41:01 +00:00
type [ i ] = ' \0 ' ;
}
2019-03-08 14:15:42 +00:00
AddLog_P2 ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_RESULT D_GROUP " %d, " D_INDEX " %d, " D_COMMAND " %s, " D_DATA " %s " ) , grpflg , index , type , dataBuf ) ;
2017-01-28 13:41:01 +00:00
2019-03-26 17:26:50 +00:00
if ( type ! = nullptr ) {
2019-03-23 16:00:59 +00:00
Response_P ( PSTR ( " { \" " D_JSON_COMMAND " \" : \" " D_JSON_ERROR " \" } " ) ) ;
2019-01-28 13:08:33 +00:00
if ( Settings . ledstate & 0x02 ) { blinks + + ; }
2017-01-28 13:41:01 +00:00
2019-01-28 13:08:33 +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 ;
2019-04-10 13:26:36 +01:00
long payload32 = strtol ( dataBuf , & p , 0 ) ; // decimal, octal (0) or hex (0x)
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
2019-04-10 13:26:36 +01:00
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_RESULT "Payload %d, Payload16 %d, payload32 %u"), payload, payload16, payload32);
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 ) {
2019-03-10 12:33:32 +00:00
// XdrvMailbox.valid = 1;
XdrvMailbox . index = index ;
XdrvMailbox . data_len = data_len ;
XdrvMailbox . payload16 = payload16 ;
XdrvMailbox . payload = payload ;
XdrvMailbox . grpflg = grpflg ;
XdrvMailbox . topic = type ;
XdrvMailbox . data = dataBuf ;
if ( ! XdrvCall ( FUNC_COMMAND ) ) {
if ( ! XsnsCall ( FUNC_COMMAND ) ) {
2019-03-26 17:26:50 +00:00
type = nullptr ; // Unknown command
2019-03-10 12:33:32 +00:00
}
2018-05-09 09:49:43 +01:00
}
}
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 , " ; " ) ;
2019-03-26 17:26:50 +00:00
while ( ( blcommand ! = nullptr ) & & ( 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 ;
}
2019-03-26 17:26:50 +00:00
blcommand = strtok ( nullptr , " ; " ) ;
2017-07-15 14:07:30 +01:00
}
2019-03-23 16:00:59 +00:00
// Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_APPENDED);
2018-05-06 15:07:42 +01:00
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 ;
2019-03-23 16:00:59 +00:00
Response_P ( 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 ; }
2019-03-23 16:00:59 +00:00
Response_P ( 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 ) ) {
2019-01-28 13:08:33 +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 ) ;
2019-01-28 13:08:33 +00:00
fallback_topic_flag = false ;
2017-01-28 13:41:01 +00:00
return ;
}
2019-02-11 18:21:49 +00:00
else if ( ( CMND_FANSPEED = = command_code ) & & ( SONOFF_IFAN02 = = my_module_type ) ) {
2018-08-11 15:12:10 +01:00
if ( data_len > 0 ) {
if ( ' - ' = = dataBuf [ 0 ] ) {
payload = ( int16_t ) GetFanspeed ( ) - 1 ;
2018-12-06 09:49:49 +00:00
if ( payload < 0 ) { payload = MAX_FAN_SPEED - 1 ; }
2018-08-11 15:12:10 +01:00
}
else if ( ' + ' = = dataBuf [ 0 ] ) {
payload = GetFanspeed ( ) + 1 ;
2018-12-06 09:49:49 +00:00
if ( payload > MAX_FAN_SPEED - 1 ) { payload = 0 ; }
2018-08-11 15:12:10 +01:00
}
}
2018-12-06 09:49:49 +00:00
if ( ( payload > = 0 ) & & ( payload < MAX_FAN_SPEED ) & & ( payload ! = GetFanspeed ( ) ) ) {
2018-08-20 14:51:46 +01:00
SetFanspeed ( payload ) ;
2018-06-30 17:50:10 +01:00
}
2019-03-23 16:00:59 +00:00
Response_P ( 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 ) ;
2019-01-28 13:08:33 +00:00
fallback_topic_flag = false ;
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-12-02 14:23:25 +00:00
if ( Settings . flag3 . hass_tele_on_power ) {
MqttPublishPrefixTopic_P ( TELE , PSTR ( D_RSLT_STATE ) , MQTT_TELE_RETAIN ) ;
}
2019-03-20 03:57:26 +00:00
# ifdef USE_HOME_ASSISTANT
if ( Settings . flag . hass_discovery ) {
HAssPublishStatus ( ) ;
}
2019-03-20 13:05:43 +00:00
# endif // USE_HOME_ASSISTANT
2018-01-20 11:12:39 +00:00
}
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
}
2019-03-23 16:00:59 +00:00
Response_P ( 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 : " " ) ;
2018-07-06 17:00:50 +01:00
}
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 ;
2019-03-23 16:00:59 +00:00
Response_P ( PSTR ( " { \" %s \" : \" " D_JSON_VERSION " %s " D_JSON_FROM " %s \" } " ) , command , my_version , GetOtaUrl ( stemp1 , sizeof ( stemp1 ) ) ) ;
2018-07-06 17:00:50 +01:00
} else {
2019-03-23 16:00:59 +00:00
Response_P ( PSTR ( " { \" %s \" : \" " D_JSON_ONE_OR_GT " \" } " ) , command , my_version ) ;
2018-07-06 17:00:50 +01:00
}
}
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
}
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_COMMAND_SVALUE , command , Settings . ota_url ) ;
2018-07-06 17:00:50 +01:00
}
else if ( CMND_SERIALLOG = = command_code ) {
if ( ( payload > = LOG_LEVEL_NONE ) & & ( payload < = LOG_LEVEL_ALL ) ) {
Settings . flag . mqtt_serial = 0 ;
SetSeriallog ( payload ) ;
}
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_COMMAND_NVALUE_ACTIVE_NVALUE , command , Settings . seriallog_level , seriallog_level ) ;
2018-07-06 17:00:50 +01:00
}
else if ( CMND_RESTART = = command_code ) {
switch ( payload ) {
case 1 :
restart_flag = 2 ;
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_COMMAND_SVALUE , command , D_JSON_RESTARTING ) ;
2018-07-06 17:00:50 +01:00
break ;
case 99 :
AddLog_P ( LOG_LEVEL_INFO , PSTR ( D_LOG_APPLICATION D_RESTARTING ) ) ;
EspRestart ( ) ;
break ;
default :
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_COMMAND_SVALUE , command , D_JSON_ONE_TO_RESTART ) ;
2018-07-06 17:00:50 +01:00
}
}
2019-02-11 18:21:49 +00:00
else if ( ( CMND_POWERONSTATE = = command_code ) & & ( my_module_type ! = 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 ) {
2019-01-28 13:08:33 +00:00
for ( uint8_t 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
}
2019-03-23 16:00:59 +00:00
Response_P ( 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
}
2019-03-23 16:00:59 +00:00
Response_P ( 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
}
2019-03-23 16:00:59 +00:00
Response_P ( 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
}
2019-03-23 16:00:59 +00:00
Response_P ( 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
}
2019-03-23 16:00:59 +00:00
Response_P ( 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 ) {
2019-03-10 12:33:32 +00:00
XsnsCall ( FUNC_COMMAND_SENSOR ) ;
2018-09-21 15:19:31 +01:00
} else {
2019-03-10 12:33:32 +00:00
XdrvCall ( FUNC_COMMAND_DRIVER ) ;
2018-09-21 15:19:31 +01:00
}
2018-09-20 21:56:07 +01:00
}
2018-07-03 11:48:56 +01:00
else if ( ( CMND_SETOPTION = = command_code ) & & ( index < 82 ) ) {
2019-01-28 13:08:33 +00:00
uint8_t ptype ;
uint8_t pindex ;
2018-07-03 11:48:56 +01:00
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)
2019-01-25 16:46:27 +00:00
case 14 : // interlock (CMND_INTERLOCK)
2018-07-03 11:48:56 +01:00
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 ) ) {
2019-01-22 11:46:55 +00:00
HAssDiscover ( ) ; // Delayed execution to provide enough resources during 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 ) ;
2019-01-03 16:30:54 +00:00
if ( 5 = = pindex ) { // SetOption55
if ( 0 = = payload ) {
restart_flag = 2 ; // Disable mDNS needs restart
2018-12-01 16:47:25 +00:00
}
}
2019-01-03 16:30:54 +00:00
if ( 10 = = pindex ) { // SetOption60 enable or disable traditional sleep
WiFiSetSleepMode ( ) ; // Update WiFi sleep mode accordingly
}
2018-07-03 11:48:56 +01:00
}
}
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 ;
2019-02-24 23:48:03 +00:00
switch ( pindex ) {
2019-02-25 18:47:45 +00:00
case P_RGB_REMAP :
LightUpdateColorMapping ( ) ;
2019-02-24 23:48:03 +00:00
break ;
}
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 ] ) ;
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_COMMAND_INDEX_SVALUE , command , index , ( 2 = = ptype ) ? stemp1 : ( 1 = = ptype ) ? GetStateText ( bitRead ( Settings . flag3 . data , pindex ) ) : GetStateText ( bitRead ( Settings . flag . data , pindex ) ) ) ;
2018-07-03 11:48:56 +01:00
}
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
}
2019-03-23 16:00:59 +00:00
Response_P ( 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
}
2019-03-23 16:00:59 +00:00
Response_P ( 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
}
2019-03-23 16:00:59 +00:00
Response_P ( 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
}
2019-03-23 16:00:59 +00:00
Response_P ( 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 ;
}
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_COMMAND_NVALUE , command , Settings . flag2 . voltage_resolution ) ;
2017-11-11 11:33:30 +00:00
}
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 ;
}
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_COMMAND_NVALUE , command , Settings . flag2 . frequency_resolution ) ;
2018-09-07 17:15:47 +01:00
}
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
}
2019-03-23 16:00:59 +00:00
Response_P ( 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
}
2019-03-23 16:00:59 +00:00
Response_P ( 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 ;
}
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_COMMAND_NVALUE , command , Settings . flag2 . weight_resolution ) ;
2018-10-08 13:39:36 +01:00
}
2017-10-29 17:18:46 +00:00
else if ( CMND_MODULE = = command_code ) {
2019-02-11 18:21:49 +00:00
if ( ( payload > = 0 ) & & ( payload < = MAXMODULE ) ) {
2019-04-05 14:27:06 +01:00
bool present = false ;
if ( 0 = = payload ) {
2019-04-08 12:26:17 +01:00
payload = USER_MODULE ;
2019-04-05 14:27:06 +01:00
present = true ;
} else {
payload - - ;
2019-04-08 12:26:17 +01:00
present = ValidTemplateModule ( payload ) ;
2019-04-05 14:27:06 +01:00
}
if ( present ) {
Settings . last_module = Settings . module ;
Settings . module = payload ;
SetModuleType ( ) ;
if ( Settings . last_module ! = payload ) {
for ( uint8_t i = 0 ; i < sizeof ( Settings . my_gp ) ; i + + ) {
Settings . my_gp . io [ i ] = GPIO_NONE ;
}
2017-04-25 17:24:42 +01:00
}
2019-04-05 14:27:06 +01:00
restart_flag = 2 ;
2017-04-03 15:38:15 +01:00
}
2017-01-28 13:41:01 +00:00
}
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_COMMAND_NVALUE_SVALUE , command , ModuleNr ( ) , ModuleName ( ) . c_str ( ) ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-29 17:18:46 +00:00
else if ( CMND_MODULES = = command_code ) {
2019-04-05 14:27:06 +01:00
uint8_t midx = USER_MODULE ;
for ( uint8_t i = 0 ; i < = sizeof ( kModuleNiceList ) ; i + + ) {
if ( i > 0 ) { midx = pgm_read_byte ( kModuleNiceList + i - 1 ) ; }
2017-09-14 14:35:38 +01:00
if ( ! jsflg ) {
2019-03-23 16:00:59 +00:00
Response_P ( PSTR ( " { \" " D_CMND_MODULES " %d \" :[ " ) , lines ) ;
2017-09-14 14:35:38 +01:00
} else {
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " , " ) ) ;
2017-04-25 17:24:42 +01:00
}
2019-01-28 13:08:33 +00:00
jsflg = true ;
2019-04-05 14:27:06 +01:00
uint8_t j = i ? midx + 1 : 0 ;
if ( ( ResponseAppend_P ( PSTR ( " \" %d (%s) \" " ) , j , AnyModuleName ( midx ) . c_str ( ) ) > ( LOGSZ - TOPSZ ) ) | | ( i = = sizeof ( kModuleNiceList ) ) ) {
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " ]} " ) ) ;
2018-01-18 15:19:28 +00:00
MqttPublishPrefixTopic_P ( RESULT_OR_STAT , type ) ;
2019-01-28 13:08:33 +00:00
jsflg = false ;
2017-09-14 14:35:38 +01:00
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
}
2018-12-29 18:46:28 +00:00
else if ( ( CMND_GPIO = = command_code ) & & ( index < sizeof ( Settings . my_gp ) ) ) {
2018-12-29 16:19:13 +00:00
myio cmodule ;
ModuleGpios ( & cmodule ) ;
2019-02-11 18:21:49 +00:00
if ( ValidGPIO ( index , cmodule . io [ index ] ) & & ( payload > = 0 ) & & ( payload < GPIO_SENSOR_END ) ) {
2018-11-05 16:27:02 +00:00
bool present = false ;
2019-01-28 13:08:33 +00:00
for ( uint8_t i = 0 ; i < sizeof ( kGpioNiceList ) ; i + + ) {
2018-11-05 16:27:02 +00:00
uint8_t midx = pgm_read_byte ( kGpioNiceList + i ) ;
if ( midx = = payload ) { present = true ; }
}
if ( present ) {
2019-01-28 13:08:33 +00:00
for ( uint8_t i = 0 ; i < sizeof ( Settings . my_gp ) ; i + + ) {
2019-02-11 18:21:49 +00:00
if ( ValidGPIO ( i , cmodule . io [ i ] ) & & ( Settings . my_gp . io [ i ] = = payload ) ) {
2018-12-29 18:46:28 +00:00
Settings . my_gp . io [ i ] = GPIO_NONE ;
2018-11-05 16:27:02 +00:00
}
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
}
}
2019-03-23 16:00:59 +00:00
Response_P ( PSTR ( " { " ) ) ;
2019-01-28 13:08:33 +00:00
for ( uint8_t i = 0 ; i < sizeof ( Settings . my_gp ) ; i + + ) {
2019-02-11 18:21:49 +00:00
if ( ValidGPIO ( i , cmodule . io [ i ] ) ) {
2019-03-23 16:00:59 +00:00
if ( jsflg ) { ResponseAppend_P ( PSTR ( " , " ) ) ; }
2019-01-28 13:08:33 +00:00
jsflg = true ;
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " \" " D_CMND_GPIO " %d \" : \" %d (%s) \" " ) , 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 ) {
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " } " ) ) ;
2017-01-28 13:41:01 +00:00
} else {
2019-03-23 16:00:59 +00:00
Response_P ( 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-12-29 16:19:13 +00:00
myio cmodule ;
ModuleGpios ( & cmodule ) ;
2018-11-05 16:27:02 +00:00
uint8_t midx ;
2019-01-28 13:08:33 +00:00
for ( uint8_t i = 0 ; i < sizeof ( kGpioNiceList ) ; i + + ) {
2018-11-05 16:27:02 +00:00
midx = pgm_read_byte ( kGpioNiceList + i ) ;
2018-12-29 16:19:13 +00:00
if ( ! GetUsedInModule ( midx , cmodule . io ) ) {
2018-08-23 15:05:51 +01:00
if ( ! jsflg ) {
2019-03-23 16:00:59 +00:00
Response_P ( PSTR ( " { \" " D_CMND_GPIOS " %d \" :[ " ) , lines ) ;
2018-08-23 15:05:51 +01:00
} else {
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " , " ) ) ;
2018-08-23 15:05:51 +01:00
}
2019-01-28 13:08:33 +00:00
jsflg = true ;
2019-03-23 16:00:59 +00:00
if ( ( ResponseAppend_P ( PSTR ( " \" %d (%s) \" " ) , midx , GetTextIndexed ( stemp1 , sizeof ( stemp1 ) , midx , kSensorNames ) ) > ( LOGSZ - TOPSZ ) ) | | ( i = = sizeof ( kGpioNiceList ) - 1 ) ) {
ResponseAppend_P ( PSTR ( " ]} " ) ) ;
2018-06-03 16:09:10 +01:00
MqttPublishPrefixTopic_P ( RESULT_OR_STAT , type ) ;
2019-01-28 13:08:33 +00:00
jsflg = false ;
2018-06-03 16:09:10 +01:00
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
}
2019-02-11 18:21:49 +00:00
else if ( CMND_TEMPLATE = = command_code ) {
2019-02-12 10:55:47 +00:00
// {"NAME":"Generic","GPIO":[17,254,29,254,7,254,254,254,138,254,139,254,254],"FLAG":1,"BASE":255}
2019-02-11 18:21:49 +00:00
bool error = false ;
2019-02-14 15:48:28 +00:00
2019-03-26 17:26:50 +00:00
if ( strstr ( dataBuf , " { " ) = = nullptr ) { // If no JSON it must be parameter
2019-02-14 15:48:28 +00:00
if ( ( payload > 0 ) & & ( payload < = MAXMODULE ) ) {
2019-04-05 14:41:01 +01:00
payload - - ;
2019-04-08 12:26:17 +01:00
if ( ValidTemplateModule ( payload ) ) {
2019-04-05 14:41:01 +01:00
ModuleDefault ( payload ) ; // Copy template module
if ( USER_MODULE = = Settings . module ) { restart_flag = 2 ; }
}
2019-02-14 15:48:28 +00:00
}
2019-03-08 16:42:21 +00:00
else if ( 0 = = payload ) { // Copy current template to user template
2019-02-14 15:48:28 +00:00
if ( Settings . module ! = USER_MODULE ) {
ModuleDefault ( Settings . module ) ;
}
}
2019-03-08 16:42:21 +00:00
else if ( 255 = = payload ) { // Copy current module with user configured GPIO
if ( Settings . module ! = USER_MODULE ) {
ModuleDefault ( Settings . module ) ;
}
snprintf_P ( Settings . user_template . name , sizeof ( Settings . user_template . name ) , PSTR ( " Merged " ) ) ;
uint8_t j = 0 ;
for ( uint8_t i = 0 ; i < sizeof ( mycfgio ) ; i + + ) {
if ( 6 = = i ) { j = 9 ; }
if ( 8 = = i ) { j = 12 ; }
if ( my_module . io [ j ] > GPIO_NONE ) {
Settings . user_template . gp . io [ i ] = my_module . io [ j ] ;
}
j + + ;
}
}
2019-02-11 18:21:49 +00:00
}
Add command WebColor
* Add rule Http#Initialized
* Add command WebColor to change non-persistent GUI colors on the fly
Use a rule like:
rule3 on http#initialized do webcolor {"webcolor":["#eeeeee","#181818","#4f4f4f","#000000","#dddddd","#008000","#222222","#ff0000","#008000","#ffffff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#ffffff","#999999","#000000"]} endon
or
rule3 on http#initialized do webcolor {"webcolor":["#eee","#181818","#4f4f4f","#000","#ddd","#008000","#222"]} endon
to make color changes persistent)
2019-04-08 21:37:39 +01:00
else {
2019-02-21 13:31:31 +00:00
if ( JsonTemplate ( dataBuf ) ) { // Free 336 bytes StaticJsonBuffer stack space by moving code to function
if ( USER_MODULE = = Settings . module ) { restart_flag = 2 ; }
} else {
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_COMMAND_SVALUE , command , D_JSON_INVALID_JSON ) ;
2019-02-11 18:21:49 +00:00
error = true ;
}
}
2019-02-12 10:55:47 +00:00
if ( ! error ) { TemplateJson ( ) ; }
2019-02-11 18:21:49 +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
}
2019-03-23 16:00:59 +00:00
Response_P ( PSTR ( " { " ) ) ;
2018-03-20 15:28:18 +00:00
MqttShowPWMState ( ) ; // Render the PWM status to MQTT
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " } " ) ) ;
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)
}
2019-03-23 16:00:59 +00:00
Response_P ( 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 ;
2019-01-28 13:08:33 +00:00
for ( uint8_t 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)
}
2019-03-23 16:00:59 +00:00
Response_P ( 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
}
2019-03-23 16:00:59 +00:00
Response_P ( 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
}
2019-03-23 16:00:59 +00:00
Response_P ( 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
}
2019-03-23 16:00:59 +00:00
Response_P ( 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
}
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_COMMAND_NVALUE , command , Settings . button_debounce ) ;
2018-08-27 11:01:20 +01:00
}
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
}
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_COMMAND_NVALUE , command , Settings . switch_debounce ) ;
2018-08-27 11:01:20 +01:00
}
2018-03-18 12:47:30 +00:00
else if ( CMND_BAUDRATE = = command_code ) {
2019-03-12 09:23:20 +00:00
if ( payload32 > 1200 ) {
2018-03-18 12:47:30 +00:00
payload32 / = 1200 ; // Make it a valid baudrate
baudrate = ( 1 = = payload ) ? APP_BAUDRATE : payload32 * 1200 ;
SetSerialBaudrate ( baudrate ) ;
}
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_COMMAND_NVALUE , command , Settings . baudrate * 1200 ) ;
2018-03-18 12:47:30 +00:00
}
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-12-24 17:14:25 +00:00
for ( uint16_t 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 ) {
2019-01-17 16:48:34 +00:00
SerialSendRaw ( RemoveSpace ( dataBuf ) ) ; // "AA004566" as hex values
2018-03-20 13:31:11 +00:00
}
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_COMMAND_SVALUE , command , D_JSON_DONE ) ;
2018-03-18 12:47:30 +00:00
}
}
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 ] ;
}
}
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_COMMAND_NVALUE , command , Settings . serial_delimiter ) ;
2018-03-20 13:31:11 +00:00
}
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 ;
}
2019-03-23 16:00:59 +00:00
Response_P ( 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
}
2019-03-23 16:00:59 +00:00
Response_P ( 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 ;
}
2019-03-23 16:00:59 +00:00
Response_P ( 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 ( ) ) ;
2019-03-23 16:00:59 +00:00
Response_P ( 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
2019-01-28 13:08:33 +00:00
ntp_force_sync = true ;
2017-03-12 17:36:33 +00:00
}
2019-03-23 16:00:59 +00:00
Response_P ( 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
}
2019-03-23 16:00:59 +00:00
Response_P ( 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
}
2019-03-23 16:00:59 +00:00
Response_P ( 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 ) ) {
2019-02-21 14:53:29 +00:00
if ( ( data_len > 4 | | SC_CLEAR = = Shortcut ( dataBuf ) | | SC_DEFAULT = = Shortcut ( dataBuf ) ) & & ( 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 ;
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_COMMAND_INDEX_SVALUE , command , index , Settings . sta_pwd [ index - 1 ] ) ;
2018-04-21 17:17:24 +01:00
} else {
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_COMMAND_INDEX_ASTERIX , command , index ) ;
2017-01-28 13:41:01 +00:00
}
}
2019-02-09 12:37:27 +00:00
else if ( CMND_HOSTNAME = = command_code ) {
if ( ! grpflg & & ( 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 ) ) ;
2019-03-26 17:26:50 +00:00
if ( strstr ( Settings . hostname , " % " ) ! = nullptr ) {
2017-10-18 17:22:34 +01:00
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
}
2019-03-23 16:00:59 +00:00
Response_P ( 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 ] ) ;
2019-03-23 16:00:59 +00:00
Response_P ( PSTR ( " { \" " D_CMND_WIFICONFIG " \" : \" %s " D_JSON_SELECTED " \" } " ) , stemp1 ) ;
2018-10-30 14:34:31 +00:00
if ( WifiState ( ) > WIFI_RESTART ) {
2019-03-23 16:57:31 +00:00
// ResponseAppend_P(PSTR(" after restart"));
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 ] ) ;
2019-03-23 16:00:59 +00:00
Response_P ( 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
}
2019-03-23 16:00:59 +00:00
Response_P ( 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 ;
}
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_COMMAND_INDEX_NVALUE , command , index , Settings . switchmode [ index - 1 ] ) ;
2017-01-28 13:41:01 +00:00
}
2019-01-25 16:46:27 +00:00
else if ( CMND_INTERLOCK = = command_code ) { // Interlock 0 - Off, Interlock 1 - On, Interlock 1,2 3,4 5,6,7
uint8_t max_relays = devices_present ;
if ( light_type ) { max_relays - - ; }
if ( max_relays > sizeof ( Settings . interlock [ 0 ] ) * 8 ) { max_relays = sizeof ( Settings . interlock [ 0 ] ) * 8 ; }
if ( max_relays > 1 ) { // Only interlock with more than 1 relay
if ( data_len > 0 ) {
2019-03-26 17:26:50 +00:00
if ( strstr ( dataBuf , " , " ) ! = nullptr ) { // Interlock entry
2019-01-28 13:08:33 +00:00
for ( uint8_t i = 0 ; i < MAX_INTERLOCKS ; i + + ) { Settings . interlock [ i ] = 0 ; } // Reset current interlocks
2019-01-25 16:46:27 +00:00
char * group ;
char * q ;
uint8_t group_index = 0 ;
power_t relay_mask = 0 ;
2019-03-26 17:26:50 +00:00
for ( group = strtok_r ( dataBuf , " " , & q ) ; group & & group_index < MAX_INTERLOCKS ; group = strtok_r ( nullptr , " " , & q ) ) {
2019-01-25 16:46:27 +00:00
char * str ;
2019-03-26 17:26:50 +00:00
for ( str = strtok_r ( group , " , " , & p ) ; str ; str = strtok_r ( nullptr , " , " , & p ) ) {
2019-01-25 16:46:27 +00:00
int pbit = atoi ( str ) ;
if ( ( pbit > 0 ) & & ( pbit < = max_relays ) ) { // Only valid relays
pbit - - ;
if ( ! bitRead ( relay_mask , pbit ) ) { // Only relay once
bitSet ( relay_mask , pbit ) ;
bitSet ( Settings . interlock [ group_index ] , pbit ) ;
}
}
}
group_index + + ;
}
2019-01-28 13:08:33 +00:00
for ( uint8_t i = 0 ; i < group_index ; i + + ) {
2019-01-25 16:46:27 +00:00
uint8_t minimal_bits = 0 ;
2019-01-28 13:08:33 +00:00
for ( uint8_t j = 0 ; j < max_relays ; j + + ) {
2019-01-25 16:46:27 +00:00
if ( bitRead ( Settings . interlock [ i ] , j ) ) { minimal_bits + + ; }
}
if ( minimal_bits < 2 ) { Settings . interlock [ i ] = 0 ; } // Discard single relay as interlock
}
} else {
Settings . flag . interlock = payload & 1 ; // Enable/disable interlock
if ( Settings . flag . interlock ) {
SetDevicePower ( power , SRC_IGNORE ) ; // Remove multiple relays if set
}
}
}
2019-03-23 16:00:59 +00:00
Response_P ( PSTR ( " { \" " D_CMND_INTERLOCK " \" : \" %s \" , \" " D_JSON_GROUPS " \" : \" " ) , GetStateText ( Settings . flag . interlock ) ) ;
2019-01-25 16:46:27 +00:00
uint8_t anygroup = 0 ;
2019-01-28 13:08:33 +00:00
for ( uint8_t i = 0 ; i < MAX_INTERLOCKS ; i + + ) {
2019-01-25 16:46:27 +00:00
if ( Settings . interlock [ i ] ) {
anygroup + + ;
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " %s " ) , ( anygroup > 1 ) ? " " : " " ) ;
2019-01-25 16:46:27 +00:00
uint8_t anybit = 0 ;
power_t mask = 1 ;
2019-01-28 13:08:33 +00:00
for ( uint8_t j = 0 ; j < max_relays ; j + + ) {
2019-01-25 16:46:27 +00:00
if ( Settings . interlock [ i ] & mask ) {
anybit + + ;
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " %s%d " ) , ( anybit > 1 ) ? " , " : " " , j + 1 ) ;
2019-01-25 16:46:27 +00:00
}
mask < < = 1 ;
}
}
}
if ( ! anygroup ) {
2019-01-28 13:08:33 +00:00
for ( uint8_t j = 1 ; j < = max_relays ; j + + ) {
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " %s%d " ) , ( j > 1 ) ? " , " : " " , j ) ;
2019-01-25 16:46:27 +00:00
}
}
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " \" } " ) ) ;
2019-01-25 16:46:27 +00:00
} else {
Settings . flag . interlock = 0 ;
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_COMMAND_SVALUE , command , GetStateText ( Settings . flag . interlock ) ) ;
2019-01-25 16:46:27 +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
}
2019-03-23 16:00:59 +00:00
Response_P ( 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 ;
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_COMMAND_SVALUE , command , D_JSON_RESET_AND_RESTARTING ) ;
2017-01-28 13:41:01 +00:00
break ;
2019-02-19 09:48:19 +00:00
case 2 . . . 6 :
2018-10-15 13:43:47 +01:00
restart_flag = 210 + payload ;
2019-03-23 16:00:59 +00:00
Response_P ( PSTR ( " { \" " D_CMND_RESET " \" : \" " D_JSON_ERASE " , " D_JSON_RESET_AND_RESTARTING " \" } " ) ) ;
2018-10-14 23:10:02 +01:00
break ;
2017-01-28 13:41:01 +00:00
default :
2019-03-23 16:00:59 +00:00
Response_P ( 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 ) {
2019-03-26 17:26:50 +00:00
p = strtok ( nullptr , " : " ) ;
2018-11-01 12:00:05 +00:00
if ( p ) {
2019-03-26 17:26:50 +00:00
Settings . timezone_minutes = strtol ( p , nullptr , 10 ) ;
2018-11-01 12:00:05 +00:00
if ( Settings . timezone_minutes > 59 ) { Settings . timezone_minutes = 59 ; }
}
}
} else {
Settings . timezone = 99 ;
}
2019-01-28 13:08:33 +00:00
ntp_force_sync = true ;
2018-11-01 12:00:05 +00:00
}
if ( 99 = = Settings . timezone ) {
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_COMMAND_NVALUE , command , Settings . timezone ) ;
2018-11-01 12:00:05 +00:00
} else {
snprintf_P ( stemp1 , sizeof ( stemp1 ) , PSTR ( " %+03d:%02d " ) , Settings . timezone , Settings . timezone_minutes ) ;
2019-03-23 16:00:59 +00:00
Response_P ( 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 ) {
2019-03-26 17:26:50 +00:00
if ( strstr ( dataBuf , " , " ) ! = nullptr ) { // Process parameter entry
2018-05-15 11:32:53 +01:00
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
}
2019-01-28 13:08:33 +00:00
ntp_force_sync = true ;
2018-05-14 22:22:29 +01:00
} else {
if ( 0 = = payload ) {
if ( 0 = = ts ) {
SettingsResetStd ( ) ;
} else {
SettingsResetDst ( ) ;
}
}
2019-01-28 13:08:33 +00:00
ntp_force_sync = true ;
2018-05-14 22:22:29 +01:00
}
}
2019-03-23 16:00:59 +00:00
Response_P ( 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 ;
}
2019-03-23 16:00:59 +00:00
Response_P ( 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
}
2019-03-23 16:00:59 +00:00
Response_P ( 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 ;
2019-01-06 17:02:21 +00:00
if ( ! Settings . ledstate ) {
SetLedPower ( 0 ) ;
2019-01-08 10:44:45 +00:00
SetLedLink ( 0 ) ;
2019-01-06 17:02:21 +00:00
}
2017-01-28 13:41:01 +00:00
}
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_COMMAND_NVALUE , command , Settings . ledstate ) ;
2017-01-28 13:41:01 +00:00
}
2019-04-10 13:26:36 +01:00
else if ( CMND_LEDMASK = = command_code ) {
if ( data_len > 0 ) {
Settings . ledmask = payload16 ;
}
2019-04-10 14:02:38 +01:00
snprintf_P ( stemp1 , sizeof ( stemp1 ) , PSTR ( " %d (0x%04X) " ) , Settings . ledmask , Settings . ledmask ) ;
Response_P ( S_JSON_COMMAND_SVALUE , command , stemp1 ) ;
2019-04-10 13:26:36 +01: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
2019-03-26 17:26:50 +00:00
else type = nullptr ; // Unknown command
2017-01-28 13:41:01 +00:00
}
2019-03-26 17:26:50 +00:00
if ( type = = nullptr ) {
2017-01-28 13:41:01 +00:00
blinks = 201 ;
2018-01-06 16:34:42 +00:00
snprintf_P ( topicBuf , sizeof ( topicBuf ) , PSTR ( D_JSON_COMMAND ) ) ;
2019-03-23 16:00:59 +00:00
Response_P ( 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
}
2019-03-23 16:00:59 +00:00
if ( mqtt_data [ 0 ] ! = ' \0 ' ) { MqttPublishPrefixTopic_P ( RESULT_OR_STAT , type ) ; }
2019-01-28 13:08:33 +00:00
fallback_topic_flag = false ;
2017-01-28 13:41:01 +00:00
}
/********************************************************************************************/
2019-01-28 13:08:33 +00:00
bool SendKey ( uint8_t key , uint8_t device , uint8_t 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 ) ] ;
2019-01-28 13:08:33 +00:00
bool 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-12-06 10:17:25 +00: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 + Settings . flag . device_index_enable ) ) ) ; // 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-12-08 07:44:59 +00:00
if ( ( Settings . flag3 . button_switch_force_local | | ! 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 ) ) ) ) {
2019-02-21 20:28:35 +00:00
MqttPublishDirect ( stopic , ( ( key ) ? Settings . flag . mqtt_switch_retain : Settings . flag . mqtt_button_retain ) & & ( state ! = 3 | | ! Settings . flag3 . no_hold_retain ) ) ;
2017-06-06 22:23:23 +01:00
}
2017-01-28 13:41:01 +00:00
# else
2019-02-21 20:28:35 +00:00
MqttPublishDirect ( stopic , ( ( key ) ? Settings . flag . mqtt_switch_retain : Settings . flag . mqtt_button_retain ) & & ( state ! = 3 | | ! Settings . flag3 . no_hold_retain ) ) ;
2017-01-28 13:41:01 +00:00
# endif // USE_DOMOTICZ
2018-12-08 07:44:59 +00:00
result = ! Settings . flag3 . button_switch_force_local ;
2018-04-13 16:42:11 +01:00
} else {
2019-03-23 16:57:31 +00:00
Response_P ( 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
}
2019-01-28 13:08:33 +00:00
void ExecuteCommandPower ( uint8_t device , uint8_t 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);
2019-02-11 18:21:49 +00:00
if ( SONOFF_IFAN02 = = my_module_type ) {
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 ) ; }
2019-01-25 16:46:27 +00:00
power_t mask = 1 < < ( device - 1 ) ; // Device to control
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
}
2019-01-25 16:46:27 +00:00
if ( Settings . flag . interlock & & ! interlock_mutex ) { // Clear all but masked relay in interlock group
2019-01-28 13:08:33 +00:00
interlock_mutex = true ;
for ( uint8_t i = 0 ; i < MAX_INTERLOCKS ; i + + ) {
2019-01-25 16:46:27 +00:00
if ( Settings . interlock [ i ] & mask ) { // Find interlock group
2019-01-28 13:08:33 +00:00
for ( uint8_t j = 0 ; j < devices_present ; j + + ) {
2019-01-25 16:46:27 +00:00
power_t imask = 1 < < j ;
if ( ( Settings . interlock [ i ] & imask ) & & ( power & imask ) & & ( mask ! = imask ) ) {
ExecuteCommandPower ( j + 1 , POWER_OFF , SRC_IGNORE ) ;
2019-01-25 17:30:10 +00:00
delay ( 50 ) ; // Add some delay to make sure never have more than one relay on
2019-01-25 16:46:27 +00:00
}
}
break ; // An interlocked relay is only present in one group so quit
2019-01-13 10:00:02 +00:00
}
2017-08-18 11:55:08 +01:00
}
2019-01-28 13:08:33 +00:00
interlock_mutex = false ;
2017-08-18 11:55:08 +01:00
}
2019-01-25 16:46:27 +00: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
2019-03-20 13:05:43 +00:00
if ( publish_power & & Settings . flag3 . hass_tele_on_power ) { MqttPublishTeleState ( ) ; }
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 ) {
2019-01-28 13:08:33 +00:00
uint8_t 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
2019-01-28 13:08:33 +00:00
for ( uint8_t 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
{
char * start ;
char * token ;
2019-03-11 09:38:41 +00:00
# ifdef USE_DEBUG_DRIVER
2018-06-26 10:48:09 +01:00
ShowFreeMem ( PSTR ( " ExecuteCommand " ) ) ;
2019-03-11 09:38:41 +00:00
# endif
2018-05-28 14:52:42 +01:00
ShowSource ( source ) ;
2017-01-28 13:41:01 +00:00
token = strtok ( cmnd , " " ) ;
2019-03-26 17:26:50 +00:00
if ( token ! = nullptr ) {
2017-01-28 13:41:01 +00:00
start = strrchr ( token , ' / ' ) ; // Skip possible cmnd/sonoff/ preamble
2019-01-28 13:08:33 +00:00
if ( start ) { token = start + 1 ; }
2017-01-28 13:41:01 +00:00
}
2019-03-26 17:26:50 +00:00
uint16_t size = ( token ! = nullptr ) ? strlen ( token ) : 0 ;
2019-02-22 11:04:05 +00:00
char stopic [ size + 2 ] ; // / + \0
2019-03-26 17:26:50 +00:00
snprintf_P ( stopic , sizeof ( stopic ) , PSTR ( " /%s " ) , ( token = = nullptr ) ? " " : token ) ;
2019-02-22 11:04:05 +00:00
2019-03-26 17:26:50 +00:00
token = strtok ( nullptr , " " ) ;
size = ( token ! = nullptr ) ? strlen ( token ) : 0 ;
2019-02-22 11:04:05 +00:00
char svalue [ size + 1 ] ;
2019-03-26 17:26:50 +00:00
strlcpy ( svalue , ( token = = nullptr ) ? " " : token , sizeof ( svalue ) ) ; // Fixed 5.8.0b
2019-01-28 13:08:33 +00:00
MqttDataHandler ( stopic , ( uint8_t * ) 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 ) ] ;
2019-02-03 11:38:41 +00:00
char stemp2 [ 64 ] ;
2017-01-28 13:41:01 +00:00
// Workaround MQTT - TCP/IP stack queueing when SUB_PREFIX = PUB_PREFIX
2019-01-28 13:08:33 +00:00
if ( ! strcmp ( Settings . mqtt_prefix [ 0 ] , Settings . mqtt_prefix [ 1 ] ) & & ( ! payload ) ) { option + + ; } // TELE
2017-01-28 13:41:01 +00:00
2019-01-28 13:08:33 +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 ;
2019-02-11 18:21:49 +00:00
if ( SONOFF_IFAN02 = = my_module_type ) { maxfn = 1 ; }
2018-03-21 09:42:56 +00:00
stemp [ 0 ] = ' \0 ' ;
2019-01-28 13:08:33 +00:00
for ( uint8_t i = 0 ; i < maxfn ; i + + ) {
2018-03-21 09:42:56 +00:00
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 ' ;
2019-01-28 13:08:33 +00:00
for ( uint8_t i = 0 ; i < MAX_SWITCHES ; i + + ) {
2018-09-26 09:13:44 +01:00
snprintf_P ( stemp2 , sizeof ( stemp2 ) , PSTR ( " %s%s%d " ) , stemp2 , ( i > 0 ? " , " : " " ) , Settings . switchmode [ i ] ) ;
}
2019-04-10 14:02:38 +01:00
Response_P ( 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_LEDMASK " \" : \" %04X \" , \" " 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}} " ) ,
ModuleNr ( ) , stemp , mqtt_topic , Settings . button_topic , power , Settings . poweronstate , Settings . ledstate , Settings . ledmask , 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 ) ) {
2019-03-23 16:00:59 +00:00
Response_P ( 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_CONFIG_HOLDER " \" :%d, \" " D_JSON_BOOTCOUNT " \" :%d, \" " D_JSON_SAVECOUNT " \" :%d, \" " D_JSON_SAVEADDRESS " \" : \" %X \" }} " ) ,
2019-02-13 09:50:02 +00:00
baudrate , Settings . mqtt_grptopic , Settings . ota_url , GetResetReason ( ) . c_str ( ) , GetUptime ( ) . c_str ( ) , GetDateAndTime ( DT_RESTART ) . c_str ( ) , Settings . sleep , Settings . cfg_holder , 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 ) ) {
2019-03-23 16:00:59 +00:00
Response_P ( 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 \" }} " ) ,
2018-11-07 14:03:41 +00:00
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 ) ) {
2019-02-03 11:38:41 +00:00
stemp2 [ 0 ] = ' \0 ' ;
for ( int8_t i = 0 ; i < PARAM8_SIZE ; i + + ) {
snprintf_P ( stemp2 , sizeof ( stemp2 ) , PSTR ( " %s%02X " ) , stemp2 , Settings . param [ i ] ) ;
}
2019-03-23 16:00:59 +00:00
Response_P ( 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_JSON_RESOLUTION " \" : \" %08X \" , \" " D_CMND_SETOPTION " \" :[ \" %08X \" , \" %s \" , \" %08X \" ]}} " ) ,
2019-02-03 11:38:41 +00:00
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 . flag2 . data , Settings . flag . data , stemp2 , 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 ) ) {
2019-03-23 16:00:59 +00:00
Response_P ( 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 \" ]}} " ) ,
2018-11-08 09:40:19 +00:00
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 ) ) {
2019-03-23 16:00:59 +00:00
Response_P ( 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 ) {
2019-03-23 16:00:59 +00:00
Response_P ( 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 \" , \" " D_JSON_MQTT_COUNT " \" :%d, \" MAX_PACKET_SIZE \" :%d, \" KEEPALIVE \" :%d}} " ) ,
2019-03-15 13:29:47 +00:00
Settings . mqtt_host , Settings . mqtt_port , Settings . mqtt_client , mqtt_client , Settings . mqtt_user , MqttConnectCount ( ) , 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)
2019-03-23 16:00:59 +00:00
Response_P ( 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 \" }} " ) ,
2018-11-01 12:00:05 +00:00
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
2019-03-23 16:00:59 +00:00
Response_P ( 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}} " ) ,
2018-11-01 12:00:05 +00:00
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 ) ) {
2019-03-23 16:00:59 +00:00
Response_P ( 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}} " ) ,
2018-03-14 16:28:30 +00:00
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 ) ) {
2019-03-23 16:00:59 +00:00
Response_P ( PSTR ( " { \" " D_CMND_STATUS D_STATUS10_SENSOR " \" : " ) ) ;
2017-11-03 17:07:25 +00:00
MqttShowSensor ( ) ;
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " } " ) ) ;
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 ) ) {
2019-03-23 16:00:59 +00:00
Response_P ( PSTR ( " { \" " D_CMND_STATUS D_STATUS11_STATUS " \" : " ) ) ;
2017-10-18 17:22:34 +01:00
MqttShowState ( ) ;
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " } " ) ) ;
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
{
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " \" " D_CMND_PWM " \" :{ " ) ) ;
2018-03-20 15:28:18 +00:00
bool first = true ;
2019-01-28 13:08:33 +00:00
for ( uint8_t i = 0 ; i < MAX_PWMS ; i + + ) {
2018-03-20 15:28:18 +00:00
if ( pin [ GPIO_PWM1 + i ] < 99 ) {
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " %s \" " D_CMND_PWM " %d \" :%d " ) , first ? " " : " , " , i + 1 , Settings . pwm_value [ i ] ) ;
2018-03-20 15:28:18 +00:00
first = false ;
}
}
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " } " ) ) ;
2018-03-20 15:28:18 +00:00
}
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
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " { \" " D_JSON_TIME " \" : \" %s \" , \" " D_JSON_UPTIME " \" : \" %s \" " ) , GetDateAndTime ( DT_LOCAL ) . c_str ( ) , GetUptime ( ) . c_str ( ) ) ;
2018-12-01 17:53:42 +00:00
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 ) ;
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " , \" " D_JSON_VCC " \" :%s " ) , stemp1 ) ;
2017-09-02 13:37:02 +01:00
# endif
2018-01-20 11:12:39 +00:00
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " , \" SleepMode \" : \" %s \" , \" Sleep \" :%u, \" LoadAvg \" :%u " ) ,
GetTextIndexed ( stemp1 , sizeof ( stemp1 ) , Settings . flag3 . sleep_normal , kSleepMode ) , sleep , loop_load_avg ) ;
2018-12-01 17:53:42 +00:00
2019-01-28 13:08:33 +00:00
for ( uint8_t i = 0 ; i < devices_present ; i + + ) {
2018-01-20 11:12:39 +00:00
if ( i = = light_device - 1 ) {
LightState ( 1 ) ;
} else {
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " , \" %s \" : \" %s \" " ) , GetPowerDevice ( stemp1 , i + 1 , sizeof ( stemp1 ) , Settings . flag . device_index_enable ) , GetStateText ( bitRead ( power , i ) ) ) ;
2019-02-11 18:21:49 +00:00
if ( SONOFF_IFAN02 = = my_module_type ) {
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " , \" " D_CMND_FANSPEED " \" :%d " ) , GetFanspeed ( ) ) ;
2018-07-01 14:06:44 +01:00
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 ) {
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " , " ) ) ;
2018-03-20 15:28:18 +00:00
MqttShowPWMState ( ) ;
}
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " , \" " D_JSON_WIFI " \" :{ \" " D_JSON_AP " \" :%d, \" " D_JSON_SSID " \" : \" %s \" , \" " D_JSON_BSSID " \" : \" %s \" , \" " D_JSON_CHANNEL " \" :%d, \" " D_JSON_RSSI " \" :%d, \" " D_JSON_LINK_COUNT " \" :%d, \" " D_JSON_DOWNTIME " \" : \" %s \" }} " ) ,
Settings . sta_active + 1 , Settings . sta_ssid [ Settings . sta_active ] , WiFi . BSSIDstr ( ) . c_str ( ) , WiFi . channel ( ) , WifiGetRssiAsQuality ( WiFi . RSSI ( ) ) , WifiLinkCount ( ) , WifiDowntime ( ) . c_str ( ) ) ;
2017-02-04 16:09:54 +00:00
}
2019-03-20 13:05:43 +00:00
void MqttPublishTeleState ( void )
{
mqtt_data [ 0 ] = ' \0 ' ;
MqttShowState ( ) ;
MqttPublishPrefixTopic_P ( TELE , PSTR ( D_RSLT_STATE ) , MQTT_TELE_RETAIN ) ;
}
2019-01-28 13:08:33 +00:00
bool MqttShowSensor ( void )
2017-02-04 16:09:54 +00:00
{
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " { \" " D_JSON_TIME " \" : \" %s \" " ) , GetDateAndTime ( DT_LOCAL ) . c_str ( ) ) ;
2017-11-04 15:36:51 +00:00
int json_data_start = strlen ( mqtt_data ) ;
2019-01-28 13:08:33 +00:00
for ( uint8_t 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
2019-01-28 13:08:33 +00:00
bool swm = ( ( FOLLOW_INV = = Settings . switchmode [ i ] ) | | ( PUSHBUTTON_INV = = Settings . switchmode [ i ] ) | | ( PUSHBUTTONHOLD_INV = = Settings . switchmode [ i ] ) ) ;
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " , \" " D_JSON_SWITCH " %d \" : \" %s \" " ) , i + 1 , GetStateText ( swm ^ SwitchLastState ( i ) ) ) ;
2017-03-19 17:19:08 +00:00
}
}
2017-12-25 16:41:12 +00:00
XsnsCall ( FUNC_JSON_APPEND ) ;
2019-01-28 13:08:33 +00:00
bool json_data_available = ( strlen ( mqtt_data ) - json_data_start ) ;
2019-03-26 17:26:50 +00:00
if ( strstr_P ( mqtt_data , PSTR ( D_JSON_PRESSURE ) ) ! = nullptr ) {
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " , \" " D_JSON_PRESSURE_UNIT " \" : \" %s \" " ) , PressureUnit ( ) . c_str ( ) ) ;
2018-11-04 15:55:12 +00:00
}
2019-03-26 17:26:50 +00:00
if ( strstr_P ( mqtt_data , PSTR ( D_JSON_TEMPERATURE ) ) ! = nullptr ) {
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " , \" " D_JSON_TEMPERATURE_UNIT " \" : \" %c \" " ) , TempUnit ( ) ) ;
2017-05-03 17:19:13 +01:00
}
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " } " ) ) ;
2018-01-05 11:26:19 +00:00
2019-03-23 16:00:59 +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
2019-03-08 14:15:42 +00:00
AddLog_P2 ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_APPLICATION D_BOOT_COUNT " %d " ) , Settings . bootcount ) ;
2018-08-30 13:27:33 +01:00
}
2019-02-11 18:21:49 +00:00
if ( ( 4 = = uptime ) & & ( SONOFF_IFAN02 = = my_module_type ) ) { // Microcontroller needs 3 seconds before accepting commands
2018-08-20 14:51:46 +01:00
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 ;
2019-03-20 13:05:43 +00:00
MqttPublishTeleState ( ) ;
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 ;
2019-03-23 16:00:59 +00:00
Response_P ( 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
/*********************************************************************************************\
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
2019-01-28 13:08:33 +00:00
for ( uint8_t i = 0 ; i < MAX_PULSETIMERS ; i + + ) {
2018-08-26 14:42:35 +01:00
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 ) {
2019-01-28 13:08:33 +00:00
backlog_mutex = true ;
2018-05-28 14:52:42 +01:00
ExecuteCommand ( ( char * ) backlog [ backlog_pointer ] . c_str ( ) , SRC_BACKLOG ) ;
2019-01-28 13:08:33 +00:00
backlog_mutex = false ;
2017-10-18 17:22:34 +01:00
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
2019-01-28 13:08:33 +00:00
blinkstate = true ; // Stay lit
2018-08-26 14:42:35 +01:00
} 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))) ) {
2019-01-06 17:02:21 +00:00
// SetLedPower(blinkstate); // Set led on or off
2019-01-08 10:44:45 +00:00
SetLedLink ( blinkstate ) ; // Set led on or off
2018-08-26 14:42:35 +01:00
}
if ( ! blinkstate ) {
blinks - - ;
if ( 200 = = blinks ) blinks = 0 ; // Disable blink
}
}
else if ( Settings . ledstate & 1 ) {
2019-04-10 13:26:36 +01:00
bool tstate = power & Settings . ledmask ;
2019-02-11 18:21:49 +00:00
if ( ( SONOFF_TOUCH = = my_module_type ) | | ( SONOFF_T11 = = my_module_type ) | | ( SONOFF_T12 = = my_module_type ) | | ( SONOFF_T13 = = my_module_type ) ) {
2018-08-26 14:42:35 +01:00
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 ) ) ;
2019-02-08 13:55:45 +00:00
# ifndef FIRMWARE_MINIMAL
2018-01-10 13:10:25 +00:00
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
2019-03-26 17:26:50 +00:00
char * pch = strrchr ( ( bch ! = nullptr ) ? bch : mqtt_data , ' - ' ) ; // Change from filename-DE.bin into filename-minimal.bin
char * ech = strrchr ( ( bch ! = nullptr ) ? bch : mqtt_data , ' . ' ) ; // Change from filename.bin into filename-minimal.bin
2019-01-28 13:08:33 +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
}
}
2019-02-08 13:55:45 +00:00
# endif // FIRMWARE_MINIMAL
2019-03-08 14:15:42 +00:00
AddLog_P2 ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_UPLOAD " %s " ) , mqtt_data ) ;
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 ) {
2019-02-08 13:55:45 +00:00
# ifndef FIRMWARE_MINIMAL
2018-01-10 13:10:25 +00:00
int ota_error = ESPhttpUpdate . getLastError ( ) ;
2019-03-08 14:15:42 +00:00
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPLOAD "Ota error %d"), ota_error);
2018-01-10 13:10:25 +00:00
if ( ( HTTP_UE_TOO_LESS_SPACE = = ota_error ) | | ( HTTP_UE_BIN_FOR_WRONG_FLASH = = ota_error ) ) {
RtcSettings . ota_loader = 1 ; // Try minimal image next
}
2019-02-08 13:55:45 +00:00
# endif // FIRMWARE_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
2019-03-23 16:00:59 +00:00
Response_P ( PSTR ( D_JSON_SUCCESSFUL " . " D_JSON_RESTARTING ) ) ;
2017-01-28 13:41:01 +00:00
} else {
2019-03-23 16:00:59 +00:00
Response_P ( 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 ;
2019-01-28 13:08:33 +00:00
for ( uint8_t 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 ) ) {
2019-02-18 19:52:22 +00:00
if ( ( 214 = = restart_flag ) | | ( 215 = = restart_flag ) | | ( 216 = = restart_flag ) ) {
2019-03-14 15:50:56 +00:00
char storage_wifi [ sizeof ( Settings . sta_ssid ) +
sizeof ( Settings . sta_pwd ) ] ;
char storage_mqtt [ sizeof ( Settings . mqtt_host ) +
sizeof ( Settings . mqtt_port ) +
sizeof ( Settings . mqtt_client ) +
sizeof ( Settings . mqtt_user ) +
sizeof ( Settings . mqtt_pwd ) +
sizeof ( Settings . mqtt_topic ) ] ;
memcpy ( storage_wifi , Settings . sta_ssid , sizeof ( storage_wifi ) ) ; // Backup current SSIDs and Passwords
2019-02-18 19:52:22 +00:00
if ( 216 = = restart_flag ) {
2019-03-14 15:50:56 +00:00
memcpy ( storage_mqtt , Settings . mqtt_host , sizeof ( storage_mqtt ) ) ; // Backup mqtt host, port, client, username and password
2019-02-18 19:52:22 +00:00
}
if ( ( 215 = = restart_flag ) | | ( 216 = = restart_flag ) ) {
2018-10-15 13:43:47 +01:00
SettingsErase ( 0 ) ; // Erase all flash from program end to end of physical flash
}
SettingsDefault ( ) ;
2019-03-14 15:50:56 +00:00
memcpy ( Settings . sta_ssid , storage_wifi , sizeof ( storage_wifi ) ) ; // Restore current SSIDs and Passwords
if ( 216 = = restart_flag ) {
memcpy ( Settings . mqtt_host , storage_mqtt , sizeof ( storage_mqtt ) ) ; // Restore the mqtt host, port, client, username and password
strlcpy ( Settings . mqtt_client , MQTT_CLIENT_ID , sizeof ( Settings . mqtt_client ) ) ; // Set client to default
2019-02-18 19:52:22 +00:00
}
2018-10-15 13:43:47 +01:00
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 ) ;
2018-12-13 23:04:48 +00:00
ArduinoOTA . setHostname ( my_hostname ) ;
2019-01-28 13:08:33 +00:00
if ( Settings . web_password [ 0 ] ! = 0 ) { ArduinoOTA . setPassword ( Settings . web_password ) ; }
2018-03-21 16:58:39 +00:00
ArduinoOTA . onStart ( [ ] ( )
{
SettingsSave ( 1 ) ; // Free flash for OTA update
# ifdef USE_WEBSERVER
2019-01-28 13:08:33 +00:00
if ( Settings . webserver ) { StopWebserver ( ) ; }
2018-03-21 16:58:39 +00:00
# endif // USE_WEBSERVER
# ifdef USE_ARILUX_RF
AriluxRfDisable ( ) ; // Prevent restart exception on Arilux Interrupt routine
# endif // USE_ARILUX_RF
2019-01-28 13:08:33 +00:00
if ( Settings . flag . mqtt_enabled ) { MqttDisconnect ( ) ; }
2019-03-08 14:15:42 +00:00
AddLog_P2 ( LOG_LEVEL_INFO , PSTR ( D_LOG_UPLOAD " Arduino OTA " D_UPLOAD_STARTED ) ) ;
2018-03-21 16:58:39 +00:00
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 ( " . " ) ;
2019-01-28 13:08:33 +00:00
if ( ! ( arduino_ota_progress_dot_count % 80 ) ) { Serial . println ( ) ; }
2018-03-21 16:58:39 +00:00
}
} ) ;
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 ] ;
2019-01-28 13:08:33 +00:00
if ( ( LOG_LEVEL_DEBUG < = seriallog_level ) & & arduino_ota_progress_dot_count ) { Serial . println ( ) ; }
2018-03-21 16:58:39 +00:00
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 ) ;
}
2019-03-08 14:15:42 +00:00
AddLog_P2 ( LOG_LEVEL_INFO , PSTR ( D_LOG_UPLOAD " Arduino OTA %s. " D_RESTARTING ) , error_str ) ;
2018-06-03 16:09:10 +01:00
EspRestart ( ) ;
2018-03-21 16:58:39 +00:00
} ) ;
ArduinoOTA . onEnd ( [ ] ( )
{
2019-01-28 13:08:33 +00:00
if ( ( LOG_LEVEL_DEBUG < = seriallog_level ) ) { Serial . println ( ) ; }
2019-03-08 14:15:42 +00:00
AddLog_P2 ( LOG_LEVEL_INFO , PSTR ( D_LOG_UPLOAD " Arduino OTA " D_SUCCESSFUL " . " D_RESTARTING ) ) ;
2018-06-03 16:09:10 +01:00
EspRestart ( ) ;
2018-03-21 16:58:39 +00:00
} ) ;
ArduinoOTA . begin ( ) ;
2019-03-08 14:15:42 +00:00
AddLog_P2 ( LOG_LEVEL_INFO , PSTR ( D_LOG_UPLOAD " Arduino OTA " D_ENABLED " " D_PORT " 8266 " ) ) ;
2018-03-21 16:58:39 +00:00
}
# 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 ( ) ) {
2019-02-21 13:31:31 +00:00
// yield();
delay ( 0 ) ;
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
\ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2019-02-11 18:21:49 +00:00
if ( ( SONOFF_DUAL = = my_module_type ) | | ( CH4 = = my_module_type ) ) {
2019-01-07 11:38:47 +00:00
serial_in_byte = ButtonSerial ( serial_in_byte ) ;
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
2019-02-09 12:25:15 +00:00
if ( serial_in_byte > 127 & & ! Settings . flag . mqtt_serial_raw ) { // Discard binary data above 127 if no raw reception allowed
2018-10-18 12:01:31 +01:00
serial_in_byte_counter = 0 ;
Serial . flush ( ) ;
return ;
}
2019-02-09 12:25:15 +00:00
if ( ! Settings . flag . mqtt_serial ) { // SerialSend active
if ( isprint ( serial_in_byte ) ) { // Any char between 32 and 127
if ( serial_in_byte_counter < INPUT_BUFFER_SIZE - 1 ) { // Add char to string if it still fits
2018-10-18 12:01:31 +01:00
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 {
2019-02-09 12:25:15 +00:00
if ( serial_in_byte | | Settings . flag . mqtt_serial_raw ) { // Any char between 1 and 127 or any char (0 - 255)
if ( ( serial_in_byte_counter < INPUT_BUFFER_SIZE - 1 ) & & // Add char to string if it still fits and ...
( ( isprint ( serial_in_byte ) & & ( 128 = = Settings . serial_delimiter ) ) | | // Any char between 32 and 127
( serial_in_byte ! = Settings . serial_delimiter ) | | // Any char between 1 and 127 and not being delimiter
Settings . flag . mqtt_serial_raw ) ) { // Any char between 0 and 255
2018-10-18 12:01:31 +01:00
serial_in_buffer [ serial_in_byte_counter + + ] = serial_in_byte ;
serial_polling_window = millis ( ) ;
} else {
2019-02-09 12:25:15 +00:00
serial_polling_window = 0 ; // Reception done - send mqtt
2018-10-18 12:01:31 +01:00
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
\ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2019-02-11 18:21:49 +00:00
if ( SONOFF_SC = = my_module_type ) {
2019-02-09 12:25:15 +00:00
if ( serial_in_byte = = ' \x1B ' ) { // Sonoff SC status from ATMEGA328P
serial_in_buffer [ serial_in_byte_counter ] = 0 ; // Serial data completed
2018-03-18 12:47:30 +00:00
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 ' ) ) {
2019-02-09 12:25:15 +00:00
serial_in_buffer [ serial_in_byte_counter ] = 0 ; // Serial data completed
2019-01-28 13:08:33 +00:00
seriallog_level = ( Settings . seriallog_level < LOG_LEVEL_INFO ) ? ( uint8_t ) LOG_LEVEL_INFO : Settings . seriallog_level ;
2019-03-08 14:15:42 +00:00
AddLog_P2 ( LOG_LEVEL_INFO , PSTR ( D_LOG_COMMAND " %s " ) , serial_in_buffer ) ;
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 ) ) ) {
2019-02-09 12:25:15 +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 ) {
2019-03-23 16:00:59 +00:00
Response_P ( PSTR ( " { \" " D_JSON_SERIALRECEIVED " \" : \" %s \" } " ) , serial_in_buffer ) ;
2018-10-18 12:01:31 +01:00
} else {
2019-03-23 16:00:59 +00:00
Response_P ( PSTR ( " { \" " D_JSON_SERIALRECEIVED " \" : \" " ) ) ;
2018-10-18 12:01:31 +01:00
for ( int i = 0 ; i < serial_in_byte_counter ; i + + ) {
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " %02x " ) , serial_in_buffer [ i ] ) ;
2018-07-27 11:17:34 +01:00
}
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " \" } " ) ) ;
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-12-28 15:35:19 +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 ;
2019-04-05 14:27:06 +01:00
if ( ! ValidModule ( Settings . module ) ) {
uint8_t module = MODULE ;
if ( ! ValidModule ( MODULE ) ) { module = SONOFF_BASIC ; }
Settings . module = module ;
Settings . last_module = module ;
2017-04-25 17:24:42 +01:00
}
2019-02-11 18:21:49 +00:00
SetModuleType ( ) ;
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
2019-02-17 15:43:52 +00:00
for ( uint8_t i = 0 ; i < sizeof ( Settings . user_template . gp ) ; i + + ) {
if ( ( Settings . user_template . gp . io [ i ] > = GPIO_SENSOR_END ) & & ( Settings . user_template . gp . io [ i ] < GPIO_USER ) ) {
Settings . user_template . gp . io [ i ] = GPIO_USER ; // Fix not supported sensor ids in template
}
}
2018-12-29 16:19:13 +00:00
myio def_gp ;
ModuleGpios ( & def_gp ) ;
2019-01-28 13:08:33 +00:00
for ( uint8_t i = 0 ; i < sizeof ( Settings . my_gp ) ; i + + ) {
2019-02-17 15:43:52 +00:00
if ( ( Settings . my_gp . io [ i ] > = GPIO_SENSOR_END ) & & ( Settings . my_gp . io [ i ] < GPIO_USER ) ) {
Settings . my_gp . io [ i ] = GPIO_NONE ; // Fix not supported sensor ids in module
}
else if ( Settings . my_gp . io [ i ] > GPIO_NONE ) {
2018-12-29 16:19:13 +00:00
my_module . io [ i ] = Settings . my_gp . io [ i ] ;
2017-04-25 17:24:42 +01:00
}
2018-12-29 16:19:13 +00:00
if ( ( def_gp . io [ i ] > GPIO_NONE ) & & ( def_gp . io [ i ] < GPIO_USER ) ) {
my_module . io [ i ] = def_gp . io [ i ] ;
2017-04-25 17:24:42 +01:00
}
2017-01-28 13:41:01 +00:00
}
2019-01-07 15:33:18 +00:00
my_module_flag = ModuleFlag ( ) ;
2017-02-11 14:06:23 +00:00
2019-02-11 18:21:49 +00:00
for ( uint16_t i = 0 ; i < GPIO_MAX ; i + + ) {
2017-04-25 17:24:42 +01:00
pin [ i ] = 99 ;
}
2019-01-28 13:08:33 +00:00
for ( uint8_t i = 0 ; i < sizeof ( my_module . io ) ; i + + ) {
2019-02-11 18:21:49 +00:00
mpin = ValidPin ( i , my_module . io [ i ] ) ;
2017-01-28 13:41:01 +00:00
2019-03-08 14:15:42 +00:00
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DBG: gpio pin %d, mpin %d"), i, mpin);
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 ) ) ) {
2018-12-28 15:35:19 +00:00
SwitchPullupFlag ( mpin - GPIO_SWT1_NP ) ;
2018-08-25 12:08:06 +01:00
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 ) ) ) {
2019-01-27 13:54:28 +00:00
ButtonPullupFlag ( mpin - GPIO_KEY1_NP ) ; // 0 .. 3
2018-08-25 12:08:06 +01:00
mpin - = ( GPIO_KEY1_NP - GPIO_KEY1 ) ;
}
2019-01-27 13:54:28 +00:00
else if ( ( mpin > = GPIO_KEY1_INV ) & & ( mpin < ( GPIO_KEY1_INV + MAX_KEYS ) ) ) {
ButtonInvertFlag ( mpin - GPIO_KEY1_INV ) ; // 0 .. 3
mpin - = ( GPIO_KEY1_INV - GPIO_KEY1 ) ;
}
else if ( ( mpin > = GPIO_KEY1_INV_NP ) & & ( mpin < ( GPIO_KEY1_INV_NP + MAX_KEYS ) ) ) {
ButtonPullupFlag ( mpin - GPIO_KEY1_INV_NP ) ; // 0 .. 3
ButtonInvertFlag ( mpin - GPIO_KEY1_INV_NP ) ; // 0 .. 3
mpin - = ( GPIO_KEY1_INV_NP - GPIO_KEY1 ) ;
}
2018-08-25 12:08:06 +01:00
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 ) ) {
2019-01-28 13:08:33 +00:00
dht_flg = true ;
2017-05-03 17:19:13 +01:00
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
}
2019-02-11 18:21:49 +00:00
if ( ( 2 = = pin [ GPIO_TXD ] ) | | ( H801 = = my_module_type ) ) { 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 ) {
2019-02-11 18:21:49 +00:00
for ( uint16_t 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
}
2018-12-29 16:19:13 +00:00
my_module . io [ 12 ] = GPIO_SPI_MISO ;
2018-01-05 11:26:19 +00:00
pin [ GPIO_SPI_MISO ] = 12 ;
2018-12-29 16:19:13 +00:00
my_module . io [ 13 ] = GPIO_SPI_MOSI ;
2018-01-05 11:26:19 +00:00
pin [ GPIO_SPI_MOSI ] = 13 ;
2018-12-29 16:19:13 +00:00
my_module . io [ 14 ] = GPIO_SPI_CLK ;
2018-01-05 11:26:19 +00:00
pin [ GPIO_SPI_CLK ] = 14 ;
}
2018-12-05 11:23:42 +00:00
soft_spi_flg = ( ( pin [ GPIO_SSPI_CS ] < 99 ) & & ( pin [ GPIO_SSPI_SCLK ] < 99 ) & & ( ( pin [ GPIO_SSPI_MOSI ] < 99 ) | | ( pin [ GPIO_SSPI_MOSI ] < 99 ) ) ) ;
2018-01-05 11:26:19 +00:00
# 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 ) ) ;
2019-01-28 13:08:33 +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 ) {
2019-01-28 13:08:33 +00:00
for ( uint8_t i = 0 ; i < MAX_PWMS ; i + + ) {
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
2019-02-11 18:21:49 +00:00
if ( SONOFF_BRIDGE = = my_module_type ) {
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
}
2019-02-11 18:21:49 +00:00
else if ( YTF_IR_BRIDGE = = my_module_type ) {
2019-02-03 17:45:20 +00:00
ClaimSerial ( ) ; // Stop serial loopback mode
}
2019-02-11 18:21:49 +00:00
else if ( SONOFF_DUAL = = my_module_type ) {
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
}
2019-02-11 18:21:49 +00:00
else if ( CH4 = = my_module_type ) {
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
}
2019-02-11 18:21:49 +00:00
else if ( SONOFF_SC = = my_module_type ) {
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
}
2019-02-11 18:21:49 +00:00
else if ( SONOFF_BN = = my_module_type ) { // 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
}
2019-02-11 18:21:49 +00:00
else if ( SONOFF_LED = = my_module_type ) { // 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
}
2019-02-11 18:21:49 +00:00
else if ( AILIGHT = = my_module_type ) { // RGBW led
2017-10-25 13:27:30 +01:00
light_type = LT_RGBW ;
2017-08-13 14:31:49 +01:00
}
2019-02-11 18:21:49 +00:00
else if ( SONOFF_B1 = = my_module_type ) { // 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 {
2019-01-28 13:08:33 +00:00
if ( ! light_type ) { devices_present = 0 ; }
for ( uint8_t 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 + + ;
2019-02-11 18:21:49 +00:00
if ( EXS_RELAY = = my_module_type ) {
2018-09-30 15:52:25 +01:00
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
2019-01-28 13:08:33 +00:00
for ( uint8_t 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
}
2018-12-28 15:35:19 +00:00
2019-01-07 11:38:47 +00:00
ButtonInit ( ) ;
2018-12-28 15:35:19 +00:00
SwitchInit ( ) ;
2019-04-05 07:41:26 +01:00
# ifdef ROTARY_V1
2019-01-11 00:50:40 +00:00
RotaryInit ( ) ;
2019-04-05 14:27:06 +01:00
# endif
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
2019-01-30 22:19:40 +00:00
# ifdef USE_SM16716
if ( SM16716_ModuleSelected ( ) ) {
light_type + = 3 ;
2019-02-02 00:41:12 +00:00
light_type | = LT_SM16716 ;
2019-01-30 22:19:40 +00:00
}
# endif // ifdef USE_SM16716
2018-01-05 11:26:19 +00:00
if ( ! light_type ) {
2019-01-28 13:08:33 +00:00
for ( uint8_t 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 ) ;
2019-01-08 10:44:45 +00:00
SetLedLink ( 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
{
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 ;
2019-01-03 16:30:54 +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
2019-01-30 13:34:31 +00:00
if ( Settings . param [ P_BOOT_LOOP_OFFSET ] ) {
// Disable functionality as possible cause of fast restart within BOOT_LOOP_TIME seconds (Exception, WDT or restarts)
if ( RtcReboot . fast_reboot_count > Settings . param [ P_BOOT_LOOP_OFFSET ] ) { // Restart twice
Settings . flag3 . user_esp8285_enable = 0 ; // Disable ESP8285 Generic GPIOs interfering with flash SPI
if ( RtcReboot . fast_reboot_count > Settings . param [ P_BOOT_LOOP_OFFSET ] + 1 ) { // Restart 3 times
for ( uint8_t 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-08-30 13:27:33 +01:00
}
}
2019-01-30 13:34:31 +00:00
if ( RtcReboot . fast_reboot_count > Settings . param [ P_BOOT_LOOP_OFFSET ] + 2 ) { // Restarted 4 times
Settings . rule_enabled = 0 ; // Disable all rules
2018-08-30 13:47:48 +01:00
}
2019-01-30 13:34:31 +00:00
if ( RtcReboot . fast_reboot_count > Settings . param [ P_BOOT_LOOP_OFFSET ] + 3 ) { // Restarted 5 times
for ( uint8_t i = 0 ; i < sizeof ( Settings . my_gp ) ; i + + ) {
Settings . my_gp . io [ i ] = GPIO_NONE ; // Reset user defined GPIO disabling sensors
}
}
if ( RtcReboot . fast_reboot_count > Settings . param [ P_BOOT_LOOP_OFFSET ] + 4 ) { // Restarted 6 times
Settings . module = SONOFF_BASIC ; // Reset module to Sonoff Basic
// Settings.last_module = SONOFF_BASIC;
}
2019-03-08 14:15:42 +00:00
AddLog_P2 ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_APPLICATION D_LOG_SOME_SETTINGS_RESET " (%d) " ) , RtcReboot . fast_reboot_count ) ;
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 ) ) ;
2019-03-26 17:26:50 +00:00
if ( strstr ( Settings . hostname , " % " ) ! = nullptr ) {
2017-10-18 17:22:34 +01:00
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
2019-02-11 18:21:49 +00:00
if ( MOTOR = = my_module_type ) { 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
2019-01-28 13:08:33 +00:00
for ( uint8_t 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 ;
2019-03-08 14:15:42 +00:00
AddLog_P2 ( LOG_LEVEL_INFO , PSTR ( D_PROJECT " %s %s " D_VERSION " %s%s- " ARDUINO_ESP8266_RELEASE ) , PROJECT , Settings . friendlyname [ 0 ] , my_version , my_image ) ;
2019-02-08 13:55:45 +00:00
# ifdef FIRMWARE_MINIMAL
2019-03-08 14:15:42 +00:00
AddLog_P2 ( LOG_LEVEL_INFO , PSTR ( D_WARNING_MINIMAL_VERSION ) ) ;
2019-02-08 13:55:45 +00:00
# endif // FIRMWARE_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-12-01 16:47:25 +00:00
uint32_t _counter = 0 ;
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 ) ;
2018-12-11 13:24:52 +00:00
XsnsCall ( FUNC_LOOP ) ;
2018-02-27 13:59:46 +00:00
2017-10-18 17:22:34 +01:00
OsWatchLoop ( ) ;
2017-09-02 13:37:02 +01:00
2019-01-07 11:38:47 +00:00
ButtonLoop ( ) ;
2018-12-28 15:35:19 +00:00
SwitchLoop ( ) ;
2019-04-05 14:27:06 +01:00
# ifdef ROTARY_V1
2019-01-11 00:50:40 +00:00
RotaryLoop ( ) ;
2019-04-05 14:27:06 +01:00
# endif
2018-12-28 15:35:19 +00:00
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
2019-01-28 13:08:33 +00: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
2018-12-13 23:04:48 +00:00
MDNS . update ( ) ;
2018-03-21 16:58:39 +00:00
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
uint32_t my_activity = millis ( ) - my_sleep ;
2018-12-01 17:53:42 +00:00
2018-12-01 16:47:25 +00:00
if ( Settings . flag3 . sleep_normal ) {
// yield(); // yield == delay(0), delay contains yield, auto yield in loop
delay ( sleep ) ; // https://github.com/esp8266/Arduino/issues/2021
2018-11-22 11:25:18 +00:00
} else {
2018-12-01 16:47:25 +00:00
if ( my_activity < ( uint32_t ) sleep ) {
delay ( ( uint32_t ) sleep - my_activity ) ; // Provide time for background tasks like wifi
} else {
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
2018-12-01 16:47:25 +00:00
uint32_t loop_delay = sleep ;
2018-11-25 16:31:53 +00:00
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-12-01 16:47:25 +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
}