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
2019-06-19 08:49:48 +01:00
# ifdef USE_MQTT_TLS
# include <t_bearssl.h> // we need to include before "sonoff_post.h" to take precedence over the BearSSL version in Arduino
# endif // USE_MQTT_TLS
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
2019-06-19 08:49:48 +01: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
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
2019-08-07 11:56:32 +01:00
unsigned long feature5 ; // Compiled 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
2019-09-04 11:20:04 +01:00
power_t last_power = 0 ; // Last power set state
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
2019-07-27 17:37:56 +01:00
uint32_t web_log_index = 1 ; // Index in Web log buffer (should never be 0)
2019-05-22 11:22:58 +01:00
float global_temperature = 9999 ; // Provide a global temperature to be used by some sensors
2018-08-27 15:07:23 +01:00
float global_humidity = 0 ; // Provide a global humidity to be used by some sensors
2019-04-15 17:12:42 +01:00
float global_pressure = 0 ; // Provide a global pressure to be used by some sensors
2018-08-27 15:07:23 +01:00
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
2019-06-08 10:38:45 +01:00
uint8_t active_device = 1 ; // Active device in ExecuteCommandPower
2019-05-21 17:11:39 +01:00
uint8_t leds_present = 0 ; // Max number of LED supported
2017-10-18 17:22:34 +01:00
uint8_t led_inverted = 0 ; // LED inverted flag (1 = (0 = On, 1 = Off))
2019-05-21 17:11:39 +01:00
uint8_t led_power = 0 ; // LED power state
uint8_t ledlnk_inverted = 0 ; // Link LED inverted flag (1 = (0 = On, 1 = Off))
2017-10-18 17:22:34 +01:00
uint8_t pwm_inverted = 0 ; // PWM inverted flag (1 = inverted)
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 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-05-13 14:56:01 +01:00
uint8_t my_adc0 ; // Active copy of Module ADC0
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
2019-07-06 11:53:07 +01:00
//bool latest_uptime_flag = true; // Signal latest uptime
2019-01-28 13:08:33 +00:00
bool pwm_present = false ; // Any PWM channel configured with SetOption15 0
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-06-09 12:34:14 +01:00
bool ntp_synced_message = false ; // NTP synced message flag
2019-01-07 15:33:18 +00:00
myio my_module ; // Active copy of Module GPIOs (17 x 8 bits)
2019-05-13 14:56:01 +01:00
gpio_flag my_module_flag ; // Active copy of Template 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 ;
2019-09-04 11:47:58 +01:00
uint32_t digits = 0 ;
2017-01-28 13:41:01 +00:00
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-09-04 11:20:04 +01: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-09-04 11:47:58 +01:00
char * GetTopic_P ( char * stopic , uint32_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-06-30 15:44:36 +01:00
for ( uint32_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 ( " // " ) , " / " ) ;
2019-09-04 11:20:04 +01: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-09-04 11:47:58 +01:00
char * GetFallbackTopic_P ( char * stopic , uint32_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-09-04 11:47:58 +01:00
char * GetStateText ( uint32_t state )
2017-05-10 13:19:36 +01:00
{
2019-09-04 11:20:04 +01: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
}
/********************************************************************************************/
2019-09-04 11:47:58 +01:00
void SetLatchingRelay ( power_t lpower , uint32_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-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < devices_present ; i + + ) {
2019-09-04 11:47:58 +01:00
uint32_t port = ( i < < 1 ) + ( ( latching_power > > i ) & 1 ) ;
2018-09-30 15:52:25 +01:00
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
}
2019-09-04 11:58:37 +01:00
void SetDevicePower ( power_t rpower , uint32_t source )
2017-01-28 13:41:01 +00: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-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < MAX_INTERLOCKS ; i + + ) {
2019-01-22 11:46:55 +00:00
power_t mask = 1 ;
2019-09-04 11:47:58 +01:00
uint32_t count = 0 ;
2019-06-30 15:44:36 +01:00
for ( uint32_t j = 0 ; j < devices_present ; j + + ) {
2019-09-04 11:20:04 +01: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
2019-09-04 11:20:04 +01:00
if ( rpower ) { // Any power set
last_power = rpower ;
}
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-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < devices_present ; i + + ) {
2019-09-04 11:47:58 +01:00
power_t state = rpower & 1 ;
2017-10-14 10:26:49 +01:00
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
}
}
2019-09-04 11:58:37 +01:00
void RestorePower ( bool publish_power , uint32_t source )
2019-09-04 11:20:04 +01:00
{
if ( power ! = last_power ) {
SetDevicePower ( last_power , source ) ;
if ( publish_power ) {
MqttPublishAllPowerState ( ) ;
}
}
}
2019-09-04 11:58:37 +01:00
void SetAllPower ( uint32_t state , uint32_t source )
2019-09-04 11:20:04 +01:00
{
// state 0 = POWER_OFF = Relay Off
// state 1 = POWER_ON = Relay On (turn off after Settings.pulse_timer * 100 mSec if enabled)
// state 2 = POWER_TOGGLE = Toggle relay
// state 8 = POWER_OFF_NO_STATE = Relay Off and no publishPowerState
// state 9 = POWER_ON_NO_STATE = Relay On and no publishPowerState
// state 10 = POWER_TOGGLE_NO_STATE = Toggle relay and no publishPowerState
// state 16 = POWER_SHOW_STATE = Show power state
bool publish_power = true ;
if ( ( state > = POWER_OFF_NO_STATE ) & & ( state < = POWER_TOGGLE_NO_STATE ) ) {
state & = 3 ; // POWER_OFF, POWER_ON or POWER_TOGGLE
publish_power = false ;
}
if ( ( state > = POWER_OFF ) & & ( state < = POWER_TOGGLE ) ) {
power_t all_on = ( 1 < < devices_present ) - 1 ;
switch ( state ) {
case POWER_OFF :
power = 0 ;
break ;
case POWER_ON :
power = all_on ;
break ;
case POWER_TOGGLE :
power ^ = all_on ; // Complement current state
}
SetDevicePower ( power , source ) ;
}
if ( publish_power ) {
MqttPublishAllPowerState ( ) ;
}
}
2019-09-04 11:47:58 +01:00
void SetLedPowerIdx ( uint32_t led , uint32_t state )
2019-05-21 17:11:39 +01:00
{
2019-09-04 11:20:04 +01:00
if ( ( 99 = = pin [ GPIO_LEDLNK ] ) & & ( 0 = = led ) ) { // Legacy - LED1 is link led only if LED2 is present
if ( pin [ GPIO_LED2 ] < 99 ) {
led = 1 ;
}
2019-05-21 17:11:39 +01:00
}
if ( pin [ GPIO_LED1 + led ] < 99 ) {
2019-09-04 11:47:58 +01:00
uint32_t mask = 1 < < led ;
2019-05-21 17:11:39 +01:00
if ( state ) {
state = 1 ;
led_power | = mask ;
} else {
led_power & = ( 0xFF ^ mask ) ;
}
digitalWrite ( pin [ GPIO_LED1 + led ] , bitRead ( led_inverted , led ) ? ! state : state ) ;
}
}
2019-09-04 11:47:58 +01:00
void SetLedPower ( uint32_t state )
2019-01-06 17:02:21 +00:00
{
2019-09-04 11:20:04 +01:00
if ( 99 = = pin [ GPIO_LEDLNK ] ) { // Legacy - Only use LED1 and/or LED2
2019-05-21 17:11:39 +01:00
SetLedPowerIdx ( 0 , state ) ;
} else {
power_t mask = 1 ;
2019-09-04 11:20:04 +01:00
for ( uint32_t i = 0 ; i < leds_present ; i + + ) { // Map leds to power
2019-05-21 17:11:39 +01:00
bool tstate = ( power & mask ) ;
SetLedPowerIdx ( i , tstate ) ;
mask < < = 1 ;
}
}
}
2019-01-06 17:02:21 +00:00
2019-09-04 11:47:58 +01:00
void SetLedPowerAll ( uint32_t state )
2019-05-21 17:11:39 +01:00
{
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < leds_present ; i + + ) {
2019-05-21 17:11:39 +01:00
SetLedPowerIdx ( i , state ) ;
}
2019-01-06 17:02:21 +00:00
}
2019-09-04 11:47:58 +01:00
void SetLedLink ( uint32_t state )
2017-01-28 13:41:01 +00:00
{
2019-09-04 11:47:58 +01:00
uint32_t led_pin = pin [ GPIO_LEDLNK ] ;
uint32_t led_inv = ledlnk_inverted ;
2019-09-04 11:20:04 +01:00
if ( 99 = = led_pin ) { // Legacy - LED1 is status
2019-05-21 17:11:39 +01:00
led_pin = pin [ GPIO_LED1 ] ;
led_inv = bitRead ( led_inverted , 0 ) ;
}
if ( led_pin < 99 ) {
if ( state ) { state = 1 ; }
digitalWrite ( led_pin , ( led_inv ) ? ! state : state ) ;
}
2017-01-28 13:41:01 +00:00
}
2019-09-04 11:47:58 +01:00
void SetPulseTimer ( uint32_t index , uint32_t time )
2018-08-26 14:42:35 +01:00
{
pulse_timer [ index ] = ( time > 111 ) ? millis ( ) + ( 1000 * ( time - 100 ) ) : ( time > 0 ) ? millis ( ) + ( 100 * time ) : 0L ;
}
2019-09-04 11:47:58 +01:00
uint32_t GetPulseTimer ( uint32_t index )
2018-08-26 14:42:35 +01:00
{
long time = TimePassedSince ( pulse_timer [ index ] ) ;
if ( time < 0 ) {
time * = - 1 ;
2019-09-04 11:47:58 +01:00
return ( time > 11100 ) ? ( time / 1000 ) + 100 : ( time > 0 ) ? time / 100 : 0 ;
2018-08-26 14:42:35 +01:00
}
2019-09-04 11:47:58 +01:00
return 0 ;
2018-08-26 14:42:35 +01:00
}
2017-02-18 17:08:55 +00:00
/********************************************************************************************/
2019-09-04 11:47:58 +01:00
bool SendKey ( uint32_t key , uint32_t device , uint32_t state )
2017-01-28 13:41:01 +00:00
{
2019-09-04 11:20:04 +01:00
// key 0 = KEY_BUTTON = button_topic
// key 1 = KEY_SWITCH = switch_topic
// state 0 = POWER_OFF = off
// state 1 = POWER_ON = on
// state 2 = POWER_TOGGLE = toggle
// state 3 = POWER_HOLD = hold
// state 9 = CLEAR_RETAIN = 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 " ) ) {
2019-09-04 11:20:04 +01:00
if ( ! key & & ( device > devices_present ) ) {
device = 1 ; // Only allow number of buttons up to number of devices
}
2018-12-06 10:17:25 +00:00
GetTopic_P ( stopic , CMND , key_topic ,
GetPowerDevice ( scommand , device , sizeof ( scommand ) , ( key + Settings . flag . device_index_enable ) ) ) ; // cmnd/switchtopic/POWERx
2019-09-04 11:20:04 +01:00
if ( CLEAR_RETAIN = = state ) {
2017-09-13 13:19:34 +01:00
mqtt_data [ 0 ] = ' \0 ' ;
2017-06-06 22:23:23 +01:00
} else {
2019-09-04 11:20:04 +01:00
if ( ( Settings . flag3 . button_switch_force_local | | ! strcmp ( mqtt_topic , key_topic ) | | ! strcmp ( Settings . mqtt_grptopic , key_topic ) ) & & ( POWER_TOGGLE = = state ) ) {
state = ~ ( power > > ( device - 1 ) ) & 1 ; // POWER_OFF or POWER_ON
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-09-04 11:20:04 +01:00
MqttPublishDirect ( stopic , ( ( key ) ? Settings . flag . mqtt_switch_retain : Settings . flag . mqtt_button_retain ) & & ( state ! = POWER_HOLD | | ! Settings . flag3 . no_hold_retain ) ) ;
2017-06-06 22:23:23 +01:00
}
2017-01-28 13:41:01 +00:00
# else
2019-09-04 11:20:04 +01:00
MqttPublishDirect ( stopic , ( ( key ) ? Settings . flag . mqtt_switch_retain : Settings . flag . mqtt_button_retain ) & & ( state ! = POWER_HOLD | | ! 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-09-04 11:58:37 +01:00
void ExecuteCommandPower ( uint32_t device , uint32_t state , uint32_t source )
2017-01-28 13:41:01 +00:00
{
// device = Relay number 1 and up
2019-09-04 11:20:04 +01:00
// state 0 = POWER_OFF = Relay Off
// state 1 = POWER_ON = Relay On (turn off after Settings.pulse_timer * 100 mSec if enabled)
// state 2 = POWER_TOGGLE = Toggle relay
// state 3 = POWER_BLINK = Blink relay
// state 4 = POWER_BLINK_STOP = Stop blinking relay
// state 8 = POWER_OFF_NO_STATE = Relay Off and no publishPowerState
// state 9 = POWER_ON_NO_STATE = Relay On and no publishPowerState
// state 10 = POWER_TOGGLE_NO_STATE = Toggle relay and no publishPowerState
// state 16 = POWER_SHOW_STATE = Show power state
2017-01-28 13:41:01 +00:00
2018-05-28 14:52:42 +01:00
// ShowSource(source);
2019-07-14 21:08:19 +01:00
# ifdef USE_SONOFF_IFAN
2019-07-14 14:23:02 +01:00
if ( IsModuleIfan ( ) ) {
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
}
2019-07-14 21:08:19 +01:00
# endif // USE_SONOFF_IFAN
2018-07-01 14:06:44 +01:00
2019-09-04 11:20:04 +01:00
bool publish_power = true ;
if ( ( state > = POWER_OFF_NO_STATE ) & & ( state < = POWER_TOGGLE_NO_STATE ) ) {
state & = 3 ; // POWER_OFF, POWER_ON or POWER_TOGGLE
publish_power = false ;
2017-07-15 14:07:30 +01:00
}
2019-06-08 10:38:45 +01:00
2019-09-04 11:20:04 +01:00
if ( ( device < 1 ) | | ( device > devices_present ) ) {
device = 1 ;
}
2019-06-08 10:38:45 +01:00
active_device = device ;
2019-09-04 11:20:04 +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 ;
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < MAX_INTERLOCKS ; i + + ) {
2019-01-25 16:46:27 +00:00
if ( Settings . interlock [ i ] & mask ) { // Find interlock group
2019-06-30 15:44:36 +01:00
for ( uint32_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-09-04 11:20:04 +01: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-09-04 11:47:58 +01:00
bool 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 ) ;
2019-09-04 11:20:04 +01:00
if ( flag ) {
ExecuteCommandPower ( device , ( blink_powersave > > ( device - 1 ) ) & 1 , SRC_IGNORE ) ; // Restore state
}
2017-01-28 13:41:01 +00:00
return ;
}
2019-09-04 11:20:04 +01: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-06-30 15:44:36 +01:00
for ( uint32_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-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-06-30 15:44:36 +01:00
for ( uint32_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 ;
}
}
Add support for Shelly 1PM Template
Add support for Shelly 1PM Template {"NAME":"Shelly 1PM","GPIO":[56,0,0,0,82,134,0,0,0,0,0,21,0],"FLAG":2,"BASE":18} (#5716)
2019-05-13 17:26:07 +01:00
ResponseJsonEnd ( ) ;
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-07-11 13:09:42 +01:00
ResponseAppendTime ( ) ;
ResponseAppend_P ( PSTR ( " , \" " D_JSON_UPTIME " \" : \" %s \" , \" UptimeSec \" :%u " ) , GetUptime ( ) . c_str ( ) , UpTime ( ) ) ;
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-07-31 18:34:23 +01:00
ResponseAppend_P ( PSTR ( " , \" " D_JSON_HEAPSIZE " \" :%d, \" SleepMode \" : \" %s \" , \" Sleep \" :%u, \" LoadAvg \" :%u, \" MqttCount \" :%u " ) ,
ESP . getFreeHeap ( ) / 1024 , GetTextIndexed ( stemp1 , sizeof ( stemp1 ) , Settings . flag3 . sleep_normal , kSleepMode ) , sleep , loop_load_avg , MqttConnectCount ( ) ) ;
2018-12-01 17:53:42 +00:00
2019-08-16 17:33:41 +01:00
for ( uint32_t i = 1 ; i < = devices_present ; i + + ) {
2019-06-16 15:43:23 +01:00
# ifdef USE_LIGHT
2019-08-17 12:17:30 +01:00
if ( ( LightDevice ( ) ) & & ( i > = LightDevice ( ) ) ) {
if ( i = = LightDevice ( ) ) { LightState ( 1 ) ; } // call it only once
2018-01-20 11:12:39 +00:00
} else {
2019-06-16 15:43:23 +01:00
# endif
2019-08-16 17:33:41 +01:00
ResponseAppend_P ( PSTR ( " , \" %s \" : \" %s \" " ) , GetPowerDevice ( stemp1 , i , sizeof ( stemp1 ) , Settings . flag . device_index_enable ) , GetStateText ( bitRead ( power , i - 1 ) ) ) ;
2019-07-14 21:08:19 +01:00
# ifdef USE_SONOFF_IFAN
2019-07-14 14:23:02 +01:00
if ( IsModuleIfan ( ) ) {
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 ;
}
2019-07-14 21:08:19 +01:00
# endif // USE_SONOFF_IFAN
2019-06-16 15:43:23 +01:00
# ifdef USE_LIGHT
2018-01-20 11:12:39 +00:00
}
2019-06-16 15:43:23 +01:00
# endif
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-05-18 08:45:04 +01:00
# ifdef USE_SCRIPT
RulesTeleperiod ( ) ; // Allow rule based HA messages
# endif // USE_SCRIPT
2019-03-20 13:05:43 +00:00
}
2019-01-28 13:08:33 +00:00
bool MqttShowSensor ( void )
2017-02-04 16:09:54 +00:00
{
2019-07-11 13:09:42 +01:00
ResponseAppendTime ( ) ;
2017-11-04 15:36:51 +00:00
int json_data_start = strlen ( mqtt_data ) ;
2019-06-30 15:44:36 +01:00
for ( uint32_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-08-31 09:10:16 +01:00
# ifdef USE_SCRIPT_JSON_EXPORT
XdrvCall ( FUNC_JSON_APPEND ) ;
# endif
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
}
Add support for Shelly 1PM Template
Add support for Shelly 1PM Template {"NAME":"Shelly 1PM","GPIO":[56,0,0,0,82,134,0,0,0,0,0,21,0],"FLAG":2,"BASE":18} (#5716)
2019-05-13 17:26:07 +01:00
ResponseJsonEnd ( ) ;
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 + + ;
2019-06-09 12:34:14 +01:00
if ( ntp_synced_message ) {
// Moved here to fix syslog UDP exception 9 during RtcSecond
2019-07-05 10:47:13 +01:00
AddLog_P2 ( LOG_LEVEL_DEBUG , PSTR ( " NTP: Drift %d, ( " D_UTC_TIME " ) %s, ( " D_DST_TIME " ) %s, ( " D_STD_TIME " ) %s " ) ,
DriftTime ( ) , GetTime ( 0 ) . c_str ( ) , GetTime ( 2 ) . c_str ( ) , GetTime ( 3 ) . c_str ( ) ) ;
2019-06-09 12:34:14 +01:00
ntp_synced_message = false ;
}
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
}
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 ) ;
2019-05-18 08:45:04 +01:00
# if defined(USE_RULES) || defined(USE_SCRIPT)
2018-04-27 17:06:19 +01:00
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-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-06-30 15:44:36 +01:00
for ( uint32_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
2019-09-04 11:47:58 +01:00
uint32_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 ) ) ) {
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
}
}
2019-08-19 21:04:27 +01:00
if ( Settings . ledstate & 1 & & ( pin [ GPIO_LEDLNK ] < 99 | | ! ( blinks | | restart_flag | | ota_state_flag ) ) ) {
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-08-08 15:24:11 +01:00
DEBUG_CORE_LOG ( PSTR ( " 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
2019-06-16 15:43:23 +01:00
if ( MidnightNow ( ) ) {
XsnsCall ( FUNC_SAVE_AT_MIDNIGHT ) ;
}
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-06-30 15:44:36 +01:00
for ( uint32_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
}
2019-05-20 09:25:49 +01:00
if ( 2 = = restart_flag ) {
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
2019-04-13 14:52:32 +01:00
( ( serial_in_byte ! = Settings . serial_delimiter ) & & ( 128 ! = Settings . serial_delimiter ) ) | | // Any char between 1 and 127 and not being delimiter
2019-02-09 12:25:15 +00:00
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
2019-08-10 16:34:59 +01:00
char hex_char [ ( serial_in_byte_counter * 2 ) + 2 ] ;
2019-09-04 17:06:34 +01:00
ResponseTime_P ( PSTR ( " , \" " D_JSON_SERIALRECEIVED " \" : \" %s \" } " ) ,
2019-08-13 18:53:12 +01:00
( Settings . flag . mqtt_serial_raw ) ? ToHex_P ( ( unsigned char * ) serial_in_buffer , serial_in_byte_counter , hex_char , sizeof ( hex_char ) ) : serial_in_buffer ) ;
2018-10-18 12:01:31 +01:00
MqttPublishPrefixTopic_P ( RESULT_OR_TELE , PSTR ( D_JSON_SERIALRECEIVED ) ) ;
2019-05-15 15:31:13 +01:00
XdrvRulesProcess ( ) ;
2018-10-18 12:01:31 +01:00
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
{
2019-09-04 11:47:58 +01:00
uint32_t mpin ;
2017-01-28 13:41:01 +00:00
2019-04-05 14:27:06 +01:00
if ( ! ValidModule ( Settings . module ) ) {
2019-09-04 11:47:58 +01:00
uint32_t module = MODULE ;
2019-04-05 14:27:06 +01:00
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-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < sizeof ( Settings . user_template . gp ) ; i + + ) {
2019-02-17 15:43:52 +00:00
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-06-30 15:44:36 +01:00
for ( uint32_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 ) {
2019-05-13 14:56:01 +01:00
my_module . io [ i ] = Settings . my_gp . io [ i ] ; // Set User selected Module sensors
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 ) ) {
2019-05-13 14:56:01 +01:00
my_module . io [ i ] = def_gp . io [ i ] ; // Force Template override
2017-04-25 17:24:42 +01:00
}
2017-01-28 13:41:01 +00:00
}
2019-05-13 14:56:01 +01:00
if ( ( Settings . my_adc0 > = ADC0_END ) & & ( Settings . my_adc0 < ADC0_USER ) ) {
Settings . my_adc0 = ADC0_NONE ; // Fix not supported sensor ids in module
}
else if ( Settings . my_adc0 > ADC0_NONE ) {
my_adc0 = Settings . my_adc0 ; // Set User selected Module sensors
}
2019-01-07 15:33:18 +00:00
my_module_flag = ModuleFlag ( ) ;
2019-09-04 11:47:58 +01:00
uint32_t template_adc0 = my_module_flag . data & 15 ;
2019-05-13 14:56:01 +01:00
if ( ( template_adc0 > ADC0_NONE ) & & ( template_adc0 < ADC0_USER ) ) {
my_adc0 = template_adc0 ; // Force Template override
}
2017-02-11 14:06:23 +00:00
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < GPIO_MAX ; i + + ) {
2017-04-25 17:24:42 +01:00
pin [ i ] = 99 ;
}
2019-06-30 15:44:36 +01:00
for ( uint32_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-08-08 16:51:49 +01:00
DEBUG_CORE_LOG ( PSTR ( " INI: 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 ) {
2019-08-12 16:18:08 +01:00
XdrvMailbox . index = mpin ;
2019-08-13 13:52:46 +01:00
XdrvMailbox . payload = i ;
2019-08-12 16:18:08 +01:00
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
}
2019-05-21 17:11:39 +01:00
else if ( mpin = = GPIO_LEDLNK_INV ) {
ledlnk_inverted = 1 ;
mpin - = ( GPIO_LEDLNK_INV - GPIO_LEDLNK ) ;
}
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
}
2019-08-12 16:18:08 +01:00
else if ( XdrvCall ( FUNC_PIN_STATE ) ) {
mpin = XdrvMailbox . index ;
}
else if ( XsnsCall ( FUNC_PIN_STATE ) ) {
mpin = XdrvMailbox . index ;
} ;
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-06-30 15:44:36 +01:00
for ( uint32_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-08-13 13:52:46 +01: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
2019-06-16 15:43:23 +01:00
# ifdef USE_LIGHT
2017-10-18 17:22:34 +01:00
if ( Settings . flag . pwm_control ) {
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < MAX_PWMS ; i + + ) {
2019-01-28 13:08:33 +00:00
if ( pin [ GPIO_PWM1 + i ] < 99 ) { light_type + + ; } // Use Dimmer/Color control for all PWM as SetOption15 = 1
2017-10-01 13:32:36 +01:00
}
}
2019-06-16 15:43:23 +01:00
# endif // USE_LIGHT
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-06-16 15:43:23 +01:00
# ifdef USE_LIGHT
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
}
2019-06-16 15:43:23 +01:00
# endif // USE_LIGHT
2017-02-13 16:25:46 +00:00
else {
2019-01-28 13:08:33 +00:00
if ( ! light_type ) { devices_present = 0 ; }
2019-06-30 15:44:36 +01:00
for ( uint32_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-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < MAX_LEDS ; i + + ) {
2017-01-28 13:41:01 +00:00
if ( pin [ GPIO_LED1 + i ] < 99 ) {
2019-05-21 17:11:39 +01:00
# ifdef USE_ARILUX_RF
if ( ( 3 = = i ) & & ( leds_present < 2 ) & & ( 99 = = pin [ GPIO_ARIRFSEL ] ) ) {
pin [ GPIO_ARIRFSEL ] = pin [ GPIO_LED4 ] ; // Legacy support where LED4 was Arilux RF enable
pin [ GPIO_LED4 ] = 99 ;
} else {
# endif
pinMode ( pin [ GPIO_LED1 + i ] , OUTPUT ) ;
leds_present + + ;
digitalWrite ( pin [ GPIO_LED1 + i ] , bitRead ( led_inverted , i ) ) ;
# ifdef USE_ARILUX_RF
}
# endif
2017-01-28 13:41:01 +00:00
}
2017-10-10 14:40:02 +01:00
}
2019-05-21 17:11:39 +01:00
if ( pin [ GPIO_LEDLNK ] < 99 ) {
pinMode ( pin [ GPIO_LEDLNK ] , OUTPUT ) ;
digitalWrite ( pin [ GPIO_LEDLNK ] , ledlnk_inverted ) ;
}
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
2019-06-16 15:43:23 +01:00
# ifdef USE_LIGHT
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
}
2019-06-16 15:43:23 +01:00
# endif // USE_SM16716
2019-08-06 09:57:50 +01:00
// post-process for lights
2019-08-07 11:08:13 +01:00
if ( Settings . flag3 . pwm_multi_channels ) {
2019-08-06 09:57:50 +01:00
uint32_t pwm_channels = ( light_type & 7 ) > LST_MAX ? LST_MAX : ( light_type & 7 ) ;
2019-08-07 11:08:13 +01:00
if ( 0 = = pwm_channels ) { pwm_channels = 1 ; }
2019-08-06 09:57:50 +01:00
devices_present + = pwm_channels - 1 ; // add the pwm channels controls at the end
}
2019-06-16 15:43:23 +01:00
# endif // USE_LIGHT
2018-01-05 11:26:19 +00:00
if ( ! light_type ) {
2019-06-30 15:44:36 +01:00
for ( uint32_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
{
2019-04-13 14:12:25 +01:00
global_state . data = 3 ; // Init global state (wifi_down, mqtt_down) to solve possible network issues
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 ) ;
}
2019-08-28 11:02:27 +01:00
baudrate = Settings . baudrate * 300 ;
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 ;
2019-05-20 14:09:42 +01:00
# else
# ifndef USE_EMULATION_WEMO
if ( EMUL_WEMO = = Settings . flag2 . emulation ) { Settings . flag2 . emulation = 0 ; }
# endif
# ifndef USE_EMULATION_HUE
if ( EMUL_HUE = = Settings . flag2 . emulation ) { Settings . flag2 . emulation = 0 ; }
# endif
2018-11-16 08:36:41 +00:00
# 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
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < MAX_RULE_SETS ; i + + ) {
2019-01-30 13:34:31 +00:00
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
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < sizeof ( Settings . my_gp ) ; i + + ) {
2019-01-30 13:34:31 +00:00
Settings . my_gp . io [ i ] = GPIO_NONE ; // Reset user defined GPIO disabling sensors
}
2019-05-16 17:43:23 +01:00
Settings . my_adc0 = ADC0_NONE ; // Reset user defined ADC0 disabling sensors
2019-01-30 13:34:31 +00:00
}
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-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < devices_present ; i + + ) {
2019-04-18 15:24:46 +01:00
if ( ! Settings . flag3 . no_power_feedback ) { // #5594 and #5663
if ( ( i < MAX_RELAYS ) & & ( pin [ GPIO_REL1 + i ] < 99 ) ) {
bitWrite ( power , i , digitalRead ( pin [ GPIO_REL1 + i ] ) ^ bitRead ( rel_inverted , i ) ) ;
}
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-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
}