This commit is contained in:
2026-02-13 12:26:11 -08:00
parent 13812abc00
commit 160c686933
22 changed files with 1634 additions and 1 deletions

6
.gitmodules vendored Normal file
View File

@@ -0,0 +1,6 @@
[submodule "TFT_eSPI"]
path = TFT_eSPI
url = https://github.com/Cincinnatu/TFT_eSPI
[submodule "sketches/doorbell/TFT_eSPI"]
path = sketches/doorbell/TFT_eSPI
url = https://github.com/Cincinnatu/TFT_eSPI.git

1
TFT_eSPI Submodule

Submodule TFT_eSPI added at 42f64b37e4

22
libraries/NTP/LICENSE Executable file
View File

@@ -0,0 +1,22 @@
MIT License
NTP library for Arduino framework
Copyright (c) 2022 Stefan Staub
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

288
libraries/NTP/NTP.cpp Executable file
View File

@@ -0,0 +1,288 @@
/**
* NTP library for Arduino framework
* The MIT License (MIT)
* (c) 2022 sstaub
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "NTP.h"
NTP::NTP(UDP& udp) {
this->udp = &udp;
}
NTP::~NTP() {
stop();
}
void NTP::begin(const char* server) {
this->server = server;
init();
}
void NTP::begin(IPAddress serverIP) {
this->serverIP = serverIP;
init();
}
void NTP::init() {
memset(ntpRequest, 0, NTP_PACKET_SIZE);
ntpRequest[0] = 0b11100011; // LI, Version, Mode
ntpRequest[1] = 0; // Stratum, or type of clock
ntpRequest[2] = 6; // Polling Interval
ntpRequest[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
ntpRequest[12] = 49;
ntpRequest[13] = 0x4E;
ntpRequest[14] = 49;
ntpRequest[15] = 52;
udp->begin(NTP_PORT);
ntpUpdate();
if (dstZone) {
timezoneOffset = dstEnd.tzOffset * SECS_PER_MINUTES;
dstOffset = (dstStart.tzOffset - dstEnd.tzOffset) * SECS_PER_MINUTES;
currentTime();
beginDST();
}
}
void NTP::stop() {
udp->stop();
}
bool NTP::update() {
if ((millis() - lastUpdate >= interval) || lastUpdate == 0) {
return ntpUpdate();
}
return false;
}
bool NTP::ntpUpdate() {
if (server == nullptr) udp->beginPacket(serverIP, NTP_PORT);
else udp->beginPacket(server, NTP_PORT);
udp->write(ntpRequest, NTP_PACKET_SIZE);
udp->endPacket();
uint8_t timeout = 0;
uint8_t size = 0;
do {
delay (10);
size = udp->parsePacket();
if (timeout > 100) return false;
timeout++;
} while (size != 48);
lastUpdate = millis() - (10 * (timeout + 1));
udp->read(ntpQuery, NTP_PACKET_SIZE);
#ifdef __AVR__
unsigned long highWord = word(ntpQuery[40], ntpQuery[41]);
unsigned long lowWord = word(ntpQuery[42], ntpQuery[43]);
timestamp = highWord << 16 | lowWord;
if (timestamp != 0) {
ntpTime = timestamp;
utcTime = ntpTime - NTP_OFFSET;
}
else return false;
#else
timestamp = ntpQuery[40] << 24 | ntpQuery[41] << 16 | ntpQuery[42] << 8 | ntpQuery[43];
if (timestamp != 0) {
ntpTime = timestamp;
utcTime = ntpTime - SEVENTYYEARS;
}
else return false;
#endif
return true;
}
void NTP::updateInterval(uint32_t interval) {
this->interval = interval;
}
void NTP::ruleDST(const char* tzName, int8_t week, int8_t wday, int8_t month, int8_t hour, int tzOffset) {
strcpy(dstStart.tzName, tzName);
dstStart.week = week;
dstStart.wday = wday;
dstStart.month = month;
dstStart.hour = hour;
dstStart.tzOffset = tzOffset;
}
const char* NTP::ruleDST() {
if(dstZone) {
return ctime(&dstTime);
}
else return RULE_DST_MESSAGE;
}
void NTP::ruleSTD(const char* tzName, int8_t week, int8_t wday, int8_t month, int8_t hour, int tzOffset) {
strcpy(dstEnd.tzName, tzName);
dstEnd.week = week;
dstEnd.wday = wday;
dstEnd.month = month;
dstEnd.hour = hour;
dstEnd.tzOffset = tzOffset;
}
const char* NTP::ruleSTD() {
if(dstZone) {
return ctime(&stdTime);
}
else return RULE_STD_MESSAGE;
}
const char* NTP::tzName() {
if (dstZone) {
if (summerTime()) return dstStart.tzName;
else return dstEnd.tzName;
}
return GMT_MESSAGE;
}
void NTP::timeZone(int8_t tzHours, int8_t tzMinutes) {
this->tzHours = tzHours;
this->tzMinutes = tzMinutes;
timezoneOffset = tzHours * 3600;
if (tzHours < 0) {
timezoneOffset -= tzMinutes * 60;
}
else {
timezoneOffset += tzMinutes * 60;
}
}
void NTP::isDST(bool dstZone) {
this->dstZone = dstZone;
}
bool NTP::isDST() {
return summerTime();
}
time_t NTP::epoch() {
currentTime();
return utcCurrent;
}
void NTP::currentTime() {
utcCurrent = utcTime + ((millis() - lastUpdate) / 1000);
if (dstZone) {
if (summerTime()) {
local = utcCurrent + dstOffset + timezoneOffset;
current = gmtime(&local);
}
else {
local = utcCurrent + timezoneOffset;
current = gmtime(&local);
}
if ((current->tm_year + 1900) > yearDST) beginDST();
}
else {
local = utcCurrent + timezoneOffset;
current = gmtime(&local);
}
}
int16_t NTP::year() {
currentTime();
return current->tm_year + 1900;
}
int8_t NTP::month() {
currentTime();
return current->tm_mon + 1;
}
int8_t NTP::day() {
currentTime();
return current->tm_mday;
}
int8_t NTP::weekDay() {
currentTime();
return current->tm_wday;
}
int8_t NTP::hours() {
currentTime();
return current->tm_hour;
}
int8_t NTP::minutes() {
currentTime();
return current->tm_min;
}
int8_t NTP::seconds() {
currentTime();
return current->tm_sec;
}
const char* NTP::formattedTime(const char *format) {
currentTime();
memset(timeString, 0, sizeof(timeString));
strftime(timeString, sizeof(timeString), format, current);
return timeString;
}
void NTP::beginDST() {
dstTime = calcDateDST(dstStart, current->tm_year + 1900);
utcDST = dstTime - (dstEnd.tzOffset * SECS_PER_MINUTES);
stdTime = calcDateDST(dstEnd, current->tm_year + 1900);
utcSTD = stdTime - (dstStart.tzOffset * SECS_PER_MINUTES);
yearDST = current->tm_year + 1900;
}
time_t NTP::calcDateDST(struct ruleDST rule, int year) {
uint8_t month = rule.month;
uint8_t week = rule.week;
if (week == 0) {
if (month++ > 11) {
month = 0;
year++;
}
week = 1;
}
struct tm tm;
tm.tm_hour = rule.hour;
tm.tm_min = 0;
tm.tm_sec = 0;
tm.tm_mday = 1;
tm.tm_mon = month;
tm.tm_year = year - 1900;
time_t t = mktime(&tm);
t += ((rule.wday - tm.tm_wday + 7) % 7 + (week - 1) * 7 ) * SECS_PER_DAY;
if (rule.week == 0) t -= 7 * SECS_PER_DAY;
return t;
}
bool NTP::summerTime() {
if ((utcCurrent > utcDST) && (utcCurrent <= utcSTD)) {
return true;
}
else {
return false;
}
}
uint32_t NTP::ntp() {
return ntpTime;
}
uint32_t NTP::utc() {
return utcTime;
}

288
libraries/NTP/NTP.h Executable file
View File

@@ -0,0 +1,288 @@
/**
* NTP library for Arduino framewoek
* The MIT License (MIT)
* (c) 2022 sstaub
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef NTP_H
#define NTP_H
#include "Arduino.h"
#include <time.h>
#include <Udp.h>
#define SEVENTYYEARS 2208988800UL
#define UNIXOFFSET 946684800UL
#ifdef __AVR__
//#define POSIX_OFFSET NTP_OFFSET - SEVENTYYEARS// - UNIX_OFFSET// + 30 years
#define POSIX_OFFSET UNIXOFFSET
#else
#define POSIX_OFFSET -SEVENTYYEARS
#endif
#define NTP_PACKET_SIZE 48
#define NTP_PORT 123
#define SECS_PER_MINUTES 60
#define SECS_PER_DAY 86400
#define GMT_MESSAGE "GMT +/- offset"
#define RULE_DST_MESSAGE "no DST rule"
#define RULE_STD_MESSAGE "no STD rule"
enum week_t {Last, First, Second, Third, Fourth};
enum dow_t {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
enum month_t {Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec};
class NTP {
public:
/**
* @brief constructor for the NTP object
*
* @param udp
*/
NTP(UDP& udp);
/**
* @brief destructor for the NTP object
*
*/
~NTP();
/**
* @brief starts the underlying UDP client with the default local port
*
* @param server NTP server host name
* @param serverIP NTP server IP address
*/
void begin(const char* server = "pool.ntp.org");
void begin(IPAddress serverIP);
/**
* @brief stops the underlying UDP client
*
*/
void stop();
/**
* @brief This should be called in the main loop of your application. By default an update from the NTP Server is only
* made every 60 seconds. This can be configured in the NTPTime constructor.
*
* @return true on success
* @return false on no update or update failure
*/
bool update();
/**
* @brief set the update interval
*
* @param updateInterval in ms, default = 60000ms
*/
void updateInterval(uint32_t interval);
/**
* @brief set the rule for DST (daylight saving time)
* start date of DST
*
* @param tzName name of the time zone
* @param week Last, First, Second, Third, Fourth (0 - 4)
* @param wday Sun, Mon, Tue, Wed, Thu, Fri, Sat (0 - 7)
* @param month Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec (0 -11)
* @param hour the local hour when rule chages
* @param tzOffset sum of summertime and timezone offset
*/
void ruleDST(const char* tzName, int8_t week, int8_t wday, int8_t month, int8_t hour, int tzOffset);
/**
* @brief get the DST time as a ctime string
*
* @return char* time string
*/
const char* ruleDST();
/**
* @brief set the rule for STD (standard day)
* end date of DST
*
* @param tzName name of the time zone
* @param week Last, First, Second, Third, Fourth (0 - 4)
* @param wday Sun, Mon, Tue, Wed, Thu, Fri, Sat (0 - 7)
* @param month Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec (0 -11)
* @param hour the local hour when rule chages
* @param tzOffset timezone offset
*/
void ruleSTD(const char* tzName, int8_t week, int8_t wday, int8_t month, int8_t hour, int tzOffset);
/**
* @brief get the STD time as a ctime string
*
* @return char* time string
*/
const char* ruleSTD();
/**
* @brief get the name of the timezone
*
* @return char* name of the timezone
*/
const char* tzName();
/**
* @brief set the timezone manually
* this should used if there is no DST!
*
* @param tzHours
* @param tzMinutes
*/
void timeZone(int8_t tzHours, int8_t tzMinutes = 0);
/**
* @brief set daylight saving manually!
* use in conjunction with timeZone, when there is no DST!
*
* @param dstZone
*/
void isDST(bool dstZone);
/**
* @brief returns the DST state
*
* @return int 1 if summertime, 0 no summertime
*/
bool isDST();
/**
* @brief get the Unix epoch timestamp
*
* @return time_t timestamp
*/
time_t epoch();
/**
* @brief get the year
*
* @return int year
*/
int16_t year();
/**
* @brief get the month
*
* @return int month, 1 = january
*/
int8_t month();
/**
* @brief get the day of a month
*
* @return int day
*/
int8_t day();
/**
* @brief get the day of a week
*
* @return int day of the week, 0 = sunday
*/
int8_t weekDay();
/**
* @brief get the hour of the day
*
* @return int
*/
int8_t hours();
/**
* @brief get the minutes of the hour
*
* @return int minutes
*/
int8_t minutes();
/**
* @brief get the seconds of a minute
*
* @return int seconds
*/
int8_t seconds();
/**
* @brief returns a formatted string
*
* @param format for strftime
* @return char* formated time string
*/
const char* formattedTime(const char *format);
/**
* @brief returns NTP timestamp
*
* @return uint32_t
*/
uint32_t ntp();
/**
* @brief returns UNIX timestamp
*
* @return uint32_t
*/
uint32_t utc();
private:
UDP *udp;
const char* server = nullptr;
IPAddress serverIP;
uint8_t ntpRequest[NTP_PACKET_SIZE]; // = {0xE3, 0x00, 0x06, 0xEC};
uint8_t ntpQuery[NTP_PACKET_SIZE];
time_t utcCurrent = 0;
time_t local = 0;
struct tm *current;
uint32_t interval = 60000;
uint32_t lastUpdate = 0;
uint8_t tzHours = 0;
uint8_t tzMinutes = 0;
int32_t timezoneOffset;
int16_t dstOffset = 0;
bool dstZone = true;
uint32_t timestamp;
uint32_t ntpTime = 0;
uint32_t utcTime = 0;
time_t utcSTD, utcDST;
time_t dstTime, stdTime;
uint16_t yearDST;
char timeString[64];
struct ruleDST {
char tzName[6]; // five chars max
int8_t week; // First, Second, Third, Fourth, or Last week of the month
int8_t wday; // day of week, 0 = Sun, 2 = Mon, ... 6 = Sat
int8_t month; // 0 = Jan, 1 = Feb, ... 11=Dec
int8_t hour; // 0 - 23
int tzOffset; // offset from UTC in minutes
} dstStart, dstEnd;
void init();
bool ntpUpdate();
time_t localTime();
void currentTime();
void beginDST();
time_t calcDateDST(struct ruleDST rule, int year);
bool summerTime();
};
#endif

330
libraries/NTP/README.md Executable file
View File

@@ -0,0 +1,330 @@
# **NTP**
The **NTP** library allows you to receive time information from the Internet. It also have support for
different timezones and daylight saving time (DST).
This NTP library uses the functions of the time.h standard library.<br>
## Changes for 1.7
- support for AVR
- optimizations
## Changes for 1.6
- change of begin(), now you can start with hostname or IP address
- no blocking
- better documentation
## Example
Example for WIFI boards like ESP32 or MKR1000, NANO RP2040 Connect and other, prints formatted time and date strings to console.
```cpp
// change next line to use with another board/shield
//#include <ESP8266WiFi.h>
//#include <WiFi.h> // for WiFi shield or ESP32
//#include <WiFi101.h> // for WiFi 101 shield or MKR1000
#include <WiFiNINA.h> // for UNO Wifi Rev 2 or Nano RP2040 connect
//#include "WiFiUdp.h" // not needed for WiFiNINA
#include "NTP.h"
const char *ssid = "yourSSID"; // your network SSID
const char *password = "yourPASSWORD"; // your network PW
WiFiUDP wifiUdp;
NTP ntp(wifiUdp);
void setup() {
Serial.begin(9600);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
Serial.println("Connecting ...");
delay(500);
}
Serial.println("Connected");
ntp.ruleDST("CEST", Last, Sun, Mar, 2, 120); // last sunday in march 2:00, timetone +120min (+1 GMT + 1h summertime offset)
ntp.ruleSTD("CET", Last, Sun, Oct, 3, 60); // last sunday in october 3:00, timezone +60min (+1 GMT)
ntp.begin();
Serial.println("start NTP");
}
void loop() {
ntp.update();
Serial.println(ntp.formattedTime("%d. %B %Y")); // dd. Mmm yyyy
Serial.println(ntp.formattedTime("%A %T")); // Www hh:mm:ss
delay(1000);
}
```
# Documentation
## Class Definitions
```cpp
NTP(UDP& udp);
```
Constructor for a NTP object
Example, this should done before ```setup()```
```cpp
WiFiUDP wifiUdp;
NTP ntp(wifiUdp);
```
```cpp
~NTP();
```
Destructor for a NTP object
## begin()
```cpp
void begin(const char* server = "pool.ntp.org");
void begin(IPAddress serverIP);
```
Start the underlaying UDP client with a hostname or IP address.
Example, this must done in ```setup()```
```cpp
ntp.begin(); // start the NTP client with the standard host
```
## stop()
```cpp
void stop();
```
Stop the underlaying UDP client
Example, this must done in ```setup()```
```cpp
ntp.stop();
```
## update()
```cpp
void update();
```
This must called in the main ```loop()```
Example
```cpp
loop() {
ntp.update();
}
```
## updateInterval()
```cpp
void updateInterval(uint32_t interval);
```
Set the update interval for connecting the NTP server in ms, default is 60000ms (60s)
Example, this must done in ```setup()```
```cpp
ntp.updateInterval(1000); // update every second
```
## ruleDST()
```cpp
void ruleDST(const char* tzName, int8_t week, int8_t wday, int8_t month, int8_t hour, int tzOffset);
```
Set the rules for the daylight save time settings
- tzname is the name of the timezone, e.g. "CEST" (central europe summer time)
- week Last, First, Second, Third, Fourth (0 - 4)
- wday Sun, Mon, Tue, Wed, Thu, Fri, Sat (0 - 7)
- month Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec (0 -11)
- hour the local hour when rule changes
- tzOffset timezone offset in minutes
Example, this must done in ```setup()```
```cpp
ntp.ruleDST("CEST", Last, Sun, Mar, 2, 120); // last sunday in march 2:00, timetone +120min (+1 GMT + 1h summertime offset)
```
## Return ruleDST()
```cpp
const char* ruleDST();
```
Returns the DST time back, formatted as an ```ctime``` string
## ruleSTD()
```cpp
void ruleSTD(const char* tzName, int8_t week, int8_t wday, int8_t month, int8_t hour, int tzOffset);
```
Set the rules for the standard time settings
- tzname is the name of the timezone, e.g. "CET" (central europe time)
- week Last, First, Second, Third, Fourth (0 - 4)
- wday Sun, Mon, Tue, Wed, Thu, Fri, Sat (0 - 7)
- month Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec (0 -11)
- hour the local hour when rule changes
- tzOffset timezone offset in minutes
Example, this must done in ```setup()```
```cpp
ntp.ruleDST("CEST", Last, Sun, Mar, 2, 120); // last sunday in march 2:00, time
```
## Return ruleSTD()
```cpp
const char* ruleSTD();
```
Return the STD time back, formatted as an ctime string
## Return tzName()
```cpp
const char* tzName();
```
Return you the name of the current timezone, based on your rule settings
## timeZone()
```cpp
void timeZone(int8_t tzHours, int8_t tzMinutes = 0);
```
Only use this function when you don't made the rules setting,
you have to the set isDST(false)
## isDST()
```cpp
void isDST(bool dstZone);
```
Use in conjunction with timeZone, when there is no DST!
## Return isDST()
```cpp
bool isDST();
```
Return the DST status back, true if summertime
## epoch()
```cpp
time_t epoch();
```
Return the Unix epoch timestamp
## year(), month(), day(), weekDay(), hours(), minutes(), seconds()
```cpp
int16_t year();
int8_t month();
int8_t day();
int8_t weekDay();
int8_t hours();
int8_t minutes();
int8_t seconds();
```
Return the datas from the tm structure of the "time.h" library
## Return formattedTime()
```cpp
const char* formattedTime(const char *format);
```
Return a string, formated with strftime function of standard time library
Example
```cpp
loop() {
ntp.update();
Serial.println(ntp.formattedTime("%d. %B %Y")); // dd. Mmm yyyy
Serial.println(ntp.formattedTime("%A %T")); // Www hh:mm:ss
delay(1000);
}
```
Format symbols:
```
| symbol | explanation
/* General */
| % | writes literal %. The full conversion specification must be %%.
| n | writes newline character
| t | writes horizontal tab character
/* Year */
| Y | writes year as a decimal number, e.g. 2017
| y | writes last 2 digits of year as a decimal number (range [00,99])
| C | writes first 2 digits of year as a decimal number (range [00,99])
| G | writes ISO 8601 week-based year, i.e. the year that contains the specified week.
In IS0 8601 weeks begin with Monday and the first week of the year must satisfy the following requirements:
- Includes January 4
- Includes first Thursday of the year
| g | writes last 2 digits of ISO 8601 week-based year, i.e. the year that contains the specified week (range [00,99]).
In IS0 8601 weeks begin with Monday and the first week of the year must satisfy the following requirements:
- Includes January 4
- Includes first Thursday of the year
/* Month */
| b | writes abbreviated month name, e.g. Oct (locale dependent)
| h | synonym of b
| B | writes full month name, e.g. October (locale dependent)
| m | writes month as a decimal number (range [01,12])
/* Week */
| U | writes week of the year as a decimal number (Sunday is the first day of the week) (range [00,53])
| W | writes week of the year as a decimal number (Monday is the first day of the week) (range [00,53])
| V | writes ISO 8601 week of the year (range [01,53]).
In IS0 8601 weeks begin with Monday and the first week of the year must satisfy the following requirements:
- Includes January 4
- Includes first Thursday of the year
/* Day of the year/month */
| j | writes day of the year as a decimal number (range [001,366])
| d | writes day of the month as a decimal number (range [01,31])
| e | writes day of the month as a decimal number (range [1,31]).
Single digit is preceded by a space.
/* Day of the week */
| a | writes abbreviated weekday name, e.g. Fri (locale dependent)
| A | writes full weekday name, e.g. Friday (locale dependent)
| w | writes weekday as a decimal number, where Sunday is 0 (range [0-6])
| u | writes weekday as a decimal number, where Monday is 1 (ISO 8601 format) (range [1-7])
/* Hour, minute, second */
| H | writes hour as a decimal number, 24 hour clock (range [00-23])
| I | writes hour as a decimal number, 12 hour clock (range [01,12])
| M | writes minute as a decimal number (range [00,59])
| S | writes second as a decimal number (range [00,60])
/* Other */
| c | writes standard date and time string, e.g. Sun Oct 17 04:41:13 2010 (locale dependent)
| x | writes localized date representation (locale dependent)
| X | writes localized time representation (locale dependent)
| D | equivalent to "%m/%d/%y"
| F | equivalent to "%Y-%m-%d" (the ISO 8601 date format)
| r | writes localized 12-hour clock time (locale dependent)
| R | equivalent to "%H:%M"
| T | equivalent to "%H:%M:%S" (the ISO 8601 time format)
| p | writes localized a.m. or p.m. (locale dependent)
```
## Return utc()
```cpp
uint32_t utc();
```
Return the timestamp received from the ntp server in Unix timestamp format
## Return ntp()
```cpp
uint32_t ntp();
```
Return the timestamp received from the ntp server in the NTP timestamp format

View File

@@ -0,0 +1,58 @@
// example ESP32 board with oled, use oled lib https://github.com/squix78/esp8266-oled-ssd1306
#include <Arduino.h>
#include "WiFi.h"
#include <WiFiUdp.h>
#include "SSD1306.h"
#include "NTP.h"
char ssid[] = "yourSSID";
char password[] = "yourPASSWORD";
SSD1306 display(0x3c, 5, 4);
WiFiUDP wifiUdp;
NTP ntp(wifiUdp);
void display_text(String text){
display.clear();
display.setColor(WHITE);
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.drawString(64, 15, text);
display.display();
}
void setup() {
Serial.begin(9600);
display.init();
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
display_text("Connecting ...");
delay (500);
}
display.clear();
display_text("Connected");
delay (500);
ntp.ruleDST("CEST", Last, Sun, Mar, 2, 120); // last sunday in march 2:00, timetone +120min (+1 GMT + 1h summertime offset)
ntp.ruleSTD("CET", Last, Sun, Oct, 3, 60); // last sunday in october 3:00, timezone +60min (+1 GMT)
// ntp.isDST(false);
// ntp.timeZone(1);
// ntp.offset(0, 0, 0, 0);
ntp.begin();
display_text("start NTP");
delay (500);
}
void loop() {
ntp.update();
display.clear();
display.fillRect(1, 0, 126 * ntp.seconds() / 59, 2);
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.drawString(64, 5, ntp.formattedTime("%d. %B %Y"));
display.drawString(64, 15, ntp.formattedTime("%A %T"));
display.drawString(64, 25, ntp.ruleDST());
display.drawString(64, 35, ntp.ruleSTD());
display.drawString(64, 45, ntp.tzName());
display.display();
delay(500);
}

View File

@@ -0,0 +1,37 @@
// example for WIFI based boards like ESP8266, ESP32, Nano RP2040 Connect, WiFi 101 shield or MKR1000
#include "Arduino.h"
// change next line to use with another board/shield
//#include <ESP8266WiFi.h>
//#include <WiFi.h> // for WiFi shield or ESP32
//#include <WiFi101.h> // for WiFi 101 shield or MKR1000
#include <WiFiNINA.h> // for e.g. Nano RP2040 Connect
//#include "WiFiUdp.h" // not needed for WiFiNINA
#include "NTP.h"
char ssid[] = "yourSSID";
char password[] = "yourPASSWORD";
WiFiUDP wifiUdp;
NTP ntp(wifiUdp);
void setup() {
Serial.begin(9600);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
Serial.println("Connecting ...");
delay(500);
}
Serial.println("Connected");
ntp.ruleDST("CEST", Last, Sun, Mar, 2, 120); // last sunday in march 2:00, timetone +120min (+1 GMT + 1h summertime offset)
ntp.ruleSTD("CET", Last, Sun, Oct, 3, 60); // last sunday in october 3:00, timezone +60min (+1 GMT)
ntp.begin();
Serial.println("start NTP");
}
void loop() {
ntp.update();
Serial.println(ntp.formattedTime("%d. %B %Y")); // dd. Mmm yyyy
Serial.println(ntp.formattedTime("%A %T")); // Www hh:mm:ss
delay(1000);
}

30
libraries/NTP/keywords.txt Executable file
View File

@@ -0,0 +1,30 @@
#######################################
# Datatypes (KEYWORD1)
#######################################
NTP KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
stop KEYWORD2
update KEYWORD2
updateInterval KEYWORD2
timeZone KEYWORD2
ruleDST KEYWORD2
ruleSTD KEYWORD2
tzName KEYWORD2
isDST KEYWORD2
epoch KEYWORD2
year KEYWORD2
month KEYWORD2
day KEYWORD2
weekDay KEYWORD2
hours KEYWORD2
minutes KEYWORD2
seconds KEYWORD2
formattedTime KEYWORD2
utc KEYWORD2
ntp KEYWORD2

13
libraries/NTP/library.json Executable file
View File

@@ -0,0 +1,13 @@
{
"name": "NTP",
"keywords": "ntp, client, time, timezone",
"description": "A NTP client with timezone support",
"repository":
{
"type": "git",
"url": "https://github.com/sstaub/NTP.git"
},
"version": "1.7",
"frameworks": "arduino",
"platforms": "*"
}

View File

@@ -0,0 +1,10 @@
name=NTP
version=1.7
author=Stefan Staub
maintainer=Stefan Staub <email@domain.com>
sentence=NTP library
paragraph=NTP library for Arduino framework, using standard time.h library.
category=Timing
url=https://github.com/sstaub/NTP
architectures=*
includes=NTP.h

View File

@@ -0,0 +1,15 @@
NTPClient 3.1.0 - 2016.05.31
* Added functions for changing the timeOffset and updateInterval later. Thanks @SirUli
NTPClient 3.0.0 - 2016.04.19
* Constructors now require UDP instance argument, to add support for non-ESP8266 boards
* Added optional begin API to override default local port
* Added end API to close UDP socket
* Changed return type of update and forceUpdate APIs to bool, and return success or failure
* Change return type of getDay, getHours, getMinutes, and getSeconds to int
Older
* Changes not recorded

212
libraries/NTPClient/NTPClient.cpp Executable file
View File

@@ -0,0 +1,212 @@
/**
* The MIT License (MIT)
* Copyright (c) 2015 by Fabrice Weinberg
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "NTPClient.h"
NTPClient::NTPClient(UDP& udp) {
this->_udp = &udp;
}
NTPClient::NTPClient(UDP& udp, long timeOffset) {
this->_udp = &udp;
this->_timeOffset = timeOffset;
}
NTPClient::NTPClient(UDP& udp, const char* poolServerName) {
this->_udp = &udp;
this->_poolServerName = poolServerName;
}
NTPClient::NTPClient(UDP& udp, IPAddress poolServerIP) {
this->_udp = &udp;
this->_poolServerIP = poolServerIP;
this->_poolServerName = NULL;
}
NTPClient::NTPClient(UDP& udp, const char* poolServerName, long timeOffset) {
this->_udp = &udp;
this->_timeOffset = timeOffset;
this->_poolServerName = poolServerName;
}
NTPClient::NTPClient(UDP& udp, IPAddress poolServerIP, long timeOffset){
this->_udp = &udp;
this->_timeOffset = timeOffset;
this->_poolServerIP = poolServerIP;
this->_poolServerName = NULL;
}
NTPClient::NTPClient(UDP& udp, const char* poolServerName, long timeOffset, unsigned long updateInterval) {
this->_udp = &udp;
this->_timeOffset = timeOffset;
this->_poolServerName = poolServerName;
this->_updateInterval = updateInterval;
}
NTPClient::NTPClient(UDP& udp, IPAddress poolServerIP, long timeOffset, unsigned long updateInterval) {
this->_udp = &udp;
this->_timeOffset = timeOffset;
this->_poolServerIP = poolServerIP;
this->_poolServerName = NULL;
this->_updateInterval = updateInterval;
}
void NTPClient::begin() {
this->begin(NTP_DEFAULT_LOCAL_PORT);
}
void NTPClient::begin(unsigned int port) {
this->_port = port;
this->_udp->begin(this->_port);
this->_udpSetup = true;
}
bool NTPClient::forceUpdate() {
#ifdef DEBUG_NTPClient
Serial.println("Update from NTP Server");
#endif
// flush any existing packets
while(this->_udp->parsePacket() != 0)
this->_udp->flush();
this->sendNTPPacket();
// Wait till data is there or timeout...
byte timeout = 0;
int cb = 0;
do {
delay ( 10 );
cb = this->_udp->parsePacket();
if (timeout > 100) return false; // timeout after 1000 ms
timeout++;
} while (cb == 0);
this->_lastUpdate = millis() - (10 * (timeout + 1)); // Account for delay in reading the time
this->_udp->read(this->_packetBuffer, NTP_PACKET_SIZE);
unsigned long highWord = word(this->_packetBuffer[40], this->_packetBuffer[41]);
unsigned long lowWord = word(this->_packetBuffer[42], this->_packetBuffer[43]);
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900):
unsigned long secsSince1900 = highWord << 16 | lowWord;
this->_currentEpoc = secsSince1900 - SEVENZYYEARS;
return true; // return true after successful update
}
bool NTPClient::update() {
if ((millis() - this->_lastUpdate >= this->_updateInterval) // Update after _updateInterval
|| this->_lastUpdate == 0) { // Update if there was no update yet.
if (!this->_udpSetup || this->_port != NTP_DEFAULT_LOCAL_PORT) this->begin(this->_port); // setup the UDP client if needed
return this->forceUpdate();
}
return false; // return false if update does not occur
}
bool NTPClient::isTimeSet() const {
return (this->_lastUpdate != 0); // returns true if the time has been set, else false
}
unsigned long NTPClient::getEpochTime() const {
return this->_timeOffset + // User offset
this->_currentEpoc + // Epoch returned by the NTP server
((millis() - this->_lastUpdate) / 1000); // Time since last update
}
int NTPClient::getDay() const {
return (((this->getEpochTime() / 86400L) + 4 ) % 7); //0 is Sunday
}
int NTPClient::getHours() const {
return ((this->getEpochTime() % 86400L) / 3600);
}
int NTPClient::getMinutes() const {
return ((this->getEpochTime() % 3600) / 60);
}
int NTPClient::getSeconds() const {
return (this->getEpochTime() % 60);
}
String NTPClient::getFormattedTime() const {
unsigned long rawTime = this->getEpochTime();
unsigned long hours = (rawTime % 86400L) / 3600;
String hoursStr = hours < 10 ? "0" + String(hours) : String(hours);
unsigned long minutes = (rawTime % 3600) / 60;
String minuteStr = minutes < 10 ? "0" + String(minutes) : String(minutes);
unsigned long seconds = rawTime % 60;
String secondStr = seconds < 10 ? "0" + String(seconds) : String(seconds);
return hoursStr + ":" + minuteStr + ":" + secondStr;
}
void NTPClient::end() {
this->_udp->stop();
this->_udpSetup = false;
}
void NTPClient::setTimeOffset(int timeOffset) {
this->_timeOffset = timeOffset;
}
void NTPClient::setUpdateInterval(unsigned long updateInterval) {
this->_updateInterval = updateInterval;
}
void NTPClient::setPoolServerName(const char* poolServerName) {
this->_poolServerName = poolServerName;
}
void NTPClient::sendNTPPacket() {
// set all bytes in the buffer to 0
memset(this->_packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
this->_packetBuffer[0] = 0b11100011; // LI, Version, Mode
this->_packetBuffer[1] = 0; // Stratum, or type of clock
this->_packetBuffer[2] = 6; // Polling Interval
this->_packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
this->_packetBuffer[12] = 49;
this->_packetBuffer[13] = 0x4E;
this->_packetBuffer[14] = 49;
this->_packetBuffer[15] = 52;
// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:
if (this->_poolServerName) {
this->_udp->beginPacket(this->_poolServerName, 123);
} else {
this->_udp->beginPacket(this->_poolServerIP, 123);
}
this->_udp->write(this->_packetBuffer, NTP_PACKET_SIZE);
this->_udp->endPacket();
}
void NTPClient::setRandomPort(unsigned int minValue, unsigned int maxValue) {
randomSeed(analogRead(0));
this->_port = random(minValue, maxValue);
}

114
libraries/NTPClient/NTPClient.h Executable file
View File

@@ -0,0 +1,114 @@
#pragma once
#include "Arduino.h"
#include <Udp.h>
#define SEVENZYYEARS 2208988800UL
#define NTP_PACKET_SIZE 48
#define NTP_DEFAULT_LOCAL_PORT 1337
class NTPClient {
private:
UDP* _udp;
bool _udpSetup = false;
const char* _poolServerName = "pool.ntp.org"; // Default time server
IPAddress _poolServerIP;
unsigned int _port = NTP_DEFAULT_LOCAL_PORT;
long _timeOffset = 0;
unsigned long _updateInterval = 60000; // In ms
unsigned long _currentEpoc = 0; // In s
unsigned long _lastUpdate = 0; // In ms
byte _packetBuffer[NTP_PACKET_SIZE];
void sendNTPPacket();
public:
NTPClient(UDP& udp);
NTPClient(UDP& udp, long timeOffset);
NTPClient(UDP& udp, const char* poolServerName);
NTPClient(UDP& udp, const char* poolServerName, long timeOffset);
NTPClient(UDP& udp, const char* poolServerName, long timeOffset, unsigned long updateInterval);
NTPClient(UDP& udp, IPAddress poolServerIP);
NTPClient(UDP& udp, IPAddress poolServerIP, long timeOffset);
NTPClient(UDP& udp, IPAddress poolServerIP, long timeOffset, unsigned long updateInterval);
/**
* Set time server name
*
* @param poolServerName
*/
void setPoolServerName(const char* poolServerName);
/**
* Set random local port
*/
void setRandomPort(unsigned int minValue = 49152, unsigned int maxValue = 65535);
/**
* Starts the underlying UDP client with the default local port
*/
void begin();
/**
* Starts the underlying UDP client with the specified local port
*/
void begin(unsigned int port);
/**
* This should be called in the main loop of your application. By default an update from the NTP Server is only
* made every 60 seconds. This can be configured in the NTPClient constructor.
*
* @return true on success, false on failure
*/
bool update();
/**
* This will force the update from the NTP Server.
*
* @return true on success, false on failure
*/
bool forceUpdate();
/**
* This allows to check if the NTPClient successfully received a NTP packet and set the time.
*
* @return true if time has been set, else false
*/
bool isTimeSet() const;
int getDay() const;
int getHours() const;
int getMinutes() const;
int getSeconds() const;
/**
* Changes the time offset. Useful for changing timezones dynamically
*/
void setTimeOffset(int timeOffset);
/**
* Set the update interval to another frequency. E.g. useful when the
* timeOffset should not be set in the constructor
*/
void setUpdateInterval(unsigned long updateInterval);
/**
* @return time formatted like `hh:mm:ss`
*/
String getFormattedTime() const;
/**
* @return time in seconds since Jan. 1, 1970
*/
unsigned long getEpochTime() const;
/**
* Stops the underlying UDP client
*/
void end();
};

View File

@@ -0,0 +1,52 @@
# NTPClient
[![Check Arduino status](https://github.com/arduino-libraries/NTPClient/actions/workflows/check-arduino.yml/badge.svg)](https://github.com/arduino-libraries/NTPClient/actions/workflows/check-arduino.yml)
[![Compile Examples status](https://github.com/arduino-libraries/NTPClient/actions/workflows/compile-examples.yml/badge.svg)](https://github.com/arduino-libraries/NTPClient/actions/workflows/compile-examples.yml)
[![Spell Check status](https://github.com/arduino-libraries/NTPClient/actions/workflows/spell-check.yml/badge.svg)](https://github.com/arduino-libraries/NTPClient/actions/workflows/spell-check.yml)
Connect to a NTP server, here is how:
```cpp
#include <NTPClient.h>
// change next line to use with another board/shield
#include <ESP8266WiFi.h>
//#include <WiFi.h> // for WiFi shield
//#include <WiFi101.h> // for WiFi 101 shield or MKR1000
#include <WiFiUdp.h>
const char *ssid = "<SSID>";
const char *password = "<PASSWORD>";
WiFiUDP ntpUDP;
// By default 'pool.ntp.org' is used with 60 seconds update interval and
// no offset
NTPClient timeClient(ntpUDP);
// You can specify the time server pool and the offset, (in seconds)
// additionally you can specify the update interval (in milliseconds).
// NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 3600, 60000);
void setup(){
Serial.begin(115200);
WiFi.begin(ssid, password);
while ( WiFi.status() != WL_CONNECTED ) {
delay ( 500 );
Serial.print ( "." );
}
timeClient.begin();
}
void loop() {
timeClient.update();
Serial.println(timeClient.getFormattedTime());
delay(1000);
}
```
## Function documentation
`getEpochTime` returns the Unix epoch, which are the seconds elapsed since 00:00:00 UTC on 1 January 1970 (leap seconds are ignored, every day is treated as having 86400 seconds). **Attention**: If you have set a time offset this time offset will be added to your epoch timestamp.

View File

@@ -0,0 +1,37 @@
#include <NTPClient.h>
// change next line to use with another board/shield
#include <ESP8266WiFi.h>
//#include <WiFi.h> // for WiFi shield
//#include <WiFi101.h> // for WiFi 101 shield or MKR1000
#include <WiFiUdp.h>
const char *ssid = "<SSID>";
const char *password = "<PASSWORD>";
WiFiUDP ntpUDP;
// You can specify the time server pool and the offset (in seconds, can be
// changed later with setTimeOffset() ). Additionally you can specify the
// update interval (in milliseconds, can be changed using setUpdateInterval() ).
NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 3600, 60000);
void setup(){
Serial.begin(115200);
WiFi.begin(ssid, password);
while ( WiFi.status() != WL_CONNECTED ) {
delay ( 500 );
Serial.print ( "." );
}
timeClient.begin();
}
void loop() {
timeClient.update();
Serial.println(timeClient.getFormattedTime());
delay(1000);
}

View File

@@ -0,0 +1,33 @@
#include <NTPClient.h>
// change next line to use with another board/shield
#include <ESP8266WiFi.h>
//#include <WiFi.h> // for WiFi shield
//#include <WiFi101.h> // for WiFi 101 shield or MKR1000
#include <WiFiUdp.h>
const char *ssid = "<SSID>";
const char *password = "<PASSWORD>";
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
void setup(){
Serial.begin(115200);
WiFi.begin(ssid, password);
while ( WiFi.status() != WL_CONNECTED ) {
delay ( 500 );
Serial.print ( "." );
}
timeClient.begin();
}
void loop() {
timeClient.update();
Serial.println(timeClient.getFormattedTime());
delay(1000);
}

View File

@@ -0,0 +1,53 @@
#include <NTPClient.h>
// change next line to use with another board/shield
#include <ESP8266WiFi.h>
//#include <WiFi.h> // for WiFi shield
//#include <WiFi101.h> // for WiFi 101 shield or MKR1000
#include <WiFiUdp.h>
const char *ssid = "<SSID>";
const char *password = "<PASSWORD>";
WiFiUDP ntpUDP;
// initialized to a time offset of 10 hours
NTPClient timeClient(ntpUDP,"pool.ntp.org", 36000, 60000);
// HH:MM:SS
// timeClient initializes to 10:00:00 if it does not receive an NTP packet
// before the 100ms timeout.
// without isTimeSet() the LED would be switched on, although the time
// was not yet set correctly.
// blue LED on ESP-12F
const int led = 2;
const int hour = 10;
const int minute = 0;
void setup(){
Serial.begin(115200);
pinMode(led, OUTPUT);
// led is off when pin is high
digitalWrite(led, 1);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay (500);
Serial.print (".");
}
timeClient.begin();
}
void loop() {
timeClient.update();
Serial.println(timeClient.getFormattedTime());
if(timeClient.isTimeSet()) {
if (hour == timeClient.getHours() && minute == timeClient.getMinutes()) {
digitalWrite(led, 0);
}
}
delay(1000);
}

View File

@@ -0,0 +1,24 @@
#######################################
# Datatypes (KEYWORD1)
#######################################
NTPClient KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
end KEYWORD2
update KEYWORD2
forceUpdate KEYWORD2
isTimeSet KEYWORD2
getDay KEYWORD2
getHours KEYWORD2
getMinutes KEYWORD2
getSeconds KEYWORD2
getFormattedTime KEYWORD2
getEpochTime KEYWORD2
setTimeOffset KEYWORD2
setUpdateInterval KEYWORD2
setPoolServerName KEYWORD2

View File

@@ -0,0 +1,9 @@
name=NTPClient
version=3.2.1
author=Fabrice Weinberg
maintainer=Fabrice Weinberg <fabrice@weinberg.me>
sentence=An NTPClient to connect to a time server
paragraph=Get time from a NTP server and keep it in sync.
category=Timing
url=https://github.com/arduino-libraries/NTPClient
architectures=*

View File

@@ -9,7 +9,7 @@
#include <TFT_eSPI.h>
// ============== CONFIG ==============
const char* WIFI_SSID = "Dobro Veče";
const char* WIFI_SSID = "KH-IoT";
const char* WIFI_PASS = "goodnight";
const char* ALERT_URL = "https://ntfy.sh/ALERT_klubhaus_topic/json?since=all";