2018-03-23 16:20:20 +00:00
/*
2019-10-27 10:13:24 +00:00
xdrv_09_timers . ino - timer support for Tasmota
2018-03-23 16:20:20 +00:00
2019-01-01 12:55:01 +00:00
Copyright ( C ) 2019 Theo Arends
2018-03-23 16:20:20 +00: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/>.
*/
# ifdef USE_TIMERS
/*********************************************************************************************\
* Timers
*
* Arm a timer using one or all of the following JSON values :
2018-04-25 16:27:40 +01:00
* { " Arm " : 1 , " Mode " : 0 , " Time " : " 09:23 " , " Window " : 0 , " Days " : " --TW--S " , " Repeat " : 1 , " Output " : 1 , " Action " : 1 }
2018-03-23 16:20:20 +00:00
*
2018-04-12 13:01:43 +01:00
* Arm 0 = Off , 1 = On
* Mode 0 = Schedule , 1 = Sunrise , 2 = Sunset
* Time hours : minutes
2018-04-18 16:28:45 +01:00
* Window minutes ( 0. .15 )
2018-04-12 13:01:43 +01:00
* Days 7 day character mask starting with Sunday ( SMTWTFS ) . 0 or - = Off , any other value = On
* Repeat 0 = Execute once , 1 = Execute again
* Output 1. .16
* Action 0 = Off , 1 = On , 2 = Toggle , 3 = Blink or Rule if USE_RULES enabled
2018-03-23 16:20:20 +00:00
*
2019-08-09 13:07:35 +01:00
* Window allows Time offset for + / - 15 minutes max as long as Time is not within Window from 00 : 00
2018-03-23 16:20:20 +00:00
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2018-11-07 09:30:03 +00:00
# define XDRV_09 9
2019-08-11 17:12:18 +01:00
const char kTimerCommands [ ] PROGMEM = " | " // No prefix
2019-08-02 14:13:51 +01:00
D_CMND_TIMER " | " D_CMND_TIMERS
2018-04-05 11:49:43 +01:00
# ifdef USE_SUNRISE
2019-08-02 14:13:51 +01:00
" | " D_CMND_LATITUDE " | " D_CMND_LONGITUDE
2018-04-05 11:49:43 +01:00
# endif
2019-08-02 14:13:51 +01:00
;
void ( * const TimerCommand [ ] ) ( void ) PROGMEM = {
& CmndTimer , & CmndTimers
2018-04-05 11:49:43 +01:00
# ifdef USE_SUNRISE
2019-08-02 14:13:51 +01:00
, & CmndLatitude , & CmndLongitude
2018-04-05 11:49:43 +01:00
# endif
2019-08-02 14:13:51 +01:00
} ;
2018-03-23 16:20:20 +00:00
2018-04-05 11:49:43 +01:00
uint16_t timer_last_minute = 60 ;
2018-04-18 16:28:45 +01:00
int8_t timer_window [ MAX_TIMERS ] = { 0 } ;
2018-04-05 11:49:43 +01:00
# ifdef USE_SUNRISE
/*********************************************************************************************\
* Sunrise and sunset ( + 13 k code )
*
* https : //forum.arduino.cc/index.php?topic=218280.0
* Source : C - Programm von http : //lexikon.astronomie.info/zeitgleichung/neu.html
* Rewrite for Arduino by ' jurs ' for German Arduino forum
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-06-21 15:57:42 +01:00
const float pi2 = TWO_PI ;
const float pi = PI ;
const float RAD = DEG_TO_RAD ;
2018-04-05 11:49:43 +01:00
2019-06-21 15:57:42 +01:00
float JulianischesDatum ( void )
2018-04-05 11:49:43 +01:00
{
// Gregorianischer Kalender
int Gregor ;
int Jahr = RtcTime . year ;
int Monat = RtcTime . month ;
int Tag = RtcTime . day_of_month ;
if ( Monat < = 2 ) {
Monat + = 12 ;
Jahr - = 1 ;
}
Gregor = ( Jahr / 400 ) - ( Jahr / 100 ) + ( Jahr / 4 ) ; // Gregorianischer Kalender
2019-06-21 15:57:42 +01:00
return 2400000.5f + 365.0f * Jahr - 679004.0f + Gregor + ( int ) ( 30.6001f * ( Monat + 1 ) ) + Tag + 0.5f ;
2018-04-05 11:49:43 +01:00
}
2019-06-21 15:57:42 +01:00
float InPi ( float x )
2018-04-05 11:49:43 +01:00
{
int n = ( int ) ( x / pi2 ) ;
x = x - n * pi2 ;
if ( x < 0 ) x + = pi2 ;
return x ;
}
2019-06-21 15:57:42 +01:00
float eps ( float T )
2018-04-05 11:49:43 +01:00
{
// Neigung der Erdachse
2019-06-21 15:57:42 +01:00
return RAD * ( 23.43929111f + ( - 46.8150f * T - 0.00059f * T * T + 0.001813f * T * T * T ) / 3600.0f ) ;
2018-04-05 11:49:43 +01:00
}
2019-06-21 15:57:42 +01:00
float BerechneZeitgleichung ( float * DK , float T )
2018-04-05 11:49:43 +01:00
{
2019-06-21 15:57:42 +01:00
float RA_Mittel = 18.71506921f + 2400.0513369f * T + ( 2.5862e-5 f - 1.72e-9 f * T ) * T * T ;
float M = InPi ( pi2 * ( 0.993133f + 99.997361f * T ) ) ;
float L = InPi ( pi2 * ( 0.7859453f + M / pi2 + ( 6893.0f * sinf ( M ) + 72.0f * sinf ( 2.0f * M ) + 6191.2f * T ) / 1296.0e3 f ) ) ;
float e = eps ( T ) ;
float RA = atanf ( tanf ( L ) * cosf ( e ) ) ;
2018-04-05 11:49:43 +01:00
if ( RA < 0.0 ) RA + = pi ;
if ( L > pi ) RA + = pi ;
RA = 24.0 * RA / pi2 ;
2019-06-21 15:57:42 +01:00
* DK = asinf ( sinf ( e ) * sinf ( L ) ) ;
2018-04-05 11:49:43 +01:00
// Damit 0<=RA_Mittel<24
2019-06-21 15:57:42 +01:00
RA_Mittel = 24.0f * InPi ( pi2 * RA_Mittel / 24.0f ) / pi2 ;
float dRA = RA_Mittel - RA ;
if ( dRA < - 12.0f ) dRA + = 24.0f ;
if ( dRA > 12.0f ) dRA - = 24.0f ;
dRA = dRA * 1.0027379f ;
2018-04-05 11:49:43 +01:00
return dRA ;
}
void DuskTillDawn ( uint8_t * hour_up , uint8_t * minute_up , uint8_t * hour_down , uint8_t * minute_down )
{
2019-06-21 15:57:42 +01:00
float JD2000 = 2451545.0f ;
float JD = JulianischesDatum ( ) ;
float T = ( JD - JD2000 ) / 36525.0f ;
float DK ;
2018-04-05 11:49:43 +01:00
/*
h ( D ) = - 0.8333 normaler SA & SU - Gang
h ( D ) = - 6.0 civile Dämmerung
h ( D ) = - 12.0 nautische Dämmerung
h ( D ) = - 18.0 astronomische Dämmerung
*/
2018-04-23 10:37:46 +01:00
// double h = -50/60.0*RAD;
2019-06-21 15:57:42 +01:00
float h = SUNRISE_DAWN_ANGLE * RAD ;
2019-06-21 18:23:35 +01:00
float B = ( ( ( float ) Settings . latitude ) / 1000000 ) * RAD ; // geographische Breite
float GeographischeLaenge = ( ( float ) Settings . longitude ) / 1000000 ;
2018-04-17 16:05:24 +01:00
// double Zeitzone = 0; //Weltzeit
// double Zeitzone = 1; //Winterzeit
// double Zeitzone = 2.0; //Sommerzeit
2019-08-17 15:49:17 +01:00
float Zeitzone = ( ( float ) Rtc . time_timezone ) / 60 ;
2019-06-21 15:57:42 +01:00
float Zeitgleichung = BerechneZeitgleichung ( & DK , T ) ;
float Zeitdifferenz = 12.0f * acosf ( ( sinf ( h ) - sinf ( B ) * sinf ( DK ) ) / ( cosf ( B ) * cosf ( DK ) ) ) / pi ;
float AufgangOrtszeit = 12.0f - Zeitdifferenz - Zeitgleichung ;
float UntergangOrtszeit = 12.0f + Zeitdifferenz - Zeitgleichung ;
float AufgangWeltzeit = AufgangOrtszeit - GeographischeLaenge / 15.0f ;
float UntergangWeltzeit = UntergangOrtszeit - GeographischeLaenge / 15.0f ;
float Aufgang = AufgangWeltzeit + Zeitzone ; // In Stunden
if ( Aufgang < 0.0f ) {
Aufgang + = 24.0f ;
2018-04-05 11:49:43 +01:00
} else {
2019-06-21 15:57:42 +01:00
if ( Aufgang > = 24.0f ) Aufgang - = 24.0f ;
2018-04-05 11:49:43 +01:00
}
2019-06-21 15:57:42 +01:00
float Untergang = UntergangWeltzeit + Zeitzone ;
if ( Untergang < 0.0f ) {
Untergang + = 24.0f ;
2018-04-05 11:49:43 +01:00
} else {
2019-06-21 15:57:42 +01:00
if ( Untergang > = 24.0f ) Untergang - = 24.0f ;
2018-04-05 11:49:43 +01:00
}
2019-06-21 15:57:42 +01:00
int AufgangMinuten = ( int ) ( 60.0f * ( Aufgang - ( int ) Aufgang ) + 0.5f ) ;
2018-04-05 11:49:43 +01:00
int AufgangStunden = ( int ) Aufgang ;
2019-06-21 15:57:42 +01:00
if ( AufgangMinuten > = 60.0f ) {
AufgangMinuten - = 60.0f ;
2018-04-05 11:49:43 +01:00
AufgangStunden + + ;
} else {
2019-06-21 15:57:42 +01:00
if ( AufgangMinuten < 0.0f ) {
AufgangMinuten + = 60.0f ;
2018-04-05 11:49:43 +01:00
AufgangStunden - - ;
2019-06-21 15:57:42 +01:00
if ( AufgangStunden < 0.0f ) AufgangStunden + = 24.0f ;
2018-04-05 11:49:43 +01:00
}
}
2019-06-21 15:57:42 +01:00
int UntergangMinuten = ( int ) ( 60.0f * ( Untergang - ( int ) Untergang ) + 0.5f ) ;
2018-04-05 11:49:43 +01:00
int UntergangStunden = ( int ) Untergang ;
2019-06-21 15:57:42 +01:00
if ( UntergangMinuten > = 60.0f ) {
UntergangMinuten - = 60.0f ;
2018-04-05 11:49:43 +01:00
UntergangStunden + + ;
} else {
if ( UntergangMinuten < 0 ) {
2019-06-21 15:57:42 +01:00
UntergangMinuten + = 60.0f ;
2018-04-05 11:49:43 +01:00
UntergangStunden - - ;
2019-06-21 15:57:42 +01:00
if ( UntergangStunden < 0.0f ) UntergangStunden + = 24.0f ;
2018-04-05 11:49:43 +01:00
}
}
* hour_up = AufgangStunden ;
* minute_up = AufgangMinuten ;
* hour_down = UntergangStunden ;
* minute_down = UntergangMinuten ;
}
2018-04-14 17:00:18 +01:00
void ApplyTimerOffsets ( Timer * duskdawn )
{
uint8_t hour [ 2 ] ;
uint8_t minute [ 2 ] ;
Timer stored = ( Timer ) * duskdawn ;
// replace hours, minutes by sunrise
DuskTillDawn ( & hour [ 0 ] , & minute [ 0 ] , & hour [ 1 ] , & minute [ 1 ] ) ;
uint8_t mode = ( duskdawn - > mode - 1 ) & 1 ;
duskdawn - > time = ( hour [ mode ] * 60 ) + minute [ mode ] ;
// apply offsets, check for over- and underflows
uint16_t timeBuffer ;
2018-09-30 16:52:41 +01:00
if ( ( uint16_t ) stored . time > 719 ) {
2018-04-14 17:00:18 +01:00
// negative offset, time after 12:00
timeBuffer = ( uint16_t ) stored . time - 720 ;
// check for underflow
if ( timeBuffer > ( uint16_t ) duskdawn - > time ) {
timeBuffer = 1440 - ( timeBuffer - ( uint16_t ) duskdawn - > time ) ;
duskdawn - > days = duskdawn - > days > > 1 ;
2018-04-27 17:06:19 +01:00
duskdawn - > days | = ( stored . days < < 6 ) ;
2018-04-14 17:00:18 +01:00
} else {
timeBuffer = ( uint16_t ) duskdawn - > time - timeBuffer ;
}
} else {
// positive offset
timeBuffer = ( uint16_t ) duskdawn - > time + ( uint16_t ) stored . time ;
// check for overflow
if ( timeBuffer > 1440 ) {
timeBuffer - = 1440 ;
duskdawn - > days = duskdawn - > days < < 1 ;
2018-04-27 17:06:19 +01:00
duskdawn - > days | = ( stored . days > > 6 ) ;
2018-04-14 17:00:18 +01:00
}
}
duskdawn - > time = timeBuffer ;
}
2019-08-02 14:13:51 +01:00
String GetSun ( uint32_t dawn )
2018-04-05 11:49:43 +01:00
{
char stime [ 6 ] ;
uint8_t hour [ 2 ] ;
uint8_t minute [ 2 ] ;
DuskTillDawn ( & hour [ 0 ] , & minute [ 0 ] , & hour [ 1 ] , & minute [ 1 ] ) ;
dawn & = 1 ;
snprintf_P ( stime , sizeof ( stime ) , PSTR ( " %02d:%02d " ) , hour [ dawn ] , minute [ dawn ] ) ;
return String ( stime ) ;
}
2019-08-02 14:13:51 +01:00
uint16_t SunMinutes ( uint32_t dawn )
2018-04-05 11:49:43 +01:00
{
uint8_t hour [ 2 ] ;
uint8_t minute [ 2 ] ;
DuskTillDawn ( & hour [ 0 ] , & minute [ 0 ] , & hour [ 1 ] , & minute [ 1 ] ) ;
dawn & = 1 ;
return ( hour [ dawn ] * 60 ) + minute [ dawn ] ;
}
# endif // USE_SUNRISE
/*******************************************************************************************/
2018-03-23 16:20:20 +00:00
2019-08-03 12:01:34 +01:00
void TimerSetRandomWindow ( uint32_t index )
2018-04-18 16:28:45 +01:00
{
timer_window [ index ] = 0 ;
if ( Settings . timer [ index ] . window ) {
timer_window [ index ] = ( random ( 0 , ( Settings . timer [ index ] . window < < 1 ) + 1 ) ) - Settings . timer [ index ] . window ; // -15 .. 15
}
}
2018-11-14 13:32:09 +00:00
void TimerSetRandomWindows ( void )
2018-04-18 16:28:45 +01:00
{
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < MAX_TIMERS ; i + + ) { TimerSetRandomWindow ( i ) ; }
2018-04-18 16:28:45 +01:00
}
2018-11-14 13:32:09 +00:00
void TimerEverySecond ( void )
2018-03-23 16:20:20 +00:00
{
if ( RtcTime . valid ) {
2018-04-18 16:28:45 +01:00
if ( ! RtcTime . hour & & ! RtcTime . minute & & ! RtcTime . second ) { TimerSetRandomWindows ( ) ; } // Midnight
2019-11-03 12:51:22 +00:00
if ( Settings . flag3 . timers_enable & & // CMND_TIMERS
( uptime > 60 ) & & ( RtcTime . minute ! = timer_last_minute ) ) { // Execute from one minute after restart every minute only once
2018-04-05 11:49:43 +01:00
timer_last_minute = RtcTime . minute ;
2019-08-02 14:13:51 +01:00
int32_t time = ( RtcTime . hour * 60 ) + RtcTime . minute ;
2018-04-05 11:49:43 +01:00
uint8_t days = 1 < < ( RtcTime . day_of_week - 1 ) ;
2018-03-23 16:20:20 +00:00
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < MAX_TIMERS ; i + + ) {
2018-04-25 16:27:40 +01:00
// if (Settings.timer[i].device >= devices_present) Settings.timer[i].data = 0; // Reset timer due to change in devices present
2018-04-14 17:00:18 +01:00
Timer xtimer = Settings . timer [ i ] ;
2018-04-05 11:49:43 +01:00
# ifdef USE_SUNRISE
2019-08-09 13:07:35 +01:00
if ( ( 1 = = xtimer . mode ) | | ( 2 = = xtimer . mode ) ) { // Sunrise or Sunset
2018-04-14 17:00:18 +01:00
ApplyTimerOffsets ( & xtimer ) ;
2018-04-05 11:49:43 +01:00
}
# endif
2018-04-14 17:00:18 +01:00
if ( xtimer . arm ) {
2019-08-09 13:07:35 +01:00
int32_t set_time = xtimer . time + timer_window [ i ] ; // Add random time offset
if ( set_time < 0 ) {
set_time = abs ( timer_window [ i ] ) ; // After midnight and within negative window so stay today but allow positive randomness;
2019-08-08 14:17:39 +01:00
}
2019-08-09 13:07:35 +01:00
if ( set_time > 1439 ) {
set_time = xtimer . time - abs ( timer_window [ i ] ) ; // Before midnight and within positive window so stay today but allow negative randomness;
}
if ( set_time > 1439 ) { set_time = 1439 ; } // Stay today
DEBUG_DRIVER_LOG ( PSTR ( " TIM: Timer %d, Time %d, Window %d, SetTime %d " ) , i + 1 , xtimer . time , timer_window [ i ] , set_time ) ;
2018-04-05 11:49:43 +01:00
if ( time = = set_time ) {
2018-04-14 17:00:18 +01:00
if ( xtimer . days & days ) {
Settings . timer [ i ] . arm = xtimer . repeat ;
2019-05-18 08:45:04 +01:00
# if defined(USE_RULES) || defined(USE_SCRIPT)
2019-09-04 11:20:04 +01:00
if ( POWER_BLINK = = xtimer . power ) { // Blink becomes Rule disregarding device and allowing use of Backlog commands
2019-03-23 16:57:31 +00:00
Response_P ( PSTR ( " { \" Clock \" :{ \" Timer \" :%d}} " ) , i + 1 ) ;
2018-05-24 15:23:20 +01:00
XdrvRulesProcess ( ) ;
2018-04-12 13:01:43 +01:00
} else
2018-04-13 16:42:11 +01:00
# endif // USE_RULES
2018-05-28 14:52:42 +01:00
if ( devices_present ) { ExecuteCommandPower ( xtimer . device + 1 , xtimer . power , SRC_TIMER ) ; }
2018-04-05 11:49:43 +01:00
}
2018-03-23 16:20:20 +00:00
}
}
}
}
}
}
2019-08-02 14:13:51 +01:00
void PrepShowTimer ( uint32_t index )
2018-03-23 16:20:20 +00:00
{
2018-04-14 17:00:18 +01:00
Timer xtimer = Settings . timer [ index - 1 ] ;
2019-08-02 14:13:51 +01:00
char days [ 8 ] = { 0 } ;
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < 7 ; i + + ) {
2018-03-23 16:20:20 +00:00
uint8_t mask = 1 < < i ;
2018-04-14 17:00:18 +01:00
snprintf ( days , sizeof ( days ) , " %s%d " , days , ( ( xtimer . days & mask ) > 0 ) ) ;
2018-03-23 16:20:20 +00:00
}
2018-04-25 16:27:40 +01:00
2019-08-02 14:13:51 +01:00
char soutput [ 80 ] ;
2018-04-25 16:27:40 +01:00
soutput [ 0 ] = ' \0 ' ;
if ( devices_present ) {
snprintf_P ( soutput , sizeof ( soutput ) , PSTR ( " , \" " D_JSON_TIMER_OUTPUT " \" :%d " ) , xtimer . device + 1 ) ;
}
2018-04-05 11:49:43 +01:00
# ifdef USE_SUNRISE
2019-08-02 14:13:51 +01:00
char sign [ 2 ] = { 0 } ;
2018-04-14 17:00:18 +01:00
int16_t hour = xtimer . time / 60 ;
if ( ( 1 = = xtimer . mode ) | | ( 2 = = xtimer . mode ) ) { // Sunrise or Sunset
2018-05-04 08:54:56 +01:00
if ( hour > 11 ) {
hour - = 12 ;
sign [ 0 ] = ' - ' ;
}
2018-04-14 17:00:18 +01:00
}
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " \" " D_CMND_TIMER " %d \" :{ \" " D_JSON_TIMER_ARM " \" :%d, \" " D_JSON_TIMER_MODE " \" :%d, \" " D_JSON_TIMER_TIME " \" : \" %s%02d:%02d \" , \" " D_JSON_TIMER_WINDOW " \" :%d, \" " D_JSON_TIMER_DAYS " \" : \" %s \" , \" " D_JSON_TIMER_REPEAT " \" :%d%s, \" " D_JSON_TIMER_ACTION " \" :%d} " ) ,
index , xtimer . arm , xtimer . mode , sign , hour , xtimer . time % 60 , xtimer . window , days , xtimer . repeat , soutput , xtimer . power ) ;
2018-04-05 11:49:43 +01:00
# else
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " \" " D_CMND_TIMER " %d \" :{ \" " D_JSON_TIMER_ARM " \" :%d, \" " D_JSON_TIMER_TIME " \" : \" %02d:%02d \" , \" " D_JSON_TIMER_WINDOW " \" :%d, \" " D_JSON_TIMER_DAYS " \" : \" %s \" , \" " D_JSON_TIMER_REPEAT " \" :%d%s, \" " D_JSON_TIMER_ACTION " \" :%d} " ) ,
index , xtimer . arm , xtimer . time / 60 , xtimer . time % 60 , xtimer . window , days , xtimer . repeat , soutput , xtimer . power ) ;
2018-04-05 11:49:43 +01:00
# endif // USE_SUNRISE
2018-03-23 16:20:20 +00:00
}
/*********************************************************************************************\
* Commands
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-08-02 14:13:51 +01:00
void CmndTimer ( void )
2018-03-23 16:20:20 +00:00
{
2019-08-02 14:13:51 +01:00
uint32_t index = XdrvMailbox . index ;
if ( ( index > 0 ) & & ( index < = MAX_TIMERS ) ) {
uint32_t error = 0 ;
2018-03-23 16:20:20 +00:00
if ( XdrvMailbox . data_len ) {
2018-03-28 17:01:38 +01:00
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = MAX_TIMERS ) ) {
if ( XdrvMailbox . payload = = 0 ) {
Settings . timer [ index - 1 ] . data = 0 ; // Clear timer
} else {
Settings . timer [ index - 1 ] . data = Settings . timer [ XdrvMailbox . payload - 1 ] . data ; // Copy timer
}
} else {
2019-05-18 08:45:04 +01:00
//#ifndef USE_RULES
# if defined(USE_RULES)==0 && defined(USE_SCRIPT)==0
2018-03-31 16:29:00 +01:00
if ( devices_present ) {
2018-04-25 16:27:40 +01:00
# endif
2019-08-02 14:13:51 +01:00
char dataBufUc [ XdrvMailbox . data_len ] ;
UpperCase ( dataBufUc , XdrvMailbox . data ) ;
2018-05-01 10:28:36 +01:00
StaticJsonBuffer < 256 > jsonBuffer ;
2018-03-31 16:29:00 +01:00
JsonObject & root = jsonBuffer . parseObject ( dataBufUc ) ;
if ( ! root . success ( ) ) {
2019-03-23 16:00:59 +00:00
Response_P ( PSTR ( " { \" " D_CMND_TIMER " %d \" : \" " D_JSON_INVALID_JSON " \" } " ) , index ) ; // JSON decode failed
2018-03-31 16:29:00 +01:00
error = 1 ;
2018-03-28 17:01:38 +01:00
}
2018-03-31 16:29:00 +01:00
else {
char parm_uc [ 10 ] ;
index - - ;
if ( root [ UpperCase_P ( parm_uc , PSTR ( D_JSON_TIMER_ARM ) ) ] . success ( ) ) {
Settings . timer [ index ] . arm = ( root [ parm_uc ] ! = 0 ) ;
}
2018-04-05 11:49:43 +01:00
# ifdef USE_SUNRISE
if ( root [ UpperCase_P ( parm_uc , PSTR ( D_JSON_TIMER_MODE ) ) ] . success ( ) ) {
Settings . timer [ index ] . mode = ( uint8_t ) root [ parm_uc ] & 0x03 ;
}
# endif
2018-03-31 16:29:00 +01:00
if ( root [ UpperCase_P ( parm_uc , PSTR ( D_JSON_TIMER_TIME ) ) ] . success ( ) ) {
uint16_t itime = 0 ;
2018-04-14 17:00:18 +01:00
int8_t value = 0 ;
2018-05-04 08:54:56 +01:00
uint8_t sign = 0 ;
2018-03-31 16:29:00 +01:00
char time_str [ 10 ] ;
2019-03-08 18:24:02 +00:00
strlcpy ( time_str , root [ parm_uc ] , sizeof ( time_str ) ) ;
2018-03-31 16:29:00 +01:00
const char * substr = strtok ( time_str , " : " ) ;
2019-03-26 17:26:50 +00:00
if ( substr ! = nullptr ) {
2018-05-04 08:54:56 +01:00
if ( strchr ( substr , ' - ' ) ) {
sign = 1 ;
substr + + ;
}
2018-03-28 17:01:38 +01:00
value = atoi ( substr ) ;
2018-05-04 08:54:56 +01:00
if ( sign ) { value + = 12 ; } // Allow entering timer offset from -11:59 to -00:01 converted to 12:01 to 23:59
2018-04-17 14:34:18 +01:00
if ( value > 23 ) { value = 23 ; }
2018-03-31 16:29:00 +01:00
itime = value * 60 ;
2019-03-26 17:26:50 +00:00
substr = strtok ( nullptr , " : " ) ;
if ( substr ! = nullptr ) {
2018-03-31 16:29:00 +01:00
value = atoi ( substr ) ;
2018-04-17 14:34:18 +01:00
if ( value < 0 ) { value = 0 ; }
if ( value > 59 ) { value = 59 ; }
2018-03-31 16:29:00 +01:00
itime + = value ;
}
2018-03-28 17:01:38 +01:00
}
2018-03-31 16:29:00 +01:00
Settings . timer [ index ] . time = itime ;
2018-03-23 16:20:20 +00:00
}
2018-04-18 16:28:45 +01:00
if ( root [ UpperCase_P ( parm_uc , PSTR ( D_JSON_TIMER_WINDOW ) ) ] . success ( ) ) {
Settings . timer [ index ] . window = ( uint8_t ) root [ parm_uc ] & 0x0F ;
TimerSetRandomWindow ( index ) ;
}
2018-03-31 16:29:00 +01:00
if ( root [ UpperCase_P ( parm_uc , PSTR ( D_JSON_TIMER_DAYS ) ) ] . success ( ) ) {
// SMTWTFS = 1234567 = 0011001 = 00TW00S = --TW--S
Settings . timer [ index ] . days = 0 ;
const char * tday = root [ parm_uc ] ;
uint8_t i = 0 ;
2018-05-04 08:54:56 +01:00
char ch = * tday + + ;
2018-03-31 16:29:00 +01:00
while ( ( ch ! = ' \0 ' ) & & ( i < 7 ) ) {
2018-04-17 14:34:18 +01:00
if ( ch = = ' - ' ) { ch = ' 0 ' ; }
2018-03-31 16:29:00 +01:00
uint8_t mask = 1 < < i + + ;
Settings . timer [ index ] . days | = ( ch = = ' 0 ' ) ? 0 : mask ;
2018-05-04 08:54:56 +01:00
ch = * tday + + ;
2018-03-31 16:29:00 +01:00
}
2018-03-28 17:01:38 +01:00
}
2018-03-31 16:29:00 +01:00
if ( root [ UpperCase_P ( parm_uc , PSTR ( D_JSON_TIMER_REPEAT ) ) ] . success ( ) ) {
Settings . timer [ index ] . repeat = ( root [ parm_uc ] ! = 0 ) ;
}
if ( root [ UpperCase_P ( parm_uc , PSTR ( D_JSON_TIMER_OUTPUT ) ) ] . success ( ) ) {
uint8_t device = ( ( uint8_t ) root [ parm_uc ] - 1 ) & 0x0F ;
2018-04-25 16:27:40 +01:00
Settings . timer [ index ] . device = ( device < devices_present ) ? device : 0 ;
2018-03-31 16:29:00 +01:00
}
2018-04-12 13:01:43 +01:00
if ( root [ UpperCase_P ( parm_uc , PSTR ( D_JSON_TIMER_ACTION ) ) ] . success ( ) ) {
2018-05-04 08:54:56 +01:00
uint8_t action = ( uint8_t ) root [ parm_uc ] & 0x03 ;
2018-04-25 16:27:40 +01:00
Settings . timer [ index ] . power = ( devices_present ) ? action : 3 ; // If no devices than only allow rules
2018-03-31 16:29:00 +01:00
}
2018-03-23 16:20:20 +00:00
2018-03-31 16:29:00 +01:00
index + + ;
}
2019-05-18 08:45:04 +01:00
//#ifndef USE_RULES
# if defined(USE_RULES)==0 && defined(USE_SCRIPT)==0
2018-03-31 16:29:00 +01:00
} else {
2019-03-23 16:00:59 +00:00
Response_P ( PSTR ( " { \" " D_CMND_TIMER " %d \" : \" " D_JSON_TIMER_NO_DEVICE " \" } " ) , index ) ; // No outputs defined so nothing to control
2018-03-31 16:29:00 +01:00
error = 1 ;
2018-03-28 17:01:38 +01:00
}
2018-04-25 16:27:40 +01:00
# endif
2018-03-23 16:20:20 +00:00
}
}
if ( ! error ) {
2019-03-23 16:00:59 +00:00
Response_P ( PSTR ( " { " ) ) ;
2018-03-23 16:20:20 +00:00
PrepShowTimer ( index ) ;
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-23 16:20:20 +00:00
}
}
2019-08-02 14:13:51 +01:00
}
void CmndTimers ( void )
{
if ( XdrvMailbox . data_len ) {
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = 1 ) ) {
2019-11-03 12:51:22 +00:00
Settings . flag3 . timers_enable = XdrvMailbox . payload ; // CMND_TIMERS
2019-08-02 14:13:51 +01:00
}
if ( XdrvMailbox . payload = = 2 ) {
2019-11-03 12:51:22 +00:00
Settings . flag3 . timers_enable = ! Settings . flag3 . timers_enable ; // CMND_TIMERS
2018-06-26 15:44:17 +01:00
}
2019-08-02 14:13:51 +01:00
}
2018-07-20 15:12:37 +01:00
2019-11-03 12:51:22 +00:00
ResponseCmndStateText ( Settings . flag3 . timers_enable ) ; // CMND_TIMERS
2019-08-02 14:13:51 +01:00
MqttPublishPrefixTopic_P ( RESULT_OR_STAT , XdrvMailbox . command ) ;
2018-07-20 15:12:37 +01:00
2019-08-02 14:13:51 +01:00
uint32_t jsflg = 0 ;
uint32_t lines = 1 ;
for ( uint32_t i = 0 ; i < MAX_TIMERS ; i + + ) {
if ( ! jsflg ) {
Response_P ( PSTR ( " { \" " D_CMND_TIMERS " %d \" :{ " ) , lines + + ) ;
} else {
ResponseAppend_P ( PSTR ( " , " ) ) ;
2018-03-23 16:20:20 +00:00
}
2019-08-02 14:13:51 +01:00
jsflg + + ;
PrepShowTimer ( i + 1 ) ;
if ( jsflg > 3 ) {
2019-09-12 13:19:44 +01:00
ResponseJsonEndEnd ( ) ;
2019-08-02 14:13:51 +01:00
MqttPublishPrefixTopic_P ( RESULT_OR_STAT , PSTR ( D_CMND_TIMERS ) ) ;
jsflg = 0 ;
2018-04-05 11:49:43 +01:00
}
}
2019-08-02 14:13:51 +01:00
mqtt_data [ 0 ] = ' \0 ' ;
}
# ifdef USE_SUNRISE
void CmndLongitude ( void )
{
if ( XdrvMailbox . data_len ) {
Settings . longitude = ( int ) ( CharToFloat ( XdrvMailbox . data ) * 1000000 ) ;
2018-04-05 11:49:43 +01:00
}
2019-08-02 14:13:51 +01:00
char lbuff [ 33 ] ;
dtostrfd ( ( ( float ) Settings . longitude ) / 1000000 , 6 , lbuff ) ;
2019-08-03 12:01:34 +01:00
ResponseCmndChar ( lbuff ) ;
2019-08-02 14:13:51 +01:00
}
2018-03-23 16:20:20 +00:00
2019-08-02 14:13:51 +01:00
void CmndLatitude ( void )
{
if ( XdrvMailbox . data_len ) {
Settings . latitude = ( int ) ( CharToFloat ( XdrvMailbox . data ) * 1000000 ) ;
}
char lbuff [ 33 ] ;
dtostrfd ( ( ( float ) Settings . latitude ) / 1000000 , 6 , lbuff ) ;
2019-08-03 12:01:34 +01:00
ResponseCmndChar ( lbuff ) ;
2018-03-23 16:20:20 +00:00
}
2019-08-02 14:13:51 +01:00
# endif // USE_SUNRISE
2018-03-23 16:20:20 +00:00
2018-03-28 17:01:38 +01:00
/*********************************************************************************************\
* Presentation
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifdef USE_WEBSERVER
# ifdef USE_TIMERS_WEB
2018-10-10 21:21:44 +01:00
# define WEB_HANDLE_TIMER "tm"
const char S_CONFIGURE_TIMER [ ] PROGMEM = D_CONFIGURE_TIMER ;
const char HTTP_BTN_MENU_TIMER [ ] PROGMEM =
2019-02-13 15:05:25 +00:00
" <p><form action=' " WEB_HANDLE_TIMER " ' method='get'><button> " D_CONFIGURE_TIMER " </button></form></p> " ;
2018-10-10 21:21:44 +01:00
2019-03-04 17:16:07 +00:00
const char HTTP_TIMER_SCRIPT1 [ ] PROGMEM =
2018-03-28 17:01:38 +01:00
" var pt=[],ct=99; "
" function ce(i,q){ " // Create select option
" var o=document.createElement('option'); "
" o.textContent=i; "
" q.appendChild(o); "
2019-03-04 17:16:07 +00:00
" } " ;
2018-04-05 11:49:43 +01:00
# ifdef USE_SUNRISE
2019-03-04 17:16:07 +00:00
const char HTTP_TIMER_SCRIPT2 [ ] PROGMEM =
2018-04-18 16:28:45 +01:00
" function gt(){ " // Set hours and minutes according to mode
2018-04-05 11:49:43 +01:00
" var m,p,q; "
" m=qs('input[name= \" rd \" ]:checked').value; " // Get mode
2018-04-18 16:28:45 +01:00
" p=pt[ct]&0x7FF; " // Get time
" if(m==0){ " // Time is set
2018-04-20 10:28:26 +01:00
" so(0); " // Hide offset span and allow Hour 00..23
2018-04-18 16:28:45 +01:00
" q=Math.floor(p/60);if(q<10){q='0'+q;}qs('#ho').value=q; " // Set hours
2019-03-10 14:36:34 +00:00
" q=p%%60;if(q<10){q='0'+q;}qs('#mi').value=q; " // Set minutes
2018-04-18 16:28:45 +01:00
" } "
2018-04-14 17:00:18 +01:00
" if((m==1)||(m==2)){ " // Sunrise or sunset is set
2018-04-20 10:28:26 +01:00
" so(1); " // Show offset span and allow Hour 00..11
2018-04-14 17:00:18 +01:00
" q=Math.floor(p/60); " // Parse hours
2018-04-18 16:28:45 +01:00
" if(q>=12){q-=12;qs('#dr').selectedIndex=1;} " // Negative offset
" else{qs('#dr').selectedIndex=0;} "
" if(q<10){q='0'+q;}qs('#ho').value=q; " // Set offset hours
2019-03-10 14:36:34 +00:00
" q=p%%60;if(q<10){q='0'+q;}qs('#mi').value=q; " // Set offset minutes
2018-04-14 17:00:18 +01:00
" } "
" } "
" function so(b){ " // Hide or show offset items
2018-04-18 16:28:45 +01:00
" o=qs('#ho'); "
" e=o.childElementCount; "
" if(b==1){ "
" qs('#dr').disabled=''; "
" if(e>12){for(i=12;i<=23;i++){o.removeChild(o.lastElementChild);}} " // Create offset hours select options
" }else{ "
" qs('#dr').disabled='disabled'; "
" if(e<23){for(i=12;i<=23;i++){ce(i,o);}} " // Create hours select options
" } "
2019-03-04 17:16:07 +00:00
" } " ;
2018-04-05 11:49:43 +01:00
# endif
2019-03-04 17:16:07 +00:00
const char HTTP_TIMER_SCRIPT3 [ ] PROGMEM =
2018-03-28 17:01:38 +01:00
" function st(){ " // Save parameters to hidden area
2018-04-14 17:00:18 +01:00
" var i,l,m,n,p,s; "
" m=0;s=0; "
2018-04-18 16:28:45 +01:00
" n=1<<31;if(eb('a0').checked){s|=n;} " // Get arm
" n=1<<15;if(eb('r0').checked){s|=n;} " // Get repeat
2018-03-28 17:01:38 +01:00
" for(i=0;i<7;i++){n=1<<(16+i);if(eb('w'+i).checked){s|=n;}} " // Get weekdays
2018-04-05 11:49:43 +01:00
# ifdef USE_SUNRISE
2018-04-14 17:00:18 +01:00
" m=qs('input[name= \" rd \" ]:checked').value; " // Check mode
2018-04-18 16:28:45 +01:00
" s|=(qs('input[name= \" rd \" ]:checked').value<<29); " // Get mode
2018-04-05 11:49:43 +01:00
# endif
2019-03-04 17:16:07 +00:00
" if(%d>0){ "
2018-04-25 16:27:40 +01:00
" i=qs('#d1').selectedIndex;if(i>=0){s|=(i<<23);} " // Get output
" s|=(qs('#p1').selectedIndex<<27); " // Get action
" }else{ "
" s|=3<<27; " // Get action (rule)
" } "
2018-04-18 16:28:45 +01:00
" l=((qs('#ho').selectedIndex*60)+qs('#mi').selectedIndex)&0x7FF; "
" if(m==0){s|=l;} " // Get time
2018-04-14 17:00:18 +01:00
# ifdef USE_SUNRISE
" if((m==1)||(m==2)){ "
2018-04-18 16:28:45 +01:00
" if(qs('#dr').selectedIndex>0){l+=720;} " // If negative offset, add 12h to given offset time
" s|=l&0x7FF; " // Save offset instead of time
2018-04-14 17:00:18 +01:00
" } "
# endif
2018-04-20 10:28:26 +01:00
" s|=((qs('#mw').selectedIndex)&0x0F)<<11; " // Get window minutes
2018-03-28 17:01:38 +01:00
" pt[ct]=s; "
" eb('t0').value=pt.join(); " // Save parameters from array to hidden area
2019-03-04 17:16:07 +00:00
" } " ;
const char HTTP_TIMER_SCRIPT4 [ ] PROGMEM =
2018-03-30 16:46:30 +01:00
" function ot(t,e){ " // Select tab and update elements
" var i,n,o,p,q,s; "
2018-04-05 11:49:43 +01:00
" if(ct<99){st();} " // Save changes
" ct=t; "
2018-03-30 16:46:30 +01:00
" o=document.getElementsByClassName('tl'); " // Restore style to all tabs/buttons
Add command WebColor
* Add rule Http#Initialized
* Add command WebColor to change non-persistent GUI colors on the fly
Use a rule like:
rule3 on http#initialized do webcolor {"webcolor":["#eeeeee","#181818","#4f4f4f","#000000","#dddddd","#008000","#222222","#ff0000","#008000","#ffffff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#ffffff","#999999","#000000"]} endon
or
rule3 on http#initialized do webcolor {"webcolor":["#eee","#181818","#4f4f4f","#000","#ddd","#008000","#222"]} endon
to make color changes persistent)
2019-04-08 21:37:39 +01:00
" for(i=0;i<o.length;i++){o[i].style.cssText= \" background:#%06x;color:#%06x;font-weight:normal; \" } " // COLOR_TIMER_TAB_BACKGROUND, COLOR_TIMER_TAB_TEXT
2019-04-09 09:24:00 +01:00
" e.style.cssText= \" background:#%06x;color:#%06x;font-weight:bold; \" ; " // COLOR_FORM, COLOR_TEXT, Change style to tab/button used to open content
2018-04-05 11:49:43 +01:00
" s=pt[ct]; " // Get parameters from array
# ifdef USE_SUNRISE
2018-04-18 16:28:45 +01:00
" p=(s>>29)&3;eb('b'+p).checked=1; " // Set mode
2018-04-05 11:49:43 +01:00
" gt(); " // Set hours and minutes according to mode
# else
2018-03-28 17:01:38 +01:00
" p=s&0x7FF; " // Get time
2018-03-30 16:46:30 +01:00
" q=Math.floor(p/60);if(q<10){q='0'+q;}qs('#ho').value=q; " // Set hours
2019-03-04 17:16:07 +00:00
" q=p%%60;if(q<10){q='0'+q;}qs('#mi').value=q; " // Set minutes
2018-04-05 11:49:43 +01:00
# endif
2018-04-18 16:28:45 +01:00
" q=(s>>11)&0xF;if(q<10){q='0'+q;}qs('#mw').value=q; " // Set window minutes
2018-03-28 17:01:38 +01:00
" for(i=0;i<7;i++){p=(s>>(16+i))&1;eb('w'+i).checked=p;} " // Set weekdays
2019-03-04 17:16:07 +00:00
" if(%d>0){ "
2018-04-25 16:27:40 +01:00
" p=(s>>23)&0xF;qs('#d1').value=p+1; " // Set output
" p=(s>>27)&3;qs('#p1').selectedIndex=p; " // Set action
" } "
2018-04-18 16:28:45 +01:00
" p=(s>>15)&1;eb('r0').checked=p; " // Set repeat
" p=(s>>31)&1;eb('a0').checked=p; " // Set arm
2019-03-04 17:16:07 +00:00
" } " ;
const char HTTP_TIMER_SCRIPT5 [ ] PROGMEM =
2018-03-30 16:46:30 +01:00
" function it(){ " // Initialize elements and select first tab
" var b,i,o,s; "
" pt=eb('t0').value.split(',').map(Number); " // Get parameters from hidden area to array
2019-04-02 14:47:39 +01:00
" s=''; "
" for(i=0;i<%d;i++){ "
" b=''; "
" if(0==i){b= \" id='dP' \" ;} "
" s+= \" <button type='button' class='tl' onclick='ot( \" +i+ \" ,this)' \" +b+ \" > \" +(i+1)+ \" </button> \" "
" } "
2018-03-30 16:46:30 +01:00
" eb('bt').innerHTML=s; " // Create tabs
2019-03-04 17:16:07 +00:00
" if(%d>0){ " // Create Output and Action drop down boxes
2019-06-02 15:44:02 +01:00
" eb('oa').innerHTML= \" <b> " D_TIMER_OUTPUT " </b> <span><select style='width:60px;' id='d1'></select></span> <b> " D_TIMER_ACTION " </b> <select style='width:99px;' id='p1'></select> \" ; "
2018-04-25 16:27:40 +01:00
" o=qs('#p1');ce(' " D_OFF " ',o);ce(' " D_ON " ',o);ce(' " D_TOGGLE " ',o); " // Create offset direction select options
2019-05-18 08:45:04 +01:00
# if defined(USE_RULES) || defined(USE_SCRIPT)
2018-04-25 16:27:40 +01:00
" ce(' " D_RULE " ',o); "
# else
" ce(' " D_BLINK " ',o); "
# endif
" }else{ "
" eb('oa').innerHTML= \" <b> " D_TIMER_ACTION " </b> " D_RULE " \" ; " // No outputs but rule is allowed
2019-03-04 17:16:07 +00:00
" } " ;
const char HTTP_TIMER_SCRIPT6 [ ] PROGMEM =
2018-04-20 10:28:26 +01:00
# ifdef USE_SUNRISE
2018-04-18 16:28:45 +01:00
" o=qs('#dr');ce('+',o);ce('-',o); " // Create offset direction select options
2018-04-14 17:00:18 +01:00
# endif
2018-04-18 16:28:45 +01:00
" o=qs('#ho');for(i=0;i<=23;i++){ce((i<10)?('0'+i):i,o);} " // Create hours select options
" o=qs('#mi');for(i=0;i<=59;i++){ce((i<10)?('0'+i):i,o);} " // Create minutes select options
" o=qs('#mw');for(i=0;i<=15;i++){ce((i<10)?('0'+i):i,o);} " // Create window minutes select options
2019-03-04 17:16:07 +00:00
" o=qs('#d1');for(i=0;i<%d;i++){ce(i+1,o);} " // Create outputs
2018-03-30 16:46:30 +01:00
" var a=' " D_DAY3LIST " '; "
2019-06-02 15:44:02 +01:00
" s='';for(i=0;i<7;i++){s+= \" <input id='w \" +i+ \" ' type='checkbox'><b> \" +a.substring(i*3,(i*3)+3)+ \" </b> \" } "
2018-03-30 16:46:30 +01:00
" eb('ds').innerHTML=s; " // Create weekdays
" eb('dP').click(); " // Get the element with id='dP' and click on it
2019-03-04 17:16:07 +00:00
" } "
2019-06-02 15:44:02 +01:00
" wl(it); " ;
2018-03-28 17:01:38 +01:00
const char HTTP_TIMER_STYLE [ ] PROGMEM =
Add command WebColor
* Add rule Http#Initialized
* Add command WebColor to change non-persistent GUI colors on the fly
Use a rule like:
rule3 on http#initialized do webcolor {"webcolor":["#eeeeee","#181818","#4f4f4f","#000000","#dddddd","#008000","#222222","#ff0000","#008000","#ffffff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#ffffff","#999999","#000000"]} endon
or
rule3 on http#initialized do webcolor {"webcolor":["#eee","#181818","#4f4f4f","#000","#ddd","#008000","#222"]} endon
to make color changes persistent)
2019-04-08 21:37:39 +01:00
" .tl{float:left;border-radius:0;border:1px solid #%06x;padding:1px;width:6.25%%;} " ; // COLOR_FORM, Border color needs to be the same as Fieldset background color from HTTP_HEAD_STYLE1 (transparent won't work)
2019-03-04 17:16:07 +00:00
const char HTTP_FORM_TIMER1 [ ] PROGMEM =
2018-11-04 17:29:53 +00:00
" <fieldset style='min-width:470px;text-align:center;'> "
" <legend style='text-align:left;'><b> " D_TIMER_PARAMETERS " </b></legend> "
" <form method='post' action=' " WEB_HANDLE_TIMER " ' onsubmit='return st();'> "
2019-06-03 14:41:32 +01:00
" <br><input id='e0' type='checkbox'%s><b> " D_TIMER_ENABLE " </b><br><br><hr> "
2019-05-31 17:24:56 +01:00
" <input id='t0' value=' " ;
2019-03-04 17:16:07 +00:00
const char HTTP_FORM_TIMER2 [ ] PROGMEM =
2019-06-03 14:41:32 +01:00
" ' hidden><div id='bt'></div><br><br><br> "
" <div id='oa' name='oa'></div><br> "
2018-03-28 17:01:38 +01:00
" <div> "
2019-05-31 17:24:56 +01:00
" <input id='a0' type='checkbox'><b> " D_TIMER_ARM " </b>  "
" <input id='r0' type='checkbox'><b> " D_TIMER_REPEAT " </b> "
2019-06-03 14:41:32 +01:00
" </div><br> "
2019-03-04 17:16:07 +00:00
" <div> " ;
2018-04-05 11:49:43 +01:00
# ifdef USE_SUNRISE
2019-03-04 17:16:07 +00:00
const char HTTP_FORM_TIMER3 [ ] PROGMEM =
" <fieldset style='width:%dpx;margin:auto;text-align:left;border:0;'> "
2019-06-03 14:41:32 +01:00
" <input id='b0' name='rd' type='radio' value='0' onclick='gt();'><b> " D_TIMER_TIME " </b><br> "
" <input id='b1' name='rd' type='radio' value='1' onclick='gt();'><b> " D_SUNRISE " </b> (%s)<br> "
" <input id='b2' name='rd' type='radio' value='2' onclick='gt();'><b> " D_SUNSET " </b> (%s)<br> "
2018-04-05 11:49:43 +01:00
" </fieldset> "
2019-02-13 15:05:25 +00:00
" <p></p> "
2019-05-31 17:24:56 +01:00
" <span><select style='width:46px;' id='dr'></select></span> "
2019-03-04 17:16:07 +00:00
" " ;
2018-04-05 11:49:43 +01:00
# else
2019-03-04 17:16:07 +00:00
const char HTTP_FORM_TIMER3 [ ] PROGMEM =
" <b> " D_TIMER_TIME " </b> " ;
2018-04-18 16:28:45 +01:00
# endif // USE_SUNRISE
2019-03-04 17:16:07 +00:00
const char HTTP_FORM_TIMER4 [ ] PROGMEM =
2019-05-31 17:24:56 +01:00
" <span><select style='width:60px;' id='ho'></select></span> "
2018-04-05 11:49:43 +01:00
" " D_HOUR_MINUTE_SEPARATOR " "
2019-05-31 17:24:56 +01:00
" <span><select style='width:60px;' id='mi'></select></span> "
2018-04-18 16:28:45 +01:00
"  <b>+/-</b> "
2019-05-31 17:24:56 +01:00
" <span><select style='width:60px;' id='mw'></select></span> "
2019-06-03 14:41:32 +01:00
" </div><br> "
2018-03-30 16:46:30 +01:00
" <div id='ds' name='ds'></div> " ;
2018-03-28 17:01:38 +01:00
2018-11-14 13:32:09 +00:00
void HandleTimerConfiguration ( void )
2018-03-28 17:01:38 +01:00
{
2019-01-10 11:57:42 +00:00
if ( ! HttpCheckPriviledgedAccess ( ) ) { return ; }
2018-03-28 17:01:38 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_CONFIGURE_TIMER ) ;
2018-10-10 21:21:44 +01:00
if ( WebServer - > hasArg ( " save " ) ) {
TimerSaveSettings ( ) ;
HandleConfiguration ( ) ;
return ;
}
2019-03-10 14:36:34 +00:00
WSContentStart_P ( S_CONFIGURE_TIMER ) ;
WSContentSend_P ( HTTP_TIMER_SCRIPT1 ) ;
2019-03-04 17:16:07 +00:00
# ifdef USE_SUNRISE
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_TIMER_SCRIPT2 ) ;
2019-03-04 17:16:07 +00:00
# endif // USE_SUNRISE
WSContentSend_P ( HTTP_TIMER_SCRIPT3 , devices_present ) ;
2019-04-09 12:56:19 +01:00
WSContentSend_P ( HTTP_TIMER_SCRIPT4 , WebColor ( COL_TIMER_TAB_BACKGROUND ) , WebColor ( COL_TIMER_TAB_TEXT ) , WebColor ( COL_FORM ) , WebColor ( COL_TEXT ) , devices_present ) ;
2019-04-02 14:47:39 +01:00
WSContentSend_P ( HTTP_TIMER_SCRIPT5 , MAX_TIMERS , devices_present ) ;
2019-03-04 17:16:07 +00:00
WSContentSend_P ( HTTP_TIMER_SCRIPT6 , devices_present ) ;
2019-04-09 12:56:19 +01:00
WSContentSendStyle_P ( HTTP_TIMER_STYLE , WebColor ( COL_FORM ) ) ;
2019-11-03 12:51:22 +00:00
WSContentSend_P ( HTTP_FORM_TIMER1 , ( Settings . flag3 . timers_enable ) ? " checked " : " " ) ; // CMND_TIMERS
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < MAX_TIMERS ; i + + ) {
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " %s%u " ) , ( i > 0 ) ? " , " : " " , Settings . timer [ i ] . data ) ;
2018-03-28 17:01:38 +01:00
}
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_FORM_TIMER2 ) ;
2018-04-05 11:49:43 +01:00
# ifdef USE_SUNRISE
2019-03-04 17:16:07 +00:00
WSContentSend_P ( HTTP_FORM_TIMER3 , 100 + ( strlen ( D_SUNSET ) * 12 ) , GetSun ( 0 ) . c_str ( ) , GetSun ( 1 ) . c_str ( ) ) ;
# else
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_FORM_TIMER3 ) ;
2018-04-05 11:49:43 +01:00
# endif // USE_SUNRISE
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_FORM_TIMER4 ) ;
WSContentSend_P ( HTTP_FORM_END ) ;
2019-03-11 09:38:41 +00:00
WSContentSpaceButton ( BUTTON_CONFIGURATION ) ;
2019-03-16 15:23:41 +00:00
WSContentStop ( ) ;
2018-03-28 17:01:38 +01:00
}
2018-11-14 13:32:09 +00:00
void TimerSaveSettings ( void )
2018-03-28 17:01:38 +01:00
{
char tmp [ MAX_TIMERS * 12 ] ; // Need space for MAX_TIMERS x 10 digit numbers separated by a comma
2018-04-05 11:49:43 +01:00
Timer timer ;
2018-03-28 17:01:38 +01:00
2019-11-03 12:51:22 +00:00
Settings . flag3 . timers_enable = WebServer - > hasArg ( " e0 " ) ; // CMND_TIMERS
2018-03-28 17:01:38 +01:00
WebGetArg ( " t0 " , tmp , sizeof ( tmp ) ) ;
char * p = tmp ;
2019-11-03 12:51:22 +00:00
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_MQTT D_CMND_TIMERS " %d " ) , Settings . flag3 . timers_enable ) ; // CMND_TIMERS
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < MAX_TIMERS ; i + + ) {
2018-04-05 11:49:43 +01:00
timer . data = strtol ( p , & p , 10 ) ;
2018-03-28 17:01:38 +01:00
p + + ; // Skip comma
2018-04-18 16:28:45 +01:00
if ( timer . time < 1440 ) {
bool flag = ( timer . window ! = Settings . timer [ i ] . window ) ;
Settings . timer [ i ] . data = timer . data ;
if ( flag ) TimerSetRandomWindow ( i ) ;
}
2018-07-21 15:47:44 +01:00
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( " %s,0x%08X " ) , log_data , Settings . timer [ i ] . data ) ;
2018-03-28 17:01:38 +01:00
}
2018-03-30 16:46:30 +01:00
AddLog ( LOG_LEVEL_DEBUG ) ;
2018-03-28 17:01:38 +01:00
}
# endif // USE_TIMERS_WEB
# endif // USE_WEBSERVER
2018-03-23 16:20:20 +00:00
/*********************************************************************************************\
* Interface
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-01-28 13:08:33 +00:00
bool Xdrv09 ( uint8_t function )
2018-03-23 16:20:20 +00:00
{
2019-01-28 13:08:33 +00:00
bool result = false ;
2018-03-23 16:20:20 +00:00
switch ( function ) {
2018-06-04 17:10:38 +01:00
case FUNC_PRE_INIT :
2018-04-18 16:28:45 +01:00
TimerSetRandomWindows ( ) ;
break ;
2018-10-10 21:21:44 +01:00
# ifdef USE_WEBSERVER
# ifdef USE_TIMERS_WEB
case FUNC_WEB_ADD_BUTTON :
2019-05-18 08:45:04 +01:00
# if defined(USE_RULES) || defined(USE_SCRIPT)
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_BTN_MENU_TIMER ) ;
2018-10-10 21:21:44 +01:00
# else
2019-03-10 14:36:34 +00:00
if ( devices_present ) { WSContentSend_P ( HTTP_BTN_MENU_TIMER ) ; }
2018-10-10 21:21:44 +01:00
# endif // USE_RULES
break ;
case FUNC_WEB_ADD_HANDLER :
WebServer - > on ( " / " WEB_HANDLE_TIMER , HandleTimerConfiguration ) ;
break ;
# endif // USE_TIMERS_WEB
# endif // USE_WEBSERVER
2018-03-23 16:20:20 +00:00
case FUNC_EVERY_SECOND :
TimerEverySecond ( ) ;
break ;
case FUNC_COMMAND :
2019-08-02 14:13:51 +01:00
result = DecodeCommand ( kTimerCommands , TimerCommand ) ;
2018-03-23 16:20:20 +00:00
break ;
}
return result ;
}
2018-08-29 18:21:13 +01:00
# endif // USE_TIMERS