diff --git a/code/espurna/config/all.h b/code/espurna/config/all.h index d21eb007..fe5124d6 100644 --- a/code/espurna/config/all.h +++ b/code/espurna/config/all.h @@ -31,6 +31,7 @@ #include "general.h" #include "prototypes.h" #include "sensors.h" +#include "rtc.h" #include "dependencies.h" #include "progmem.h" #include "debug.h" diff --git a/code/espurna/config/arduino.h b/code/espurna/config/arduino.h index 0f2cb40d..e69cf669 100644 --- a/code/espurna/config/arduino.h +++ b/code/espurna/config/arduino.h @@ -89,7 +89,7 @@ //#define BLITZWOLF_BWSHP2 //#define BH_ONOFRE //#define ITEAD_SONOFF_IFAN02 - +//#define SHAPEsp //-------------------------------------------------------------------------------- // Features (values below are non-default values) //-------------------------------------------------------------------------------- diff --git a/code/espurna/config/general.h b/code/espurna/config/general.h index 950d33d7..cded0582 100644 --- a/code/espurna/config/general.h +++ b/code/espurna/config/general.h @@ -990,7 +990,7 @@ #endif #ifndef NTP_UPDATE_INTERVAL -#define NTP_UPDATE_INTERVAL 1800 // NTP check every 30 minutes +#define NTP_UPDATE_INTERVAL 180 // NTP check every 30 minutes #endif #ifndef NTP_START_DELAY diff --git a/code/espurna/config/hardware.h b/code/espurna/config/hardware.h index 00e1f6c4..ba4d79a2 100644 --- a/code/espurna/config/hardware.h +++ b/code/espurna/config/hardware.h @@ -112,6 +112,14 @@ #define I2C_SDA_PIN 12 // D6 #define I2C_SCL_PIN 14 // D5 + // ----------------------------------------------------------------------------- + // RTC_SUPPORT example + // ----------------------------------------------------------------------------- + //#define RTC_SUPPORT 1 // for test + //#define RTC_PROVIDER RTC_PROVIDER_DS1307 // for test + //#define RTC_RECOVERY_CNT 3 // 0 no recovery default 10 + //#define RTC_NTP_SYNC_ENA 1 // 0 rtc not synced with ntp default 1 + #elif defined(WEMOS_D1_TARPUNA_SHIELD) // Info @@ -2595,6 +2603,56 @@ #define NETBIOS_SUPPORT 1 #define SSDP_SUPPORT 1 +#elif defined(SHAPEsp) + + // Info + #define MANUFACTURER "POULCH74" + #define DEVICE "SHAPEsp" + + // Buttons + + //#define BUTTON1_PIN 2 + //#define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH | BUTTON_ONCE + //#define BUTTON1_PRESS BUTTON_MODE_TOGGLE + //#define BUTTON1_CLICK BUTTON_MODE_TOGGLE + //#define BUTTON1_DBLCLICK BUTTON_MODE_TOGGLE + //#define BUTTON1_LNGCLICK BUTTON_MODE_TOGGLE + //#define BUTTON1_LNGLNGCLICK BUTTON_MODE_TOGGLE + + //#define BUTTON1_RELAY 1 + + // Relays + //#define RELAY1_PIN 14 + //#define RELAY1_PIN2 12 + //#define RELAY1_PINP 13 // GPIO_NONE to leave it unused, so no pulse on start valve (autostop not used) + //#define RELAY1_TYPE RELAY_TYPE_HBRIDGE + // pulse duration for pinP pulse to start valve + //#define RELAY1_HBPULSE 100 + + // Relays + //#define RELAY2_PIN 98 // fake pin for relay + //#define RELAY2_TYPE RELAY_TYPE_BTNRESET + //#define RELAY2_BUTTON 1 + + // LEDs + #define LED1_PIN 2 //15 to free pin 2 which can be used for dallas support or water sensor for example + #define LED1_PIN_INVERSE 1 + + #define I2C_SDA_PIN 4 + #define I2C_SCL_PIN 5 + + //#define ADC_MODE_VALUE ADC_VCC_CUSTOM + //#define ADC_VCC_CUSTOM_MUL (15.63) + //#define ADC_VCC_CUSTOM_ADD (0) + + // ----------------------------------------------------------------------------- + // RTC_SUPPORT + // ----------------------------------------------------------------------------- + #define RTC_SUPPORT 1 // for test + #define RTC_PROVIDER RTC_PROVIDER_DS3231 // for test + #define RTC_RECOVERY_CNT 3 // 0 no recovery + #define RTC_NTP_SYNC_ENA 1 // 0 rtc not synced with ntp + #endif // ----------------------------------------------------------------------------- diff --git a/code/espurna/config/rtc.h b/code/espurna/config/rtc.h new file mode 100644 index 00000000..7d6e95a9 --- /dev/null +++ b/code/espurna/config/rtc.h @@ -0,0 +1,37 @@ +/* + +RTC support module + +Copyright (C) 2018 by Pavel Chauzov + +*/ + +// ----------------------------------------------------------------------------- +// RTC3231_SUPPORT +// ----------------------------------------------------------------------------- + +#ifndef RTC_SUPPORT +#define RTC_SUPPORT 0 // enable battery backed RTC for ntp +#define RTC_PROVIDER RTC_DUMMY +#endif + +#ifndef RTC_RECOVERY_CNT +#define RTC_RECOVERY_CNT 10 // 0 no recovery +#endif + +#ifndef RTC_NTP_SYNC_ENA +#define RTC_NTP_SYNC_ENA 1 // enable sync RTC on NTP sync success +#endif + + +#if RTC_SUPPORT + +#if RTC_PROVIDER == RTC_PROVIDER_DS3231 + #include "../rtc/ds3231.h" +#elif RTC_PROVIDER == RTC_PROVIDER_DS1307 + #include "../rtc/ds1307.h" +#else + #include "../rtc/dummy.h" +#endif + +#endif diff --git a/code/espurna/config/types.h b/code/espurna/config/types.h index 59666e60..c2729482 100644 --- a/code/espurna/config/types.h +++ b/code/espurna/config/types.h @@ -301,3 +301,10 @@ #define MAGNITUDE_GEIGER_SIEVERT 24 #define MAGNITUDE_MAX 25 + +//----------------------------------------------------------------------------- +// RTC providers +//----------------------------------------------------------------------------- +#define RTC_PROVIDER_DUMMY 0 +#define RTC_PROVIDER_DS3231 1 +#define RTC_PROVIDER_DS1307 2 diff --git a/code/espurna/ntp.ino b/code/espurna/ntp.ino index 2a8134a6..fc785697 100644 --- a/code/espurna/ntp.ino +++ b/code/espurna/ntp.ino @@ -17,6 +17,11 @@ unsigned long _ntp_start = 0; bool _ntp_update = false; bool _ntp_configure = false; +#if RTC_SUPPORT && RTC_NTP_SYNC_ENA +bool _rtc_update = false; +#endif + + // ----------------------------------------------------------------------------- // NTP // ----------------------------------------------------------------------------- @@ -44,6 +49,12 @@ void _ntpStart() { _ntp_start = 0; NTP.begin(getSetting("ntpServer", NTP_SERVER)); + +#if RTC_SUPPORT + // set alter sync provider. two attempts for NTP synchro at start occure... + setSyncProvider(ntp_getTime); +#endif + NTP.setInterval(NTP_SYNC_INTERVAL, NTP_UPDATE_INTERVAL); NTP.setNTPTimeout(NTP_TIMEOUT); _ntpConfigure(); @@ -90,6 +101,11 @@ void _ntpUpdate() { if (ntpSynced()) { time_t t = now(); + #if RTC_SUPPORT && RTC_NTP_SYNC_ENA + // sync/update rtc here!!!!!!!!!!!! + if(_rtc_update) setTime_rtc(t); + #endif + DEBUG_MSG_P(PSTR("[NTP] UTC Time : %s\n"), (char *) ntpDateTime(ntpLocal2UTC(t)).c_str()); DEBUG_MSG_P(PSTR("[NTP] Local Time: %s\n"), (char *) ntpDateTime(t).c_str()); } @@ -167,13 +183,24 @@ void ntpSetup() { } else if (error == invalidAddress) { DEBUG_MSG_P(PSTR("[NTP] Error: Invalid NTP server address\n")); } + _ntp_update = false; } else { _ntp_update = true; + #if RTC_SUPPORT && RTC_NTP_SYNC_ENA + _rtc_update = true; + #endif + } }); wifiRegister([](justwifi_messages_t code, char * parameter) { if (code == MESSAGE_CONNECTED) _ntp_start = millis() + NTP_START_DELAY; + #if RTC_SUPPORT + // system time from local RTC, but still try recovery if enabled (without success) + else + if(code == MESSAGE_ACCESSPOINT_CREATED) _ntp_start = millis() + NTP_START_DELAY; + #endif + }); #if WEB_SUPPORT @@ -184,6 +211,12 @@ void ntpSetup() { // Register loop espurnaRegisterLoop(_ntpLoop); + + #if RTC_SUPPORT + #if TERMINAL_SUPPORT + _rtcInitCommands(); + #endif + #endif } diff --git a/code/espurna/rtc.ino b/code/espurna/rtc.ino new file mode 100644 index 00000000..b67490db --- /dev/null +++ b/code/espurna/rtc.ino @@ -0,0 +1,95 @@ +/* + +RTC support module + +Copyright (C) 2018 by Pavel Chauzov + +in debug terminal - RTC return current rtc time + - RTC YYYY-MM-DD DoW HH:MM:SS setup rtc + + +*/ + +#if RTC_SUPPORT + +static int _rtc_recovery = 0; + +static time_t ntp_getTime() { + time_t tm = 0; + if(_rtc_recovery == 0) { tm = NTP.getTime(); } + if((_rtc_recovery !=0) || (tm == 0)) { + _rtc_recovery++; + tm = getTime_rtc(); + // signal ntp loop to update clock but not rtc... + _ntp_update = true; + #if RTC_SUPPORT && RTC_NTP_SYNC_ENA + _rtc_update = false; + #endif + } + if(_rtc_recovery > RTC_RECOVERY_CNT) { _rtc_recovery = RTC_RECOVERY_CNT ? 0:1; } + DEBUG_MSG_P(PSTR("[NTP] RTC Time : %s\n"), (char *) ntpDateTime(tm).c_str()); + return tm; +} + +//------------------------------------------------------------------------------ +// Settings +//------------------------------------------------------------------------------ + +#if TERMINAL_SUPPORT + +String _rtc_getValue(String data, char sep, int idx) { + int found = 0; + int si[] = {0, -1}; + int maxi = data.length()-1; + + for(int i=0; i<=maxi && found<=idx; i++) { + if(data.charAt(i)==sep || i==maxi) { + found++; + si[0] = si[1]+1; + si[1] = (i == maxi) ? i+1 : i; + } + } + return found>idx ? data.substring(si[0], si[1]) : "0"; +} + +void _rtcInitCommands() { + + settingsRegisterCommand(F("RTC"), [](Embedis* e) { + String rtc; + time_t t; + tmElements_t tm; + if (e->argc == 1) { + t = getTime_rtc(); + DEBUG_MSG_P(PSTR("[NTP] GET RTC Local Time: %s\n"), (char *) ntpDateTime(t).c_str()); + } + + if (e->argc > 3) { + String sdate = String(e->argv[1]); + String sdow = String(e->argv[2]); + String stime = String(e->argv[3]); + + tm.Second = _rtc_getValue(stime,':',2).toInt(); + tm.Minute = _rtc_getValue(stime,':',1).toInt(); + tm.Hour = _rtc_getValue(stime,':',0).toInt(); + + tm.Wday = sdow.toInt(); + + tm.Day = _rtc_getValue(sdate,'-',2).toInt(); + tm.Month = _rtc_getValue(sdate,'-',1).toInt(); + tm.Year = y2kYearToTm(_rtc_getValue(sdate,'-',0).toInt()-2000); + + t = makeTime(tm); + setTime_rtc(t); + setTime(t); + + DEBUG_MSG_P(PSTR("[NTP] SET RTC Local Time: %s\n"), (char *) ntpDateTime(t).c_str()); + } + DEBUG_MSG_P(PSTR("+OK\n")); + }); + +} + +#endif // TERMINAL_SUPPORT + + +#endif \ No newline at end of file diff --git a/code/espurna/rtc/README.md b/code/espurna/rtc/README.md new file mode 100644 index 00000000..a09e7d90 --- /dev/null +++ b/code/espurna/rtc/README.md @@ -0,0 +1,17 @@ +# RTC support module + +## commands in debug terminal + - RTC return current rtc time + - RTC YYYY-MM-DD DoW HH:MM:SS setup rtc + +## defines to enable support for modules in hardware.h + - #define RTC_SUPPORT 0/1 enable/disable RTC support + - #define RTC_PROVIDER RTC_PROVIDER_DS3231 etc... spec which rtc ic to use + - #define RTC_RECOVERY_CNT 10(def) // 0 no attempt to switch back to NTP time + - #define RTC_NTP_SYNC_ENA 0/1 // 0 independed rtc, not synced with ntp, + 1 rtc synced with ntp on ntp success +## to add new rtc ic support + - see ds3231.h as example, create your_ic.h file and write two + functions time_t getTime_rtc() and uint8_t setTime_rtc(time_t nt) + - define your provider constant in config/types.h + - add your provider section in config/rtc.h diff --git a/code/espurna/rtc/ds1307.h b/code/espurna/rtc/ds1307.h new file mode 100644 index 00000000..660e2a8c --- /dev/null +++ b/code/espurna/rtc/ds1307.h @@ -0,0 +1,55 @@ +/* + +ds1307 support module + +not tested but it almost similar to ds3231, so it maybe work + +Copyright (C) 2018 by Pavel Chauzov + +*/ + +#pragma once + +#undef I2C_SUPPORT +#define I2C_SUPPORT 1 // Explicitly request I2C support. + +#include + +#define DS1307ADDR 0x68 + +#define _bcdToDec(val) ((uint8_t) ((val / 16 * 10) + (val % 16))) +#define _decToBcd(val) ((uint8_t) ((val / 10 * 16) + (val % 10))) + +time_t getTime_rtc() { + uint8_t data[7]; + tmElements_t tm; + + i2c_write_uint8(DS1307ADDR,0); + i2c_read_buffer(DS1307ADDR, data, 7); + tm.Second = _bcdToDec(data[0]); + tm.Minute = _bcdToDec(data[1]); + tm.Hour = _bcdToDec(data[2]); + tm.Wday = _bcdToDec(data[3]); + tm.Day = _bcdToDec(data[4]); + tm.Month = _bcdToDec(data[5]); + tm.Year = y2kYearToTm(_bcdToDec(data[6])); + + return makeTime(tm); +} + +uint8_t setTime_rtc(time_t nt) { + uint8_t data[8]; + tmElements_t ct; + breakTime(nt, ct); + + data[0] = 0; + data[1] = _decToBcd(ct.Second); + data[2] = _decToBcd(ct.Minute); + data[3] = _decToBcd(ct.Hour); + data[4] = _decToBcd(ct.Wday); + data[5] = _decToBcd(ct.Day); + data[6] = _decToBcd(ct.Month); + data[7] = _decToBcd(tmYearToY2k(ct.Year)); + uint8_t s = i2c_write_buffer(DS1307ADDR, data, 8); + return s; +} diff --git a/code/espurna/rtc/ds3231.h b/code/espurna/rtc/ds3231.h new file mode 100644 index 00000000..c1d93e30 --- /dev/null +++ b/code/espurna/rtc/ds3231.h @@ -0,0 +1,52 @@ +/* +ds3231 support module + +Copyright (C) 2018 by Pavel Chauzov + +*/ +#pragma once + +#undef I2C_SUPPORT +#define I2C_SUPPORT 1 // Explicitly request I2C support. + +#include + + +#define DS3231ADDR 0x68 + +#define _bcdToDec(val) ((uint8_t) ((val / 16 * 10) + (val % 16))) +#define _decToBcd(val) ((uint8_t) ((val / 10 * 16) + (val % 10))) + +time_t getTime_rtc() { + uint8_t data[7]; + tmElements_t tm; + + i2c_write_uint8(DS3231ADDR,0); + i2c_read_buffer(DS3231ADDR, data, 7); + tm.Second = _bcdToDec(data[0]); + tm.Minute = _bcdToDec(data[1]); + tm.Hour = _bcdToDec(data[2]); + tm.Wday = _bcdToDec(data[3]); + tm.Day = _bcdToDec(data[4]); + tm.Month = _bcdToDec(data[5]); + tm.Year = y2kYearToTm(_bcdToDec(data[6])); + + return makeTime(tm); +} + +uint8_t setTime_rtc(time_t nt) { + uint8_t data[8]; + tmElements_t ct; + breakTime(nt, ct); + + data[0] = 0; + data[1] = _decToBcd(ct.Second); + data[2] = _decToBcd(ct.Minute); + data[3] = _decToBcd(ct.Hour); + data[4] = _decToBcd(ct.Wday); + data[5] = _decToBcd(ct.Day); + data[6] = _decToBcd(ct.Month); + data[7] = _decToBcd(tmYearToY2k(ct.Year)); + uint8_t s = i2c_write_buffer(DS3231ADDR, data, 8); + return s; +} diff --git a/code/espurna/rtc/dummy.h b/code/espurna/rtc/dummy.h new file mode 100644 index 00000000..fce7421d --- /dev/null +++ b/code/espurna/rtc/dummy.h @@ -0,0 +1,30 @@ +/* + +dummyRTC support module + +Copyright (C) 2018 by Pavel Chauzov + +*/ +#include + +#define _bcdToDec(val) ((uint8_t) ((val / 16 * 10) + (val % 16))) +#define _decToBcd(val) ((uint8_t) ((val / 10 * 16) + (val % 10))) + +time_t getTime_rtc() { + + tmElements_t tm; + + tm.Second = _bcdToDec(1); + tm.Minute = _bcdToDec(0); + tm.Hour = _bcdToDec(0); + tm.Wday = _bcdToDec(0); + tm.Day = _bcdToDec(1); + tm.Month = _bcdToDec(1); + tm.Year = y2kYearToTm(16); + + return makeTime(tm); +} + +uint8_t setTime_rtc(time_t nt) { + return 0; +}