From 23c16e58a991f3934af5ae1dc3c66bd68e1ae83d Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 20 Nov 2018 15:00:24 +0100 Subject: [PATCH] Housekeeping Housekeeping --- sonoff/_changelog.ino | 2 +- sonoff/sonoff.ino | 3 +- sonoff/support.ino | 748 +---------------------------------- sonoff/support_features.ino | 381 ++++++++++++++++++ sonoff/support_rtc.ino | 418 ++++++++++++++++++++ sonoff/support_wifi.ino | 6 - sonoff/xdrv_01_webserver.ino | 2 +- sonoff/xdrv_02_mqtt.ino | 6 + sonoff/xdrv_03_energy.ino | 2 + tools/decode-status.py | 7 +- 10 files changed, 817 insertions(+), 758 deletions(-) create mode 100644 sonoff/support_features.ino create mode 100644 sonoff/support_rtc.ino diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index bcca8cde8..cd44e7dbd 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -2,7 +2,7 @@ * Add delays removed in 6.3.0.9 (#4233) * Allow user definition of defines WIFI_RSSI_THRESHOLD (default 10) and WIFI_RESCAN_MINUTES (default 44) * Add support for Fujitsu HVac and IrRemote (#4387) - * + * * 6.3.0.10 20181118 * Add command SetOption36 0..255 milliseconds (50 default) to tune main loop dynamic delay * Add support for LG HVac and IrRemote (#4377) diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 486a3ba93..949f82cb7 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -45,8 +45,7 @@ #endif // Libraries -#include // RTC, Energy, OSWatch -#include // MQTT, Ota +#include // Ota #include // Ota #include // Webserver, Updater #include // WemoHue, IRremote, Domoticz diff --git a/sonoff/support.ino b/sonoff/support.ino index 64af2e472..f32657c37 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -24,6 +24,8 @@ uint32_t syslog_host_hash = 0; // Syslog host name hash * Watchdog extension (https://github.com/esp8266/Arduino/issues/1532) \*********************************************************************************************/ +#include + Ticker tickerOSWatch; #define OSWATCH_RESET_TIME 120 @@ -835,347 +837,6 @@ void SetNextTimeInterval(unsigned long& timer, const unsigned long step) } // Try to get in sync again. timer = millis() + (step - passed); -} - -/*********************************************************************************************\ - * Fill feature list -\*********************************************************************************************/ - -void GetFeatures(void) -{ - feature_drv1 = 0x00000000; // xdrv_01_mqtt.ino, xdrv_01_light.ino, xdrv_04_snfbridge.ino - -// feature_drv1 |= 0x00000001; -// feature_drv1 |= 0x00000002; - -#ifdef USE_I2C - feature_drv1 |= 0x00000004; // sonoff.ino -#endif -#ifdef USE_SPI - feature_drv1 |= 0x00000008; // sonoff.ino -#endif -#ifdef USE_DISCOVERY - feature_drv1 |= 0x00000010; // sonoff.ino -#endif -#ifdef USE_ARDUINO_OTA - feature_drv1 |= 0x00000020; // sonoff.ino -#endif -#ifdef USE_MQTT_TLS - feature_drv1 |= 0x00000040; // sonoff.ino -#endif -#ifdef USE_WEBSERVER - feature_drv1 |= 0x00000080; // xdrv_02_webserver.ino -#endif -#ifdef WEBSERVER_ADVERTISE - feature_drv1 |= 0x00000100; // xdrv_02_webserver.ino -#endif -#ifdef USE_EMULATION - feature_drv1 |= 0x00000200; // xplg_wemohue.ino -#endif -#if (MQTT_LIBRARY_TYPE == MQTT_PUBSUBCLIENT) - feature_drv1 |= 0x00000400; // xdrv_01_mqtt.ino -#endif -#if (MQTT_LIBRARY_TYPE == MQTT_TASMOTAMQTT) - feature_drv1 |= 0x00000800; // xdrv_01_mqtt.ino -#endif -#if (MQTT_LIBRARY_TYPE == MQTT_ESPMQTTARDUINO) // Obsolete since 6.2.1.11 - feature_drv1 |= 0x00001000; // xdrv_01_mqtt.ino -#endif -#ifdef MQTT_HOST_DISCOVERY - feature_drv1 |= 0x00002000; // xdrv_01_mqtt.ino -#endif -#ifdef USE_ARILUX_RF - feature_drv1 |= 0x00004000; // xdrv_04_light.ino -#endif -#ifdef USE_WS2812 - feature_drv1 |= 0x00008000; // xdrv_04_light.ino -#endif -#ifdef USE_WS2812_DMA - feature_drv1 |= 0x00010000; // xdrv_04_light.ino -#endif -#ifdef USE_IR_REMOTE - feature_drv1 |= 0x00020000; // xdrv_05_irremote.ino -#endif -#ifdef USE_IR_HVAC - feature_drv1 |= 0x00040000; // xdrv_05_irremote.ino -#endif -#ifdef USE_IR_RECEIVE - feature_drv1 |= 0x00080000; // xdrv_05_irremote.ino -#endif -#ifdef USE_DOMOTICZ - feature_drv1 |= 0x00100000; // xdrv_07_domoticz.ino -#endif -#ifdef USE_DISPLAY - feature_drv1 |= 0x00200000; // xdrv_13_display.ino -#endif -#ifdef USE_HOME_ASSISTANT - feature_drv1 |= 0x00400000; // xdrv_12_home_assistant.ino -#endif -#ifdef USE_SERIAL_BRIDGE - feature_drv1 |= 0x00800000; // xdrv_08_serial_bridge.ino -#endif -#ifdef USE_TIMERS - feature_drv1 |= 0x01000000; // xdrv_09_timers.ino -#endif -#ifdef USE_SUNRISE - feature_drv1 |= 0x02000000; // xdrv_09_timers.ino -#endif -#ifdef USE_TIMERS_WEB - feature_drv1 |= 0x04000000; // xdrv_09_timers.ino -#endif -#ifdef USE_RULES - feature_drv1 |= 0x08000000; // xdrv_10_rules.ino -#endif -#ifdef USE_KNX - feature_drv1 |= 0x10000000; // xdrv_11_knx.ino -#endif -#ifdef USE_WPS - feature_drv1 |= 0x20000000; // support.ino -#endif -#ifdef USE_SMARTCONFIG - feature_drv1 |= 0x40000000; // support.ino -#endif -#if (MQTT_LIBRARY_TYPE == MQTT_ARDUINOMQTT) - feature_drv1 |= 0x80000000; // xdrv_01_mqtt.ino -#endif - -/*********************************************************************************************/ - - feature_drv2 = 0x00000000; - -#ifdef USE_CONFIG_OVERRIDE - feature_drv2 |= 0x00000001; // user_config(_override).h -#endif -#ifdef BE_MINIMAL - feature_drv2 |= 0x00000002; // user_config(_override).h -#endif -#ifdef USE_SENSORS - feature_drv2 |= 0x00000004; // user_config(_override).h -#endif -#ifdef USE_CLASSIC - feature_drv2 |= 0x00000008; // user_config(_override).h -#endif -#ifdef USE_KNX_NO_EMULATION - feature_drv2 |= 0x00000010; // user_config(_override).h -#endif -#ifdef USE_DISPLAY_MODES1TO5 - feature_drv2 |= 0x00000020; // xdrv_13_display.ino -#endif -#ifdef USE_DISPLAY_GRAPH - feature_drv2 |= 0x00000040; // xdrv_13_display.ino -#endif -#ifdef USE_DISPLAY_LCD - feature_drv2 |= 0x00000080; // xdsp_01_lcd.ino -#endif -#ifdef USE_DISPLAY_SSD1306 - feature_drv2 |= 0x00000100; // xdsp_02_ssd1306.ino -#endif -#ifdef USE_DISPLAY_MATRIX - feature_drv2 |= 0x00000200; // xdsp_03_matrix.ino -#endif -#ifdef USE_DISPLAY_ILI9341 - feature_drv2 |= 0x00000400; // xdsp_04_ili9341.ino -#endif -#ifdef USE_DISPLAY_EPAPER - feature_drv2 |= 0x00000800; // xdsp_05_epaper.ino -#endif -#ifdef USE_DISPLAY_SH1106 - feature_drv2 |= 0x00001000; // xdsp_06_sh1106.ino -#endif -#ifdef USE_MP3_PLAYER - feature_drv2 |= 0x00002000; // xdrv_14_mp3.ino -#endif -#ifdef USE_PCA9685 - feature_drv2 |= 0x00004000; // xdrv_15_pca9685.ino -#endif -#ifdef USE_TUYA_DIMMER - feature_drv2 |= 0x00008000; // xdrv_16_tuyadimmer.ino -#endif -#ifdef USE_RC_SWITCH - feature_drv2 |= 0x00010000; // xdrv_17_rcswitch.ino -#endif -#ifdef USE_ARMTRONIX_DIMMERS - feature_drv2 |= 0x00020000; // xdrv_18_armtronixdimmer.ino -#endif - - -#ifdef NO_EXTRA_4K_HEAP - feature_drv2 |= 0x00800000; // sonoff_post.h -#endif -#ifdef VTABLES_IN_IRAM - feature_drv2 |= 0x01000000; // platformio.ini -#endif -#ifdef VTABLES_IN_DRAM - feature_drv2 |= 0x02000000; // platformio.ini -#endif -#ifdef VTABLES_IN_FLASH - feature_drv2 |= 0x04000000; // platformio.ini -#endif -#ifdef PIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH - feature_drv2 |= 0x08000000; // platformio.ini -#endif -#ifdef PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY - feature_drv2 |= 0x10000000; // platformio.ini -#endif -#ifdef PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH - feature_drv2 |= 0x20000000; // platformio.ini -#endif -#ifdef DEBUG_THEO - feature_drv2 |= 0x40000000; // xdrv_99_debug.ino -#endif -#ifdef USE_DEBUG_DRIVER - feature_drv2 |= 0x80000000; // xdrv_99_debug.ino -#endif - -/*********************************************************************************************/ - - feature_sns1 = 0x00000000; // xsns_01_counter.ino, xsns_04_snfsc.ino - -// feature_sns1 |= 0x00000001; - -#ifdef USE_ADC_VCC - feature_sns1 |= 0x00000002; // support.ino (ADC) -#endif -#ifdef USE_ENERGY_SENSOR - feature_sns1 |= 0x00000004; // xdrv_03_energy.ino -#endif -#ifdef USE_PZEM004T - feature_sns1 |= 0x00000008; // xnrg_03_pzem004t.ino -#endif -#ifdef USE_DS18B20 - feature_sns1 |= 0x00000010; // xsns_05_ds18b20.ino -#endif -#ifdef USE_DS18x20_LEGACY - feature_sns1 |= 0x00000020; // xsns_05_ds18x20_legacy.ino -#endif -#ifdef USE_DS18x20 - feature_sns1 |= 0x00000040; // xsns_05_ds18x20.ino -#endif -#ifdef USE_DHT - feature_sns1 |= 0x00000080; // xsns_06_dht.ino -#endif -#ifdef USE_SHT - feature_sns1 |= 0x00000100; // xsns_07_sht1x.ino -#endif -#ifdef USE_HTU - feature_sns1 |= 0x00000200; // xsns_08_htu21.ino -#endif -#ifdef USE_BMP - feature_sns1 |= 0x00000400; // xsns_09_bmp.ino -#endif -#ifdef USE_BME680 - feature_sns1 |= 0x00000800; // xsns_09_bmp.ino - BME680 -#endif -#ifdef USE_BH1750 - feature_sns1 |= 0x00001000; // xsns_10_bh1750.ino -#endif -#ifdef USE_VEML6070 - feature_sns1 |= 0x00002000; // xsns_11_veml6070.ino -#endif -#ifdef USE_ADS1115_I2CDEV - feature_sns1 |= 0x00004000; // xsns_12_ads1115_i2cdev.ino -#endif -#ifdef USE_ADS1115 - feature_sns1 |= 0x00008000; // xsns_12_ads1115.ino -#endif -#ifdef USE_INA219 - feature_sns1 |= 0x00010000; // xsns_13_ina219.ino -#endif -#ifdef USE_SHT3X - feature_sns1 |= 0x00020000; // xsns_14_sht3x.ino -#endif -#ifdef USE_MHZ19 - feature_sns1 |= 0x00040000; // xsns_15_mhz19.ino -#endif -#ifdef USE_TSL2561 - feature_sns1 |= 0x00080000; // xsns_16_tsl2561.ino -#endif -#ifdef USE_SENSEAIR - feature_sns1 |= 0x00100000; // xsns_17_senseair.ino -#endif -#ifdef USE_PMS5003 - feature_sns1 |= 0x00200000; // xsns_18_pms5003.ino -#endif -#ifdef USE_MGS - feature_sns1 |= 0x00400000; // xsns_19_mgs.ino -#endif -#ifdef USE_NOVA_SDS - feature_sns1 |= 0x00800000; // xsns_20_novasds.ino -#endif -#ifdef USE_SGP30 - feature_sns1 |= 0x01000000; // xsns_21_sgp30.ino -#endif -#ifdef USE_SR04 - feature_sns1 |= 0x02000000; // xsns_22_sr04.ino -#endif -#ifdef USE_SDM120 - feature_sns1 |= 0x04000000; // xsns_23_sdm120.ino -#endif -#ifdef USE_SI1145 - feature_sns1 |= 0x08000000; // xsns_24_si1145.ino -#endif -#ifdef USE_SDM630 - feature_sns1 |= 0x10000000; // xsns_25_sdm630.ino -#endif -#ifdef USE_LM75AD - feature_sns1 |= 0x20000000; // xsns_26_lm75ad.ino -#endif -#ifdef USE_APDS9960 - feature_sns1 |= 0x40000000; // xsns_27_apds9960.ino -#endif -#ifdef USE_TM1638 - feature_sns1 |= 0x80000000; // xsns_28_tm1638.ino -#endif - -/*********************************************************************************************/ - - feature_sns2 = 0x00000000; - -#ifdef USE_MCP230xx - feature_sns2 |= 0x00000001; // xsns_29_mcp230xx.ino -#endif -#ifdef USE_MPR121 - feature_sns2 |= 0x00000002; // xsns_30_mpr121.ino -#endif -#ifdef USE_CCS811 - feature_sns2 |= 0x00000004; // xsns_31_ccs811.ino -#endif -#ifdef USE_MPU6050 - feature_sns2 |= 0x00000008; // xsns_32_mpu6050.ino -#endif -#ifdef USE_MCP230xx_OUTPUT - feature_sns2 |= 0x00000010; // xsns_29_mcp230xx.ino -#endif -#ifdef USE_MCP230xx_DISPLAYOUTPUT - feature_sns2 |= 0x00000020; // xsns_29_mcp230xx.ino -#endif -#ifdef USE_HLW8012 - feature_sns2 |= 0x00000040; // xnrg_01_hlw8012.ino -#endif -#ifdef USE_CSE7766 - feature_sns2 |= 0x00000080; // xnrg_02_cse7766.ino -#endif -#ifdef USE_MCP39F501 - feature_sns2 |= 0x00000100; // xnrg_04_mcp39f501.ino -#endif -#ifdef USE_PZEM_AC - feature_sns2 |= 0x00000200; // xnrg_05_pzem_ac.ino -#endif -#ifdef USE_DS3231 - feature_sns2 |= 0x00000400; // xsns_33_ds3231.ino -#endif -#ifdef USE_HX711 - feature_sns2 |= 0x00000800; // xsns_34_hx711.ino -#endif -#ifdef USE_PZEM_DC - feature_sns2 |= 0x00001000; // xnrg_06_pzem_dc.ino -#endif -#ifdef USE_TX20_WIND_SENSOR - feature_sns2 |= 0x00002000; // xsns_35_tx20.ino -#endif - - - } /*********************************************************************************************\ @@ -1388,407 +1049,6 @@ boolean I2cDevice(byte addr) } #endif // USE_I2C -/*********************************************************************************************\ - * Real Time Clock - * - * Sources: Time by Michael Margolis and Paul Stoffregen (https://github.com/PaulStoffregen/Time) - * Timezone by Jack Christensen (https://github.com/JChristensen/Timezone) -\*********************************************************************************************/ - -extern "C" { -#include "sntp.h" -} - -#define SECS_PER_MIN ((uint32_t)(60UL)) -#define SECS_PER_HOUR ((uint32_t)(3600UL)) -#define SECS_PER_DAY ((uint32_t)(SECS_PER_HOUR * 24UL)) -#define MINS_PER_HOUR ((uint32_t)(60UL)) -#define LEAP_YEAR(Y) (((1970+Y)>0) && !((1970+Y)%4) && (((1970+Y)%100) || !((1970+Y)%400))) - -Ticker TickerRtc; - -static const uint8_t kDaysInMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; // API starts months from 1, this array starts from 0 -static const char kMonthNamesEnglish[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; - -uint32_t utc_time = 0; -uint32_t local_time = 0; -uint32_t daylight_saving_time = 0; -uint32_t standard_time = 0; -uint32_t ntp_time = 0; -uint32_t midnight = 1451602800; -uint32_t restart_time = 0; -int32_t time_timezone = 0; -uint8_t midnight_now = 0; -uint8_t ntp_sync_minute = 0; - -String GetBuildDateAndTime(void) -{ - // "2017-03-07T11:08:02" - ISO8601:2004 - char bdt[21]; - char *p; - char mdate[] = __DATE__; // "Mar 7 2017" - char *smonth = mdate; - int day = 0; - int year = 0; - - // sscanf(mdate, "%s %d %d", bdt, &day, &year); // Not implemented in 2.3.0 and probably too much code - byte i = 0; - for (char *str = strtok_r(mdate, " ", &p); str && i < 3; str = strtok_r(NULL, " ", &p)) { - switch (i++) { - case 0: // Month - smonth = str; - break; - case 1: // Day - day = atoi(str); - break; - case 2: // Year - year = atoi(str); - } - } - int month = (strstr(kMonthNamesEnglish, smonth) -kMonthNamesEnglish) /3 +1; - snprintf_P(bdt, sizeof(bdt), PSTR("%d" D_YEAR_MONTH_SEPARATOR "%02d" D_MONTH_DAY_SEPARATOR "%02d" D_DATE_TIME_SEPARATOR "%s"), year, month, day, __TIME__); - return String(bdt); // 2017-03-07T11:08:02 -} - -String GetTimeZone(void) -{ - char tz[7]; - - snprintf_P(tz, sizeof(tz), PSTR("%+03d:%02d"), time_timezone / 60, abs(time_timezone % 60)); - - return String(tz); // -03:45 -} - -/* - * timestamps in https://en.wikipedia.org/wiki/ISO_8601 format - * - * DT_UTC - current data and time in Greenwich, England (aka GMT) - * DT_LOCAL - current date and time taking timezone into account - * DT_RESTART - the date and time this device last started, in local timezone - * - * Format: - * "2017-03-07T11:08:02-07:00" - if DT_LOCAL and SetOption52 = 1 - * "2017-03-07T11:08:02" - otherwise - */ -String GetDateAndTime(byte time_type) -{ - // "2017-03-07T11:08:02-07:00" - ISO8601:2004 - char dt[27]; - TIME_T tmpTime; - - switch (time_type) { - case DT_ENERGY: - BreakTime(Settings.energy_kWhtotal_time, tmpTime); - tmpTime.year += 1970; - break; - case DT_UTC: - BreakTime(utc_time, tmpTime); - tmpTime.year += 1970; - break; - case DT_RESTART: - if (restart_time == 0) { - return ""; - } - BreakTime(restart_time, tmpTime); - tmpTime.year += 1970; - break; - default: - tmpTime = RtcTime; - } - - snprintf_P(dt, sizeof(dt), PSTR("%04d-%02d-%02dT%02d:%02d:%02d"), - tmpTime.year, tmpTime.month, tmpTime.day_of_month, tmpTime.hour, tmpTime.minute, tmpTime.second); - - if (Settings.flag3.time_append_timezone && (DT_LOCAL == time_type)) { -// if (Settings.flag3.time_append_timezone && ((DT_LOCAL == time_type) || (DT_ENERGY == time_type))) { - strncat(dt, GetTimeZone().c_str(), sizeof(dt)); - } - - return String(dt); // 2017-03-07T11:08:02-07:00 -} - -String GetTime(int type) -{ - /* type 1 - Local time - * type 2 - Daylight Savings time - * type 3 - Standard time - */ - char stime[25]; // Skip newline - - uint32_t time = utc_time; - if (1 == type) time = local_time; - if (2 == type) time = daylight_saving_time; - if (3 == type) time = standard_time; - snprintf_P(stime, sizeof(stime), sntp_get_real_time(time)); - - return String(stime); // Thu Nov 01 11:41:02 2018 -} - -String GetUptime(void) -{ - char dt[16]; - - TIME_T ut; - - if (restart_time) { - BreakTime(utc_time - restart_time, ut); - } else { - BreakTime(uptime, ut); - } - - // "P128DT14H35M44S" - ISO8601:2004 - https://en.wikipedia.org/wiki/ISO_8601 Durations -// snprintf_P(dt, sizeof(dt), PSTR("P%dDT%02dH%02dM%02dS"), ut.days, ut.hour, ut.minute, ut.second); - - // "128 14:35:44" - OpenVMS - // "128T14:35:44" - Tasmota - snprintf_P(dt, sizeof(dt), PSTR("%dT%02d:%02d:%02d"), ut.days, ut.hour, ut.minute, ut.second); - - return String(dt); // 128T14:35:44 -} - -uint32_t GetMinutesUptime(void) -{ - TIME_T ut; - - if (restart_time) { - BreakTime(utc_time - restart_time, ut); - } else { - BreakTime(uptime, ut); - } - - return (ut.days *1440) + (ut.hour *60) + ut.minute; -} - -uint32_t GetMinutesPastMidnight(void) -{ - uint32_t minutes = 0; - - if (RtcTime.valid) { - minutes = (RtcTime.hour *60) + RtcTime.minute; - } - return minutes; -} - -void BreakTime(uint32_t time_input, TIME_T &tm) -{ -// break the given time_input into time components -// this is a more compact version of the C library localtime function -// note that year is offset from 1970 !!! - - uint8_t year; - uint8_t month; - uint8_t month_length; - uint32_t time; - unsigned long days; - - time = time_input; - tm.second = time % 60; - time /= 60; // now it is minutes - tm.minute = time % 60; - time /= 60; // now it is hours - tm.hour = time % 24; - time /= 24; // now it is days - tm.days = time; - tm.day_of_week = ((time + 4) % 7) + 1; // Sunday is day 1 - - year = 0; - days = 0; - while((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) { - year++; - } - tm.year = year; // year is offset from 1970 - - days -= LEAP_YEAR(year) ? 366 : 365; - time -= days; // now it is days in this year, starting at 0 - tm.day_of_year = time; - - days = 0; - month = 0; - month_length = 0; - for (month = 0; month < 12; month++) { - if (1 == month) { // february - if (LEAP_YEAR(year)) { - month_length = 29; - } else { - month_length = 28; - } - } else { - month_length = kDaysInMonth[month]; - } - - if (time >= month_length) { - time -= month_length; - } else { - break; - } - } - strlcpy(tm.name_of_month, kMonthNames + (month *3), 4); - tm.month = month + 1; // jan is month 1 - tm.day_of_month = time + 1; // day of month - tm.valid = (time_input > 1451602800); // 2016-01-01 -} - -uint32_t MakeTime(TIME_T &tm) -{ -// assemble time elements into time_t -// note year argument is offset from 1970 - - int i; - uint32_t seconds; - - // seconds from 1970 till 1 jan 00:00:00 of the given year - seconds = tm.year * (SECS_PER_DAY * 365); - for (i = 0; i < tm.year; i++) { - if (LEAP_YEAR(i)) { - seconds += SECS_PER_DAY; // add extra days for leap years - } - } - - // add days for this year, months start from 1 - for (i = 1; i < tm.month; i++) { - if ((2 == i) && LEAP_YEAR(tm.year)) { - seconds += SECS_PER_DAY * 29; - } else { - seconds += SECS_PER_DAY * kDaysInMonth[i-1]; // monthDay array starts from 0 - } - } - seconds+= (tm.day_of_month - 1) * SECS_PER_DAY; - seconds+= tm.hour * SECS_PER_HOUR; - seconds+= tm.minute * SECS_PER_MIN; - seconds+= tm.second; - return seconds; -} - -uint32_t RuleToTime(TimeRule r, int yr) -{ - TIME_T tm; - uint32_t t; - uint8_t m; - uint8_t w; // temp copies of r.month and r.week - - m = r.month; - w = r.week; - if (0 == w) { // Last week = 0 - if (++m > 12) { // for "Last", go to the next month - m = 1; - yr++; - } - w = 1; // and treat as first week of next month, subtract 7 days later - } - - tm.hour = r.hour; - tm.minute = 0; - tm.second = 0; - tm.day_of_month = 1; - tm.month = m; - tm.year = yr - 1970; - t = MakeTime(tm); // First day of the month, or first day of next month for "Last" rules - BreakTime(t, tm); - t += (7 * (w - 1) + (r.dow - tm.day_of_week + 7) % 7) * SECS_PER_DAY; - if (0 == r.week) { - t -= 7 * SECS_PER_DAY; // back up a week if this is a "Last" rule - } - return t; -} - -uint32_t LocalTime(void) -{ - return local_time; -} - -uint32_t Midnight(void) -{ - return midnight; -} - -boolean MidnightNow(void) -{ - boolean mnflg = midnight_now; - if (mnflg) midnight_now = 0; - return mnflg; -} - -void RtcSecond(void) -{ - TIME_T tmpTime; - - if ((ntp_sync_minute > 59) && (RtcTime.minute > 2)) ntp_sync_minute = 1; // If sync prepare for a new cycle - uint8_t offset = (uptime < 30) ? RtcTime.second : (((ESP.getChipId() & 0xF) * 3) + 3) ; // First try ASAP to sync. If fails try once every 60 seconds based on chip id - if (!global_state.wifi_down && (offset == RtcTime.second) && ((RtcTime.year < 2016) || (ntp_sync_minute == RtcTime.minute) || ntp_force_sync)) { - ntp_time = sntp_get_current_timestamp(); - if (ntp_time > 1451602800) { // Fix NTP bug in core 2.4.1/SDK 2.2.1 (returns Thu Jan 01 08:00:10 1970 after power on) - ntp_force_sync = 0; - utc_time = ntp_time; - ntp_sync_minute = 60; // Sync so block further requests - if (restart_time == 0) { - restart_time = utc_time - uptime; // save first ntp time as restart time - } - BreakTime(utc_time, tmpTime); - RtcTime.year = tmpTime.year + 1970; - daylight_saving_time = RuleToTime(Settings.tflag[1], RtcTime.year); - standard_time = RuleToTime(Settings.tflag[0], RtcTime.year); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION "(" D_UTC_TIME ") %s, (" D_DST_TIME ") %s, (" D_STD_TIME ") %s"), - GetTime(0).c_str(), GetTime(2).c_str(), GetTime(3).c_str()); - AddLog(LOG_LEVEL_DEBUG); - if (local_time < 1451602800) { // 2016-01-01 - rules_flag.time_init = 1; - } else { - rules_flag.time_set = 1; - } - } else { - ntp_sync_minute++; // Try again in next minute - } - } - utc_time++; - local_time = utc_time; - if (local_time > 1451602800) { // 2016-01-01 - int16_t timezone_minutes = Settings.timezone_minutes; - if (Settings.timezone < 0) { timezone_minutes *= -1; } - time_timezone = (Settings.timezone * SECS_PER_HOUR) + (timezone_minutes * SECS_PER_MIN); - if (99 == Settings.timezone) { - int32_t dstoffset = Settings.toffset[1] * SECS_PER_MIN; - int32_t stdoffset = Settings.toffset[0] * SECS_PER_MIN; - if (Settings.tflag[1].hemis) { - // Southern hemisphere - if ((utc_time >= (standard_time - dstoffset)) && (utc_time < (daylight_saving_time - stdoffset))) { - time_timezone = stdoffset; // Standard Time - } else { - time_timezone = dstoffset; // Daylight Saving Time - } - } else { - // Northern hemisphere - if ((utc_time >= (daylight_saving_time - stdoffset)) && (utc_time < (standard_time - dstoffset))) { - time_timezone = dstoffset; // Daylight Saving Time - } else { - time_timezone = stdoffset; // Standard Time - } - } - } - local_time += time_timezone; - time_timezone /= 60; - if (!Settings.energy_kWhtotal_time) { Settings.energy_kWhtotal_time = local_time; } - } - BreakTime(local_time, RtcTime); - if (!RtcTime.hour && !RtcTime.minute && !RtcTime.second && RtcTime.valid) { - midnight = local_time; - midnight_now = 1; - } - RtcTime.year += 1970; -} - -void RtcInit(void) -{ - sntp_setservername(0, Settings.ntp_server[0]); - sntp_setservername(1, Settings.ntp_server[1]); - sntp_setservername(2, Settings.ntp_server[2]); - sntp_stop(); - sntp_set_timezone(0); // UTC time - sntp_init(); - utc_time = 0; - BreakTime(utc_time, RtcTime); - TickerRtc.attach(1, RtcSecond); -} - /*********************************************************************************************\ * Syslog * @@ -1920,7 +1180,3 @@ void AddLogMissed(char *sensor, uint8_t misses) snprintf_P(log_data, sizeof(log_data), PSTR("SNS: %s missed %d"), sensor, SENSOR_MAX_MISS - misses); AddLog(LOG_LEVEL_DEBUG); } - -/*********************************************************************************************\ - * -\*********************************************************************************************/ diff --git a/sonoff/support_features.ino b/sonoff/support_features.ino new file mode 100644 index 000000000..826e73090 --- /dev/null +++ b/sonoff/support_features.ino @@ -0,0 +1,381 @@ +/* + support_features.ino - feature support for Sonoff-Tasmota + + Copyright (C) 2018 Theo Arends + + 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 . +*/ + +/*********************************************************************************************\ + * Fill feature list +\*********************************************************************************************/ + +void GetFeatures(void) +{ + feature_drv1 = 0x00000000; // xdrv_01_mqtt.ino, xdrv_01_light.ino, xdrv_04_snfbridge.ino + +// feature_drv1 |= 0x00000001; +// feature_drv1 |= 0x00000002; + +#ifdef USE_I2C + feature_drv1 |= 0x00000004; // sonoff.ino +#endif +#ifdef USE_SPI + feature_drv1 |= 0x00000008; // sonoff.ino +#endif +#ifdef USE_DISCOVERY + feature_drv1 |= 0x00000010; // sonoff.ino +#endif +#ifdef USE_ARDUINO_OTA + feature_drv1 |= 0x00000020; // sonoff.ino +#endif +#ifdef USE_MQTT_TLS + feature_drv1 |= 0x00000040; // sonoff.ino +#endif +#ifdef USE_WEBSERVER + feature_drv1 |= 0x00000080; // xdrv_02_webserver.ino +#endif +#ifdef WEBSERVER_ADVERTISE + feature_drv1 |= 0x00000100; // xdrv_02_webserver.ino +#endif +#ifdef USE_EMULATION + feature_drv1 |= 0x00000200; // xplg_wemohue.ino +#endif +#if (MQTT_LIBRARY_TYPE == MQTT_PUBSUBCLIENT) + feature_drv1 |= 0x00000400; // xdrv_01_mqtt.ino +#endif +#if (MQTT_LIBRARY_TYPE == MQTT_TASMOTAMQTT) + feature_drv1 |= 0x00000800; // xdrv_01_mqtt.ino +#endif +#if (MQTT_LIBRARY_TYPE == MQTT_ESPMQTTARDUINO) // Obsolete since 6.2.1.11 + feature_drv1 |= 0x00001000; // xdrv_01_mqtt.ino +#endif +#ifdef MQTT_HOST_DISCOVERY + feature_drv1 |= 0x00002000; // xdrv_01_mqtt.ino +#endif +#ifdef USE_ARILUX_RF + feature_drv1 |= 0x00004000; // xdrv_04_light.ino +#endif +#ifdef USE_WS2812 + feature_drv1 |= 0x00008000; // xdrv_04_light.ino +#endif +#ifdef USE_WS2812_DMA + feature_drv1 |= 0x00010000; // xdrv_04_light.ino +#endif +#ifdef USE_IR_REMOTE + feature_drv1 |= 0x00020000; // xdrv_05_irremote.ino +#endif +#ifdef USE_IR_HVAC + feature_drv1 |= 0x00040000; // xdrv_05_irremote.ino +#endif +#ifdef USE_IR_RECEIVE + feature_drv1 |= 0x00080000; // xdrv_05_irremote.ino +#endif +#ifdef USE_DOMOTICZ + feature_drv1 |= 0x00100000; // xdrv_07_domoticz.ino +#endif +#ifdef USE_DISPLAY + feature_drv1 |= 0x00200000; // xdrv_13_display.ino +#endif +#ifdef USE_HOME_ASSISTANT + feature_drv1 |= 0x00400000; // xdrv_12_home_assistant.ino +#endif +#ifdef USE_SERIAL_BRIDGE + feature_drv1 |= 0x00800000; // xdrv_08_serial_bridge.ino +#endif +#ifdef USE_TIMERS + feature_drv1 |= 0x01000000; // xdrv_09_timers.ino +#endif +#ifdef USE_SUNRISE + feature_drv1 |= 0x02000000; // xdrv_09_timers.ino +#endif +#ifdef USE_TIMERS_WEB + feature_drv1 |= 0x04000000; // xdrv_09_timers.ino +#endif +#ifdef USE_RULES + feature_drv1 |= 0x08000000; // xdrv_10_rules.ino +#endif +#ifdef USE_KNX + feature_drv1 |= 0x10000000; // xdrv_11_knx.ino +#endif +#ifdef USE_WPS + feature_drv1 |= 0x20000000; // support.ino +#endif +#ifdef USE_SMARTCONFIG + feature_drv1 |= 0x40000000; // support.ino +#endif +#if (MQTT_LIBRARY_TYPE == MQTT_ARDUINOMQTT) + feature_drv1 |= 0x80000000; // xdrv_01_mqtt.ino +#endif + +/*********************************************************************************************/ + + feature_drv2 = 0x00000000; + +#ifdef USE_CONFIG_OVERRIDE + feature_drv2 |= 0x00000001; // user_config(_override).h +#endif +#ifdef BE_MINIMAL + feature_drv2 |= 0x00000002; // user_config(_override).h +#endif +#ifdef USE_SENSORS + feature_drv2 |= 0x00000004; // user_config(_override).h +#endif +#ifdef USE_CLASSIC + feature_drv2 |= 0x00000008; // user_config(_override).h +#endif +#ifdef USE_KNX_NO_EMULATION + feature_drv2 |= 0x00000010; // user_config(_override).h +#endif +#ifdef USE_DISPLAY_MODES1TO5 + feature_drv2 |= 0x00000020; // xdrv_13_display.ino +#endif +#ifdef USE_DISPLAY_GRAPH + feature_drv2 |= 0x00000040; // xdrv_13_display.ino +#endif +#ifdef USE_DISPLAY_LCD + feature_drv2 |= 0x00000080; // xdsp_01_lcd.ino +#endif +#ifdef USE_DISPLAY_SSD1306 + feature_drv2 |= 0x00000100; // xdsp_02_ssd1306.ino +#endif +#ifdef USE_DISPLAY_MATRIX + feature_drv2 |= 0x00000200; // xdsp_03_matrix.ino +#endif +#ifdef USE_DISPLAY_ILI9341 + feature_drv2 |= 0x00000400; // xdsp_04_ili9341.ino +#endif +#ifdef USE_DISPLAY_EPAPER + feature_drv2 |= 0x00000800; // xdsp_05_epaper.ino +#endif +#ifdef USE_DISPLAY_SH1106 + feature_drv2 |= 0x00001000; // xdsp_06_sh1106.ino +#endif +#ifdef USE_MP3_PLAYER + feature_drv2 |= 0x00002000; // xdrv_14_mp3.ino +#endif +#ifdef USE_PCA9685 + feature_drv2 |= 0x00004000; // xdrv_15_pca9685.ino +#endif +#ifdef USE_TUYA_DIMMER + feature_drv2 |= 0x00008000; // xdrv_16_tuyadimmer.ino +#endif +#ifdef USE_RC_SWITCH + feature_drv2 |= 0x00010000; // xdrv_17_rcswitch.ino +#endif +#ifdef USE_ARMTRONIX_DIMMERS + feature_drv2 |= 0x00020000; // xdrv_18_armtronixdimmer.ino +#endif + +// feature_drv2 |= 0x00040000; +// feature_drv2 |= 0x00080000; +// feature_drv2 |= 0x00100000; +// feature_drv2 |= 0x00200000; +// feature_drv2 |= 0x00400000; + +#ifdef NO_EXTRA_4K_HEAP + feature_drv2 |= 0x00800000; // sonoff_post.h +#endif +#ifdef VTABLES_IN_IRAM + feature_drv2 |= 0x01000000; // platformio.ini +#endif +#ifdef VTABLES_IN_DRAM + feature_drv2 |= 0x02000000; // platformio.ini +#endif +#ifdef VTABLES_IN_FLASH + feature_drv2 |= 0x04000000; // platformio.ini +#endif +#ifdef PIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH + feature_drv2 |= 0x08000000; // platformio.ini +#endif +#ifdef PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY + feature_drv2 |= 0x10000000; // platformio.ini +#endif +#ifdef PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH + feature_drv2 |= 0x20000000; // platformio.ini +#endif +#ifdef DEBUG_THEO + feature_drv2 |= 0x40000000; // xdrv_99_debug.ino +#endif +#ifdef USE_DEBUG_DRIVER + feature_drv2 |= 0x80000000; // xdrv_99_debug.ino +#endif + +/*********************************************************************************************/ + + feature_sns1 = 0x00000000; // xsns_01_counter.ino, xsns_04_snfsc.ino + +// feature_sns1 |= 0x00000001; + +#ifdef USE_ADC_VCC + feature_sns1 |= 0x00000002; // support.ino (ADC) +#endif +#ifdef USE_ENERGY_SENSOR + feature_sns1 |= 0x00000004; // xdrv_03_energy.ino +#endif +#ifdef USE_PZEM004T + feature_sns1 |= 0x00000008; // xnrg_03_pzem004t.ino +#endif +#ifdef USE_DS18B20 + feature_sns1 |= 0x00000010; // xsns_05_ds18b20.ino +#endif +#ifdef USE_DS18x20_LEGACY + feature_sns1 |= 0x00000020; // xsns_05_ds18x20_legacy.ino +#endif +#ifdef USE_DS18x20 + feature_sns1 |= 0x00000040; // xsns_05_ds18x20.ino +#endif +#ifdef USE_DHT + feature_sns1 |= 0x00000080; // xsns_06_dht.ino +#endif +#ifdef USE_SHT + feature_sns1 |= 0x00000100; // xsns_07_sht1x.ino +#endif +#ifdef USE_HTU + feature_sns1 |= 0x00000200; // xsns_08_htu21.ino +#endif +#ifdef USE_BMP + feature_sns1 |= 0x00000400; // xsns_09_bmp.ino +#endif +#ifdef USE_BME680 + feature_sns1 |= 0x00000800; // xsns_09_bmp.ino - BME680 +#endif +#ifdef USE_BH1750 + feature_sns1 |= 0x00001000; // xsns_10_bh1750.ino +#endif +#ifdef USE_VEML6070 + feature_sns1 |= 0x00002000; // xsns_11_veml6070.ino +#endif +#ifdef USE_ADS1115_I2CDEV + feature_sns1 |= 0x00004000; // xsns_12_ads1115_i2cdev.ino +#endif +#ifdef USE_ADS1115 + feature_sns1 |= 0x00008000; // xsns_12_ads1115.ino +#endif +#ifdef USE_INA219 + feature_sns1 |= 0x00010000; // xsns_13_ina219.ino +#endif +#ifdef USE_SHT3X + feature_sns1 |= 0x00020000; // xsns_14_sht3x.ino +#endif +#ifdef USE_MHZ19 + feature_sns1 |= 0x00040000; // xsns_15_mhz19.ino +#endif +#ifdef USE_TSL2561 + feature_sns1 |= 0x00080000; // xsns_16_tsl2561.ino +#endif +#ifdef USE_SENSEAIR + feature_sns1 |= 0x00100000; // xsns_17_senseair.ino +#endif +#ifdef USE_PMS5003 + feature_sns1 |= 0x00200000; // xsns_18_pms5003.ino +#endif +#ifdef USE_MGS + feature_sns1 |= 0x00400000; // xsns_19_mgs.ino +#endif +#ifdef USE_NOVA_SDS + feature_sns1 |= 0x00800000; // xsns_20_novasds.ino +#endif +#ifdef USE_SGP30 + feature_sns1 |= 0x01000000; // xsns_21_sgp30.ino +#endif +#ifdef USE_SR04 + feature_sns1 |= 0x02000000; // xsns_22_sr04.ino +#endif +#ifdef USE_SDM120 + feature_sns1 |= 0x04000000; // xsns_23_sdm120.ino +#endif +#ifdef USE_SI1145 + feature_sns1 |= 0x08000000; // xsns_24_si1145.ino +#endif +#ifdef USE_SDM630 + feature_sns1 |= 0x10000000; // xsns_25_sdm630.ino +#endif +#ifdef USE_LM75AD + feature_sns1 |= 0x20000000; // xsns_26_lm75ad.ino +#endif +#ifdef USE_APDS9960 + feature_sns1 |= 0x40000000; // xsns_27_apds9960.ino +#endif +#ifdef USE_TM1638 + feature_sns1 |= 0x80000000; // xsns_28_tm1638.ino +#endif + +/*********************************************************************************************/ + + feature_sns2 = 0x00000000; + +#ifdef USE_MCP230xx + feature_sns2 |= 0x00000001; // xsns_29_mcp230xx.ino +#endif +#ifdef USE_MPR121 + feature_sns2 |= 0x00000002; // xsns_30_mpr121.ino +#endif +#ifdef USE_CCS811 + feature_sns2 |= 0x00000004; // xsns_31_ccs811.ino +#endif +#ifdef USE_MPU6050 + feature_sns2 |= 0x00000008; // xsns_32_mpu6050.ino +#endif +#ifdef USE_MCP230xx_OUTPUT + feature_sns2 |= 0x00000010; // xsns_29_mcp230xx.ino +#endif +#ifdef USE_MCP230xx_DISPLAYOUTPUT + feature_sns2 |= 0x00000020; // xsns_29_mcp230xx.ino +#endif +#ifdef USE_HLW8012 + feature_sns2 |= 0x00000040; // xnrg_01_hlw8012.ino +#endif +#ifdef USE_CSE7766 + feature_sns2 |= 0x00000080; // xnrg_02_cse7766.ino +#endif +#ifdef USE_MCP39F501 + feature_sns2 |= 0x00000100; // xnrg_04_mcp39f501.ino +#endif +#ifdef USE_PZEM_AC + feature_sns2 |= 0x00000200; // xnrg_05_pzem_ac.ino +#endif +#ifdef USE_DS3231 + feature_sns2 |= 0x00000400; // xsns_33_ds3231.ino +#endif +#ifdef USE_HX711 + feature_sns2 |= 0x00000800; // xsns_34_hx711.ino +#endif +#ifdef USE_PZEM_DC + feature_sns2 |= 0x00001000; // xnrg_06_pzem_dc.ino +#endif +#ifdef USE_TX20_WIND_SENSOR + feature_sns2 |= 0x00002000; // xsns_35_tx20.ino +#endif + +// feature_sns2 |= 0x00004000; +// feature_sns2 |= 0x00008000; +// feature_sns2 |= 0x00010000; +// feature_sns2 |= 0x00020000; +// feature_sns2 |= 0x00040000; +// feature_sns2 |= 0x00080000; +// feature_sns2 |= 0x00100000; +// feature_sns2 |= 0x00200000; +// feature_sns2 |= 0x00400000; +// feature_sns2 |= 0x00800000; +// feature_sns2 |= 0x01000000; +// feature_sns2 |= 0x02000000; +// feature_sns2 |= 0x04000000; +// feature_sns2 |= 0x08000000; +// feature_sns2 |= 0x10000000; +// feature_sns2 |= 0x20000000; +// feature_sns2 |= 0x40000000; +// feature_sns2 |= 0x80000000; + +} diff --git a/sonoff/support_rtc.ino b/sonoff/support_rtc.ino new file mode 100644 index 000000000..b6067bd15 --- /dev/null +++ b/sonoff/support_rtc.ino @@ -0,0 +1,418 @@ +/* + support_rtc.ino - Real Time Clock support for Sonoff-Tasmota + + Copyright (C) 2018 Theo Arends + + 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 . +*/ + +/*********************************************************************************************\ + * Sources: Time by Michael Margolis and Paul Stoffregen (https://github.com/PaulStoffregen/Time) + * Timezone by Jack Christensen (https://github.com/JChristensen/Timezone) +\*********************************************************************************************/ + +#define SECS_PER_MIN ((uint32_t)(60UL)) +#define SECS_PER_HOUR ((uint32_t)(3600UL)) +#define SECS_PER_DAY ((uint32_t)(SECS_PER_HOUR * 24UL)) +#define MINS_PER_HOUR ((uint32_t)(60UL)) +#define LEAP_YEAR(Y) (((1970+Y)>0) && !((1970+Y)%4) && (((1970+Y)%100) || !((1970+Y)%400))) + +extern "C" { +#include "sntp.h" +} +#include + +Ticker TickerRtc; + +static const uint8_t kDaysInMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; // API starts months from 1, this array starts from 0 +static const char kMonthNamesEnglish[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; + +uint32_t utc_time = 0; +uint32_t local_time = 0; +uint32_t daylight_saving_time = 0; +uint32_t standard_time = 0; +uint32_t ntp_time = 0; +uint32_t midnight = 1451602800; +uint32_t restart_time = 0; +int32_t time_timezone = 0; +uint8_t midnight_now = 0; +uint8_t ntp_sync_minute = 0; + +String GetBuildDateAndTime(void) +{ + // "2017-03-07T11:08:02" - ISO8601:2004 + char bdt[21]; + char *p; + char mdate[] = __DATE__; // "Mar 7 2017" + char *smonth = mdate; + int day = 0; + int year = 0; + + // sscanf(mdate, "%s %d %d", bdt, &day, &year); // Not implemented in 2.3.0 and probably too much code + byte i = 0; + for (char *str = strtok_r(mdate, " ", &p); str && i < 3; str = strtok_r(NULL, " ", &p)) { + switch (i++) { + case 0: // Month + smonth = str; + break; + case 1: // Day + day = atoi(str); + break; + case 2: // Year + year = atoi(str); + } + } + int month = (strstr(kMonthNamesEnglish, smonth) -kMonthNamesEnglish) /3 +1; + snprintf_P(bdt, sizeof(bdt), PSTR("%d" D_YEAR_MONTH_SEPARATOR "%02d" D_MONTH_DAY_SEPARATOR "%02d" D_DATE_TIME_SEPARATOR "%s"), year, month, day, __TIME__); + return String(bdt); // 2017-03-07T11:08:02 +} + +String GetTimeZone(void) +{ + char tz[7]; + + snprintf_P(tz, sizeof(tz), PSTR("%+03d:%02d"), time_timezone / 60, abs(time_timezone % 60)); + + return String(tz); // -03:45 +} + +/* + * timestamps in https://en.wikipedia.org/wiki/ISO_8601 format + * + * DT_UTC - current data and time in Greenwich, England (aka GMT) + * DT_LOCAL - current date and time taking timezone into account + * DT_RESTART - the date and time this device last started, in local timezone + * + * Format: + * "2017-03-07T11:08:02-07:00" - if DT_LOCAL and SetOption52 = 1 + * "2017-03-07T11:08:02" - otherwise + */ +String GetDateAndTime(byte time_type) +{ + // "2017-03-07T11:08:02-07:00" - ISO8601:2004 + char dt[27]; + TIME_T tmpTime; + + switch (time_type) { + case DT_ENERGY: + BreakTime(Settings.energy_kWhtotal_time, tmpTime); + tmpTime.year += 1970; + break; + case DT_UTC: + BreakTime(utc_time, tmpTime); + tmpTime.year += 1970; + break; + case DT_RESTART: + if (restart_time == 0) { + return ""; + } + BreakTime(restart_time, tmpTime); + tmpTime.year += 1970; + break; + default: + tmpTime = RtcTime; + } + + snprintf_P(dt, sizeof(dt), PSTR("%04d-%02d-%02dT%02d:%02d:%02d"), + tmpTime.year, tmpTime.month, tmpTime.day_of_month, tmpTime.hour, tmpTime.minute, tmpTime.second); + + if (Settings.flag3.time_append_timezone && (DT_LOCAL == time_type)) { +// if (Settings.flag3.time_append_timezone && ((DT_LOCAL == time_type) || (DT_ENERGY == time_type))) { + strncat(dt, GetTimeZone().c_str(), sizeof(dt)); + } + + return String(dt); // 2017-03-07T11:08:02-07:00 +} + +String GetTime(int type) +{ + /* type 1 - Local time + * type 2 - Daylight Savings time + * type 3 - Standard time + */ + char stime[25]; // Skip newline + + uint32_t time = utc_time; + if (1 == type) time = local_time; + if (2 == type) time = daylight_saving_time; + if (3 == type) time = standard_time; + snprintf_P(stime, sizeof(stime), sntp_get_real_time(time)); + + return String(stime); // Thu Nov 01 11:41:02 2018 +} + +String GetUptime(void) +{ + char dt[16]; + + TIME_T ut; + + if (restart_time) { + BreakTime(utc_time - restart_time, ut); + } else { + BreakTime(uptime, ut); + } + + // "P128DT14H35M44S" - ISO8601:2004 - https://en.wikipedia.org/wiki/ISO_8601 Durations +// snprintf_P(dt, sizeof(dt), PSTR("P%dDT%02dH%02dM%02dS"), ut.days, ut.hour, ut.minute, ut.second); + + // "128 14:35:44" - OpenVMS + // "128T14:35:44" - Tasmota + snprintf_P(dt, sizeof(dt), PSTR("%dT%02d:%02d:%02d"), ut.days, ut.hour, ut.minute, ut.second); + + return String(dt); // 128T14:35:44 +} + +uint32_t GetMinutesUptime(void) +{ + TIME_T ut; + + if (restart_time) { + BreakTime(utc_time - restart_time, ut); + } else { + BreakTime(uptime, ut); + } + + return (ut.days *1440) + (ut.hour *60) + ut.minute; +} + +uint32_t GetMinutesPastMidnight(void) +{ + uint32_t minutes = 0; + + if (RtcTime.valid) { + minutes = (RtcTime.hour *60) + RtcTime.minute; + } + return minutes; +} + +void BreakTime(uint32_t time_input, TIME_T &tm) +{ +// break the given time_input into time components +// this is a more compact version of the C library localtime function +// note that year is offset from 1970 !!! + + uint8_t year; + uint8_t month; + uint8_t month_length; + uint32_t time; + unsigned long days; + + time = time_input; + tm.second = time % 60; + time /= 60; // now it is minutes + tm.minute = time % 60; + time /= 60; // now it is hours + tm.hour = time % 24; + time /= 24; // now it is days + tm.days = time; + tm.day_of_week = ((time + 4) % 7) + 1; // Sunday is day 1 + + year = 0; + days = 0; + while((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) { + year++; + } + tm.year = year; // year is offset from 1970 + + days -= LEAP_YEAR(year) ? 366 : 365; + time -= days; // now it is days in this year, starting at 0 + tm.day_of_year = time; + + days = 0; + month = 0; + month_length = 0; + for (month = 0; month < 12; month++) { + if (1 == month) { // february + if (LEAP_YEAR(year)) { + month_length = 29; + } else { + month_length = 28; + } + } else { + month_length = kDaysInMonth[month]; + } + + if (time >= month_length) { + time -= month_length; + } else { + break; + } + } + strlcpy(tm.name_of_month, kMonthNames + (month *3), 4); + tm.month = month + 1; // jan is month 1 + tm.day_of_month = time + 1; // day of month + tm.valid = (time_input > 1451602800); // 2016-01-01 +} + +uint32_t MakeTime(TIME_T &tm) +{ +// assemble time elements into time_t +// note year argument is offset from 1970 + + int i; + uint32_t seconds; + + // seconds from 1970 till 1 jan 00:00:00 of the given year + seconds = tm.year * (SECS_PER_DAY * 365); + for (i = 0; i < tm.year; i++) { + if (LEAP_YEAR(i)) { + seconds += SECS_PER_DAY; // add extra days for leap years + } + } + + // add days for this year, months start from 1 + for (i = 1; i < tm.month; i++) { + if ((2 == i) && LEAP_YEAR(tm.year)) { + seconds += SECS_PER_DAY * 29; + } else { + seconds += SECS_PER_DAY * kDaysInMonth[i-1]; // monthDay array starts from 0 + } + } + seconds+= (tm.day_of_month - 1) * SECS_PER_DAY; + seconds+= tm.hour * SECS_PER_HOUR; + seconds+= tm.minute * SECS_PER_MIN; + seconds+= tm.second; + return seconds; +} + +uint32_t RuleToTime(TimeRule r, int yr) +{ + TIME_T tm; + uint32_t t; + uint8_t m; + uint8_t w; // temp copies of r.month and r.week + + m = r.month; + w = r.week; + if (0 == w) { // Last week = 0 + if (++m > 12) { // for "Last", go to the next month + m = 1; + yr++; + } + w = 1; // and treat as first week of next month, subtract 7 days later + } + + tm.hour = r.hour; + tm.minute = 0; + tm.second = 0; + tm.day_of_month = 1; + tm.month = m; + tm.year = yr - 1970; + t = MakeTime(tm); // First day of the month, or first day of next month for "Last" rules + BreakTime(t, tm); + t += (7 * (w - 1) + (r.dow - tm.day_of_week + 7) % 7) * SECS_PER_DAY; + if (0 == r.week) { + t -= 7 * SECS_PER_DAY; // back up a week if this is a "Last" rule + } + return t; +} + +uint32_t LocalTime(void) +{ + return local_time; +} + +uint32_t Midnight(void) +{ + return midnight; +} + +boolean MidnightNow(void) +{ + boolean mnflg = midnight_now; + if (mnflg) midnight_now = 0; + return mnflg; +} + +void RtcSecond(void) +{ + TIME_T tmpTime; + + if ((ntp_sync_minute > 59) && (RtcTime.minute > 2)) ntp_sync_minute = 1; // If sync prepare for a new cycle + uint8_t offset = (uptime < 30) ? RtcTime.second : (((ESP.getChipId() & 0xF) * 3) + 3) ; // First try ASAP to sync. If fails try once every 60 seconds based on chip id + if (!global_state.wifi_down && (offset == RtcTime.second) && ((RtcTime.year < 2016) || (ntp_sync_minute == RtcTime.minute) || ntp_force_sync)) { + ntp_time = sntp_get_current_timestamp(); + if (ntp_time > 1451602800) { // Fix NTP bug in core 2.4.1/SDK 2.2.1 (returns Thu Jan 01 08:00:10 1970 after power on) + ntp_force_sync = 0; + utc_time = ntp_time; + ntp_sync_minute = 60; // Sync so block further requests + if (restart_time == 0) { + restart_time = utc_time - uptime; // save first ntp time as restart time + } + BreakTime(utc_time, tmpTime); + RtcTime.year = tmpTime.year + 1970; + daylight_saving_time = RuleToTime(Settings.tflag[1], RtcTime.year); + standard_time = RuleToTime(Settings.tflag[0], RtcTime.year); + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION "(" D_UTC_TIME ") %s, (" D_DST_TIME ") %s, (" D_STD_TIME ") %s"), + GetTime(0).c_str(), GetTime(2).c_str(), GetTime(3).c_str()); + AddLog(LOG_LEVEL_DEBUG); + if (local_time < 1451602800) { // 2016-01-01 + rules_flag.time_init = 1; + } else { + rules_flag.time_set = 1; + } + } else { + ntp_sync_minute++; // Try again in next minute + } + } + utc_time++; + local_time = utc_time; + if (local_time > 1451602800) { // 2016-01-01 + int16_t timezone_minutes = Settings.timezone_minutes; + if (Settings.timezone < 0) { timezone_minutes *= -1; } + time_timezone = (Settings.timezone * SECS_PER_HOUR) + (timezone_minutes * SECS_PER_MIN); + if (99 == Settings.timezone) { + int32_t dstoffset = Settings.toffset[1] * SECS_PER_MIN; + int32_t stdoffset = Settings.toffset[0] * SECS_PER_MIN; + if (Settings.tflag[1].hemis) { + // Southern hemisphere + if ((utc_time >= (standard_time - dstoffset)) && (utc_time < (daylight_saving_time - stdoffset))) { + time_timezone = stdoffset; // Standard Time + } else { + time_timezone = dstoffset; // Daylight Saving Time + } + } else { + // Northern hemisphere + if ((utc_time >= (daylight_saving_time - stdoffset)) && (utc_time < (standard_time - dstoffset))) { + time_timezone = dstoffset; // Daylight Saving Time + } else { + time_timezone = stdoffset; // Standard Time + } + } + } + local_time += time_timezone; + time_timezone /= 60; + if (!Settings.energy_kWhtotal_time) { Settings.energy_kWhtotal_time = local_time; } + } + BreakTime(local_time, RtcTime); + if (!RtcTime.hour && !RtcTime.minute && !RtcTime.second && RtcTime.valid) { + midnight = local_time; + midnight_now = 1; + } + RtcTime.year += 1970; +} + +void RtcInit(void) +{ + sntp_setservername(0, Settings.ntp_server[0]); + sntp_setservername(1, Settings.ntp_server[1]); + sntp_setservername(2, Settings.ntp_server[2]); + sntp_stop(); + sntp_set_timezone(0); // UTC time + sntp_init(); + utc_time = 0; + BreakTime(utc_time, RtcTime); + TickerRtc.attach(1, RtcSecond); +} diff --git a/sonoff/support_wifi.ino b/sonoff/support_wifi.ino index b427a3f9b..4a7902303 100644 --- a/sonoff/support_wifi.ino +++ b/sonoff/support_wifi.ino @@ -34,12 +34,6 @@ #include // Wifi, MQTT, Ota, WifiManager -#ifdef USE_MQTT_TLS - WiFiClientSecure EspClient; // Wifi Secure Client -#else - WiFiClient EspClient; // Wifi Client -#endif - uint8_t wifi_counter; uint8_t wifi_retry_init; uint8_t wifi_retry; diff --git a/sonoff/xdrv_01_webserver.ino b/sonoff/xdrv_01_webserver.ino index 85f1c71e2..09df2dd7d 100644 --- a/sonoff/xdrv_01_webserver.ino +++ b/sonoff/xdrv_01_webserver.ino @@ -2058,7 +2058,7 @@ boolean Xdrv01(byte function) switch (function) { case FUNC_LOOP: - if (!global_state.wifi_down) { + if (!global_state.wifi_down) { PollDnsWebserver(); #ifdef USE_EMULATION if (Settings.flag2.emulation) PollUdp(); diff --git a/sonoff/xdrv_02_mqtt.ino b/sonoff/xdrv_02_mqtt.ino index a67a15d7e..b4876d436 100644 --- a/sonoff/xdrv_02_mqtt.ino +++ b/sonoff/xdrv_02_mqtt.ino @@ -55,6 +55,12 @@ /*********************************************************************************************/ +#ifdef USE_MQTT_TLS + WiFiClientSecure EspClient; // Wifi Secure Client +#else + WiFiClient EspClient; // Wifi Client +#endif + enum MqttCommands { CMND_MQTTHOST, CMND_MQTTPORT, CMND_MQTTRETRY, CMND_STATETEXT, CMND_MQTTFINGERPRINT, CMND_MQTTCLIENT, CMND_MQTTUSER, CMND_MQTTPASSWORD, CMND_FULLTOPIC, CMND_PREFIX, CMND_GROUPTOPIC, CMND_TOPIC, CMND_PUBLISH, diff --git a/sonoff/xdrv_03_energy.ino b/sonoff/xdrv_03_energy.ino index 9486a577f..1c54c12e5 100644 --- a/sonoff/xdrv_03_energy.ino +++ b/sonoff/xdrv_03_energy.ino @@ -29,6 +29,8 @@ #define FEATURE_POWER_LIMIT true +#include + enum EnergyCommands { CMND_POWERDELTA, CMND_POWERLOW, CMND_POWERHIGH, CMND_VOLTAGELOW, CMND_VOLTAGEHIGH, CMND_CURRENTLOW, CMND_CURRENTHIGH, diff --git a/tools/decode-status.py b/tools/decode-status.py index 3fad3c5c6..cca379ca6 100644 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -88,7 +88,10 @@ a_setoption = [[ "Generic ESP8285 GPIO enabled", "Add UTC time offset to JSON message", "Show hostname and IP address in GUI", - "","","","", + "Apply SetOption20 to Tuya", + "Use short Hass discovery messages", + "Use wifi network scan at restart", + "Use wifi network rescan regularly", "","","","", "","","","", "","","","", @@ -111,7 +114,7 @@ a_features = [[ "USE_KNX_NO_EMULATION","USE_DISPLAY_MODES1TO5","USE_DISPLAY_GRAPH","USE_DISPLAY_LCD", "USE_DISPLAY_SSD1306","USE_DISPLAY_MATRIX","USE_DISPLAY_ILI9341","USE_DISPLAY_EPAPER", "USE_DISPLAY_SH1106","USE_MP3_PLAYER","USE_PCA9685","USE_TUYA_DIMMER", - "USE_RC_SWITCH","","","", + "USE_RC_SWITCH","USE_ARMTRONIX_DIMMERS","","", "","","","NO_EXTRA_4K_HEAP", "VTABLES_IN_IRAM","VTABLES_IN_DRAM","VTABLES_IN_FLASH","PIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH", "PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY","PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH","DEBUG_THEO","USE_DEBUG_DRIVER"