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