mirror of https://github.com/arendst/Tasmota.git
Add deep sleep support
Add define USE_DEEPSLEEP and command DeepSleepTime 0 or 10..86400 (seconds) to enter deepsleep mode (#6638)
This commit is contained in:
parent
ccf13080e2
commit
5527f424a0
|
@ -3,6 +3,7 @@
|
|||
* Add command DimmerRange in Light module to support 2 byte dimming ranges from Tuya
|
||||
* Add Zigbee additional commands and sending messages to control devices (#6095)
|
||||
* Fix Rules were not triggered with IR unknown protocol or in sonoff-it (#6629)
|
||||
* Add define USE_DEEPSLEEP and command DeepSleepTime 0 or 10..86400 (seconds) to enter deepsleep mode (#6638)
|
||||
*
|
||||
* 6.6.0.17 20191009
|
||||
* Add command SetOption34 0..255 to set backlog delay. Default value is 200 (mSeconds) (#6562)
|
||||
|
|
|
@ -316,6 +316,7 @@
|
|||
#define USE_PS_16_DZ // Add support for PS-16-DZ Dimmer and Sonoff L1 (+2k code)
|
||||
//#define ROTARY_V1 // Add support for MI Desk Lamp
|
||||
//#define USE_SHUTTER // Add Shutter support for up to 4 shutter with different motortypes (+6k code)
|
||||
//#define USE_DEEPSLEEP // Add support for deepsleep (+1k code)
|
||||
|
||||
// -- Optional light modules ----------------------
|
||||
#define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+5k code, +1k mem, 232 iram) - Disable by //
|
||||
|
|
|
@ -384,10 +384,11 @@ struct SYSCFG {
|
|||
uint8_t shutter_position[MAX_SHUTTERS]; // E80
|
||||
uint8_t shutter_startrelay[MAX_SHUTTERS]; // E84
|
||||
uint8_t pcf8574_config[MAX_PCF8574]; // E88
|
||||
uint16_t dimmer_hw_min; // E8A
|
||||
uint16_t dimmer_hw_max; // E8C
|
||||
uint16_t dimmer_hw_min; // E90
|
||||
uint16_t dimmer_hw_max; // E92
|
||||
uint32_t deepsleep; // E94
|
||||
|
||||
uint8_t free_e90[356]; // E90
|
||||
uint8_t free_e98[352]; // E98
|
||||
|
||||
uint32_t cfg_timestamp; // FF8
|
||||
uint32_t cfg_crc32; // FFC
|
||||
|
@ -408,7 +409,12 @@ struct RTCMEM {
|
|||
unsigned long pulse_counter[MAX_COUNTERS]; // 29C
|
||||
power_t power; // 2AC
|
||||
EnergyUsage energy_usage; // 2B0
|
||||
uint8_t free_038[36]; // 2C8
|
||||
unsigned long nextwakeup; // 2C8
|
||||
unsigned long uptime_old; // 2CC
|
||||
uint32_t ultradeepsleep; // 2D0
|
||||
uint16_t deepsleep_slip; // 2D4
|
||||
|
||||
uint8_t free_022[22]; // 2D6
|
||||
// 2EC - 2FF free locations
|
||||
} RtcSettings;
|
||||
|
||||
|
|
|
@ -269,7 +269,7 @@ enum LightTypes { LT_BASIC, LT_PWM1, LT_PWM2, LT_PWM3, LT_PWM4, LT
|
|||
enum XsnsFunctions {FUNC_SETTINGS_OVERRIDE, FUNC_PIN_STATE, FUNC_MODULE_INIT, FUNC_PRE_INIT, FUNC_INIT,
|
||||
FUNC_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_100_MSECOND, FUNC_EVERY_200_MSECOND, FUNC_EVERY_250_MSECOND, FUNC_EVERY_300_MSECOND, FUNC_EVERY_SECOND,
|
||||
FUNC_SAVE_AT_MIDNIGHT, FUNC_SAVE_BEFORE_RESTART,
|
||||
FUNC_PREP_BEFORE_TELEPERIOD, FUNC_JSON_APPEND, FUNC_WEB_SENSOR, FUNC_COMMAND, FUNC_COMMAND_SENSOR, FUNC_COMMAND_DRIVER,
|
||||
FUNC_PREP_BEFORE_TELEPERIOD, FUNC_AFTER_TELEPERIOD, FUNC_JSON_APPEND, FUNC_WEB_SENSOR, FUNC_COMMAND, FUNC_COMMAND_SENSOR, FUNC_COMMAND_DRIVER,
|
||||
FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_INIT, FUNC_MQTT_DATA,
|
||||
FUNC_SET_POWER, FUNC_SET_DEVICE_POWER, FUNC_SHOW_SENSOR,
|
||||
FUNC_ENERGY_EVERY_SECOND, FUNC_ENERGY_RESET,
|
||||
|
|
|
@ -107,8 +107,8 @@ int blinks = 201; // Number of LED blinks
|
|||
uint32_t uptime = 0; // Counting every second until 4294967295 = 130 year
|
||||
uint32_t loop_load_avg = 0; // Indicative loop load average
|
||||
uint32_t global_update = 0; // Timestamp of last global temperature and humidity update
|
||||
uint32_t web_log_index = 1; // Index in Web log buffer (should never be 0)
|
||||
float global_temperature = 9999; // Provide a global temperature to be used by some sensors
|
||||
uint32_t web_log_index = 1; // Index in Web log buffer (should never be 0)
|
||||
float global_temperature = 9999; // Provide a global temperature to be used by some sensors
|
||||
float global_humidity = 0; // Provide a global humidity to be used by some sensors
|
||||
float global_pressure = 0; // Provide a global pressure to be used by some sensors
|
||||
char *ota_url; // OTA url string pointer
|
||||
|
@ -155,6 +155,7 @@ bool spi_flg = false; // SPI configured
|
|||
bool soft_spi_flg = false; // Software SPI configured
|
||||
bool ntp_force_sync = false; // Force NTP sync
|
||||
bool ntp_synced_message = false; // NTP synced message flag
|
||||
bool prep_called = false; // Deep sleep flag to detect a proper start of initialize sensors
|
||||
myio my_module; // Active copy of Module GPIOs (17 x 8 bits)
|
||||
gpio_flag my_module_flag; // Active copy of Template GPIO flags
|
||||
StateBitfield global_state; // Global states (currently Wifi and Mqtt) (8 bits)
|
||||
|
@ -169,12 +170,12 @@ char log_data[LOGSZ]; // Logging
|
|||
char web_log[WEB_LOG_SIZE] = {'\0'}; // Web log buffer
|
||||
#ifdef SUPPORT_IF_STATEMENT
|
||||
#include <LinkedList.h>
|
||||
LinkedList<String> backlog; // Command backlog implemented with LinkedList
|
||||
LinkedList<String> backlog; // Command backlog implemented with LinkedList
|
||||
#define BACKLOG_EMPTY (backlog.size() == 0)
|
||||
#else
|
||||
uint8_t backlog_index = 0; // Command backlog index
|
||||
uint8_t backlog_pointer = 0; // Command backlog pointer
|
||||
String backlog[MAX_BACKLOG]; // Command backlog buffer
|
||||
uint8_t backlog_index = 0; // Command backlog index
|
||||
uint8_t backlog_pointer = 0; // Command backlog pointer
|
||||
String backlog[MAX_BACKLOG]; // Command backlog buffer
|
||||
#define BACKLOG_EMPTY (backlog_pointer == backlog_index)
|
||||
#endif
|
||||
|
||||
|
@ -809,10 +810,14 @@ void PerformEverySecond(void)
|
|||
|
||||
if (Settings.tele_period) {
|
||||
tele_period++;
|
||||
if (tele_period == Settings.tele_period -1) {
|
||||
// increase time for prepare and document state to ensure TELEPERIOD deliver results
|
||||
if (tele_period == Settings.tele_period -3 && !prep_called) {
|
||||
// sensores must be called later if driver switch on e.g. power on deepsleep
|
||||
XdrvCall(FUNC_PREP_BEFORE_TELEPERIOD);
|
||||
XsnsCall(FUNC_PREP_BEFORE_TELEPERIOD);
|
||||
prep_called = true;
|
||||
}
|
||||
if (tele_period >= Settings.tele_period) {
|
||||
if (tele_period >= Settings.tele_period && prep_called) {
|
||||
tele_period = 0;
|
||||
|
||||
MqttPublishTeleState();
|
||||
|
@ -824,6 +829,8 @@ void PerformEverySecond(void)
|
|||
RulesTeleperiod(); // Allow rule based HA messages
|
||||
#endif // USE_RULES
|
||||
}
|
||||
prep_called = true;
|
||||
XdrvCall(FUNC_AFTER_TELEPERIOD);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -206,6 +206,7 @@ enum UserSelectablePins {
|
|||
GPIO_DDSU666_RX, // DDSU666 Serial interface
|
||||
GPIO_SM2135_CLK, // SM2135 Clk
|
||||
GPIO_SM2135_DAT, // SM2135 Dat
|
||||
GPIO_DEEPSLEEP, // Kill switch for deepsleep
|
||||
GPIO_SENSOR_END };
|
||||
|
||||
// Programmer selectable GPIO functionality
|
||||
|
@ -283,6 +284,7 @@ const char kSensorNames[] PROGMEM =
|
|||
D_SENSOR_DDS2382_TX "|" D_SENSOR_DDS2382_RX "|"
|
||||
D_SENSOR_DDSU666_TX "|" D_SENSOR_DDSU666_RX "|"
|
||||
D_SENSOR_SM2135_CLK "|" D_SENSOR_SM2135_DAT "|"
|
||||
D_SENSOR_DEEPSLEEP "|"
|
||||
;
|
||||
|
||||
const char kSensorNamesFixed[] PROGMEM =
|
||||
|
@ -738,6 +740,9 @@ const uint8_t kGpioNiceList[] PROGMEM = {
|
|||
GPIO_A4988_MS2, // A4988 microstep pin2
|
||||
GPIO_A4988_MS3, // A4988 microstep pin3
|
||||
#endif
|
||||
#ifdef USE_DEEPSLEEP
|
||||
GPIO_DEEPSLEEP
|
||||
#endif
|
||||
};
|
||||
|
||||
const uint8_t kModuleNiceList[] PROGMEM = {
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
xdrv_29_deepsleep.ino - DeepSleep support for Sonoff-Tasmota
|
||||
|
||||
Copyright (C) 2019 Stefan Bode
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifdef USE_DEEPSLEEP
|
||||
/*********************************************************************************************\
|
||||
* DeepSleep Support
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define XDRV_29 29
|
||||
|
||||
#define MAX_DEEPSLEEP_CYCLE 3600 // Maximum time for a deepsleep
|
||||
#define MIN_DEEPSLEEP_TIME 5
|
||||
|
||||
#define D_PRFX_DEEPSLEEP "DeepSleep"
|
||||
#define D_CMND_DEEPSLEEP_TIME "Time"
|
||||
|
||||
const char kDeepsleepCommands[] PROGMEM = D_PRFX_DEEPSLEEP "|"
|
||||
D_CMND_DEEPSLEEP_TIME ;
|
||||
|
||||
void (* const DeepsleepCommand[])(void) PROGMEM = {
|
||||
&CmndDeepsleepTime };
|
||||
|
||||
const char JSON_DEEPSLEEP[] PROGMEM = "\"" D_PRFX_DEEPSLEEP "%d\":{\"Time\":%d}";
|
||||
|
||||
void DeepSleepInit(void)
|
||||
{
|
||||
if (pin[GPIO_DEEPSLEEP] < 99) {
|
||||
if (!digitalRead(pin[GPIO_DEEPSLEEP])) {
|
||||
RtcSettings.ultradeepsleep = 0;
|
||||
}
|
||||
}
|
||||
if ((RtcSettings.ultradeepsleep > MAX_DEEPSLEEP_CYCLE) && (RtcSettings.ultradeepsleep < 1700000000)) {
|
||||
RtcSettings.ultradeepsleep = RtcSettings.ultradeepsleep - MAX_DEEPSLEEP_CYCLE;
|
||||
RtcReboot.fast_reboot_count = 0;
|
||||
RtcRebootSave();
|
||||
AddLog_P2(LOG_LEVEL_ERROR, PSTR("DSL: Remain DeepSleep %d"), RtcSettings.ultradeepsleep);
|
||||
RtcSettingsSave();
|
||||
ESP.deepSleep(100 * RtcSettings.deepsleep_slip * (MAX_DEEPSLEEP_CYCLE < RtcSettings.ultradeepsleep ? MAX_DEEPSLEEP_CYCLE : RtcSettings.ultradeepsleep), WAKE_RF_DEFAULT);
|
||||
yield();
|
||||
}
|
||||
RtcSettings.ultradeepsleep = 0;
|
||||
}
|
||||
|
||||
void CheckForDeepsleep(void)
|
||||
{
|
||||
uint8_t disable_deepsleep_switch = 0;
|
||||
if (pin[GPIO_DEEPSLEEP] < 99) {
|
||||
disable_deepsleep_switch = !digitalRead(pin[GPIO_DEEPSLEEP]);
|
||||
}
|
||||
// new function AFTER_TELEPERIOD can take some time therefore <2
|
||||
if ((Settings.deepsleep > 10) && (Settings.deepsleep < 4294967295) && !disable_deepsleep_switch && (tele_period < 2) && prep_called) {
|
||||
SettingsSaveAll();
|
||||
Response_P(S_OFFLINE);
|
||||
MqttPublishPrefixTopic_P(TELE, PSTR(D_LWT), true); // Offline or remove previous retained topic
|
||||
yield();
|
||||
// deepsleep_slip is ideally 10.000 == 100%
|
||||
// typically the device has up to 4% slip. Anything else is a wrong setting in the deepsleep_slip
|
||||
// therefore all values >110% or <90% will be resetted to 100% to avoid crazy sleep times.
|
||||
// This should normally never executed, but can happen an manual wakeup and problems during wakeup
|
||||
if ((RtcSettings.nextwakeup == 0) || (RtcSettings.deepsleep_slip < 9000) || (RtcSettings.deepsleep_slip > 11000) || (RtcSettings.nextwakeup > (UtcTime() + Settings.deepsleep))) {
|
||||
AddLog_P2(LOG_LEVEL_ERROR, PSTR("DSL: Reset wrong settings wakeup: %ld, slip %ld"), RtcSettings.nextwakeup, RtcSettings.deepsleep_slip );
|
||||
RtcSettings.nextwakeup = 0;
|
||||
RtcSettings.deepsleep_slip = 10000;
|
||||
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("new settings wakeup: %ld, slip %ld"), RtcSettings.nextwakeup, RtcSettings.deepsleep_slip );
|
||||
}
|
||||
// timeslip in 0.1 seconds between the real wakeup and the calculated wakeup
|
||||
// because deepsleep is in second and timeslip in 0.1 sec the compare always check if the slip is in the 10% range
|
||||
int16_t timeslip = (int16_t)(RtcSettings.nextwakeup+millis()/1000-UtcTime())*10;
|
||||
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("DSL: Timeslip 0.1 sec:? %d < %d < %ld"), -Settings.deepsleep, timeslip, Settings.deepsleep );
|
||||
//allow 10% of deepsleep error to count as valid deepsleep; expecting 3-4%
|
||||
// if more then 10% timeslip = 0 == non valid wakeup; maybe manual
|
||||
timeslip = (timeslip < -(int32_t)Settings.deepsleep) ? 0 : (timeslip > (int32_t)Settings.deepsleep) ? 0 : 1;
|
||||
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("DSL: Normal deepsleep? %d"), timeslip );
|
||||
if (timeslip) {
|
||||
RtcSettings.deepsleep_slip = (Settings.deepsleep + RtcSettings.nextwakeup-UtcTime()) * RtcSettings.deepsleep_slip / (Settings.deepsleep - (millis() / 1000));
|
||||
//Avoid crazy numbers. Again maximum 10% deviation.
|
||||
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("DSL: %% calculate drift %ld"), RtcSettings.deepsleep_slip );
|
||||
RtcSettings.deepsleep_slip = tmin(tmax(RtcSettings.deepsleep_slip, 9000),11000);
|
||||
|
||||
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("DSL: %% new drift %ld"), RtcSettings.deepsleep_slip );
|
||||
RtcSettings.nextwakeup += Settings.deepsleep;
|
||||
}
|
||||
// it may happen that wakeup in just <5 seconds in future
|
||||
// in this case also add deepsleep to nextwakeup
|
||||
if (RtcSettings.nextwakeup <= (UtcTime() - MIN_DEEPSLEEP_TIME)) {
|
||||
// ensure nextwakeup is at least in the future
|
||||
RtcSettings.nextwakeup += (((UtcTime() + MIN_DEEPSLEEP_TIME - RtcSettings.nextwakeup) / Settings.deepsleep) + 1) * Settings.deepsleep;
|
||||
}
|
||||
Response_P(PSTR("%d"), RtcSettings.nextwakeup);
|
||||
MqttPublishPrefixTopic_P(TELE, PSTR(D_DOMOTICZ_UPDATE_TIMER), false); // Offline or remove previous retained topic
|
||||
yield();
|
||||
MqttDisconnect();
|
||||
String dt = GetDT(RtcSettings.nextwakeup + LocalTime() - UtcTime()); // 2017-03-07T11:08:02
|
||||
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("DSL: Next wakeup %s"), (char*)dt.c_str());
|
||||
//limit sleeptime to MAX_DEEPSLEEP_CYCLE
|
||||
//uint32_t sleeptime = MAX_DEEPSLEEP_CYCLE < (RtcSettings.nextwakeup - UtcTime()) ? (uint32_t)MAX_DEEPSLEEP_CYCLE : RtcSettings.nextwakeup - UtcTime();
|
||||
uint32_t sleeptime = tmin((uint32_t)MAX_DEEPSLEEP_CYCLE , RtcSettings.nextwakeup - UtcTime());
|
||||
|
||||
RtcSettings.ultradeepsleep = RtcSettings.nextwakeup - UtcTime();
|
||||
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("DSL: Sleeptime %d sec, deepsleep_slip %ld"), sleeptime, RtcSettings.deepsleep_slip);
|
||||
RtcSettingsSave();
|
||||
ESP.deepSleep(100 * RtcSettings.deepsleep_slip * sleeptime);
|
||||
yield();
|
||||
}
|
||||
prep_called = false;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Commands
|
||||
\*********************************************************************************************/
|
||||
|
||||
void CmndDeepsleepTime(void)
|
||||
{
|
||||
// if ((XdrvMailbox.payload == 0) || ((XdrvMailbox.payload > 10) && (XdrvMailbox.payload < 4294967295))) {
|
||||
if ((XdrvMailbox.payload == 0) || ((XdrvMailbox.payload > 10) && (XdrvMailbox.payload < (24 * 60 * 60)))) { // Allow max 24 hours sleep
|
||||
Settings.deepsleep = XdrvMailbox.payload;
|
||||
RtcSettings.nextwakeup = 0;
|
||||
}
|
||||
Response_P(S_JSON_COMMAND_NVALUE, XdrvMailbox.command, Settings.deepsleep);
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
||||
bool Xdrv29(uint8_t function)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
switch (function) {
|
||||
case FUNC_AFTER_TELEPERIOD:
|
||||
CheckForDeepsleep();
|
||||
break;
|
||||
case FUNC_COMMAND:
|
||||
result = DecodeCommand(kDeepsleepCommands, DeepsleepCommand);
|
||||
break;
|
||||
case FUNC_PRE_INIT:
|
||||
DeepSleepInit();
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif //USE_DEEPSLEEP
|
Loading…
Reference in New Issue