Toki 1st experiment
This commit is contained in:
parent
9b796531b2
commit
b455f432d5
6
tools/WLED_ESP32_4MB_1MB_FS.csv
Normal file
6
tools/WLED_ESP32_4MB_1MB_FS.csv
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# Name, Type, SubType, Offset, Size, Flags
|
||||||
|
nvs, data, nvs, 0x9000, 0x5000,
|
||||||
|
otadata, data, ota, 0xe000, 0x2000,
|
||||||
|
app0, app, ota_0, 0x10000, 0x17B000,
|
||||||
|
app1, app, ota_1, 0x18B000,0x17B000,
|
||||||
|
spiffs, data, spiffs, 0x306000,0x0FA000,
|
|
@ -41,18 +41,14 @@ class ElekstubeIPSUsermod : public Usermod {
|
|||||||
tfts.begin();
|
tfts.begin();
|
||||||
tfts.fillScreen(TFT_BLACK);
|
tfts.fillScreen(TFT_BLACK);
|
||||||
tfts.setTextColor(TFT_WHITE, TFT_BLACK);
|
tfts.setTextColor(TFT_WHITE, TFT_BLACK);
|
||||||
tfts.setCursor(0, 0, 2);
|
tfts.setCursor(0, 100, 2);
|
||||||
tfts.println("<STARTUP>");
|
tfts.println("<STARTUP>");
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
if (lastTime == 0) {
|
if (toki.isTick()) {
|
||||||
tfts.fillScreen(TFT_BLACK);
|
updateLocalTime();
|
||||||
updateClockDisplay(TFTs::force);
|
|
||||||
}
|
|
||||||
if (millis() - lastTime > 100) {
|
|
||||||
updateClockDisplay();
|
updateClockDisplay();
|
||||||
lastTime = millis();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,20 +183,30 @@ bool checkNTPResponse()
|
|||||||
{
|
{
|
||||||
int cb = ntpUdp.parsePacket();
|
int cb = ntpUdp.parsePacket();
|
||||||
if (cb) {
|
if (cb) {
|
||||||
|
uint32_t ntpPacketReceivedTime = millis();
|
||||||
DEBUG_PRINT(F("NTP recv, l="));
|
DEBUG_PRINT(F("NTP recv, l="));
|
||||||
DEBUG_PRINTLN(cb);
|
DEBUG_PRINTLN(cb);
|
||||||
byte pbuf[NTP_PACKET_SIZE];
|
byte pbuf[NTP_PACKET_SIZE];
|
||||||
ntpUdp.read(pbuf, NTP_PACKET_SIZE); // read the packet into the buffer
|
ntpUdp.read(pbuf, NTP_PACKET_SIZE); // read the packet into the buffer
|
||||||
|
|
||||||
unsigned long highWord = word(pbuf[40], pbuf[41]);
|
Toki::Time arrived = toki.fromNTP(pbuf + 32);
|
||||||
unsigned long lowWord = word(pbuf[42], pbuf[43]);
|
Toki::Time departed = toki.fromNTP(pbuf + 40);
|
||||||
if (highWord == 0 && lowWord == 0) return false;
|
//basic half roundtrip estimation
|
||||||
|
uint32_t offset = (ntpPacketReceivedTime - ntpPacketSentTime - toki.msDifference(arrived, departed)) >> 1;
|
||||||
unsigned long secsSince1900 = highWord << 16 | lowWord;
|
offset += millis() - ntpPacketReceivedTime +1;
|
||||||
|
toki.adjust(departed, offset);
|
||||||
|
toki.setTime(departed);
|
||||||
|
Serial.print("Roundtrip: ");
|
||||||
|
Serial.println(ntpPacketReceivedTime - ntpPacketSentTime);
|
||||||
|
Serial.print("Offset: ");
|
||||||
|
Serial.println(offset);
|
||||||
|
Serial.print("Time: ");
|
||||||
|
toki.printTime(toki.getTime());
|
||||||
|
|
||||||
DEBUG_PRINT(F("Unix time = "));
|
DEBUG_PRINT(F("Unix time = "));
|
||||||
unsigned long epoch = secsSince1900 - 2208988799UL; //subtract 70 years -1sec (on avg. more precision)
|
uint32_t epoch = toki.second();
|
||||||
setTime(epoch);
|
if (epoch == 0) return false;
|
||||||
|
setTime(epoch); //legacy
|
||||||
DEBUG_PRINTLN(epoch);
|
DEBUG_PRINTLN(epoch);
|
||||||
if (countdownTime - now() > 0) countdownOverTriggered = false;
|
if (countdownTime - now() > 0) countdownOverTriggered = false;
|
||||||
// if time changed re-calculate sunrise/sunset
|
// if time changed re-calculate sunrise/sunset
|
||||||
@ -210,7 +220,7 @@ bool checkNTPResponse()
|
|||||||
void updateLocalTime()
|
void updateLocalTime()
|
||||||
{
|
{
|
||||||
if (currentTimezone != tzCurrent) updateTimezone();
|
if (currentTimezone != tzCurrent) updateTimezone();
|
||||||
unsigned long tmc = now()+ utcOffsetSecs;
|
unsigned long tmc = toki.second()+ utcOffsetSecs;
|
||||||
localTime = tz->toLocal(tmc);
|
localTime = tz->toLocal(tmc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,13 +21,16 @@ void initCronixie()
|
|||||||
|
|
||||||
void handleOverlays()
|
void handleOverlays()
|
||||||
{
|
{
|
||||||
if (millis() - overlayRefreshedTime > overlayRefreshMs)
|
if (toki.isTick())
|
||||||
{
|
{
|
||||||
initCronixie();
|
initCronixie();
|
||||||
updateLocalTime();
|
updateLocalTime();
|
||||||
checkTimers();
|
checkTimers();
|
||||||
checkCountdown();
|
checkCountdown();
|
||||||
if (overlayCurrent == 3) _overlayCronixie();//Diamex cronixie clock kit
|
if (overlayCurrent == 3) {
|
||||||
|
_overlayCronixie();//Diamex cronixie clock kit
|
||||||
|
strip.trigger();
|
||||||
|
}
|
||||||
overlayRefreshedTime = millis();
|
overlayRefreshedTime = millis();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,6 @@
|
|||||||
|
|
||||||
static tmElements_t tm; // a cache of time elements
|
static tmElements_t tm; // a cache of time elements
|
||||||
static time_t cacheTime; // the time the cache was updated
|
static time_t cacheTime; // the time the cache was updated
|
||||||
static uint32_t syncInterval = 300; // time sync will be attempted after this many seconds
|
|
||||||
|
|
||||||
void refreshCache(time_t t) {
|
void refreshCache(time_t t) {
|
||||||
if (t != cacheTime) {
|
if (t != cacheTime) {
|
||||||
@ -234,18 +233,9 @@ time_t makeTime(tmElements_t &tm){
|
|||||||
/*=====================================================*/
|
/*=====================================================*/
|
||||||
/* Low level system time functions */
|
/* Low level system time functions */
|
||||||
|
|
||||||
static uint32_t sysTime = 0;
|
static uint32_t sysTime = 0; //seconds
|
||||||
|
static uint16_t sysMillis = 0;
|
||||||
static uint32_t prevMillis = 0;
|
static uint32_t prevMillis = 0;
|
||||||
static uint32_t nextSyncTime = 0;
|
|
||||||
static timeStatus_t Status = timeNotSet;
|
|
||||||
|
|
||||||
getExternalTime getTimePtr; // pointer to external sync function
|
|
||||||
//setExternalTime setTimePtr; // not used in this version
|
|
||||||
|
|
||||||
#ifdef TIME_DRIFT_INFO // define this to get drift data
|
|
||||||
time_t sysUnsyncedTime = 0; // the time sysTime unadjusted by sync
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
time_t now() {
|
time_t now() {
|
||||||
// calculate number of seconds passed since last call to now()
|
// calculate number of seconds passed since last call to now()
|
||||||
@ -253,33 +243,18 @@ time_t now() {
|
|||||||
// millis() and prevMillis are both unsigned ints thus the subtraction will always be the absolute value of the difference
|
// millis() and prevMillis are both unsigned ints thus the subtraction will always be the absolute value of the difference
|
||||||
sysTime++;
|
sysTime++;
|
||||||
prevMillis += 1000;
|
prevMillis += 1000;
|
||||||
#ifdef TIME_DRIFT_INFO
|
|
||||||
sysUnsyncedTime++; // this can be compared to the synced time to measure long term drift
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
if (nextSyncTime <= sysTime) {
|
|
||||||
if (getTimePtr != 0) {
|
|
||||||
time_t t = getTimePtr();
|
|
||||||
if (t != 0) {
|
|
||||||
setTime(t);
|
|
||||||
} else {
|
|
||||||
nextSyncTime = sysTime + syncInterval;
|
|
||||||
Status = (Status == timeNotSet) ? timeNotSet : timeNeedsSync;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (time_t)sysTime;
|
return (time_t)sysTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTime(time_t t) {
|
uint16_t millisecond() { // the millisecond (0-999) now
|
||||||
#ifdef TIME_DRIFT_INFO
|
return (sysMillis - millis()) % 1000;
|
||||||
if(sysUnsyncedTime == 0)
|
}
|
||||||
sysUnsyncedTime = t; // store the time of the first call to set a valid Time
|
|
||||||
#endif
|
|
||||||
|
|
||||||
sysTime = (uint32_t)t;
|
void setTime(time_t t, uint16_t ms) {
|
||||||
nextSyncTime = (uint32_t)t + syncInterval;
|
sysTime = (uint32_t)t;
|
||||||
Status = timeSet;
|
sysMillis = ms;
|
||||||
prevMillis = millis(); // restart counting from now (thanks to Korman for this fix)
|
prevMillis = millis(); // restart counting from now (thanks to Korman for this fix)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,27 +274,10 @@ time_t getUnixTime(int hr,int min,int sec,int dy, int mnth, int yr){
|
|||||||
return makeTime(tm);
|
return makeTime(tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTime(int hr,int min,int sec,int dy, int mnth, int yr){
|
void setTime(int hr,int min,int sec,int dy, int mnth, int yr, uint16_t ms){
|
||||||
setTime(getUnixTime(hr,min,sec,dy,mnth,yr));
|
setTime(getUnixTime(hr,min,sec,dy,mnth,yr), ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
void adjustTime(long adjustment) {
|
void adjustTime(long adjustment) {
|
||||||
sysTime += adjustment;
|
sysTime += adjustment;
|
||||||
}
|
}
|
||||||
|
|
||||||
// indicates if time has been set and recently synchronized
|
|
||||||
timeStatus_t timeStatus() {
|
|
||||||
now(); // required to actually update the status
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSyncProvider( getExternalTime getTimeFunction){
|
|
||||||
getTimePtr = getTimeFunction;
|
|
||||||
nextSyncTime = sysTime;
|
|
||||||
now(); // this will sync the clock
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSyncInterval(time_t interval){ // set the number of seconds between re-sync
|
|
||||||
syncInterval = (uint32_t)interval;
|
|
||||||
nextSyncTime = sysTime + syncInterval;
|
|
||||||
}
|
|
@ -31,8 +31,6 @@ typedef unsigned long time_t;
|
|||||||
// but at least this hack lets us define C++ functions as intended. Hopefully
|
// but at least this hack lets us define C++ functions as intended. Hopefully
|
||||||
// nothing too terrible will result from overriding the C library header?!
|
// nothing too terrible will result from overriding the C library header?!
|
||||||
extern "C++" {
|
extern "C++" {
|
||||||
typedef enum {timeNotSet, timeNeedsSync, timeSet
|
|
||||||
} timeStatus_t ;
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
dowInvalid, dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday
|
dowInvalid, dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday
|
||||||
@ -116,10 +114,11 @@ int month(); // the month now (Jan is month 1)
|
|||||||
int month(time_t t); // the month for the given time
|
int month(time_t t); // the month for the given time
|
||||||
int year(); // the full four digit year: (2009, 2010 etc)
|
int year(); // the full four digit year: (2009, 2010 etc)
|
||||||
int year(time_t t); // the year for the given time
|
int year(time_t t); // the year for the given time
|
||||||
|
uint16_t millisecond(); // the millisecond now
|
||||||
|
|
||||||
time_t now(); // return the current time as seconds since Jan 1 1970
|
time_t now(); // return the current time as seconds since Jan 1 1970
|
||||||
void setTime(time_t t);
|
void setTime(time_t t, uint16_t ms = 0);
|
||||||
void setTime(int hr,int min,int sec,int day, int month, int yr);
|
void setTime(int hr,int min,int sec,int day, int month, int yr, uint16_t ms = 0);
|
||||||
time_t getUnixTime(int hr,int min,int sec,int day, int month, int yr); //added by Aircoookie to get epoch time
|
time_t getUnixTime(int hr,int min,int sec,int day, int month, int yr); //added by Aircoookie to get epoch time
|
||||||
void adjustTime(long adjustment);
|
void adjustTime(long adjustment);
|
||||||
|
|
||||||
@ -129,13 +128,8 @@ char* monthStr(uint8_t month);
|
|||||||
char* dayStr(uint8_t day);
|
char* dayStr(uint8_t day);
|
||||||
char* monthShortStr(uint8_t month);
|
char* monthShortStr(uint8_t month);
|
||||||
char* dayShortStr(uint8_t day);
|
char* dayShortStr(uint8_t day);
|
||||||
|
|
||||||
/* time sync functions */
|
|
||||||
timeStatus_t timeStatus(); // indicates if time has been set and recently synchronized
|
|
||||||
void setSyncProvider( getExternalTime getTimeFunction); // identify the external time provider
|
|
||||||
void setSyncInterval(time_t interval); // set the number of seconds between re-sync
|
|
||||||
|
|
||||||
/* low level functions to convert to and from system time */
|
/* low level functions to convert to and from system time */
|
||||||
void breakTime(time_t time, tmElements_t &tm); // break time_t into elements
|
void breakTime(time_t time, tmElements_t &tm); // break time_t into elements
|
||||||
time_t makeTime(tmElements_t &tm); // convert time elements into time_t
|
time_t makeTime(tmElements_t &tm); // convert time elements into time_t
|
||||||
|
|
||||||
|
128
wled00/src/dependencies/toki/Toki.h
Normal file
128
wled00/src/dependencies/toki/Toki.h
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
Toki.h - Minimal millisecond accurate timekeeping.
|
||||||
|
|
||||||
|
LICENSE
|
||||||
|
The MIT License (MIT)
|
||||||
|
Copyright (c) 2021 Christian Schwinne
|
||||||
|
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 <Arduino.h>
|
||||||
|
|
||||||
|
#define YEARS_70 2208988800UL
|
||||||
|
|
||||||
|
//3:13 24.05.2012 ==> 2021-4-29, 06:41:37.
|
||||||
|
|
||||||
|
class Toki {
|
||||||
|
typedef enum {
|
||||||
|
inactive, marked, active
|
||||||
|
} TickT;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef struct {
|
||||||
|
uint32_t sec;
|
||||||
|
uint16_t ms;
|
||||||
|
} Time;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t fullSecondMillis = 0;
|
||||||
|
uint32_t unix = 0;
|
||||||
|
TickT tick = TickT::inactive;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void setTime(Time t) {
|
||||||
|
fullSecondMillis = millis() - t.ms;
|
||||||
|
unix = t.sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTime(uint32_t sec, uint16_t ms) {
|
||||||
|
Time t = {sec, ms};
|
||||||
|
setTime(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
Time fromNTP(byte *timestamp) { //ntp timestamp is 8 bytes, 4 bytes second and 4 bytes sub-second fraction
|
||||||
|
unsigned long highWord = word(timestamp[0], timestamp[1]);
|
||||||
|
unsigned long lowWord = word(timestamp[2], timestamp[3]);
|
||||||
|
|
||||||
|
unsigned long unix = highWord << 16 | lowWord;
|
||||||
|
if (!unix) return {0,0};
|
||||||
|
unix -= YEARS_70; //NTP begins 1900, Unix 1970
|
||||||
|
|
||||||
|
unsigned long frac = word(timestamp[5], timestamp[6]); //65536ths of a second
|
||||||
|
frac = (frac*1000) >> 16; //convert to ms
|
||||||
|
return {unix, (uint16_t)frac};
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t millisecond() {
|
||||||
|
uint32_t ms = millis() - fullSecondMillis;
|
||||||
|
while (ms > 999) {
|
||||||
|
ms -= 1000;
|
||||||
|
fullSecondMillis += 1000;
|
||||||
|
unix++;
|
||||||
|
if (tick == TickT::inactive) tick = TickT::marked; //marked, will be active on next loop
|
||||||
|
}
|
||||||
|
return ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t second() {
|
||||||
|
millisecond();
|
||||||
|
return unix;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t msDifference(Time &t0, Time &t1) {
|
||||||
|
bool t1BiggerSec = (t1.sec > t0.sec);
|
||||||
|
uint32_t secDiff = (t1BiggerSec) ? t1.sec - t0.sec : t0.sec - t1.sec;
|
||||||
|
uint32_t t0ms = t0.ms, t1ms = t1.ms;
|
||||||
|
if (t1BiggerSec) t1ms += secDiff;
|
||||||
|
else t0ms += secDiff;
|
||||||
|
uint32_t msDiff = (t1ms > t0ms) ? t1ms - t0ms : t0ms - t1ms;
|
||||||
|
return msDiff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void adjust(Time&t, int32_t offset) {
|
||||||
|
int32_t secs = offset /1000;
|
||||||
|
int32_t ms = offset - secs*1000;
|
||||||
|
t.sec += offset /1000;
|
||||||
|
int32_t nms = t.ms + ms;
|
||||||
|
if (nms > 1000) {nms -= 1000; t.sec++;}
|
||||||
|
if (nms < 0) {nms += 1000; t.sec--;}
|
||||||
|
t.ms += nms;
|
||||||
|
}
|
||||||
|
|
||||||
|
Time getTime() {
|
||||||
|
Time t;
|
||||||
|
t.ms = millisecond();
|
||||||
|
t.sec = unix;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTick() {
|
||||||
|
if (tick == TickT::marked) tick = TickT::active;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetTick() {
|
||||||
|
tick = TickT::inactive;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isTick() {
|
||||||
|
return (tick == TickT::active);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printTime(const Time& t) {
|
||||||
|
Serial.printf_P(PSTR("%u,%03u\n"),t.sec,t.ms);
|
||||||
|
}
|
||||||
|
};
|
@ -177,6 +177,8 @@ void WiFiEvent(WiFiEvent_t event)
|
|||||||
|
|
||||||
void WLED::loop()
|
void WLED::loop()
|
||||||
{
|
{
|
||||||
|
toki.millisecond();
|
||||||
|
toki.setTick();
|
||||||
handleIR(); // 2nd call to function needed for ESP32 to return valid results -- should be good for ESP8266, too
|
handleIR(); // 2nd call to function needed for ESP32 to return valid results -- should be good for ESP8266, too
|
||||||
handleConnection();
|
handleConnection();
|
||||||
handleSerial();
|
handleSerial();
|
||||||
@ -287,6 +289,7 @@ void WLED::loop()
|
|||||||
}
|
}
|
||||||
loops++;
|
loops++;
|
||||||
#endif // WLED_DEBUG
|
#endif // WLED_DEBUG
|
||||||
|
toki.resetTick();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WLED::setup()
|
void WLED::setup()
|
||||||
|
@ -90,6 +90,7 @@
|
|||||||
#include <SPIFFSEditor.h>
|
#include <SPIFFSEditor.h>
|
||||||
#include "src/dependencies/time/TimeLib.h"
|
#include "src/dependencies/time/TimeLib.h"
|
||||||
#include "src/dependencies/timezone/Timezone.h"
|
#include "src/dependencies/timezone/Timezone.h"
|
||||||
|
#include "src/dependencies/toki/Toki.h"
|
||||||
|
|
||||||
#ifndef WLED_DISABLE_ALEXA
|
#ifndef WLED_DISABLE_ALEXA
|
||||||
#define ESPALEXA_ASYNC
|
#define ESPALEXA_ASYNC
|
||||||
@ -516,6 +517,7 @@ WLED_GLOBAL float longitude _INIT(0.0);
|
|||||||
WLED_GLOBAL float latitude _INIT(0.0);
|
WLED_GLOBAL float latitude _INIT(0.0);
|
||||||
WLED_GLOBAL time_t sunrise _INIT(0);
|
WLED_GLOBAL time_t sunrise _INIT(0);
|
||||||
WLED_GLOBAL time_t sunset _INIT(0);
|
WLED_GLOBAL time_t sunset _INIT(0);
|
||||||
|
WLED_GLOBAL Toki toki _INIT(Toki());
|
||||||
|
|
||||||
// Temp buffer
|
// Temp buffer
|
||||||
WLED_GLOBAL char* obuf;
|
WLED_GLOBAL char* obuf;
|
||||||
|
Loading…
Reference in New Issue
Block a user