mirror of
https://github.com/lumapu/ahoy.git
synced 2025-05-23 05:46:09 +02:00
fix #480 AP Mode on fresh ESP
included #483 improvements fix #468 last_success MQTT fix #468 update available status at sunset fix #447 reorderd enqueue commands to not have same payload length in a row added ssd1306 and nokia display to build script
This commit is contained in:
parent
9da0fc4058
commit
d9290d9fdf
15 changed files with 285 additions and 206 deletions
2
.github/workflows/compile_development.yml
vendored
2
.github/workflows/compile_development.yml
vendored
|
@ -47,7 +47,7 @@ jobs:
|
|||
run: python convert.py
|
||||
|
||||
- name: Run PlatformIO
|
||||
run: pio run -d src --environment esp8266-release --environment esp8285-release --environment esp32-wroom32-release
|
||||
run: pio run -d src --environment esp8266-release --environment esp8285-release --environment esp8266-nokia5110 --environment esp8266-ssd1306 --environment esp32-wroom32-release
|
||||
|
||||
- name: Rename Binary files
|
||||
id: rename-binary-files
|
||||
|
|
2
.github/workflows/compile_esp8266.yml
vendored
2
.github/workflows/compile_esp8266.yml
vendored
|
@ -49,7 +49,7 @@ jobs:
|
|||
working-directory: src/web/html
|
||||
run: python convert.py
|
||||
- name: Run PlatformIO
|
||||
run: pio run -d tools/esp8266 --environment esp8266-release --environment esp8285-release --environment esp32-wroom32-release
|
||||
run: pio run -d tools/esp8266 --environment esp8266-release --environment esp8285-release --environment esp8266-nokia5110 --environment esp8266-ssd1306 --environment esp32-wroom32-release
|
||||
|
||||
- name: Rename Binary files
|
||||
id: rename-binary-files
|
||||
|
|
53
src/app.cpp
53
src/app.cpp
|
@ -19,24 +19,29 @@ app::app() : ah::Scheduler() {
|
|||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void app::setup(uint32_t timeout) {
|
||||
void app::setup() {
|
||||
Serial.begin(115200);
|
||||
while (!Serial)
|
||||
yield();
|
||||
|
||||
ah::Scheduler::setup();
|
||||
|
||||
resetSystem();
|
||||
mSettings.setup();
|
||||
mSettings.getPtr(mConfig);
|
||||
DPRINTLN(DBG_INFO, F("Settings valid: ") + String((mSettings.getValid()) ? F("true") : F("false")));
|
||||
|
||||
addListener(EVERY_SEC, std::bind(&app::tickSecond, this));
|
||||
addListener(EVERY_MIN, std::bind(&app::tickMinute, this));
|
||||
addListener(EVERY_12H, std::bind(&app::tickNtpUpdate, this));
|
||||
once(mConfig->nrf.sendInterval, std::bind(&app::tickSend, this), "tickSend");
|
||||
if((mConfig->sun.lat) && (mConfig->sun.lon)) {
|
||||
once(5, std::bind(&app::tickCalcSunrise, this));
|
||||
mCalculatedTimezoneOffset = (int8_t)((mConfig->sun.lon >= 0 ? mConfig->sun.lon + 7.5 : mConfig->sun.lon - 7.5) / 15) * 3600;
|
||||
}
|
||||
|
||||
everySec(std::bind(&app::tickSecond, this));
|
||||
everyMin(std::bind(&app::tickMinute, this));
|
||||
every12h(std::bind(&app::tickNtpUpdate, this));
|
||||
every(std::bind(&app::tickSend, this), mConfig->nrf.sendInterval);
|
||||
#if !defined(AP_ONLY)
|
||||
if((mConfig->sun.lat) && (mConfig->sun.lon)) {
|
||||
mCalculatedTimezoneOffset = (int8_t)((mConfig->sun.lon >= 0 ? mConfig->sun.lon + 7.5 : mConfig->sun.lon - 7.5) / 15) * 3600;
|
||||
once(std::bind(&app::tickCalcSunrise, this), 5);
|
||||
}
|
||||
#endif
|
||||
|
||||
mSys = new HmSystemType();
|
||||
mSys->enableDebug();
|
||||
|
@ -54,10 +59,9 @@ void app::setup(uint32_t timeout) {
|
|||
#if !defined(AP_ONLY)
|
||||
if (mConfig->mqtt.broker[0] > 0) {
|
||||
mPayload.addListener(std::bind(&PubMqttType::payloadEventListener, &mMqtt, std::placeholders::_1));
|
||||
addListener(EVERY_SEC, std::bind(&PubMqttType::tickerSecond, &mMqtt));
|
||||
addListener(EVERY_MIN, std::bind(&PubMqttType::tickerMinute, &mMqtt));
|
||||
everySec(std::bind(&PubMqttType::tickerSecond, &mMqtt));
|
||||
everyMin(std::bind(&PubMqttType::tickerMinute, &mMqtt));
|
||||
mMqtt.setSubscriptionCb(std::bind(&app::mqttSubRxCb, this, std::placeholders::_1));
|
||||
|
||||
}
|
||||
#endif
|
||||
setupLed();
|
||||
|
@ -65,16 +69,17 @@ void app::setup(uint32_t timeout) {
|
|||
mWeb = new web(this, mConfig, &mStat, mVersion);
|
||||
mWeb->setup();
|
||||
mWeb->setProtection(strlen(mConfig->sys.adminPwd) != 0);
|
||||
addListener(EVERY_SEC, std::bind(&web::tickSecond, mWeb));
|
||||
everySec(std::bind(&web::tickSecond, mWeb));
|
||||
|
||||
// Plugins
|
||||
#if defined(ENA_NOKIA) || defined(ENA_SSD1306)
|
||||
mMonoDisplay.setup(mSys, &mTimestamp);
|
||||
mPayload.addListener(std::bind(&MonoDisplayType::payloadEventListener, &mMonoDisplay, std::placeholders::_1));
|
||||
addListener(EVERY_SEC, std::bind(&MonoDisplayType::tickerSecond, &mMonoDisplay));
|
||||
everySec(std::bind(&MonoDisplayType::tickerSecond, &mMonoDisplay));
|
||||
#endif
|
||||
|
||||
//addListener(EVERY_MIN, std::bind(&PubSerialType::tickerMinute, &mPubSerial));
|
||||
mPubSerial.setup(mConfig, mSys, &mTimestamp);
|
||||
every(std::bind(&PubSerialType::tick, &mPubSerial), mConfig->serial.interval);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -129,27 +134,26 @@ void app::loop(void) {
|
|||
//-----------------------------------------------------------------------------
|
||||
void app::tickCalcSunrise(void) {
|
||||
if (0 == mTimestamp) {
|
||||
once(5, std::bind(&app::tickCalcSunrise, this)); // check again in 5 secs
|
||||
once(std::bind(&app::tickCalcSunrise, this), 5); // check again in 5 secs
|
||||
return;
|
||||
}
|
||||
ah::calculateSunriseSunset(mTimestamp, mCalculatedTimezoneOffset, mConfig->sun.lat, mConfig->sun.lon, &mSunrise, &mSunset);
|
||||
|
||||
uint32_t nxtTrig = mTimestamp - (mTimestamp % 86400) + 86400; // next midnight
|
||||
onceAt(nxtTrig, std::bind(&app::tickCalcSunrise, this), "calc sunrise");
|
||||
onceAt(mSunrise, std::bind(&app::tickSend, this), "tickSend"); // register next event
|
||||
onceAt(std::bind(&app::tickCalcSunrise, this), nxtTrig);
|
||||
if (mConfig->mqtt.broker[0] > 0) {
|
||||
once(1, std::bind(&PubMqttType::tickerSun, &mMqtt), "MQTT-tickerSun");
|
||||
onceAt(mSunset, std::bind(&PubMqttType::tickSunset, &mMqtt));
|
||||
once(std::bind(&PubMqttType::tickerSun, &mMqtt), 1);
|
||||
onceAt(std::bind(&PubMqttType::tickSunset, &mMqtt), mSunset);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void app::tickSend(void) {
|
||||
if(!mSys->Radio.isChipConnected()) {
|
||||
DPRINTLN(DBG_WARN, "NRF24 not connected!");
|
||||
return;
|
||||
}
|
||||
if ((mTimestamp > 0) && (!mConfig->sun.disNightCom || (mTimestamp >= mSunrise && mTimestamp <= mSunset))) { // Timestamp is set and (inverter communication only during the day if the option is activated and sunrise/sunset is set)
|
||||
once(mConfig->nrf.sendInterval, std::bind(&app::tickSend, this), "tickSend"); // register next event
|
||||
if (mConfig->serial.debug)
|
||||
DPRINTLN(DBG_DEBUG, F("Free heap: 0x") + String(ESP.getFreeHeap(), HEX));
|
||||
|
||||
if (!mSys->BufCtrl.empty()) {
|
||||
if (mConfig->serial.debug)
|
||||
DPRINTLN(DBG_DEBUG, F("recbuf not empty! #") + String(mSys->BufCtrl.getFill()));
|
||||
|
@ -206,7 +210,6 @@ void app::tickSend(void) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
once(3600, std::bind(&app::tickSend, this), "tickSend"); // register next event (one hour)
|
||||
if (mConfig->serial.debug)
|
||||
DPRINTLN(DBG_WARN, F("Time not set or it is night time, therefore no communication to the inverter!"));
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ class app : public ah::Scheduler {
|
|||
app();
|
||||
~app() {}
|
||||
|
||||
void setup(uint32_t timeout);
|
||||
void setup(void);
|
||||
void loop(void);
|
||||
void handleIntr(void);
|
||||
void cbMqtt(char* topic, byte* payload, unsigned int length);
|
||||
|
|
|
@ -98,6 +98,7 @@ typedef struct {
|
|||
cfgMqtt_t mqtt;
|
||||
cfgLed_t led;
|
||||
cfgInst_t inst;
|
||||
bool valid;
|
||||
} settings_t;
|
||||
|
||||
class settings {
|
||||
|
@ -107,7 +108,7 @@ class settings {
|
|||
void setup() {
|
||||
DPRINTLN(DBG_INFO, F("Initializing FS .."));
|
||||
|
||||
mValid = false;
|
||||
mCfg.valid = false;
|
||||
#if !defined(ESP32)
|
||||
LittleFSConfig cfg;
|
||||
cfg.setAutoFormat(false);
|
||||
|
@ -145,7 +146,7 @@ class settings {
|
|||
}
|
||||
|
||||
bool getValid(void) {
|
||||
return mValid;
|
||||
return mCfg.valid;
|
||||
}
|
||||
|
||||
void getInfo(uint32_t *used, uint32_t *size) {
|
||||
|
@ -173,7 +174,7 @@ class settings {
|
|||
DynamicJsonDocument root(4096);
|
||||
DeserializationError err = deserializeJson(root, fp);
|
||||
if(!err) {
|
||||
mValid = true;
|
||||
mCfg.valid = true;
|
||||
jsonWifi(root["wifi"]);
|
||||
jsonNrf(root["nrf"]);
|
||||
jsonNtp(root["ntp"]);
|
||||
|
@ -409,7 +410,6 @@ class settings {
|
|||
}
|
||||
|
||||
settings_t mCfg;
|
||||
bool mValid;
|
||||
};
|
||||
|
||||
#endif /*__SETTINGS_H__*/
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
//-------------------------------------
|
||||
#define VERSION_MAJOR 0
|
||||
#define VERSION_MINOR 5
|
||||
#define VERSION_PATCH 48
|
||||
#define VERSION_PATCH 49
|
||||
|
||||
//-------------------------------------
|
||||
typedef struct {
|
||||
|
|
|
@ -160,17 +160,12 @@ class Inverter {
|
|||
}
|
||||
|
||||
uint8_t getQueuedCmd() {
|
||||
if (_commandQueue.empty()){
|
||||
// Fill with default commands
|
||||
enqueCommand<InfoCommand>(RealTimeRunData_Debug);
|
||||
if (_commandQueue.empty()) {
|
||||
if (fwVersion == 0)
|
||||
{ // info needed maybe after "one night" (=> DC>0 to DC=0 and to DC>0) or reboot
|
||||
enqueCommand<InfoCommand>(InverterDevInform_All);
|
||||
}
|
||||
enqueCommand<InfoCommand>(RealTimeRunData_Debug);
|
||||
if (actPowerLimit == 0xffff)
|
||||
{ // info needed maybe after "one nigth" (=> DC>0 to DC=0 and to DC>0) or reboot
|
||||
enqueCommand<InfoCommand>(SystemConfigPara);
|
||||
}
|
||||
}
|
||||
return _commandQueue.front().get()->getCmd();
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ IRAM_ATTR void handleIntr(void) {
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
void setup() {
|
||||
myApp.setup(WIFI_TRY_CONNECT_TIME);
|
||||
myApp.setup();
|
||||
|
||||
// TODO: move to HmRadio
|
||||
attachInterrupt(digitalPinToInterrupt(myApp.getIrqPin()), handleIntr, FALLING);
|
||||
|
|
|
@ -95,6 +95,7 @@ class PubMqtt {
|
|||
}
|
||||
|
||||
void tickSunset() {
|
||||
printf("tickSunset\n");
|
||||
char topic[MAX_NAME_LENGTH + 15], val[32];
|
||||
for (uint8_t id = 0; id < mSys->getNumInverters(); id++) {
|
||||
Inverter<> *iv = mSys->getInverterByPos(id);
|
||||
|
@ -387,7 +388,7 @@ class PubMqtt {
|
|||
publish(topic, val, true);
|
||||
|
||||
snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/last_success", iv->config->name);
|
||||
snprintf(val, 40, "%i", iv->getLastTs(rec) * 1000);
|
||||
snprintf(val, 40, "%d", iv->getLastTs(rec));
|
||||
publish(topic, val, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,28 +21,24 @@ class PubSerial {
|
|||
mUtcTimestamp = utcTs;
|
||||
}
|
||||
|
||||
void tickerMinute() {
|
||||
DPRINTLN(DBG_INFO, "tickerMinute");
|
||||
if(++mTick >= mCfg->serial.interval) {
|
||||
mTick = 0;
|
||||
if (mCfg->serial.showIv) {
|
||||
char topic[30], val[10];
|
||||
for (uint8_t id = 0; id < mSys->getNumInverters(); id++) {
|
||||
Inverter<> *iv = mSys->getInverterByPos(id);
|
||||
if (NULL != iv) {
|
||||
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||
if (iv->isAvailable(*mUtcTimestamp, rec)) {
|
||||
DPRINTLN(DBG_INFO, F("Inverter: ") + String(id));
|
||||
for (uint8_t i = 0; i < rec->length; i++) {
|
||||
if (0.0f != iv->getValue(i, rec)) {
|
||||
snprintf(topic, 30, "%s/ch%d/%s", iv->config->name, rec->assign[i].ch, iv->getFieldName(i, rec));
|
||||
snprintf(val, 10, "%.3f %s", iv->getValue(i, rec), iv->getUnit(i, rec));
|
||||
DPRINTLN(DBG_INFO, String(topic) + ": " + String(val));
|
||||
}
|
||||
yield();
|
||||
void tick(void) {
|
||||
if (mCfg->serial.showIv) {
|
||||
char topic[32 + MAX_NAME_LENGTH], val[40];
|
||||
for (uint8_t id = 0; id < mSys->getNumInverters(); id++) {
|
||||
Inverter<> *iv = mSys->getInverterByPos(id);
|
||||
if (NULL != iv) {
|
||||
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||
if (iv->isAvailable(*mUtcTimestamp, rec)) {
|
||||
DPRINTLN(DBG_INFO, F("Inverter: ") + String(id));
|
||||
for (uint8_t i = 0; i < rec->length; i++) {
|
||||
if (0.0f != iv->getValue(i, rec)) {
|
||||
snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/ch%d/%s", iv->config->name, rec->assign[i].ch, iv->getFieldName(i, rec));
|
||||
snprintf(val, 40, "%.3f %s", iv->getValue(i, rec), iv->getUnit(i, rec));
|
||||
DPRINTLN(DBG_INFO, String(topic) + ": " + String(val));
|
||||
}
|
||||
DPRINTLN(DBG_INFO, "");
|
||||
yield();
|
||||
}
|
||||
DPRINTLN(DBG_INFO, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +48,6 @@ class PubSerial {
|
|||
private:
|
||||
settings_t *mCfg;
|
||||
HMSYSTEM *mSys;
|
||||
uint8_t mTick;
|
||||
uint32_t *mUtcTimestamp;
|
||||
};
|
||||
|
||||
|
|
108
src/utils/llist.h
Normal file
108
src/utils/llist.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 2022 Ahoy, https://ahoydtu.de
|
||||
// Lukas Pusch, lukas@lpusch.de
|
||||
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef __LIST_H__
|
||||
#define __LIST_H__
|
||||
|
||||
template<class T, class... Args>
|
||||
struct node_s {
|
||||
typedef T dT;
|
||||
node_s *pre;
|
||||
node_s *nxt;
|
||||
uint32_t id;
|
||||
dT d;
|
||||
node_s() : pre(NULL), nxt(NULL), d() {}
|
||||
node_s(Args... args) : id(0), pre(NULL), nxt(NULL), d(args...) {}
|
||||
};
|
||||
|
||||
template<int MAX_NUM, class T, class... Args>
|
||||
class llist {
|
||||
typedef node_s<T, Args...> elmType;
|
||||
typedef T dataType;
|
||||
public:
|
||||
llist() : root(mPool) {
|
||||
root = NULL;
|
||||
elmType *p = mPool;
|
||||
for(uint32_t i = 0; i < MAX_NUM; i++) {
|
||||
p->id = i;
|
||||
p++;
|
||||
}
|
||||
mFill = mMax = 0;
|
||||
}
|
||||
|
||||
elmType *add(Args... args) {
|
||||
elmType *p = root, *t;
|
||||
if(NULL == (t = getFreeNode()))
|
||||
return NULL;
|
||||
if(++mFill > mMax)
|
||||
mMax = mFill;
|
||||
|
||||
if(NULL == root) {
|
||||
p = root = t;
|
||||
p->pre = p;
|
||||
p->nxt = p;
|
||||
}
|
||||
else {
|
||||
p = root->pre;
|
||||
t->pre = p;
|
||||
p->nxt->pre = t;
|
||||
t->nxt = p->nxt;
|
||||
p->nxt = t;
|
||||
}
|
||||
t->d = dataType(args...);
|
||||
return p;
|
||||
}
|
||||
|
||||
elmType *getFront() {
|
||||
return root;
|
||||
}
|
||||
|
||||
elmType *get(elmType *p) {
|
||||
p = p->nxt;
|
||||
return (p == root) ? NULL : p;
|
||||
}
|
||||
|
||||
elmType *rem(elmType *p) {
|
||||
if(NULL == p)
|
||||
return NULL;
|
||||
elmType *t = p->nxt;
|
||||
p->nxt->pre = p->pre;
|
||||
p->pre->nxt = p->nxt;
|
||||
if(root == p)
|
||||
root = NULL;
|
||||
p->nxt = NULL;
|
||||
p->pre = NULL;
|
||||
p = NULL;
|
||||
mFill--;
|
||||
return (NULL == root) ? NULL : ((t == root) ? NULL : t);
|
||||
}
|
||||
|
||||
uint16_t getFill(void) {
|
||||
return mFill;
|
||||
}
|
||||
|
||||
uint16_t getMaxFill(void) {
|
||||
return mMax;
|
||||
}
|
||||
|
||||
protected:
|
||||
elmType *root;
|
||||
|
||||
private:
|
||||
elmType *getFreeNode(void) {
|
||||
elmType *n = mPool;
|
||||
for(uint32_t i = 0; i < MAX_NUM; i++) {
|
||||
if(NULL == n->nxt)
|
||||
return n;
|
||||
n++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
elmType mPool[MAX_NUM];
|
||||
uint16_t mFill, mMax;
|
||||
};
|
||||
|
||||
#endif /*__LIST_H__*/
|
|
@ -7,152 +7,132 @@
|
|||
#ifndef __SCHEDULER_H__
|
||||
#define __SCHEDULER_H__
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
|
||||
enum {EVERY_SEC = 1, EVERY_MIN, EVERY_HR, EVERY_12H, EVERY_DAY};
|
||||
typedef std::function<void()> SchedulerCb;
|
||||
|
||||
struct once_t {
|
||||
uint32_t n;
|
||||
SchedulerCb f;
|
||||
once_t(uint32_t a, SchedulerCb b) : n(a), f(b) {}
|
||||
once_t() : n(0), f(NULL) {}
|
||||
};
|
||||
#include "llist.h"
|
||||
#include "dbg.h"
|
||||
|
||||
namespace ah {
|
||||
class Scheduler {
|
||||
public:
|
||||
Scheduler() {}
|
||||
typedef std::function<void()> scdCb;
|
||||
|
||||
void setup() {
|
||||
mPrevMillis = 0;
|
||||
mSeconds = 0;
|
||||
mMinutes = 0;
|
||||
mHours = 0;
|
||||
mUptime = 0;
|
||||
mTimestamp = 0;
|
||||
}
|
||||
enum {SCD_SEC = 1, SCD_MIN = 60, SCD_HOUR = 3600, SCD_12H = 43200, SCD_DAY = 86400};
|
||||
|
||||
void loop() {
|
||||
if (millis() - mPrevMillis >= 1000) {
|
||||
mPrevMillis += 1000;
|
||||
mUptime++;
|
||||
if(0 != mTimestamp)
|
||||
mTimestamp++;
|
||||
notify(&mListSecond);
|
||||
onceFuncTick();
|
||||
if(++mSeconds >= 60) {
|
||||
mSeconds = 0;
|
||||
notify(&mListMinute);
|
||||
onceAtFuncTick();
|
||||
if(++mMinutes >= 60) {
|
||||
mMinutes = 0;
|
||||
notify(&mListHour);
|
||||
if(++mHours >= 24) {
|
||||
mHours = 0;
|
||||
notify(&mListDay);
|
||||
notify(&mList12h);
|
||||
}
|
||||
else if(mHours == 12)
|
||||
notify(&mList12h);
|
||||
struct scdEvry_s {
|
||||
scdCb c;
|
||||
uint32_t timeout;
|
||||
uint32_t reload;
|
||||
scdEvry_s() : c(NULL), timeout(0), reload(0) {}
|
||||
scdEvry_s(scdCb a, uint32_t tmt, uint32_t rl) : c(a), timeout(tmt), reload(rl) {}
|
||||
};
|
||||
|
||||
struct scdAt_s {
|
||||
scdCb c;
|
||||
uint32_t timestamp;
|
||||
scdAt_s() : c(NULL), timestamp(0) {}
|
||||
scdAt_s(scdCb a, uint32_t ts) : c(a), timestamp(ts) {}
|
||||
};
|
||||
|
||||
|
||||
typedef node_s<scdEvry_s, scdCb, uint32_t, uint32_t> sP;
|
||||
typedef node_s<scdAt_s, scdCb, uint32_t> sPAt;
|
||||
class Scheduler {
|
||||
public:
|
||||
Scheduler() {}
|
||||
|
||||
void setup() {
|
||||
mUptime = 0;
|
||||
mTimestamp = 0;
|
||||
mPrevMillis = millis();
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
mMillis = millis();
|
||||
mDiff = mMillis - mPrevMillis;
|
||||
if(mDiff >= 1000) {
|
||||
if(mMillis < mPrevMillis) { // overflow
|
||||
mPrevMillis = mMillis;
|
||||
return;
|
||||
}
|
||||
mDiffSeconds = mDiff / 1000;
|
||||
mPrevMillis += (mPrevMillis * 1000);
|
||||
checkEvery();
|
||||
checkAt();
|
||||
mUptime += mDiffSeconds;
|
||||
if(0 != mTimestamp)
|
||||
mTimestamp += mDiffSeconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checked every second
|
||||
void once(uint32_t sec, SchedulerCb cb, const char *info = NULL) {
|
||||
if(NULL != info) {
|
||||
DPRINT(DBG_INFO, F("once in [s]: ") + String(sec));
|
||||
DBGPRINTLN(F(", ") + String(info));
|
||||
void once(scdCb c, uint32_t timeout) { mStack.add(c, timeout, 0); }
|
||||
void every(scdCb c, uint32_t interval) { mStack.add(c, interval, interval); }
|
||||
void onceAt(scdCb c, uint32_t timestamp) { mStackAt.add(c, timestamp); }
|
||||
|
||||
void everySec(scdCb c) { mStack.add(c, SCD_SEC, SCD_SEC); }
|
||||
void everyMin(scdCb c) { mStack.add(c, SCD_MIN, SCD_MIN); }
|
||||
void everyHour(scdCb c) { mStack.add(c, SCD_HOUR, SCD_HOUR); }
|
||||
void every12h(scdCb c) { mStack.add(c, SCD_12H, SCD_12H); }
|
||||
void everyDay(scdCb c) { mStack.add(c, SCD_DAY, SCD_DAY); }
|
||||
|
||||
virtual void setTimestamp(uint32_t ts) {
|
||||
mTimestamp = ts;
|
||||
}
|
||||
mOnce.push_back(once_t(sec, cb));
|
||||
}
|
||||
|
||||
// checked every minute
|
||||
void onceAt(uint32_t timestamp, SchedulerCb cb, const char *info = NULL) {
|
||||
if(timestamp > mTimestamp) {
|
||||
if(NULL != info) {
|
||||
DPRINT(DBG_INFO, F("onceAt (UTC): ") + getDateTimeStr(timestamp));
|
||||
DBGPRINTLN(F(", ") + String(info));
|
||||
uint32_t getUptime(void) {
|
||||
return mUptime;
|
||||
}
|
||||
|
||||
uint32_t getTimestamp(void) {
|
||||
return mTimestamp;
|
||||
}
|
||||
|
||||
void stat() {
|
||||
DPRINTLN(DBG_INFO, "max fill every: " + String(mStack.getMaxFill()));
|
||||
DPRINTLN(DBG_INFO, "max fill at: " + String(mStackAt.getMaxFill()));
|
||||
}
|
||||
|
||||
protected:
|
||||
uint32_t mTimestamp;
|
||||
|
||||
private:
|
||||
inline void checkEvery(void) {
|
||||
bool expired;
|
||||
sP *p = mStack.getFront();
|
||||
while(NULL != p) {
|
||||
if(mDiffSeconds >= p->d.timeout) expired = true;
|
||||
else if((p->d.timeout--) == 0) expired = true;
|
||||
else expired = false;
|
||||
|
||||
if(expired) {
|
||||
(p->d.c)();
|
||||
if(0 == p->d.reload)
|
||||
p = mStack.rem(p);
|
||||
else {
|
||||
p->d.timeout = p->d.reload - 1;
|
||||
p = mStack.get(p);
|
||||
}
|
||||
}
|
||||
else
|
||||
p = mStack.get(p);
|
||||
}
|
||||
mOnceAt.push_back(once_t(timestamp, cb));
|
||||
}
|
||||
}
|
||||
|
||||
virtual void setTimestamp(uint32_t ts) {
|
||||
mTimestamp = ts;
|
||||
}
|
||||
|
||||
void addListener(uint8_t every, SchedulerCb cb) {
|
||||
switch(every) {
|
||||
case EVERY_SEC: mListSecond.push_back(cb); break;
|
||||
case EVERY_MIN: mListMinute.push_back(cb); break;
|
||||
case EVERY_HR: mListHour.push_back(cb); break;
|
||||
case EVERY_12H: mList12h.push_back(cb); break;
|
||||
case EVERY_DAY: mListDay.push_back(cb); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t getUptime(void) {
|
||||
return mUptime;
|
||||
}
|
||||
|
||||
uint32_t getTimestamp(void) {
|
||||
return mTimestamp;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void notify(std::list<SchedulerCb> *lType) {
|
||||
for(std::list<SchedulerCb>::iterator it = lType->begin(); it != lType->end(); ++it) {
|
||||
(*it)();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t mTimestamp;
|
||||
|
||||
private:
|
||||
void onceFuncTick(void) {
|
||||
if(mOnce.empty())
|
||||
return;
|
||||
for(std::list<once_t>::iterator it = mOnce.begin(); it != mOnce.end();) {
|
||||
if(((*it).n)-- == 0) {
|
||||
((*it).f)();
|
||||
it = mOnce.erase(it);
|
||||
inline void checkAt(void) {
|
||||
sPAt *p = mStackAt.getFront();
|
||||
while(NULL != p) {
|
||||
if((p->d.timestamp) <= mTimestamp) {
|
||||
(p->d.c)();
|
||||
p = mStackAt.rem(p);
|
||||
}
|
||||
else
|
||||
p = mStackAt.get(p);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void onceAtFuncTick(void) {
|
||||
if(mOnceAt.empty())
|
||||
return;
|
||||
for(std::list<once_t>::iterator it = mOnceAt.begin(); it != mOnceAt.end();) {
|
||||
if(((*it).n) < mTimestamp) {
|
||||
((*it).f)();
|
||||
it = mOnceAt.erase(it);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
std::list<SchedulerCb> mListSecond;
|
||||
std::list<SchedulerCb> mListMinute;
|
||||
std::list<SchedulerCb> mListHour;
|
||||
std::list<SchedulerCb> mList12h;
|
||||
std::list<SchedulerCb> mListDay;
|
||||
|
||||
std::list<once_t> mOnce;
|
||||
std::list<once_t> mOnceAt;
|
||||
|
||||
uint32_t mPrevMillis, mUptime;
|
||||
uint8_t mSeconds, mMinutes, mHours;
|
||||
};
|
||||
llist<25, scdEvry_s, scdCb, uint32_t, uint32_t> mStack;
|
||||
llist<10, scdAt_s, scdCb, uint32_t> mStackAt;
|
||||
uint32_t mMillis, mPrevMillis, mDiff;
|
||||
uint32_t mUptime;
|
||||
uint8_t mDiffSeconds;
|
||||
};
|
||||
}
|
||||
|
||||
#endif /*__SCHEDULER_H__*/
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace ah {
|
|||
void calculateSunriseSunset(uint32_t utcTs, uint32_t offset, float lat, float lon, uint32_t *sunrise, uint32_t *sunset) {
|
||||
// Source: https://en.wikipedia.org/wiki/Sunrise_equation#Complete_calculation_on_Earth
|
||||
|
||||
// Julian day since 1.1.2000 12:00 + correction 69.12s
|
||||
// Julian day since 1.1.2000 12:00
|
||||
double n_JulianDay = (utcTs + offset) / 86400 - 10957.0;
|
||||
// Mean solar time
|
||||
double J = n_JulianDay - lon / 360;
|
||||
|
|
|
@ -48,9 +48,6 @@
|
|||
|
||||
<div id="note">
|
||||
Discuss with us on <a href="https://discord.gg/WzhxEY62mB">Discord</a><br/>
|
||||
<h3>Documentation</h3>
|
||||
<a href="https://ahoydtu.de" target="_blank">ahoydtu.de</a>
|
||||
|
||||
<h3>Support this project:</h3>
|
||||
<ul>
|
||||
<li>Report <a href="https://github.com/lumapu/ahoy/issues" target="_blank">issues</a></li>
|
||||
|
@ -118,10 +115,13 @@
|
|||
var sec = up % 60;
|
||||
var sunrise = new Date(obj["ts_sunrise"] * 1000);
|
||||
var sunset = new Date(obj["ts_sunset"] * 1000);
|
||||
document.getElementById("uptime").innerHTML = days + " Days, "
|
||||
+ ("0"+hrs).substr(-2) + ":"
|
||||
+ ("0"+min).substr(-2) + ":"
|
||||
+ ("0"+sec).substr(-2);
|
||||
var e = document.getElementById("uptime");
|
||||
e.innerHTML = days + " Day";
|
||||
if(1 != days)
|
||||
e.innerHTML += "s";
|
||||
e.innerHTML += ", " + ("0"+hrs).substr(-2) + ":"
|
||||
+ ("0"+min).substr(-2) + ":"
|
||||
+ ("0"+sec).substr(-2);
|
||||
var dSpan = document.getElementById("date");
|
||||
if(0 != obj["ts_now"])
|
||||
dSpan.innerHTML = date.toLocaleString('de-DE');
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
#define F(sl) (sl)
|
||||
#endif
|
||||
#include "ahoywifi.h"
|
||||
#include "../utils/ahoyTimer.h"
|
||||
|
||||
|
||||
// NTP CONFIG
|
||||
#define NTP_PACKET_SIZE 48
|
||||
|
@ -25,17 +23,16 @@ ahoywifi::ahoywifi() {
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ahoywifi::setup(settings_t *config, uint32_t *utcTimestamp) {
|
||||
char ipSta[16];
|
||||
mConfig = config;
|
||||
mUtcTimestamp = utcTimestamp;
|
||||
|
||||
#if !defined(FB_WIFI_OVERRIDDEN)
|
||||
if(strncmp(mConfig->sys.stationSsid, FB_WIFI_SSID, 14) != 0)
|
||||
if(strncmp(mConfig->sys.stationSsid, FB_WIFI_SSID, 14) == 0)
|
||||
setupAp();
|
||||
#endif
|
||||
#if !defined(AP_ONLY)
|
||||
setupStation();
|
||||
ah::ip2Char(mConfig->sys.ip.ip, ipSta);
|
||||
if(mConfig->valid)
|
||||
setupStation();
|
||||
#endif
|
||||
|
||||
#if defined(ESP8266)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue