diff --git a/README.md b/README.md index 7734cacfd..60700342d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ## Sonoff-Tasmota Provide ESP8266 based Sonoff by [iTead Studio](https://www.itead.cc/) and ElectroDragon IoT Relay with Serial, Web and MQTT control allowing 'Over the Air' or OTA firmware updates using Arduino IDE. -Current version is **5.12.0i** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_releasenotes.ino) for change information. +Current version is **5.12.0j** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_releasenotes.ino) for change information. ### Quick install diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino index 6f2e91046..a61c583fb 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,4 +1,7 @@ -/* 5.12.0i +/* 5.12.0j + * Add optional Sunrise and Sunset timers with commands Latitide and Longitude to be enabled with define USE_SUNRISE in user_config.h (#2317) + * + * 5.12.0i * Add 16 timers using commands Timer and Timers (#1091) * Add commands Timer 0 to clear timer and Timer 1..16 to copy timer * Add optional Timer configuration webpage to be enabled in user_config.h with define USE_TIMERS_WEB diff --git a/sonoff/i18n.h b/sonoff/i18n.h index 95b17fea6..5dea3bbe9 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -105,6 +105,8 @@ #define D_JSON_STARTUPUTC "StartupUTC" #define D_JSON_SUBNETMASK "Subnetmask" #define D_JSON_SUCCESSFUL "Successful" +#define D_JSON_SUNRISE "Sunrise" +#define D_JSON_SUNSET "Sunset" #define D_JSON_SWITCH "Switch" #define D_JSON_SYNC "Sync" #define D_JSON_TEMPERATURE "Temperature" @@ -270,9 +272,9 @@ #define D_CMND_IRSEND "IRSend" #define D_JSON_INVALID_JSON "Invalid JSON" #define D_JSON_PROTOCOL_NOT_SUPPORTED "Protocol not supported" - #define D_JSON_IR_PROTOCOL "PROTOCOL" - #define D_JSON_IR_BITS "BITS" - #define D_JSON_IR_DATA "DATA" + #define D_JSON_IR_PROTOCOL "Protocol" + #define D_JSON_IR_BITS "Bits" + #define D_JSON_IR_DATA "Data" #define D_CMND_IRHVAC "IRHVAC" #define D_JSON_IRHVAC_VENDOR "VENDOR" #define D_JSON_IRHVAC_POWER "POWER" @@ -354,6 +356,7 @@ // Commands xdrv_09_timers.ino #define D_CMND_TIMER "Timer" #define D_JSON_TIMER_ARM "Arm" + #define D_JSON_TIMER_MODE "Mode" #define D_JSON_TIMER_TIME "Time" #define D_JSON_TIMER_DAYS "Days" #define D_JSON_TIMER_REPEAT "Repeat" @@ -361,6 +364,8 @@ #define D_JSON_TIMER_POWER "Power" #define D_JSON_TIMER_NO_DEVICE "No GPIO as output configured" #define D_CMND_TIMERS "Timers" +#define D_CMND_LATITUDE "Latitude" +#define D_CMND_LONGITUDE "Longitude" /********************************************************************************************/ diff --git a/sonoff/language/cs-CZ.h b/sonoff/language/cs-CZ.h index 21336443c..0920fc2e6 100644 --- a/sonoff/language/cs-CZ.h +++ b/sonoff/language/cs-CZ.h @@ -137,6 +137,8 @@ #define D_SUBNET_MASK "Maska podsítě" #define D_SUBSCRIBE_TO "Přihlaš se do" #define D_SUCCESSFUL "úspěšné." +#define D_SUNRISE "Sunrise" +#define D_SUNSET "Sunset" #define D_TEMPERATURE "Teplota" #define D_TO "do" #define D_TOGGLE "Přepni" diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index caa74fd41..2b9295e34 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -137,6 +137,8 @@ #define D_SUBNET_MASK "Subnetzmaske" #define D_SUBSCRIBE_TO "subscribe to" #define D_SUCCESSFUL "erfolgreich" +#define D_SUNRISE "Sunrise" +#define D_SUNSET "Sunset" #define D_TEMPERATURE "Temperatur" #define D_TO "zu" #define D_TOGGLE "An/Aus" diff --git a/sonoff/language/en-GB.h b/sonoff/language/en-GB.h index 484946200..26a2e9fe0 100644 --- a/sonoff/language/en-GB.h +++ b/sonoff/language/en-GB.h @@ -137,6 +137,8 @@ #define D_SUBNET_MASK "Subnet Mask" #define D_SUBSCRIBE_TO "Subscribe to" #define D_SUCCESSFUL "Successful" +#define D_SUNRISE "Sunrise" +#define D_SUNSET "Sunset" #define D_TEMPERATURE "Temperature" #define D_TO "to" #define D_TOGGLE "Toggle" diff --git a/sonoff/language/es-AR.h b/sonoff/language/es-AR.h index 143ee4d3c..5dfc111da 100644 --- a/sonoff/language/es-AR.h +++ b/sonoff/language/es-AR.h @@ -137,6 +137,8 @@ #define D_SUBNET_MASK "Máscara Subred" #define D_SUBSCRIBE_TO "Suscribir a" #define D_SUCCESSFUL "Exitosa" +#define D_SUNRISE "Sunrise" +#define D_SUNSET "Sunset" #define D_TEMPERATURE "Temperatura" #define D_TO "a" #define D_TOGGLE "Conmutar" diff --git a/sonoff/language/fr-FR.h b/sonoff/language/fr-FR.h index 5d09cfcb6..d0aff6c77 100644 --- a/sonoff/language/fr-FR.h +++ b/sonoff/language/fr-FR.h @@ -137,6 +137,8 @@ #define D_SUBNET_MASK "Masque sous réseau" #define D_SUBSCRIBE_TO "Souscrire à" #define D_SUCCESSFUL "Réussi" +#define D_SUNRISE "Sunrise" +#define D_SUNSET "Sunset" #define D_TEMPERATURE "Temperature" #define D_TO "à" #define D_TOGGLE "Bascule" diff --git a/sonoff/language/hu-HU.h b/sonoff/language/hu-HU.h index e043b1b96..455e0ba1f 100644 --- a/sonoff/language/hu-HU.h +++ b/sonoff/language/hu-HU.h @@ -137,6 +137,8 @@ #define D_SUBNET_MASK "Subnet Mask" #define D_SUBSCRIBE_TO "Feliratkozás a" #define D_SUCCESSFUL "Sikeres" +#define D_SUNRISE "Sunrise" +#define D_SUNSET "Sunset" #define D_TEMPERATURE "Hőmérséklet" #define D_TO "-nak" #define D_TOGGLE "Toggle" diff --git a/sonoff/language/it-IT.h b/sonoff/language/it-IT.h index 59851e677..cab2e7892 100644 --- a/sonoff/language/it-IT.h +++ b/sonoff/language/it-IT.h @@ -137,6 +137,8 @@ #define D_SUBNET_MASK "Maschera sottorete" #define D_SUBSCRIBE_TO "Sottoscrivi a" #define D_SUCCESSFUL "Riuscito" +#define D_SUNRISE "Sunrise" +#define D_SUNSET "Sunset" #define D_TEMPERATURE "Temperatura" #define D_TO "a" #define D_TOGGLE "Toggle" diff --git a/sonoff/language/nl-NL.h b/sonoff/language/nl-NL.h index b21bea2aa..802255b3a 100644 --- a/sonoff/language/nl-NL.h +++ b/sonoff/language/nl-NL.h @@ -137,6 +137,8 @@ #define D_SUBNET_MASK "Subnet Masker" #define D_SUBSCRIBE_TO "Abonneer op" #define D_SUCCESSFUL "Gelukt" +#define D_SUNRISE "Zonsopgang" +#define D_SUNSET "Zonsondergang" #define D_TEMPERATURE "Temperatuur" #define D_TO "naar" #define D_TOGGLE "Toggle" // Wissel, Tuimel diff --git a/sonoff/language/pl-PL.h b/sonoff/language/pl-PL.h index 9d0352315..3ce638de6 100644 --- a/sonoff/language/pl-PL.h +++ b/sonoff/language/pl-PL.h @@ -137,6 +137,8 @@ #define D_SUBNET_MASK "Maska podsieci" #define D_SUBSCRIBE_TO "Subskrybuj do" #define D_SUCCESSFUL "Powodzenie" +#define D_SUNRISE "Sunrise" +#define D_SUNSET "Sunset" #define D_TEMPERATURE "Temperatura" #define D_TO "do" #define D_TOGGLE "Przełącz" diff --git a/sonoff/language/pt-PT.h b/sonoff/language/pt-PT.h index 5c52cd528..cae2832db 100644 --- a/sonoff/language/pt-PT.h +++ b/sonoff/language/pt-PT.h @@ -137,6 +137,8 @@ #define D_SUBNET_MASK "Mascara sub rede" #define D_SUBSCRIBE_TO "Subescrever para" #define D_SUCCESSFUL "Successo" +#define D_SUNRISE "Sunrise" +#define D_SUNSET "Sunset" #define D_TEMPERATURE "Temperatura" #define D_TO "para" #define D_TOGGLE "Pressionar" diff --git a/sonoff/language/ru-RU.h b/sonoff/language/ru-RU.h index d11bfcda2..0fa85d5a9 100644 --- a/sonoff/language/ru-RU.h +++ b/sonoff/language/ru-RU.h @@ -137,6 +137,8 @@ #define D_SUBNET_MASK "Маска Подсети" #define D_SUBSCRIBE_TO "Подписаться на" #define D_SUCCESSFUL "Успешно" +#define D_SUNRISE "Sunrise" +#define D_SUNSET "Sunset" #define D_TEMPERATURE "Температура" #define D_TO "до" #define D_TOGGLE "Переключить" diff --git a/sonoff/language/zh-CN.h b/sonoff/language/zh-CN.h index f9d0d5cc2..0f1a97347 100644 --- a/sonoff/language/zh-CN.h +++ b/sonoff/language/zh-CN.h @@ -137,6 +137,8 @@ #define D_SUBNET_MASK "子网掩码" #define D_SUBSCRIBE_TO "订阅" #define D_SUCCESSFUL "成功" +#define D_SUNRISE "Sunrise" +#define D_SUNSET "Sunset" #define D_TEMPERATURE "温度" #define D_TO "to" #define D_TOGGLE "切换" diff --git a/sonoff/language/zh-TW.h b/sonoff/language/zh-TW.h index a95b772ca..f0ae1d59e 100644 --- a/sonoff/language/zh-TW.h +++ b/sonoff/language/zh-TW.h @@ -137,6 +137,8 @@ #define D_SUBNET_MASK "子網遮罩" #define D_SUBSCRIBE_TO "訂閱" #define D_SUCCESSFUL "成功" +#define D_SUNRISE "Sunrise" +#define D_SUNSET "Sunset" #define D_TEMPERATURE "溫度" #define D_TO "to" #define D_TOGGLE "切換" diff --git a/sonoff/settings.h b/sonoff/settings.h index 5c18c9ca2..a83b24e1e 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -93,7 +93,7 @@ typedef union { uint32_t data; struct { uint32_t time : 11; // bits 0 - 10 = minutes in a day - uint32_t mday : 5; // bits 11 - 15 = 32 days in a month + uint32_t mode : 5; // bits 11 - 15 = timer modes - Scheduler, Sunrise, Sunset uint32_t days : 7; // bits 16 - 22 = week day mask uint32_t device : 4; // bits 23 - 26 = 16 devices uint32_t power : 2; // bits 27 - 28 = 4 power states - Off, On, Toggle, Blink @@ -253,8 +253,9 @@ struct SYSCFG { byte free_66d[3]; // 66D Timer timer[MAX_TIMERS]; // 670 - - // 6B0 - FFF free locations + int latitude; // 6B0 + int longitude; // 6B4 + // 6B8 - FFF free locations } Settings; struct RTCMEM { diff --git a/sonoff/settings.ino b/sonoff/settings.ino index db75406b4..7a8105c3e 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -54,6 +54,13 @@ #define HOME_ASSISTANT_DISCOVERY_ENABLE 0 #endif +#ifndef LATITUDE +#define LATITUDE 48.858360 // [Latitude] Your location to be used with sunrise and sunset +#endif +#ifndef LONGITUDE +#define LONGITUDE 2.294442 // [Longitude] Your location to be used with sunrise and sunset +#endif + /*********************************************************************************************\ * RTC memory \*********************************************************************************************/ @@ -597,6 +604,9 @@ void SettingsDefaultSet2() // 5.10.1 SettingsDefaultSet_5_10_1(); + + Settings.latitude = (int)((double)LATITUDE * 1000000); + Settings.longitude = (int)((double)LONGITUDE * 1000000); } /********************************************************************************************/ @@ -913,6 +923,10 @@ void SettingsDelta() if (Settings.version < 0x050C0009) { memset(&Settings.timer, 0x00, sizeof(Timer) * MAX_TIMERS); } + if (Settings.version < 0x050C000A) { + Settings.latitude = (int)((double)LATITUDE * 1000000); + Settings.longitude = (int)((double)LONGITUDE * 1000000); + } Settings.version = VERSION; SettingsSave(1); diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index ba91347ed..c354aabc8 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -25,20 +25,18 @@ - Select IDE Tools - Flash Size: "1M (no SPIFFS)" ====================================================*/ -#define VERSION 0x050C0009 // 5.12.0i +#define VERSION 0x050C000A // 5.12.0j // Location specific includes #include // Arduino_Esp8266 version information (ARDUINO_ESP8266_RELEASE and ARDUINO_ESP8266_RELEASE_2_3_0) #include "sonoff.h" // Enumeration used in user_config.h #include "user_config.h" // Fixed user configurable options - #ifdef USE_CONFIG_OVERRIDE #include "user_config_override.h" // Configuration overrides for user_config.h #endif - +#include "sonoff_post.h" // Configuration overrides for all previous includes #include "i18n.h" // Language support configured by user_config.h #include "sonoff_template.h" // Hardware configuration -#include "sonoff_post.h" // Configuration overrides for all previous includes #ifdef ARDUINO_ESP8266_RELEASE_2_4_0 #include "lwip/init.h" @@ -1036,7 +1034,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) } } else if (CMND_TIMEZONE == command_code) { - if ((data_len > 0) && (((payload >= -13) && (payload <= 13)) || (99 == payload))) Settings.timezone = payload; + if ((data_len > 0) && (((payload >= -13) && (payload <= 14)) || (99 == payload))) Settings.timezone = payload; snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.timezone); } else if (CMND_ALTITUDE == command_code) { @@ -1307,8 +1305,13 @@ void PublishStatus(uint8_t payload) } if ((0 == payload) || (7 == payload)) { +#ifdef USE_SUNRISE + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS7_TIME "\":{\"" D_JSON_UTC_TIME "\":\"%s\",\"" D_JSON_LOCAL_TIME "\":\"%s\",\"" D_JSON_STARTDST "\":\"%s\",\"" D_JSON_ENDDST "\":\"%s\",\"" D_CMND_TIMEZONE "\":%d,\"" D_JSON_SUNRISE "\":\"%s\",\"" D_JSON_SUNSET "\":\"%s\"}}"), + GetTime(0).c_str(), GetTime(1).c_str(), GetTime(2).c_str(), GetTime(3).c_str(), Settings.timezone, GetSun(0).c_str(), GetSun(1).c_str()); +#else snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS7_TIME "\":{\"" D_JSON_UTC_TIME "\":\"%s\",\"" D_JSON_LOCAL_TIME "\":\"%s\",\"" D_JSON_STARTDST "\":\"%s\",\"" D_JSON_ENDDST "\":\"%s\",\"" D_CMND_TIMEZONE "\":%d}}"), GetTime(0).c_str(), GetTime(1).c_str(), GetTime(2).c_str(), GetTime(3).c_str(), Settings.timezone); +#endif // USE_SUNRISE MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "7")); } diff --git a/sonoff/sonoff_post.h b/sonoff/sonoff_post.h index f1f980edf..4455519d0 100644 --- a/sonoff/sonoff_post.h +++ b/sonoff/sonoff_post.h @@ -105,6 +105,9 @@ void WifiWpsStatusCallback(wps_cb_status status); #ifdef USE_TIMERS #undef USE_TIMERS // Disable support for up to 16 timers #endif +#ifdef USE_SUNRISE +#undef USE_SUNRISE // Disable support for Sunrise and sunset tools +#endif #ifdef USE_PZEM004T #undef USE_PZEM004T // Disable PZEM004T energy sensor #endif diff --git a/sonoff/support.ino b/sonoff/support.ino index d0250690a..b845af708 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -192,6 +192,35 @@ size_t strchrspn(const char *str1, int character) return ret; } +double AtoD(char *str) +{ + // simple ascii to double, because atof or strtod are too large + char strbuf[24]; + + strcpy(strbuf, str); + char *pt; + double left = atoi(strbuf); + double right = 0; + short len = 0; + pt = strtok (strbuf, "."); + if (pt) { + pt = strtok (NULL, "."); + if (pt) { + right = atoi(pt); + len = strlen(pt); + double fac = 1; + while (len) { + fac /= 10.0; + len--; + } + // pow is also very large + //double fac=pow(10,-len); + right *= fac; + } + } + return left + right; +} + char* dtostrfd(double number, unsigned char prec, char *s) { return dtostrf(number, 1, prec, s); @@ -1077,6 +1106,7 @@ uint32_t standard_time = 0; uint32_t ntp_time = 0; uint32_t midnight = 1451602800; uint32_t restart_time = 0; +int16_t time_timezone = 0; // Timezone * 10 uint8_t midnight_now = 0; uint8_t ntp_sync_minute = 0; @@ -1325,8 +1355,8 @@ boolean MidnightNow() void RtcSecond() { - uint32_t stdoffset; - uint32_t dstoffset; + int32_t stdoffset; + int32_t dstoffset; TIME_T tmpTime; if ((ntp_sync_minute > 59) && (RtcTime.minute > 2)) ntp_sync_minute = 1; // If sync prepare for a new cycle @@ -1353,6 +1383,7 @@ void RtcSecond() utc_time++; local_time = utc_time; if (local_time > 1451602800) { // 2016-01-01 + int32_t time_offset = Settings.timezone * SECS_PER_HOUR; if (99 == Settings.timezone) { if (DaylightSavingTime.hemis) { dstoffset = StandardTime.offset * SECS_PER_MIN; // Southern hemisphere @@ -1362,13 +1393,13 @@ void RtcSecond() stdoffset = StandardTime.offset * SECS_PER_MIN; } if ((utc_time >= (daylight_saving_time - stdoffset)) && (utc_time < (standard_time - dstoffset))) { - local_time += dstoffset; // Daylight Saving Time + time_offset = dstoffset; // Daylight Saving Time } else { - local_time += stdoffset; // Standard Time + time_offset = stdoffset; // Standard Time } - } else { - local_time += Settings.timezone * SECS_PER_HOUR; } + local_time += time_offset; + time_timezone = time_offset / (SECS_PER_HOUR / 10); } BreakTime(local_time, RtcTime); if (!RtcTime.hour && !RtcTime.minute && !RtcTime.second && RtcTime.valid) { diff --git a/sonoff/user_config.h b/sonoff/user_config.h index db5e9a50d..6b4386058 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -21,35 +21,33 @@ #define _USER_CONFIG_H_ /*********************************************************************************************\ - * ATTENTION: Changes to most PARAMETER defines will only override flash settings if you change - * define CFG_HOLDER. - * Most parameters can be changed online using commands via MQTT, WebConsole or serial + * This file consists of TWO sections. * - * Corresponding MQTT/Serial/Console commands in [brackets] + * SECTION 1: + * The first section contains PARAMETERS overriding flash settings if define CFG_HOLDER is CHANGED. + * All parameters can be persistent changed online using commands via MQTT, WebConsole or Serial. + * Corresponding MQTT/Serial/Console commands are shown in [brackets] + * + * SECTION 2: + * The second section contains Enabled and Disabled FEATURES allowing different program size. + * Changes in this section do NOT need a change of define CFG_HOLDER. + * + * ATTENTION: + * Users are advised to use the user_config_override.h file for most changes. \*********************************************************************************************/ -// -- Localization -------------------------------- -//#define MY_LANGUAGE cs-CZ // Czech in Czech -//#define MY_LANGUAGE de-DE // German in Germany -//#define MY_LANGUAGE en-GB // English in Great Britain. Enabled by Default -//#define MY_LANGUAGE es-AR // Spanish in Argentina -//#define MY_LANGUAGE fr-FR // French in France -//#define MY_LANGUAGE hu-HU // Hungarian in Hungary -//#define MY_LANGUAGE it-IT // Italian in Italy -//#define MY_LANGUAGE nl-NL // Dutch in the Netherlands -//#define MY_LANGUAGE pl-PL // Polish in Poland -//#define MY_LANGUAGE pt-PT // Portuguese in Portugal -//#define MY_LANGUAGE ru-RU // Russian in Russia -//#define MY_LANGUAGE zh-CN // Chinese (Simplified) in China -//#define MY_LANGUAGE zh-TW // Chinese (Traditional) in Taiwan +//#define USE_CONFIG_OVERRIDE // Uncomment to use user_config_override.h file. See README.md + +/*********************************************************************************************\ + * SECTION 1 + * - After initial load any change here only take effect if CFG_HOLDER is changed too +\*********************************************************************************************/ + +// -- Master parameter control -------------------- +#define CFG_HOLDER 0x20161209 // [Reset 1] Change this value to load SECTION1 configuration parameters to flash // -- Project ------------------------------------- -#define PROJECT "sonoff" // PROJECT is used as the default topic delimiter and OTA file name - // As an IDE restriction it needs to be the same as the main .ino file - -#define CFG_HOLDER 0x20161209 // [Reset 1] Change this value to load following default configuration parameters - -//#define USE_CONFIG_OVERRIDE // Uncomment to use your own user_config_override.h file. See README.md +#define PROJECT "sonoff" // PROJECT is used as the default topic delimiter #define SAVE_DATA 1 // [SaveData] Save changed parameters to Flash (0 = disable, 1 - 3600 seconds) #define SAVE_STATE 1 // [SetOption0] Save changed power state to Flash (0 = disable, 1 = enable) @@ -76,37 +74,16 @@ // -- Ota ----------------------------------------- #define OTA_URL "http://sonoff.maddox.co.uk/tasmota/sonoff.ino.bin" // [OtaUrl] -//#define USE_ARDUINO_OTA // Add optional support for Arduino OTA (+4k5 code) - -/*********************************************************************************************\ - * Select ONE of possible MQTT library types below -\*********************************************************************************************/ -// Default MQTT driver for both non-TLS and TLS connections. Blocks network if MQTT server is unavailable. -#define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT // Use PubSubClient library -// Alternative MQTT driver does not block network when MQTT server is unavailable. No TLS support -//#define MQTT_LIBRARY_TYPE MQTT_TASMOTAMQTT // Use TasmotaMqtt library (+4k4 code, +4k mem) - non-TLS only -// Alternative MQTT driver does not block network when MQTT server is unavailable. No TLS support -//#define MQTT_LIBRARY_TYPE MQTT_ESPMQTTARDUINO // Use (patched) esp-mqtt-arduino library (+4k8 code, +4k mem) - non-TLS only // -- MQTT ---------------------------------------- #define MQTT_USE 1 // [SetOption3] Select default MQTT use (0 = Off, 1 = On) -// !!! TLS uses a LOT OF MEMORY (20k) so be careful to enable other options at the same time !!! -//#define USE_MQTT_TLS // Use TLS for MQTT connection (+53k code, +15k mem) - Disable by // - // Needs Fingerprint, TLS Port, UserId and Password -#ifdef USE_MQTT_TLS - #define MQTT_HOST "" // [MqttHost] - #define MQTT_FINGERPRINT1 "A5 02 FF 13 99 9F 8B 39 8E F1 83 4F 11 23 65 0B 32 36 FC 07" // [MqttFingerprint1] - #define MQTT_FINGERPRINT2 "A5 02 FF 13 99 9F 8B 39 8E F1 83 4F 11 23 65 0B 32 36 FC 07" // [MqttFingerprint2] - #define MQTT_PORT 20123 // [MqttPort] MQTT TLS port - #define MQTT_USER "cloudmqttuser" // [MqttUser] Mandatory user - #define MQTT_PASS "cloudmqttpassword" // [MqttPassword] Mandatory password -#else - #define MQTT_HOST "" // [MqttHost] - #define MQTT_PORT 1883 // [MqttPort] MQTT port (10123 on CloudMQTT) - #define MQTT_USER "DVES_USER" // [MqttUser] Optional user - #define MQTT_PASS "DVES_PASS" // [MqttPassword] Optional password -#endif +#define MQTT_HOST "" // [MqttHost] +#define MQTT_FINGERPRINT1 "A5 02 FF 13 99 9F 8B 39 8E F1 83 4F 11 23 65 0B 32 36 FC 07" // [MqttFingerprint1] +#define MQTT_FINGERPRINT2 "A5 02 FF 13 99 9F 8B 39 8E F1 83 4F 11 23 65 0B 32 36 FC 07" // [MqttFingerprint2] +#define MQTT_PORT 1883 // [MqttPort] MQTT port (10123 on CloudMQTT) +#define MQTT_USER "DVES_USER" // [MqttUser] MQTT user +#define MQTT_PASS "DVES_PASS" // [MqttPassword] MQTT password #define MQTT_BUTTON_RETAIN 0 // [ButtonRetain] Button may send retain flag (0 = off, 1 = on) #define MQTT_POWER_RETAIN 0 // [PowerRetain] Power status message may send retain flag (0 = off, 1 = on) @@ -118,7 +95,7 @@ #define MQTT_CMND_HOLD "HOLD" // [StateText4] Command to send when button is kept down for over KEY_HOLD_TIME * 0.1 seconds (needs to be a string like "HOLD") // -- MQTT topics --------------------------------- -//#define MQTT_FULLTOPIC "tasmota/bedroom/%topic%/%prefix%/" // Up to max 80 characers + // Example "tasmota/bedroom/%topic%/%prefix%/" up to 80 characers #define MQTT_FULLTOPIC "%prefix%/%topic%/" // [FullTopic] Subscribe and Publish full topic name - Legacy topic // %prefix% token options @@ -135,57 +112,40 @@ #define TELE_PERIOD 300 // [TelePeriod] Telemetry (0 = disable, 10 - 3600 seconds) // -- MQTT - Domoticz ----------------------------- -#define USE_DOMOTICZ // Enable Domoticz (+6k code, +0.3k mem) - Disable by // - #define DOMOTICZ_IN_TOPIC "domoticz/in" // Domoticz Input Topic - #define DOMOTICZ_OUT_TOPIC "domoticz/out" // Domoticz Output Topic - #define DOMOTICZ_UPDATE_TIMER 0 // [DomoticzUpdateTimer] Send relay status (0 = disable, 1 - 3600 seconds) (Optional) +#define DOMOTICZ_UPDATE_TIMER 0 // [DomoticzUpdateTimer] Send relay status (0 = disable, 1 - 3600 seconds) // -- MQTT - Home Assistant Discovery ------------- -#define USE_HOME_ASSISTANT // Enable Home Assistant Discovery Support (+2k code) - #define HOME_ASSISTANT_DISCOVERY_PREFIX "homeassistant" // Home Assistant discovery prefix - #define HOME_ASSISTANT_DISCOVERY_ENABLE 0 // [SetOption19] Home Assistant Discovery (0 = Disable, 1 = Enable) +#define HOME_ASSISTANT_DISCOVERY_ENABLE 0 // [SetOption19] Home Assistant Discovery (0 = Disable, 1 = Enable) // -- HTTP ---------------------------------------- -#define USE_WEBSERVER // Enable web server and wifi manager (+66k code, +8k mem) - Disable by // - #define WEB_SERVER 2 // [WebServer] Web server (0 = Off, 1 = Start as User, 2 = Start as Admin) - #define WEB_PORT 80 // Web server Port for User and Admin mode - #define WEB_USERNAME "admin" // Web server Admin mode user name - #define WEB_PASSWORD "" // [WebPassword] Web server Admin mode Password for WEB_USERNAME (empty string = Disable) - #define FRIENDLY_NAME "Sonoff" // [FriendlyName] Friendlyname up to 32 characters used by webpages and Alexa - #define USE_EMULATION // Enable Belkin WeMo and Hue Bridge emulation for Alexa (+16k code, +2k mem) - #define EMULATION EMUL_NONE // [Emulation] Select Belkin WeMo (single relay/light) or Hue Bridge emulation (multi relay/light) (EMUL_NONE, EMUL_WEMO or EMUL_HUE) - -// -- mDNS ---------------------------------------- -#define USE_DISCOVERY // Enable mDNS for the following services (+8k code, +0.3k mem) - Disable by // - #define WEBSERVER_ADVERTISE // Provide access to webserver by name .local/ - #define MQTT_HOST_DISCOVERY // Find MQTT host server (overrides MQTT_HOST if found) +#define WEB_SERVER 2 // [WebServer] Web server (0 = Off, 1 = Start as User, 2 = Start as Admin) +#define WEB_PASSWORD "" // [WebPassword] Web server Admin mode Password for WEB_USERNAME (empty string = Disable) +#define FRIENDLY_NAME "Sonoff" // [FriendlyName] Friendlyname up to 32 characters used by webpages and Alexa +#define EMULATION EMUL_NONE // [Emulation] Select Belkin WeMo (single relay/light) or Hue Bridge emulation (multi relay/light) (EMUL_NONE, EMUL_WEMO or EMUL_HUE) // -- Time - Up to three NTP servers in your region #define NTP_SERVER1 "pool.ntp.org" // [NtpServer1] Select first NTP server by name or IP address (129.250.35.250) #define NTP_SERVER2 "nl.pool.ntp.org" // [NtpServer2] Select second NTP server by name or IP address (5.39.184.5) #define NTP_SERVER3 "0.nl.pool.ntp.org" // [NtpServer3] Select third NTP server by name or IP address (93.94.224.67) -#define USE_TIMERS // Add support for up to 16 timers (+2k2 code) - #define USE_TIMERS_WEB // Add timer webpage support (+4k5 code) - -// -- Time - Start Daylight Saving Time and timezone offset from UTC in minutes -#define TIME_DST North, Last, Sun, Mar, 2, +120 // Northern Hemisphere, Last sunday in march at 02:00 +120 minutes - -// -- Time - Start Standard Time and timezone offset from UTC in minutes -#define TIME_STD North, Last, Sun, Oct, 3, +60 // Northern Hemisphere, Last sunday in october 02:00 +60 minutes +// -- Location ------------------------------------ +#define LATITUDE 48.858360 // [Latitude] Your location to be used with sunrise and sunset +#define LONGITUDE 2.294442 // [Longitude] Your location to be used with sunrise and sunset // -- Application --------------------------------- -#define APP_TIMEZONE 1 // [Timezone] +1 hour (Amsterdam) (-12 .. 12 = hours from UTC, 99 = use TIME_DST/TIME_STD) -#define APP_LEDSTATE LED_POWER // [LedState] Function of led (LED_OFF, LED_POWER, LED_MQTTSUB, LED_POWER_MQTTSUB, LED_MQTTPUB, LED_POWER_MQTTPUB, LED_MQTT, LED_POWER_MQTT) +#define APP_TIMEZONE 1 // [Timezone] +1 hour (Amsterdam) (-13 .. 14 = hours from UTC, 99 = use TIME_DST/TIME_STD) +#define APP_LEDSTATE LED_POWER // [LedState] Function of led + // (LED_OFF, LED_POWER, LED_MQTTSUB, LED_POWER_MQTTSUB, LED_MQTTPUB, LED_POWER_MQTTPUB, LED_MQTT, LED_POWER_MQTT) #define APP_PULSETIME 0 // [PulseTime] Time in 0.1 Sec to turn off power for relay 1 (0 = disabled) -#define APP_POWERON_STATE 3 // [PowerOnState] Power On Relay state (0 = Off, 1 = On, 2 = Toggle Saved state, 3 = Saved state) +#define APP_POWERON_STATE POWER_ALL_SAVED // [PowerOnState] Power On Relay state + // (POWER_ALL_OFF, POWER_ALL_ON, POWER_ALL_SAVED_TOGGLE, POWER_ALL_SAVED, POWER_ALL_ALWAYS_ON, POWER_ALL_OFF_PULSETIME_ON) #define APP_BLINKTIME 10 // [BlinkTime] Time in 0.1 Sec to blink/toggle power for relay 1 #define APP_BLINKCOUNT 10 // [BlinkCount] Number of blinks (0 = 32000) #define APP_SLEEP 0 // [Sleep] Sleep time to lower energy consumption (0 = Off, 1 - 250 mSec) #define KEY_HOLD_TIME 40 // [SetOption32] Number of 0.1 seconds to hold Button or external Pushbutton before sending HOLD message -#define SWITCH_MODE TOGGLE // [SwitchMode] TOGGLE, FOLLOW, FOLLOW_INV, PUSHBUTTON, PUSHBUTTON_INV, PUSHBUTTONHOLD, PUSHBUTTONHOLD_INV or PUSHBUTTON_TOGGLE (the wall switch state) -#define WS2812_LEDS 30 // [Pixels] Number of WS2812 LEDs to start with +#define SWITCH_MODE TOGGLE // [SwitchMode] TOGGLE, FOLLOW, FOLLOW_INV, PUSHBUTTON, PUSHBUTTON_INV, PUSHBUTTONHOLD, PUSHBUTTONHOLD_INV, PUSHBUTTON_TOGGLE (the wall switch state) +#define WS2812_LEDS 30 // [Pixels] Number of WS2812 LEDs to start with (max is 512) #define TEMP_CONVERSION 0 // [SetOption8] Return temperature in (0 = Celsius or 1 = Fahrenheit) #define TEMP_RESOLUTION 1 // [TempRes] Maximum number of decimals (0 - 3) showing sensor Temperature @@ -193,6 +153,77 @@ #define PRESSURE_RESOLUTION 1 // [PressRes] Maximum number of decimals (0 - 3) showing sensor Pressure #define ENERGY_RESOLUTION 3 // [EnergyRes] Maximum number of decimals (0 - 5) showing energy usage in kWh +/*********************************************************************************************\ + * END OF SECTION 1 + * + * SECTION 2 + * - Enable a feature by removing both // in front of it + * - Disable a feature by preceding it with // +\*********************************************************************************************/ + +//#define USE_ARDUINO_OTA // Add optional support for Arduino OTA (+4k5 code) + +// -- Localization -------------------------------- + // If non selected the default en-GB will be used +//#define MY_LANGUAGE cs-CZ // Czech in Czech +//#define MY_LANGUAGE de-DE // German in Germany +//#define MY_LANGUAGE en-GB // English in Great Britain. Enabled by Default +//#define MY_LANGUAGE es-AR // Spanish in Argentina +//#define MY_LANGUAGE fr-FR // French in France +//#define MY_LANGUAGE hu-HU // Hungarian in Hungary +//#define MY_LANGUAGE it-IT // Italian in Italy +//#define MY_LANGUAGE nl-NL // Dutch in the Netherlands +//#define MY_LANGUAGE pl-PL // Polish in Poland +//#define MY_LANGUAGE pt-PT // Portuguese in Portugal +//#define MY_LANGUAGE ru-RU // Russian in Russia +//#define MY_LANGUAGE zh-CN // Chinese (Simplified) in China +//#define MY_LANGUAGE zh-TW // Chinese (Traditional) in Taiwan + +/*-------------------------------------------------------------------------------------------*\ + * Select ONE of possible three MQTT library types below +\*-------------------------------------------------------------------------------------------*/ + // Default MQTT driver for both non-TLS and TLS connections. Blocks network if MQTT server is unavailable. +#define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT // Use PubSubClient library + // Alternative MQTT driver does not block network when MQTT server is unavailable. No TLS support +//#define MQTT_LIBRARY_TYPE MQTT_TASMOTAMQTT // Use TasmotaMqtt library (+4k4 code, +4k mem) - non-TLS only + // Alternative MQTT driver does not block network when MQTT server is unavailable. No TLS support +//#define MQTT_LIBRARY_TYPE MQTT_ESPMQTTARDUINO // Use (patched) esp-mqtt-arduino library (+4k8 code, +4k mem) - non-TLS only + +// -- MQTT - Domoticz ----------------------------- +#define USE_DOMOTICZ // Enable Domoticz (+6k code, +0.3k mem) + #define DOMOTICZ_IN_TOPIC "domoticz/in" // Domoticz Input Topic + #define DOMOTICZ_OUT_TOPIC "domoticz/out" // Domoticz Output Topic + +// -- MQTT - Home Assistant Discovery ------------- +#define USE_HOME_ASSISTANT // Enable Home Assistant Discovery Support (+2k code) + #define HOME_ASSISTANT_DISCOVERY_PREFIX "homeassistant" // Home Assistant discovery prefix + +// -- MQTT - TLS ---------------------------------- + // !!! TLS uses a LOT OF MEMORY so be careful to enable other options at the same time !!! +//#define USE_MQTT_TLS // Use TLS for MQTT connection (+53k code, +15k mem) + +// -- HTTP ---------------------------------------- +#define USE_WEBSERVER // Enable web server and wifi manager (+66k code, +8k mem) + #define WEB_PORT 80 // Web server Port for User and Admin mode + #define WEB_USERNAME "admin" // Web server Admin mode user name + #define USE_EMULATION // Enable Belkin WeMo and Hue Bridge emulation for Alexa (+16k code, +2k mem) + +// -- mDNS ---------------------------------------- +#define USE_DISCOVERY // Enable mDNS for the following services (+8k code, +0.3k mem) + #define WEBSERVER_ADVERTISE // Provide access to webserver by name .local/ + #define MQTT_HOST_DISCOVERY // Find MQTT host server (overrides MQTT_HOST if found) + +// -- Time - Start Daylight Saving Time and timezone offset from UTC in minutes +#define TIME_DST North, Last, Sun, Mar, 2, +120 // Northern Hemisphere, Last sunday in march at 02:00 +120 minutes + +// -- Time - Start Standard Time and timezone offset from UTC in minutes +#define TIME_STD North, Last, Sun, Oct, 3, +60 // Northern Hemisphere, Last sunday in october 02:00 +60 minutes + +// -- Time ---------------------------------------- +#define USE_TIMERS // Add support for up to 16 timers (+2k2 code) + #define USE_TIMERS_WEB // Add timer webpage support (+4k5 code) + #define USE_SUNRISE // Add support for Sunrise and sunset tools (+16k) + // -- Internal Analog input ----------------------- #define USE_ADC_VCC // Display Vcc in Power status. Disable for use as Analog input on selected devices @@ -220,6 +251,12 @@ #define MGS_SENSOR_ADDR 0x04 // Default Mutichannel Gas sensor i2c address #endif // USE_I2C +// -- SPI sensors --------------------------------- +//#define USE_SPI // SPI using default library +#ifdef USE_SPI + +#endif // USE_SPI + // -- Serial sensors ------------------------------ #define USE_MHZ19 // Add support for MH-Z19 CO2 sensor (+2k code) #define USE_SENSEAIR // Add support for SenseAir K30, K70 and S8 CO2 sensor (+2k3 code) @@ -251,7 +288,6 @@ * Compile a minimal version if upgrade memory gets tight ONLY TO BE USED FOR UPGRADE STEP 1! * To be used as step 1 during upgrade. * Step 2 is re-compile with option BE_MINIMAL commented out. - * !!! Needed for next release of Arduino/ESP8266 (+22k code, +2k mem) !!! \*********************************************************************************************/ //#define BE_MINIMAL // Minimal version if upgrade memory gets tight (-45k code, -2k mem) diff --git a/sonoff/user_config_override_sample.h b/sonoff/user_config_override_sample.h index 81e209c5d..acd66cebe 100644 --- a/sonoff/user_config_override_sample.h +++ b/sonoff/user_config_override_sample.h @@ -21,7 +21,7 @@ #define _USER_CONFIG_OVERRIDE_H_ // force the compiler to show a warning to confirm that this file is inlcuded -#warning **** Using Settings from user_config_override.h File *** +#warning **** user_config_override.h: Using Settings from this File **** /*****************************************************************************************************\ * USAGE: @@ -31,57 +31,60 @@ * (3) for platformio: * define USE_CONFIG_OVERRIDE as a build flags. * ie1 : export PLATFORMIO_BUILD_FLAGS='-DUSE_CONFIG_OVERRIDE' - * ie2 : enable in file platformio.ini ;build_flags = -Wl,-Tesp8266.flash.1m0.ld -DUSE_CONFIG_OVERRIDE + * ie2 : enable in file platformio.ini "build_flags = -Wl,-Tesp8266.flash.1m0.ld -DUSE_CONFIG_OVERRIDE" * for Arduino IDE: * enable define USE_CONFIG_OVERRIDE in user_config.h ****************************************************************************************************** * ATTENTION: - * - Changes to most PARAMETER defines will only override flash settings if you change define CFG_HOLDER. + * - Changes to SECTION1 PARAMETER defines will only override flash settings if you change define CFG_HOLDER. * - Expect compiler warnings when no ifdef/undef/endif sequence is used. - * - You still need to update user_config.h for major defines MODULE and USE_MQTT_TLS. - * - Changing MODULE defines are not being tested for validity as they are in user_config.h. - * - Most parameters can be changed online using commands via MQTT, WebConsole or serial. + * - You still need to update user_config.h for major define USE_MQTT_TLS. + * - All parameters can be persistent changed online using commands via MQTT, WebConsole or Serial. \*****************************************************************************************************/ /* Examples : -// Setup your own Wifi settings ------------------------------------------------------- +// -- Master parameter control -------------------- +#undef CFG_HOLDER +#define CFG_HOLDER 0x20161209 // [Reset 1] Change this value to load SECTION1 configuration parameters to flash + +// -- Setup your own Wifi settings --------------- #undef STA_SSID1 -#define STA_SSID1 "YourSSID" // [Ssid1] Wifi SSID +#define STA_SSID1 "YourSSID" // [Ssid1] Wifi SSID #undef STA_PASS1 -#define STA_PASS1 "YourWifiPassword" // [Password1] Wifi password +#define STA_PASS1 "YourWifiPassword" // [Password1] Wifi password -// Setup your own MQTT settings ------------------------------------------------------- +// -- Setup your own MQTT settings --------------- #undef MQTT_HOST -#define MQTT_HOST "your-mqtt-server.com" // [MqttHost] +#define MQTT_HOST "your-mqtt-server.com" // [MqttHost] #undef MQTT_PORT -#define MQTT_PORT 1883 // [MqttPort] MQTT port (10123 on CloudMQTT) +#define MQTT_PORT 1883 // [MqttPort] MQTT port (10123 on CloudMQTT) #undef MQTT_USER -#define MQTT_USER "YourMqttUser" // [MqttUser] Optional user +#define MQTT_USER "YourMqttUser" // [MqttUser] Optional user #undef MQTT_PASS -#define MQTT_PASS "YourMqttPass" // [MqttPassword] Optional password +#define MQTT_PASS "YourMqttPass" // [MqttPassword] Optional password // You might even pass some parameters from the command line ---------------------------- -// Ie: export PLATFORMIO_BUILD_FLAGS='-DUSE_CONFIG_OVER -DMY_IP="192.168.1.99" -DMY_GW="192.168.1.1" -DMY_DNS="192.168.1.1"' +// Ie: export PLATFORMIO_BUILD_FLAGS='-DUSE_CONFIG_OVERRIDE -DMY_IP="192.168.1.99" -DMY_GW="192.168.1.1" -DMY_DNS="192.168.1.1"' #ifdef MY_IP #undef WIFI_IP_ADDRESS -#define WIFI_IP_ADDRESS MY_IP // Set to 0.0.0.0 for using DHCP or IP address +#define WIFI_IP_ADDRESS MY_IP // Set to 0.0.0.0 for using DHCP or IP address #endif #ifdef MY_GW #undef WIFI_GATEWAY -#define WIFI_GATEWAY MY_GW // if not using DHCP set Gateway IP address +#define WIFI_GATEWAY MY_GW // if not using DHCP set Gateway IP address #endif #ifdef MY_DNS #undef WIFI_DNS -#define WIFI_DNS MY_DNS // If not using DHCP set DNS IP address (might be equal to WIFI_GATEWAY) +#define WIFI_DNS MY_DNS // If not using DHCP set DNS IP address (might be equal to WIFI_GATEWAY) #endif */ diff --git a/sonoff/xdrv_09_timers.ino b/sonoff/xdrv_09_timers.ino index b82eb7e2c..0975c8c64 100644 --- a/sonoff/xdrv_09_timers.ino +++ b/sonoff/xdrv_09_timers.ino @@ -22,9 +22,10 @@ * Timers * * Arm a timer using one or all of the following JSON values: - * {"Arm":1,"Time":"09:23","Days":"--TW--S","Repeat":1,"Device":1,"Power":1} + * {"Arm":1,"Mode":0,"Time":"09:23","Days":"--TW--S","Repeat":1,"Device":1,"Power":1} * * Arm 0 = Off, 1 = On + * Mode 0 = Schedule, 1 = Sunrise, 2 = Sunset * Time hours:minutes * Days 7 day character mask starting with Sunday (SMTWTFS). 0 or - = Off, any other value = On * Repeat 0 = Execute once, 1 = Execute again @@ -33,28 +34,201 @@ * \*********************************************************************************************/ -enum TimerCommands { CMND_TIMER, CMND_TIMERS }; -const char kTimerCommands[] PROGMEM = D_CMND_TIMER "|" D_CMND_TIMERS ; +enum TimerCommands { CMND_TIMER, CMND_TIMERS +#ifdef USE_SUNRISE +, CMND_LATITUDE, CMND_LONGITUDE +#endif + }; +const char kTimerCommands[] PROGMEM = D_CMND_TIMER "|" D_CMND_TIMERS +#ifdef USE_SUNRISE +"|" D_CMND_LATITUDE "|" D_CMND_LONGITUDE +#endif +; -uint16_t fired = 0; +uint16_t timer_fired = 0; +uint16_t timer_last_minute = 60; + +#ifdef USE_SUNRISE +/*********************************************************************************************\ + * Sunrise and sunset (+13k 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 +\*********************************************************************************************/ + +const double pi2 = TWO_PI; +const double pi = PI; +const double RAD = DEG_TO_RAD; + +double JulianischesDatum() +{ + // 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 + return 2400000.5 + 365.0*Jahr - 679004.0 + Gregor + (int)(30.6001 * (Monat +1)) + Tag + 0.5; +} + +double InPi(double x) +{ + int n = (int)(x / pi2); + x = x - n*pi2; + if (x < 0) x += pi2; + return x; +} + +double eps(double T) +{ + // Neigung der Erdachse + return RAD * (23.43929111 + (-46.8150*T - 0.00059*T*T + 0.001813*T*T*T)/3600.0); +} + +double BerechneZeitgleichung(double *DK,double T) +{ + double RA_Mittel = 18.71506921 + 2400.0513369*T +(2.5862e-5 - 1.72e-9*T)*T*T; + double M = InPi(pi2 * (0.993133 + 99.997361*T)); + double L = InPi(pi2 * (0.7859453 + M/pi2 + (6893.0*sin(M)+72.0*sin(2.0*M)+6191.2*T) / 1296.0e3)); + double e = eps(T); + double RA = atan(tan(L)*cos(e)); + if (RA < 0.0) RA += pi; + if (L > pi) RA += pi; + RA = 24.0*RA/pi2; + *DK = asin(sin(e)*sin(L)); + // Damit 0<=RA_Mittel<24 + RA_Mittel = 24.0 * InPi(pi2*RA_Mittel/24.0)/pi2; + double dRA = RA_Mittel - RA; + if (dRA < -12.0) dRA += 24.0; + if (dRA > 12.0) dRA -= 24.0; + dRA = dRA * 1.0027379; + return dRA; +} + +void DuskTillDawn(uint8_t *hour_up,uint8_t *minute_up, uint8_t *hour_down, uint8_t *minute_down) +{ + double JD2000 = 2451545.0; + double JD = JulianischesDatum(); + double T = (JD - JD2000) / 36525.0; + double DK; + /* + 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 + */ + double h = -50/60.0*RAD; + double B = ((double)Settings.latitude/1000000) * RAD; // geographische Breite + double GeographischeLaenge = (double)Settings.longitude/1000000; + double Zeitzone = (double)time_timezone / 10; + double Zeitgleichung = BerechneZeitgleichung(&DK, T); + double Minuten = Zeitgleichung * 60.0; + double Zeitdifferenz = 12.0*acos((sin(h) - sin(B)*sin(DK)) / (cos(B)*cos(DK)))/pi; + double AufgangOrtszeit = 12.0 - Zeitdifferenz - Zeitgleichung; + double UntergangOrtszeit = 12.0 + Zeitdifferenz - Zeitgleichung; + double AufgangWeltzeit = AufgangOrtszeit - GeographischeLaenge / 15.0; + double UntergangWeltzeit = UntergangOrtszeit - GeographischeLaenge / 15.0; + double Aufgang = AufgangWeltzeit + Zeitzone; // In Stunden + if (Aufgang < 0.0) { + Aufgang += 24.0; + } else { + if (Aufgang >= 24.0) Aufgang -= 24.0; + } + double Untergang = UntergangWeltzeit + Zeitzone; + if (Untergang < 0.0) { + Untergang += 24.0; + } else { + if (Untergang >= 24.0) Untergang -= 24.0; + } + int AufgangMinuten = (int)(60.0*(Aufgang - (int)Aufgang)+0.5); + int AufgangStunden = (int)Aufgang; + if (AufgangMinuten >= 60.0) { + AufgangMinuten -= 60.0; + AufgangStunden++; + } else { + if (AufgangMinuten < 0.0) { + AufgangMinuten += 60.0; + AufgangStunden--; + if (AufgangStunden < 0.0) AufgangStunden += 24.0; + } + } + int UntergangMinuten = (int)(60.0*(Untergang - (int)Untergang)+0.5); + int UntergangStunden = (int)Untergang; + if (UntergangMinuten >= 60.0) { + UntergangMinuten -= 60.0; + UntergangStunden++; + } else { + if (UntergangMinuten<0) { + UntergangMinuten += 60.0; + UntergangStunden--; + if (UntergangStunden < 0.0) UntergangStunden += 24.0; + } + } + *hour_up = AufgangStunden; + *minute_up = AufgangMinuten; + *hour_down = UntergangStunden; + *minute_down = UntergangMinuten; +} + +String GetSun(byte dawn) +{ + 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); +} + +uint16_t GetSunMinutes(byte dawn) +{ + 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 + +/*******************************************************************************************/ void TimerEverySecond() { if (RtcTime.valid) { - uint16_t time = (RtcTime.hour * 60) + RtcTime.minute; - uint8_t days = 1 << (RtcTime.day_of_week -1); + if (RtcTime.minute != timer_last_minute) { // Execute every minute + timer_last_minute = RtcTime.minute; + uint16_t time = (RtcTime.hour *60) + RtcTime.minute; + uint8_t days = 1 << (RtcTime.day_of_week -1); - for (byte i = 0; i < MAX_TIMERS; i++) { - if (Settings.timer[i].device >= devices_present) Settings.timer[i].data = 0; // Reset timer due to change in devices present - if (Settings.timer[i].arm) { - if (time == Settings.timer[i].time) { - if (!bitRead(fired, i) && (Settings.timer[i].days & days)) { - bitSet(fired, i); - Settings.timer[i].arm = Settings.timer[i].repeat; - ExecuteCommandPower(Settings.timer[i].device +1, Settings.timer[i].power); + for (byte i = 0; i < MAX_TIMERS; i++) { + if (Settings.timer[i].device >= devices_present) Settings.timer[i].data = 0; // Reset timer due to change in devices present + uint16_t set_time = Settings.timer[i].time; +#ifdef USE_SUNRISE + if ((1 == Settings.timer[i].mode) || (2 == Settings.timer[i].mode)) { // Sunrise or Sunset + set_time = GetSunMinutes(Settings.timer[i].mode -1); + } +#endif + if (Settings.timer[i].arm) { + if (time == set_time) { + if (!bitRead(timer_fired, i) && (Settings.timer[i].days & days)) { + bitSet(timer_fired, i); + Settings.timer[i].arm = Settings.timer[i].repeat; + ExecuteCommandPower(Settings.timer[i].device +1, Settings.timer[i].power); + } + } else { + bitClear(timer_fired, i); } - } else { - bitClear(fired, i); } } } @@ -70,8 +244,13 @@ void PrepShowTimer(uint8_t index) uint8_t mask = 1 << i; snprintf(days, sizeof(days), "%s%d", days, ((Settings.timer[index].days & mask) > 0)); } +#ifdef USE_SUNRISE + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"" D_CMND_TIMER "%d\":{\"" D_JSON_TIMER_ARM "\":%d,\"" D_JSON_TIMER_MODE "\":%d,\"" D_JSON_TIMER_TIME "\":\"%02d:%02d\",\"" D_JSON_TIMER_DAYS "\":\"%s\",\"" D_JSON_TIMER_REPEAT "\":%d,\"" D_JSON_TIMER_OUTPUT "\":%d,\"" D_JSON_TIMER_POWER "\":%d}"), + mqtt_data, index +1, Settings.timer[index].arm, Settings.timer[index].mode, Settings.timer[index].time / 60, Settings.timer[index].time % 60, days, Settings.timer[index].repeat, Settings.timer[index].device +1, Settings.timer[index].power); +#else snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"" D_CMND_TIMER "%d\":{\"" D_JSON_TIMER_ARM "\":%d,\"" D_JSON_TIMER_TIME "\":\"%02d:%02d\",\"" D_JSON_TIMER_DAYS "\":\"%s\",\"" D_JSON_TIMER_REPEAT "\":%d,\"" D_JSON_TIMER_OUTPUT "\":%d,\"" D_JSON_TIMER_POWER "\":%d}"), mqtt_data, index +1, Settings.timer[index].arm, Settings.timer[index].time / 60, Settings.timer[index].time % 60, days, Settings.timer[index].repeat, Settings.timer[index].device +1, Settings.timer[index].power); +#endif // USE_SUNRISE } /*********************************************************************************************\ @@ -110,6 +289,11 @@ boolean TimerCommand() if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_ARM))].success()) { Settings.timer[index].arm = (root[parm_uc] != 0); } +#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 if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_TIME))].success()) { uint16_t itime = 0; uint8_t value = 0; @@ -154,7 +338,7 @@ boolean TimerCommand() if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_POWER))].success()) { Settings.timer[index].power = (uint8_t)root[parm_uc] & 0x03; } - if (Settings.timer[index].arm) bitClear(fired, index); + if (Settings.timer[index].arm) bitClear(timer_fired, index); index++; } @@ -181,7 +365,7 @@ boolean TimerCommand() } jsflg = 1; PrepShowTimer(i +1); - if ((strlen(mqtt_data) > (LOGSZ - TOPSZ)) || (i == MAX_TIMERS -1)) { + if ((strlen(mqtt_data) > (LOGSZ - TOPSZ - 20)) || (i == MAX_TIMERS -1)) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}}"), mqtt_data); MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_TIMERS)); jsflg = 0; @@ -189,6 +373,24 @@ boolean TimerCommand() } mqtt_data[0] = '\0'; } +#ifdef USE_SUNRISE + else if (CMND_LONGITUDE == command_code) { + if (XdrvMailbox.data_len) { + Settings.longitude = (int)(AtoD(XdrvMailbox.data) *1000000); + } + char lbuff[32]; + dtostrfd(((double)Settings.longitude) /1000000, 6, lbuff); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, lbuff); + } + else if (CMND_LATITUDE == command_code) { + if (XdrvMailbox.data_len) { + Settings.latitude = (int)(AtoD(XdrvMailbox.data) *1000000); + } + char lbuff[32]; + dtostrfd(((double)Settings.latitude) /1000000, 6, lbuff); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, lbuff); + } +#endif else serviced = false; return serviced; @@ -210,12 +412,26 @@ const char HTTP_TIMER_SCRIPT[] PROGMEM = "o.textContent=i;" "q.appendChild(o);" "}" +#ifdef USE_SUNRISE + "function gt(){" // Set hours and minutas according to mode + "var m,p,q;" + "m=qs('input[name=\"rd\"]:checked').value;" // Get mode + "if(m==0){p=pt[ct]&0x7FF;}" // Schedule time + "if(m==1){p=pt[" STR(MAX_TIMERS) "];}" // Sunrise + "if(m==2){p=pt[" STR(MAX_TIMERS +1) "];}" // Sunset + "q=Math.floor(p/60);if(q<10){q='0'+q;}qs('#ho').value=q;" // Set hours + "q=p%60;if(q<10){q='0'+q;}qs('#mi').value=q;" // Set minutes + "}" +#endif "function st(){" // Save parameters to hidden area "var i,n,p,s;" "s=0;" "n=1<<30;if(eb('a0').checked){s|=n;}" // Get arm "n=1<<29;if(eb('r0').checked){s|=n;}" // Get repeat "for(i=0;i<7;i++){n=1<<(16+i);if(eb('w'+i).checked){s|=n;}}" // Get weekdays +#ifdef USE_SUNRISE + "s|=(qs('input[name=\"rd\"]:checked').value<<11);" // Get mode +#endif "s|=(eb('p1').value<<27);" // Get power "s|=(qs('#d1').selectedIndex<<23);" // Get device "s|=((qs('#ho').selectedIndex*60)+qs('#mi').selectedIndex)&0x7FF;" // Get time @@ -224,22 +440,25 @@ const char HTTP_TIMER_SCRIPT[] PROGMEM = "}" "function ot(t,e){" // Select tab and update elements "var i,n,o,p,q,s;" - "if(ct<99){" - "st();" // Save changes - "}" + "if(ct<99){st();}" // Save changes + "ct=t;" "o=document.getElementsByClassName('tl');" // Restore style to all tabs/buttons "for(i=0;i>11)&3;eb('b'+p).checked=1;" // Set mode + "gt();" // Set hours and minutes according to mode +#else "p=s&0x7FF;" // Get time "q=Math.floor(p/60);if(q<10){q='0'+q;}qs('#ho').value=q;" // Set hours "q=p%60;if(q<10){q='0'+q;}qs('#mi').value=q;" // Set minutes +#endif "for(i=0;i<7;i++){p=(s>>(16+i))&1;eb('w'+i).checked=p;}" // Set weekdays "p=(s>>23)&0xF;qs('#d1').value=p+1;" // Set device "p=(s>>27)&3;eb('p1').value=p;" // Set power "p=(s>>29)&1;eb('r0').checked=p;" // Set repeat "p=(s>>30)&1;eb('a0').checked=p;" // Set arm - "ct=t;" "}" "function it(){" // Initialize elements and select first tab "var b,i,o,s;" @@ -256,6 +475,9 @@ const char HTTP_TIMER_SCRIPT[] PROGMEM = "}"; const char HTTP_TIMER_STYLE[] PROGMEM = ".tl{float:left;border-radius:0;border:1px solid #fff;padding:1px;width:6.25%;}" +#ifdef USE_SUNRISE + "input[type='radio']{width:13px;height:34px;margin-top:-1px;margin-right:8px;vertical-align:middle;}" +#endif ""; const char HTTP_FORM_TIMER[] PROGMEM = "
 " D_TIMER_PARAMETERS " 
" @@ -263,8 +485,8 @@ const char HTTP_FORM_TIMER[] PROGMEM = const char HTTP_FORM_TIMER1[] PROGMEM = "' hidden>



" "
" - "" D_TIMER_OUTPUT "  " - "" D_TIMER_POWER "  " + "" D_TIMER_POWER " " "

" "
" -// "Time  " - "" D_TIMER_TIME "  " D_HOUR_MINUTE_SEPARATOR "  " "" D_TIMER_ARM " " "" D_TIMER_REPEAT "" + "

" + "
" +// "Time " +#ifdef USE_SUNRISE + "
" + "" D_TIMER_TIME " " + "" + " " D_HOUR_MINUTE_SEPARATOR " " + "
" + "" D_SUNRISE "
" + "" D_SUNSET "
" + "
" +#else + "" D_TIMER_TIME " " + "" + " " D_HOUR_MINUTE_SEPARATOR " " + "" +#endif // USE_SUNRISE "

" "
"; const char HTTP_FORM_TIMER2[] PROGMEM = @@ -301,8 +539,15 @@ void HandleTimerConfiguration() if (i > 0) page += F(","); page += String(Settings.timer[i].data); } +#ifdef USE_SUNRISE + page += F(","); page += String(GetSunMinutes(0)); // Add Sunrise + page += F(","); page += String(GetSunMinutes(1)); // Add Sunset +#endif // USE_SUNRISE page += FPSTR(HTTP_FORM_TIMER1); page.replace(F("}1"), String(devices_present)); +#ifdef USE_SUNRISE + page.replace(F("299"), String(180 + (strlen(D_TIMER_TIME) *10))); // Fix string length to keep radios centered +#endif // USE_SUNRISE page += FPSTR(HTTP_FORM_END); page.replace(F("type='submit'"), FPSTR(HTTP_FORM_TIMER2)); page += F(""); // Init elements and select first tab/button @@ -313,14 +558,20 @@ void HandleTimerConfiguration() void TimerSaveSettings() { char tmp[MAX_TIMERS *12]; // Need space for MAX_TIMERS x 10 digit numbers separated by a comma + Timer timer; WebGetArg("t0", tmp, sizeof(tmp)); char *p = tmp; snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_CMND_TIMERS " ")); for (byte i = 0; i < MAX_TIMERS; i++) { - uint32_t data = strtol(p, &p, 10); + timer.data = strtol(p, &p, 10); p++; // Skip comma - if ((data & 0x7FF) < 1440) Settings.timer[i].data = data; + if (timer.time < 1440) { +#ifdef USE_SUNRISE + if ((1 == timer.mode) || (2 == timer.mode)) timer.time = Settings.timer[i].time; // Do not save time on Sunrise or Sunset +#endif + Settings.timer[i].data = timer.data; + } snprintf_P(log_data, sizeof(log_data), PSTR("%s%s0x%08X"), log_data, (i > 0)?",":"", Settings.timer[i].data); } AddLog(LOG_LEVEL_DEBUG);