From fbd8c861a3485b9c6f8090ebfac326fd7167308a Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 13 Mar 2022 18:13:40 +0100 Subject: [PATCH] Consolidate three RTC chip drivers into one driver - Consolidate three RTC chip drivers (DS3231, BM8563, PCF85363) into one driver updating RTC as soon as possible after restart - Removed command ``Sensor33`` and replaced by ``RtcNtpserver`` - define ``USE_RTC_ADDR`` into ``DS3231_ADDRESS`` --- CHANGELOG.md | 4 + RELEASENOTES.md | 3 + tasmota/my_user_config.h | 2 +- tasmota/settings.h | 2 +- tasmota/support.ino | 10 +- tasmota/support_rtc.ino | 2 +- tasmota/xdrv_56_BM8563_RTC.ino | 132 ----------- tasmota/xdrv_56_rtc_chips.ino | 422 +++++++++++++++++++++++++++++++++ tasmota/xsns_33_ds3231.ino | 208 ---------------- tasmota/xsns_96_pcf85363.ino | 161 ------------- 10 files changed, 434 insertions(+), 512 deletions(-) delete mode 100644 tasmota/xdrv_56_BM8563_RTC.ino create mode 100644 tasmota/xdrv_56_rtc_chips.ino delete mode 100644 tasmota/xsns_33_ds3231.ino delete mode 100644 tasmota/xsns_96_pcf85363.ino diff --git a/CHANGELOG.md b/CHANGELOG.md index b249e1aec..f1bc41096 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,12 @@ All notable changes to this project will be documented in this file. ## [11.0.0.4] ### Added +- command ``RtcNtpserver 0/1`` to enable Tasmota NTP server when enabled by define ``RTC_NTP_SERVER`` ### Changed +- Consolidate three RTC chip drivers (DS3231, BM8563, PCF85363) into one driver updating RTC as soon as possible after restart +- Removed command ``Sensor33`` and replaced by ``RtcNtpserver`` +- define ``USE_RTC_ADDR`` into ``DS3231_ADDRESS`` ### Fixed diff --git a/RELEASENOTES.md b/RELEASENOTES.md index db15593d5..bdb4295c9 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -129,6 +129,9 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo - TasmotaSerial library from v3.4.0 to v3.5.0 [#14981](https://github.com/arendst/Tasmota/issues/14981) - Sonoff SPM increase max number of relays supported to 32 (8 SPM-4Relay modules) - Extent number of pulsetimers from 8 to 32 [#8266](https://github.com/arendst/Tasmota/issues/8266) +- Consolidate three RTC chip drivers (DS3231, BM8563, PCF85363) into one driver updating RTC as soon as possible after restart +- Removed command ``Sensor33`` and replaced by ``RtcNtpserver`` +- define ``USE_RTC_ADDR`` into ``DS3231_ADDRESS`` - ESP32 Arduino core from v2.0.2.2 to v2.0.2.3 - ESP32 LVGL library from v8.1.0 to v8.2.0 - ESP32 NimBLE library from v1.3.3 to v1.3.6 diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index efe605e83..bf8373714 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -613,7 +613,7 @@ // #define USE_MPU6050 // [I2cDriver25] Enable MPU6050 sensor (I2C address 0x68 AD0 low or 0x69 AD0 high) (+3K3 of code and 188 Bytes of RAM) // #define USE_MPU6050_DMP // Enable in MPU6050 to use the DMP on the chip, should create better results (+8k6 of code) // #define USE_DS3231 // [I2cDriver26] Enable DS3231 external RTC in case no Wi-Fi is avaliable. See docs in the source file (+1k2 code) -// #define USE_RTC_ADDR 0x68 // Default I2C address 0x68 +// #define DS3231_ADDRESS 0x68 // Default I2C address 0x68 // #define USE_MGC3130 // [I2cDriver27] Enable MGC3130 Electric Field Effect Sensor (I2C address 0x42) (+2k7 code, 0k3 mem) // #define USE_MAX44009 // [I2cDriver28] Enable MAX44009 Ambient Light sensor (I2C addresses 0x4A and 0x4B) (+0k8 code) // #define USE_SCD30 // [I2cDriver29] Enable Sensiron SCd30 CO2 sensor (I2C address 0x61) (+3k3 code) diff --git a/tasmota/settings.h b/tasmota/settings.h index 4596332f8..90f637db9 100644 --- a/tasmota/settings.h +++ b/tasmota/settings.h @@ -251,7 +251,7 @@ typedef union { uint32_t influxdb_default : 1; // bit 6 (v9.5.0.5) - Set influxdb initial defaults if 0 uint32_t influxdb_state : 1; // bit 7 (v9.5.0.5) - CMND_IFX - Enable influxdb support uint32_t sspm_display : 1; // bit 8 (v10.0.0.4) - CMND_SSPMDISPLAY - Enable gui display of powered on relays only - uint32_t spare09 : 1; // bit 9 + uint32_t local_ntp_server : 1; // bit 9 (v11.0.0.4) - CMND_RTCNTPSERVER - Enable local NTP server uint32_t spare10 : 1; // bit 10 uint32_t spare11 : 1; // bit 11 uint32_t spare12 : 1; // bit 12 diff --git a/tasmota/support.ino b/tasmota/support.ino index e56fe4d73..dab3d1e1a 100644 --- a/tasmota/support.ino +++ b/tasmota/support.ino @@ -2305,8 +2305,7 @@ void I2cSetActive(uint32_t addr, uint32_t count = 1) } void I2cSetActiveFound(uint32_t addr, const char *types, uint32_t bus = 0); -void I2cSetActiveFound(uint32_t addr, const char *types, uint32_t bus) -{ +void I2cSetActiveFound(uint32_t addr, const char *types, uint32_t bus) { I2cSetActive(addr); #ifdef ESP32 if (0 == bus) { @@ -2328,13 +2327,8 @@ bool I2cActive(uint32_t addr) return false; } -#ifdef ESP32 bool I2cSetDevice(uint32_t addr, uint32_t bus = 0); -bool I2cSetDevice(uint32_t addr, uint32_t bus) -#else -bool I2cSetDevice(uint32_t addr) -#endif -{ +bool I2cSetDevice(uint32_t addr, uint32_t bus) { #ifdef ESP32 if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } TwoWire & myWire = (bus == 0) ? Wire : Wire1; diff --git a/tasmota/support_rtc.ino b/tasmota/support_rtc.ino index ce2ce2482..4726028cf 100644 --- a/tasmota/support_rtc.ino +++ b/tasmota/support_rtc.ino @@ -475,7 +475,7 @@ void RtcSync(const char* source) { Rtc.time_synced = true; RtcSecond(); AddLog(LOG_LEVEL_DEBUG, PSTR("RTC: Synced by %s"), source); - XsnsCall(FUNC_TIME_SYNCED); + XdrvCall(FUNC_TIME_SYNCED); } void RtcSetTime(uint32_t epoch) { diff --git a/tasmota/xdrv_56_BM8563_RTC.ino b/tasmota/xdrv_56_BM8563_RTC.ino deleted file mode 100644 index b166e3827..000000000 --- a/tasmota/xdrv_56_BM8563_RTC.ino +++ /dev/null @@ -1,132 +0,0 @@ -/* - xdrv_56_BM8563_RTC.ino - BM8563 RTC - - Copyright (C) 2021 Stephan Hadinger and 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 . -*/ - -#ifdef USE_I2C -#ifdef USE_BM8563 -/*********************************************************************************************\ - * BM8563 - Real Time Clock - * - * I2C Address: 0x51 (Fixed in library as BM8563_ADRESS) -\*********************************************************************************************/ - -#define XDRV_56 56 -#define XI2C_59 59 // See I2CDEVICES.md - -#include "BM8563.h" - -struct { - BM8563 Rtc; - bool rtc_ready = false; - bool ntp_time_ok = false; -} bm8563_driver; - -uint32_t BM8563GetUtc(void) { - RTC_TimeTypeDef RTCtime; - // 1. read has errors ??? - bm8563_driver.Rtc.GetTime(&RTCtime); -// core2_globs.Rtc.GetTime(&RTCtime); - RTC_DateTypeDef RTCdate; - bm8563_driver.Rtc.GetDate(&RTCdate); - TIME_T tm; - tm.second = RTCtime.Seconds; - tm.minute = RTCtime.Minutes; - tm.hour = RTCtime.Hours; - tm.day_of_week = RTCdate.WeekDay; - tm.day_of_month = RTCdate.Date; - tm.month = RTCdate.Month; - tm.year = RTCdate.Year - 1970; - return MakeTime(tm); -} - -void BM8563SetUtc(uint32_t epoch_time) { - TIME_T tm; - BreakTime(epoch_time, tm); - RTC_TimeTypeDef RTCtime; - RTCtime.Hours = tm.hour; - RTCtime.Minutes = tm.minute; - RTCtime.Seconds = tm.second; - bm8563_driver.Rtc.SetTime(&RTCtime); - RTC_DateTypeDef RTCdate; - RTCdate.WeekDay = tm.day_of_week; - RTCdate.Month = tm.month; - RTCdate.Date = tm.day_of_month; - RTCdate.Year = tm.year + 1970; - bm8563_driver.Rtc.SetDate(&RTCdate); -} - -/*********************************************************************************************/ - -void BM8563Detect(void) { -#ifdef ESP32 - if (!I2cSetDevice(BM8563_ADRESS, 0)) { - if (!I2cSetDevice(BM8563_ADRESS, 1)) { return; } // check on bus 1 - bm8563_driver.Rtc.setBus(1); // switch to bus 1 - I2cSetActiveFound(BM8563_ADRESS, "BM8563", 1); - } else { - I2cSetActiveFound(BM8563_ADRESS, "BM8563", 0); - } -#else - if (!I2cSetDevice(BM8563_ADRESS)) { return; } - I2cSetActiveFound(BM8563_ADRESS, "BM8563"); -#endif - - bm8563_driver.Rtc.begin(); - bm8563_driver.rtc_ready = true; - - if (Rtc.utc_time < START_VALID_TIME) { // Not sync with NTP/GPS (time not valid), so read time - uint32_t time = BM8563GetUtc(); // Read UTC TIME - if (time > START_VALID_TIME) { - Rtc.utc_time = time; - RtcSync("BM8563"); - } - } -} - -void BM8563TimeSynced(void) { - if ((Rtc.utc_time > START_VALID_TIME) && // Valid UTC time - (abs((int32_t)(Rtc.utc_time - BM8563GetUtc())) > 2)) { // Time has drifted from RTC more than 2 seconds - BM8563SetUtc(Rtc.utc_time); // Update time - AddLog(LOG_LEVEL_DEBUG, PSTR("BM8: Re-synced (" D_UTC_TIME ") %s"), GetDateAndTime(DT_UTC).c_str()); - } -} - -/*********************************************************************************************\ - * Interface -\*********************************************************************************************/ - -bool Xdrv56(uint8_t function) { - if (!I2cEnabled(XI2C_59)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - BM8563Detect(); - } - else if (bm8563_driver.rtc_ready) { - switch (function) { - case FUNC_TIME_SYNCED: - BM8563TimeSynced(); - break; - } - } - return result; -} - -#endif // USE_BM8563 -#endif // USE_I2C diff --git a/tasmota/xdrv_56_rtc_chips.ino b/tasmota/xdrv_56_rtc_chips.ino new file mode 100644 index 000000000..d4f54f6c2 --- /dev/null +++ b/tasmota/xdrv_56_rtc_chips.ino @@ -0,0 +1,422 @@ +/* + xsns_56_rtc_chips.ino - RTC chip support for Tasmota + + SPDX-FileCopyrightText: 2022 Theo Arends + + SPDX-License-Identifier: GPL-3.0-only +*/ + +#define USE_RTC_CHIPS + +#ifdef USE_I2C +#ifdef USE_RTC_CHIPS +/*********************************************************************************************\ + * RTC chip support +\*********************************************************************************************/ + +#define XDRV_56 56 + +#ifdef USE_GPS // GPS driver has it's own NTP server +#undef RTC_NTP_SERVER // Disable NTP server (+0k8 code) +#endif + +struct { + uint32_t (* ReadTime)(void); + void (* SetTime)(uint32_t); + bool detected; + uint8_t address; + uint8_t bus; + char name[10]; +} RtcChip; + +/*********************************************************************************************\ + * DS1307 and DS3231 + * + * I2C Address: 0x68 +\*********************************************************************************************/ +#ifdef USE_DS3231 + +#define XI2C_26 26 // See I2CDEVICES.md + +#ifndef DS3231_ADDRESS +#define DS3231_ADDRESS 0x68 // DS3231 I2C Address +#endif + +// DS3231 Register Addresses +#define DS3231_SECONDS 0x00 +#define DS3231_MINUTES 0x01 +#define DS3231_HOURS 0x02 +#define DS3231_DAY 0x03 +#define DS3231_DATE 0x04 +#define DS3231_MONTH 0x05 +#define DS3231_YEAR 0x06 +#define DS3231_CONTROL 0x0E +#define DS3231_STATUS 0x0F + +// Control register bits +#define DS3231_OSF 7 +#define DS3231_EOSC 7 +#define DS3231_BBSQW 6 +#define DS3231_CONV 5 +#define DS3231_RS2 4 +#define DS3231_RS1 3 +#define DS3231_INTCN 2 + +//Other +#define DS3231_HR1224 6 // Hours register 12 or 24 hour mode (24 hour mode==0) +#define DS3231_CENTURY 7 // Century bit in Month register +#define DS3231_DYDT 6 // Day/Date flag bit in alarm Day/Date registers + +/*-------------------------------------------------------------------------------------------*\ + * Read time from DS3231 and return the epoch time (second since 1-1-1970 00:00) +\*-------------------------------------------------------------------------------------------*/ +uint32_t DS3231ReadTime(void) { + TIME_T tm; + tm.second = Bcd2Dec(I2cRead8(RtcChip.address, DS3231_SECONDS)); + tm.minute = Bcd2Dec(I2cRead8(RtcChip.address, DS3231_MINUTES)); + tm.hour = Bcd2Dec(I2cRead8(RtcChip.address, DS3231_HOURS) & ~_BV(DS3231_HR1224)); // Assumes 24hr clock + tm.day_of_week = I2cRead8(RtcChip.address, DS3231_DAY); + tm.day_of_month = Bcd2Dec(I2cRead8(RtcChip.address, DS3231_DATE)); + tm.month = Bcd2Dec(I2cRead8(RtcChip.address, DS3231_MONTH) & ~_BV(DS3231_CENTURY)); // Don't use the Century bit + tm.year = Bcd2Dec(I2cRead8(RtcChip.address, DS3231_YEAR)); + return MakeTime(tm); +} + +/*-------------------------------------------------------------------------------------------*\ + * Get time as TIME_T and set the DS3231 time to this value +\*-------------------------------------------------------------------------------------------*/ +void DS3231SetTime(uint32_t epoch_time) { + TIME_T tm; + BreakTime(epoch_time, tm); + I2cWrite8(RtcChip.address, DS3231_SECONDS, Dec2Bcd(tm.second)); + I2cWrite8(RtcChip.address, DS3231_MINUTES, Dec2Bcd(tm.minute)); + I2cWrite8(RtcChip.address, DS3231_HOURS, Dec2Bcd(tm.hour)); + I2cWrite8(RtcChip.address, DS3231_DAY, tm.day_of_week); + I2cWrite8(RtcChip.address, DS3231_DATE, Dec2Bcd(tm.day_of_month)); + I2cWrite8(RtcChip.address, DS3231_MONTH, Dec2Bcd(tm.month)); + I2cWrite8(RtcChip.address, DS3231_YEAR, Dec2Bcd(tm.year)); + I2cWrite8(RtcChip.address, DS3231_STATUS, I2cRead8(RtcChip.address, DS3231_STATUS) & ~_BV(DS3231_OSF)); // Clear the Oscillator Stop Flag +} + +void DS3231Detected(void) { + if (!RtcChip.detected && I2cEnabled(XI2C_26)) { + RtcChip.address = DS3231_ADDRESS; + if (I2cSetDevice(RtcChip.address)) { + if (I2cValidRead(RtcChip.address, DS3231_STATUS, 1)) { + RtcChip.detected = 1; + strcpy_P(RtcChip.name, PSTR("DS3231")); + RtcChip.ReadTime = &DS3231ReadTime; + RtcChip.SetTime = &DS3231SetTime; + } + } + } +} +#endif // USE_DS3231 + +/*********************************************************************************************\ + * BM8563 - Real Time Clock + * + * I2C Address: 0x51 (Fixed in library as BM8563_ADRESS) +\*********************************************************************************************/ +#ifdef USE_BM8563 + +#define XI2C_59 59 // See I2CDEVICES.md + +#include "BM8563.h" + +struct { + BM8563 Rtc; + bool rtc_ready = false; + bool ntp_time_ok = false; +} bm8563_driver; + +uint32_t BM8563GetUtc(void) { + RTC_TimeTypeDef RTCtime; + // 1. read has errors ??? + bm8563_driver.Rtc.GetTime(&RTCtime); +// core2_globs.Rtc.GetTime(&RTCtime); + RTC_DateTypeDef RTCdate; + bm8563_driver.Rtc.GetDate(&RTCdate); + TIME_T tm; + tm.second = RTCtime.Seconds; + tm.minute = RTCtime.Minutes; + tm.hour = RTCtime.Hours; + tm.day_of_week = RTCdate.WeekDay; + tm.day_of_month = RTCdate.Date; + tm.month = RTCdate.Month; + tm.year = RTCdate.Year - 1970; + return MakeTime(tm); +} + +void BM8563SetUtc(uint32_t epoch_time) { + TIME_T tm; + BreakTime(epoch_time, tm); + RTC_TimeTypeDef RTCtime; + RTCtime.Hours = tm.hour; + RTCtime.Minutes = tm.minute; + RTCtime.Seconds = tm.second; + bm8563_driver.Rtc.SetTime(&RTCtime); + RTC_DateTypeDef RTCdate; + RTCdate.WeekDay = tm.day_of_week; + RTCdate.Month = tm.month; + RTCdate.Date = tm.day_of_month; + RTCdate.Year = tm.year + 1970; + bm8563_driver.Rtc.SetDate(&RTCdate); +} + +void BM8563Detected(void) { + if (!RtcChip.detected && I2cEnabled(XI2C_59)) { + RtcChip.address = BM8563_ADRESS; + if (I2cSetDevice(RtcChip.address, 0)) { + RtcChip.detected = 1; + } +#ifdef ESP32 + else if (I2cSetDevice(RtcChip.address, 1)) { + RtcChip.detected = 1; + RtcChip.bus = 1; + bm8563_driver.Rtc.setBus(1); // switch to bus 1 + } +#endif + if (RtcChip.detected) { + bm8563_driver.Rtc.begin(); + strcpy_P(RtcChip.name, PSTR("BM8563")); + RtcChip.ReadTime = &BM8563GetUtc; + RtcChip.SetTime = &BM8563SetUtc; + } + } +} +#endif // USE_BM8563 + + +/*********************************************************************************************\ + * PCF85363 support + * + * I2C Address: 0x51 +\*********************************************************************************************/ +#ifdef USE_PCF85363 + +#define XI2C_66 66 // See I2CDEVICES.md + +#define PCF85363_ADDRESS 0x51 // PCF85363 I2C Address + +/*-------------------------------------------------------------------------------------------*\ + * Read time and return the epoch time (second since 1-1-1970 00:00) +\*-------------------------------------------------------------------------------------------*/ +uint32_t Pcf85363ReadTime(void) { + Wire.beginTransmission(RtcChip.address); + Wire.write(0x00); + Wire.endTransmission(); + + uint8_t buffer[8]; + Wire.requestFrom(RtcChip.address, (uint8_t)8); + for (uint32_t i = 0; i < 8; i++) { buffer[i] = Wire.read(); } + Wire.endTransmission(); + + TIME_T tm; + tm.second = Bcd2Dec(buffer[1] & 0x7F); + tm.minute = Bcd2Dec(buffer[2] & 0x7F); + tm.hour = Bcd2Dec(buffer[3]); + tm.day_of_month = Bcd2Dec(buffer[4]); + tm.day_of_week = buffer[5]; + tm.month = Bcd2Dec(buffer[6]); + tm.year = 30 + Bcd2Dec(buffer[7]); // Offset from 1970. So 2022 - 1970 = 52 + return MakeTime(tm); +} + +/*-------------------------------------------------------------------------------------------*\ + * Get time as TIME_T and set time to this value +\*-------------------------------------------------------------------------------------------*/ +void Pcf85363SetTime(uint32_t epoch_time) { + TIME_T tm; + BreakTime(epoch_time, tm); + + uint8_t buffer[8]; + buffer[0] = 0x00; // 100th_seconds (not used) + buffer[1] = Dec2Bcd(tm.second); + buffer[2] = Dec2Bcd(tm.minute); + buffer[3] = Dec2Bcd(tm.hour); + buffer[4] = Dec2Bcd(tm.day_of_month); + buffer[5] = tm.day_of_week; + buffer[6] = Dec2Bcd(tm.month); + buffer[7] = Dec2Bcd(tm.year -30); // Offset from 1970 +/* + // Handbook page 13 + Wire.beginTransmission(RtcChip.address); + Wire.write(0x2E); + Wire.write(0x01); // Set stop + Wire.write(0xA4); // Clear prescaler + for (uint32_t i = 0; i < 8; i++) { Wire.write(buffer[i]); } + Wire.endTransmission(); + Wire.beginTransmission(RtcChip.address); + Wire.write(0x2E); + Wire.write(0x00); // Set start + Wire.endTransmission(); +*/ + Wire.beginTransmission(RtcChip.address); + Wire.write(0x00); + for (uint32_t i = 0; i < 8; i++) { Wire.write(buffer[i]); } + Wire.endTransmission(); +} + +/*-------------------------------------------------------------------------------------------*\ + * Dump all registers +\*-------------------------------------------------------------------------------------------*/ +/* +void Pcf85363Dump(void) { + uint8_t buffer[64]; + + // 0x00 to 0x2F + Wire.beginTransmission(RtcChip.address); + Wire.write(0x00); + Wire.endTransmission(); + Wire.requestFrom(RtcChip.address, (uint8_t)48); + for (uint32_t i = 0; i < 48; i++) { + buffer[i] = Wire.read(); + } + Wire.endTransmission(); + AddLog(LOG_LEVEL_DEBUG, PSTR("P85: Read 0x00: %48_H"), buffer); + + // 0x40 to 0x7F + Wire.beginTransmission(RtcChip.address); + Wire.write(0x40); + Wire.endTransmission(); + Wire.requestFrom(RtcChip.address, (uint8_t)64); + for (uint32_t i = 0; i < 64; i++) { + buffer[i] = Wire.read(); + } + Wire.endTransmission(); + AddLog(LOG_LEVEL_DEBUG, PSTR("P85: Read 0x40: %64_H"), buffer); +} +*/ + +void Pcf85363Detected(void) { + if (!RtcChip.detected && I2cEnabled(XI2C_66)) { + RtcChip.address = PCF85363_ADDRESS; + if (I2cSetDevice(RtcChip.address)) { + RtcChip.detected = 1; + strcpy_P(RtcChip.name, PSTR("PCF85363")); + RtcChip.ReadTime = &Pcf85363ReadTime; + RtcChip.SetTime = &Pcf85363SetTime; + } + } +} +#endif // USE_PCF85363 + +/*********************************************************************************************\ + * RTC Detect and time set +\*********************************************************************************************/ + +void RtcChipDetect(void) { + RtcChip.detected = 0; + RtcChip.bus = 0; + +#ifdef USE_DS3231 + DS3231Detected(); +#endif // USE_DS3231 +#ifdef USE_BM8563 + BM8563Detected(); +#endif // USE_BM8563 +#ifdef USE_PCF85363 + Pcf85363Detected(); +#endif // USE_PCF85363 + + if (!RtcChip.detected) { return; } + + I2cSetActiveFound(RtcChip.address, RtcChip.name, RtcChip.bus); + + if (Rtc.utc_time < START_VALID_TIME) { // Not sync with NTP/GPS (time not valid), so read time + uint32_t time = RtcChip.ReadTime(); // Read UTC TIME + if (time > START_VALID_TIME) { + Rtc.utc_time = time; + RtcSync(RtcChip.name); + } + } +} + +void RtcChipTimeSynced(void) { + if ((Rtc.utc_time > START_VALID_TIME) && // Valid UTC time + (abs((int32_t)(Rtc.utc_time - RtcChip.ReadTime())) > 2)) { // Time has drifted from RTC more than 2 seconds + RtcChip.SetTime(Rtc.utc_time); // Update time + AddLog(LOG_LEVEL_DEBUG, PSTR("RTC: %s re-synced (" D_UTC_TIME ") %s"), RtcChip.name, GetDateAndTime(DT_UTC).c_str()); + } +} + +/*********************************************************************************************\ + * NTP server functions +\*********************************************************************************************/ +#ifdef RTC_NTP_SERVER + +#include "NTPServer.h" +#include "NTPPacket.h" + +#define NTP_MILLIS_OFFSET 50 + +const char kRtcChipCommands[] PROGMEM = "Rtc|" // Prefix + D_CMND_NTPSERVER; + +void (* const RtcChipCommand[])(void) PROGMEM = { + &CmndRtcNtpServer }; + +NtpServer RtcChipTimeServer(PortUdp); + +void RtcChipEverySecond(void) { + static bool ntp_server_started = false; + + if (Settings->sbflag1.local_ntp_server && (Rtc.utc_time > START_VALID_TIME)) { + if (!ntp_server_started) { + if (RtcChipTimeServer.beginListening()) { + ntp_server_started = true; + AddLog(LOG_LEVEL_DEBUG, PSTR("RTC: NTP server started")); + } + } else { + RtcChipTimeServer.processOneRequest(Rtc.utc_time, NTP_MILLIS_OFFSET); + } + } +} + +void CmndRtcNtpServer(void) { + // RtcChipNtpServer 0 or 1 + if (XdrvMailbox.payload >= 0) { + Settings->sbflag1.local_ntp_server = 0; + if ((XdrvMailbox.payload &1) && RtcChipTimeServer.beginListening()) { + Settings->sbflag1.local_ntp_server = 1; + } + } + ResponseCmndStateText(Settings->sbflag1.local_ntp_server); +} +#endif // RTC_NTP_SERVER + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdrv56(uint8_t function) { + bool result = false; + +#ifdef RTC_NTP_SERVER + switch (function) { + case FUNC_EVERY_SECOND: + RtcChipEverySecond(); + break; + case FUNC_COMMAND: + result = DecodeCommand(kRtcChipCommands, RtcChipCommand); + break; + } +#endif // RTC_NTP_SERVER + + if (FUNC_MODULE_INIT == function) { + RtcChipDetect(); + } + else if (RtcChip.detected) { + switch (function) { + case FUNC_TIME_SYNCED: + RtcChipTimeSynced(); + break; + } + } + + return result; +} + +#endif // USE_RTC_CHIPS +#endif // USE_I2C diff --git a/tasmota/xsns_33_ds3231.ino b/tasmota/xsns_33_ds3231.ino deleted file mode 100644 index a9c9fc343..000000000 --- a/tasmota/xsns_33_ds3231.ino +++ /dev/null @@ -1,208 +0,0 @@ -/* - xsns_33_ds3231.ino - DS3231/DS1307 RTC chip support for Tasmota - - Copyright (C) 2021 Guy Elgabsi (guy.elg AT gmail.com) and 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 . -*/ - -#ifdef USE_I2C -#ifdef USE_DS3231 -/*********************************************************************************************\ - * DS1307 and DS3231 support - * - * DS3231 - An accurate RTC that used for get time when you do not have internet connection. - * We store UTC time in the DS3231, so we can use the standart functions. - * HOWTO Use : Initially the time needs to be set into the DS3231 either - * - manual using command TIME - * - by internet using NTP - * - by GPS using UBX driver - * Once stored the time will be automaticaly updated by the DS2331 after power on - * Source: Guy Elgabsi with special thanks to Jack Christensen - * - * I2C Address: 0x68 -\*********************************************************************************************/ - -#define XSNS_33 33 -#define XI2C_26 26 // See I2CDEVICES.md - -#ifndef USE_RTC_ADDR -#define USE_RTC_ADDR 0x68 // DS3231 I2C Address -#endif - -#ifndef USE_GPS // GPS driver has it's own NTP server -#define DS3231_NTP_SERVER // Enable NTP server (+0k8 code) -#endif - -// DS3231 Register Addresses -#define DS3231_SECONDS 0x00 -#define DS3231_MINUTES 0x01 -#define DS3231_HOURS 0x02 -#define DS3231_DAY 0x03 -#define DS3231_DATE 0x04 -#define DS3231_MONTH 0x05 -#define DS3231_YEAR 0x06 -#define DS3231_CONTROL 0x0E -#define DS3231_STATUS 0x0F - -// Control register bits -#define DS3231_OSF 7 -#define DS3231_EOSC 7 -#define DS3231_BBSQW 6 -#define DS3231_CONV 5 -#define DS3231_RS2 4 -#define DS3231_RS1 3 -#define DS3231_INTCN 2 - -//Other -#define DS3231_HR1224 6 // Hours register 12 or 24 hour mode (24 hour mode==0) -#define DS3231_CENTURY 7 // Century bit in Month register -#define DS3231_DYDT 6 // Day/Date flag bit in alarm Day/Date registers - -bool ds3231_detected = false; - -/*-------------------------------------------------------------------------------------------*\ - * Read time from DS3231 and return the epoch time (second since 1-1-1970 00:00) -\*-------------------------------------------------------------------------------------------*/ -uint32_t DS3231ReadTime(void) { - TIME_T tm; - tm.second = Bcd2Dec(I2cRead8(USE_RTC_ADDR, DS3231_SECONDS)); - tm.minute = Bcd2Dec(I2cRead8(USE_RTC_ADDR, DS3231_MINUTES)); - tm.hour = Bcd2Dec(I2cRead8(USE_RTC_ADDR, DS3231_HOURS) & ~_BV(DS3231_HR1224)); // Assumes 24hr clock - tm.day_of_week = I2cRead8(USE_RTC_ADDR, DS3231_DAY); - tm.day_of_month = Bcd2Dec(I2cRead8(USE_RTC_ADDR, DS3231_DATE)); - tm.month = Bcd2Dec(I2cRead8(USE_RTC_ADDR, DS3231_MONTH) & ~_BV(DS3231_CENTURY)); // Don't use the Century bit - tm.year = Bcd2Dec(I2cRead8(USE_RTC_ADDR, DS3231_YEAR)); - return MakeTime(tm); -} - -/*-------------------------------------------------------------------------------------------*\ - * Get time as TIME_T and set the DS3231 time to this value -\*-------------------------------------------------------------------------------------------*/ -void DS3231SetTime (uint32_t epoch_time) { - TIME_T tm; - BreakTime(epoch_time, tm); - I2cWrite8(USE_RTC_ADDR, DS3231_SECONDS, Dec2Bcd(tm.second)); - I2cWrite8(USE_RTC_ADDR, DS3231_MINUTES, Dec2Bcd(tm.minute)); - I2cWrite8(USE_RTC_ADDR, DS3231_HOURS, Dec2Bcd(tm.hour)); - I2cWrite8(USE_RTC_ADDR, DS3231_DAY, tm.day_of_week); - I2cWrite8(USE_RTC_ADDR, DS3231_DATE, Dec2Bcd(tm.day_of_month)); - I2cWrite8(USE_RTC_ADDR, DS3231_MONTH, Dec2Bcd(tm.month)); - I2cWrite8(USE_RTC_ADDR, DS3231_YEAR, Dec2Bcd(tm.year)); - I2cWrite8(USE_RTC_ADDR, DS3231_STATUS, I2cRead8(USE_RTC_ADDR, DS3231_STATUS) & ~_BV(DS3231_OSF)); // Clear the Oscillator Stop Flag -} - -/*********************************************************************************************/ - -void DS3231Detect(void) { - if (!I2cSetDevice(USE_RTC_ADDR)) { return; } - - if (I2cValidRead(USE_RTC_ADDR, DS3231_STATUS, 1)) { - I2cSetActiveFound(USE_RTC_ADDR, "DS3231"); - ds3231_detected = true; - - if (Rtc.utc_time < START_VALID_TIME) { // We still did not sync with NTP/GPS (time not valid), so read time from DS3231 - uint32_t ds3231_time = DS3231ReadTime(); // Read UTC TIME from DS3231 - if (ds3231_time > START_VALID_TIME) { - Rtc.utc_time = ds3231_time; - RtcSync("DS3231"); - } - } - } -} - -void DS3231TimeSynced(void) { - if ((Rtc.utc_time > START_VALID_TIME) && // Valid UTC time - (abs((int32_t)(Rtc.utc_time - DS3231ReadTime())) > 2)) { // Time has drifted from RTC more than 2 seconds - DS3231SetTime(Rtc.utc_time); // Update the DS3231 time - AddLog(LOG_LEVEL_DEBUG, PSTR("DS3: Re-synced (" D_UTC_TIME ") %s"), GetDateAndTime(DT_UTC).c_str()); - } -} - -#ifdef DS3231_NTP_SERVER -/*********************************************************************************************\ - * NTP functions -\*********************************************************************************************/ - -#include "NTPServer.h" -#include "NTPPacket.h" - -#define NTP_MILLIS_OFFSET 50 - -NtpServer DS3231timeServer(PortUdp); - -bool ds3231_running_NTP = false; - -void DS3231EverySecond(void) { - if (ds3231_running_NTP) { - DS3231timeServer.processOneRequest(Rtc.utc_time, NTP_MILLIS_OFFSET); - } -} - -/*********************************************************************************************\ - * Supported commands for Sensor33: - * - * Sensor33 0 - NTP server off (default) - * Sensor33 1 - NTP server on -\*********************************************************************************************/ - -bool DS3231NTPCmd(void) { - bool serviced = true; - - if (XdrvMailbox.payload >= 0) { - ds3231_running_NTP = 0; - if ((XdrvMailbox.payload &1) && DS3231timeServer.beginListening()) { - ds3231_running_NTP = 1; - } - } - Response_P(PSTR("{\"Sensor33\":{\"NTPServer\":\"%s\"}}"), GetStateText(ds3231_running_NTP)); - - return serviced; -} -#endif // DS3231_NTP_SERVER - -/*********************************************************************************************\ - * Interface -\*********************************************************************************************/ - -bool Xsns33(uint8_t function) { - if (!I2cEnabled(XI2C_26)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - DS3231Detect(); - } - else if (ds3231_detected) { - switch (function) { -#ifdef DS3231_NTP_SERVER - case FUNC_EVERY_SECOND: - DS3231EverySecond(); - break; - case FUNC_COMMAND_SENSOR: - if (XSNS_33 == XdrvMailbox.index) { - result = DS3231NTPCmd(); - } - break; -#endif // DS3231_NTP_SERVER - case FUNC_TIME_SYNCED: - DS3231TimeSynced(); - break; - } - } - return result; -} - -#endif // USE_DS3231 -#endif // USE_I2C diff --git a/tasmota/xsns_96_pcf85363.ino b/tasmota/xsns_96_pcf85363.ino deleted file mode 100644 index c7a070636..000000000 --- a/tasmota/xsns_96_pcf85363.ino +++ /dev/null @@ -1,161 +0,0 @@ -/* - xsns_96_pcf85363.ino - PCF85363 RTC chip support for Tasmota - - SPDX-FileCopyrightText: 2022 Theo Arends - - SPDX-License-Identifier: GPL-3.0-only -*/ - -#ifdef USE_I2C -#ifdef USE_PCF85363 -/*********************************************************************************************\ - * PCF85363 support - * - * I2C Address: 0x51 -\*********************************************************************************************/ - -#define XSNS_96 96 -#define XI2C_66 66 // See I2CDEVICES.md - -#define USE_PCF85363_ADDR 0x51 // PCF85363 I2C Address - -bool pcf85363_detected = false; - -/*-------------------------------------------------------------------------------------------*\ - * Read time and return the epoch time (second since 1-1-1970 00:00) -\*-------------------------------------------------------------------------------------------*/ -uint32_t Pcf85363ReadTime(void) { - Wire.beginTransmission((uint8_t)USE_PCF85363_ADDR); - Wire.write(0x00); - Wire.endTransmission(); - - uint8_t buffer[8]; - Wire.requestFrom((int)USE_PCF85363_ADDR, (int)8); - for (uint32_t i = 0; i < 8; i++) { buffer[i] = Wire.read(); } - Wire.endTransmission(); - - TIME_T tm; - tm.second = Bcd2Dec(buffer[1] & 0x7F); - tm.minute = Bcd2Dec(buffer[2] & 0x7F); - tm.hour = Bcd2Dec(buffer[3]); - tm.day_of_month = Bcd2Dec(buffer[4]); - tm.day_of_week = buffer[5]; - tm.month = Bcd2Dec(buffer[6]); - tm.year = 30 + Bcd2Dec(buffer[7]); // Offset from 1970. So 2022 - 1970 = 52 - return MakeTime(tm); -} - -/*-------------------------------------------------------------------------------------------*\ - * Get time as TIME_T and set time to this value -\*-------------------------------------------------------------------------------------------*/ -void Pcf85363SetTime(uint32_t epoch_time) { - TIME_T tm; - BreakTime(epoch_time, tm); - - uint8_t buffer[8]; - buffer[0] = 0x00; // 100th_seconds (not used) - buffer[1] = Dec2Bcd(tm.second); - buffer[2] = Dec2Bcd(tm.minute); - buffer[3] = Dec2Bcd(tm.hour); - buffer[4] = Dec2Bcd(tm.day_of_month); - buffer[5] = tm.day_of_week; - buffer[6] = Dec2Bcd(tm.month); - buffer[7] = Dec2Bcd(tm.year -30); // Offset from 1970 -/* - // Handbook page 13 - Wire.beginTransmission((uint8_t)USE_PCF85363_ADDR); - Wire.write(0x2E); - Wire.write(0x01); // Set stop - Wire.write(0xA4); // Clear prescaler - for (uint32_t i = 0; i < 8; i++) { Wire.write(buffer[i]); } - Wire.endTransmission(); - Wire.beginTransmission((uint8_t)USE_PCF85363_ADDR); - Wire.write(0x2E); - Wire.write(0x00); // Set start - Wire.endTransmission(); -*/ - Wire.beginTransmission((uint8_t)USE_PCF85363_ADDR); - Wire.write(0x00); - for (uint32_t i = 0; i < 8; i++) { Wire.write(buffer[i]); } - Wire.endTransmission(); -} - -/*-------------------------------------------------------------------------------------------*\ - * Dump all registers -\*-------------------------------------------------------------------------------------------*/ -/* -void Pcf85363Dump(void) { - uint8_t buffer[64]; - - // 0x00 to 0x2F - Wire.beginTransmission((uint8_t)USE_PCF85363_ADDR); - Wire.write(0x00); - Wire.endTransmission(); - Wire.requestFrom((int)USE_PCF85363_ADDR, (int)48); - for (uint32_t i = 0; i < 48; i++) { - buffer[i] = Wire.read(); - } - Wire.endTransmission(); - AddLog(LOG_LEVEL_DEBUG, PSTR("P85: Read 0x00: %48_H"), buffer); - - // 0x40 to 0x7F - Wire.beginTransmission((uint8_t)USE_PCF85363_ADDR); - Wire.write(0x40); - Wire.endTransmission(); - Wire.requestFrom((int)USE_PCF85363_ADDR, (int)64); - for (uint32_t i = 0; i < 64; i++) { - buffer[i] = Wire.read(); - } - Wire.endTransmission(); - AddLog(LOG_LEVEL_DEBUG, PSTR("P85: Read 0x40: %64_H"), buffer); -} -*/ -/*********************************************************************************************/ - -void Pcf85363Detect(void) { - if (!I2cSetDevice(USE_PCF85363_ADDR)) { return; } - I2cSetActiveFound(USE_PCF85363_ADDR, "PCF85363"); - - pcf85363_detected = true; - - if (Rtc.utc_time < START_VALID_TIME) { // Not sync with NTP/GPS (time not valid), so read time - uint32_t time = Pcf85363ReadTime(); // Read UTC TIME - if (time > START_VALID_TIME) { - Rtc.utc_time = time; - RtcSync("PCF85363"); - } - } -} - -void Pcf85363TimeSynced(void) { - if ((Rtc.utc_time > START_VALID_TIME) && // Valid UTC time - (abs((int32_t)(Rtc.utc_time - Pcf85363ReadTime())) > 2)) { // Time has drifted from RTC more than 2 seconds - Pcf85363SetTime(Rtc.utc_time); // Update time - AddLog(LOG_LEVEL_DEBUG, PSTR("P85: Re-synced (" D_UTC_TIME ") %s"), GetDateAndTime(DT_UTC).c_str()); - } -} - -/*********************************************************************************************\ - * Interface -\*********************************************************************************************/ - -bool Xsns96(uint8_t function) { - if (!I2cEnabled(XI2C_66)) { return false; } - - bool result = false; - - if (FUNC_INIT == function) { - Pcf85363Detect(); - } - else if (pcf85363_detected) { - switch (function) { - case FUNC_TIME_SYNCED: - Pcf85363TimeSynced(); - break; - } - } - return result; -} - -#endif // USE_PCF85363 -#endif // USE_I2C