mirror of
https://github.com/lumapu/ahoy.git
synced 2025-05-23 13:56:10 +02:00
convertion to littfs storage - not complete
This commit is contained in:
parent
56cfffbcd8
commit
faa28ce1a8
22 changed files with 666 additions and 746 deletions
3
src/.vscode/settings.json
vendored
3
src/.vscode/settings.json
vendored
|
@ -20,4 +20,7 @@
|
|||
|
||||
// https://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||
"C_Cpp.clang_format_fallbackStyle": "{ BasedOnStyle: Google, IndentWidth: 4, ColumnLimit: 0}",
|
||||
"files.associations": {
|
||||
"typeinfo": "cpp"
|
||||
},
|
||||
}
|
216
src/app.cpp
216
src/app.cpp
|
@ -13,33 +13,27 @@
|
|||
#include "utils/sun.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
app::app() {
|
||||
void app::setup(uint32_t timeout) {
|
||||
Serial.begin(115200);
|
||||
DPRINTLN(DBG_VERBOSE, F("app::app"));
|
||||
mEep = new eep();
|
||||
while (!Serial)
|
||||
yield();
|
||||
|
||||
resetSystem();
|
||||
loadDefaultConfig();
|
||||
mSettings.setup();
|
||||
mSettings.getPtr(mConfig);
|
||||
|
||||
mWifi = new ahoywifi(mConfig);
|
||||
|
||||
mWifi = new ahoywifi(this, &mSysConfig, &mConfig);
|
||||
mSys = new HmSystemType();
|
||||
mSys->enableDebug();
|
||||
mShouldReboot = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void app::setup(uint32_t timeout) {
|
||||
DPRINTLN(DBG_VERBOSE, F("app::setup"));
|
||||
mWifi->setup(timeout, mSettings.getValid());
|
||||
|
||||
mWifiSettingsValid = checkEEpCrc(ADDR_START, ADDR_WIFI_CRC, ADDR_WIFI_CRC);
|
||||
mSettingsValid = checkEEpCrc(ADDR_START_SETTINGS, ((ADDR_NEXT) - (ADDR_START_SETTINGS)), ADDR_SETTINGS_CRC);
|
||||
loadEEpconfig();
|
||||
|
||||
mWifi->setup(timeout, mWifiSettingsValid);
|
||||
|
||||
mSys->setup(mConfig.amplifierPower, mConfig.pinIrq, mConfig.pinCe, mConfig.pinCs);
|
||||
mSys->setup(mConfig->nrf.amplifierPower, mConfig->nrf.pinIrq, mConfig->nrf.pinCe, mConfig->nrf.pinCs);
|
||||
mSys->addInverters(&mConfig->inst);
|
||||
mPayload.setup(mSys);
|
||||
mPayload.enableSerialDebug(mConfig.serialDebug);
|
||||
mPayload.enableSerialDebug(mConfig->serial.debug);
|
||||
#ifndef AP_ONLY
|
||||
setupMqtt();
|
||||
if(mMqttActive)
|
||||
|
@ -47,11 +41,12 @@ void app::setup(uint32_t timeout) {
|
|||
#endif
|
||||
setupLed();
|
||||
|
||||
mWebInst = new web(this, &mSysConfig, &mConfig, &mStat, mVersion);
|
||||
|
||||
mWebInst = new web(this, mConfig, &mStat, mVersion);
|
||||
mWebInst->setup();
|
||||
mWebInst->setProtection(strlen(mConfig.password) != 0);
|
||||
DPRINTLN(DBG_INFO, F("Settings valid: ") + String((mSettingsValid) ? F("true") : F("false")));
|
||||
DPRINTLN(DBG_INFO, F("EEprom storage size: 0x") + String(ADDR_SETTINGS_CRC, HEX));
|
||||
mWebInst->setProtection(strlen(mConfig->sys.adminPwd) != 0);
|
||||
DPRINTLN(DBG_INFO, F("Settings valid: ") + String((mSettings.getValid()) ? F("true") : F("false")));
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -88,7 +83,7 @@ void app::loop(void) {
|
|||
|
||||
if (mFlagSendDiscoveryConfig) {
|
||||
mFlagSendDiscoveryConfig = false;
|
||||
mMqtt.sendMqttDiscoveryConfig(mConfig.mqtt.topic);
|
||||
mMqtt.sendMqttDiscoveryConfig(mConfig->mqtt.topic);
|
||||
}
|
||||
|
||||
mSys->Radio.loop();
|
||||
|
@ -104,7 +99,7 @@ void app::loop(void) {
|
|||
|
||||
if (mSys->Radio.checkPaketCrc(p->packet, &len, p->rxCh)) {
|
||||
// process buffer only on first occurrence
|
||||
if (mConfig.serialDebug) {
|
||||
if (mConfig->serial.debug) {
|
||||
DPRINT(DBG_INFO, "RX " + String(len) + "B Ch" + String(p->rxCh) + " | ");
|
||||
mSys->Radio.dumpBuf(NULL, p->packet, len);
|
||||
}
|
||||
|
@ -119,23 +114,23 @@ void app::loop(void) {
|
|||
yield();
|
||||
|
||||
if (rxRdy)
|
||||
mPayload.process(true, mConfig.maxRetransPerPyld, &mStat);
|
||||
mPayload.process(true, mConfig->nrf.maxRetransPerPyld, &mStat);
|
||||
}
|
||||
|
||||
if (mMqttActive)
|
||||
mMqtt.loop();
|
||||
|
||||
if (ah::checkTicker(&mTicker, 1000)) {
|
||||
if (mUtcTimestamp > 946684800 && mConfig.sunLat && mConfig.sunLon && (mUtcTimestamp + mCalculatedTimezoneOffset) / 86400 != (mLatestSunTimestamp + mCalculatedTimezoneOffset) / 86400) { // update on reboot or midnight
|
||||
if (mUtcTimestamp > 946684800 && mConfig->sun.lat && mConfig->sun.lon && (mUtcTimestamp + mCalculatedTimezoneOffset) / 86400 != (mLatestSunTimestamp + mCalculatedTimezoneOffset) / 86400) { // update on reboot or midnight
|
||||
if (!mLatestSunTimestamp) { // first call: calculate time zone from longitude to refresh at local midnight
|
||||
mCalculatedTimezoneOffset = (int8_t)((mConfig.sunLon >= 0 ? mConfig.sunLon + 7.5 : mConfig.sunLon - 7.5) / 15) * 3600;
|
||||
mCalculatedTimezoneOffset = (int8_t)((mConfig->sun.lon >= 0 ? mConfig->sun.lon + 7.5 : mConfig->sun.lon - 7.5) / 15) * 3600;
|
||||
}
|
||||
ah::calculateSunriseSunset(mUtcTimestamp, mCalculatedTimezoneOffset, mConfig.sunLat, mConfig.sunLon, &mSunrise, &mSunset);
|
||||
ah::calculateSunriseSunset(mUtcTimestamp, mCalculatedTimezoneOffset, mConfig->sun.lat, mConfig->sun.lon, &mSunrise, &mSunset);
|
||||
mLatestSunTimestamp = mUtcTimestamp;
|
||||
}
|
||||
|
||||
if (mConfig.serialShowIv) {
|
||||
if (++mSerialTicker >= mConfig.serialInterval) {
|
||||
if (mConfig->serial.showIv) {
|
||||
if (++mSerialTicker >= mConfig->serial.interval) {
|
||||
mSerialTicker = 0;
|
||||
char topic[30], val[10];
|
||||
for (uint8_t id = 0; id < mSys->getNumInverters(); id++) {
|
||||
|
@ -146,7 +141,7 @@ void app::loop(void) {
|
|||
DPRINTLN(DBG_INFO, "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->name, rec->assign[i].ch, iv->getFieldName(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));
|
||||
}
|
||||
|
@ -159,15 +154,15 @@ void app::loop(void) {
|
|||
}
|
||||
}
|
||||
|
||||
if (++mSendTicker >= mConfig.sendInterval) {
|
||||
if (++mSendTicker >= mConfig->nrf.sendInterval) {
|
||||
mSendTicker = 0;
|
||||
|
||||
if (mUtcTimestamp > 946684800 && (!mConfig.sunDisNightCom || !mLatestSunTimestamp || (mUtcTimestamp >= mSunrise && mUtcTimestamp <= mSunset))) { // Timestamp is set and (inverter communication only during the day if the option is activated and sunrise/sunset is set)
|
||||
if (mConfig.serialDebug)
|
||||
if (mUtcTimestamp > 946684800 && (!mConfig->sun.disNightCom || !mLatestSunTimestamp || (mUtcTimestamp >= mSunrise && mUtcTimestamp <= mSunset))) { // Timestamp is set and (inverter communication only during the day if the option is activated and sunrise/sunset is set)
|
||||
if (mConfig->serial.debug)
|
||||
DPRINTLN(DBG_DEBUG, F("Free heap: 0x") + String(ESP.getFreeHeap(), HEX));
|
||||
|
||||
if (!mSys->BufCtrl.empty()) {
|
||||
if (mConfig.serialDebug)
|
||||
if (mConfig->serial.debug)
|
||||
DPRINTLN(DBG_DEBUG, F("recbuf not empty! #") + String(mSys->BufCtrl.getFill()));
|
||||
}
|
||||
|
||||
|
@ -180,7 +175,7 @@ void app::loop(void) {
|
|||
|
||||
if (NULL != iv) {
|
||||
if (!mPayload.isComplete(iv))
|
||||
mPayload.process(false, mConfig.maxRetransPerPyld, &mStat);
|
||||
mPayload.process(false, mConfig->nrf.maxRetransPerPyld, &mStat);
|
||||
|
||||
if (!mPayload.isComplete(iv)) {
|
||||
if (0 == mPayload.getMaxPacketId(iv))
|
||||
|
@ -189,9 +184,9 @@ void app::loop(void) {
|
|||
mStat.rxFail++;
|
||||
|
||||
iv->setQueuedCmdFinished(); // command failed
|
||||
if (mConfig.serialDebug)
|
||||
if (mConfig->serial.debug)
|
||||
DPRINTLN(DBG_INFO, F("enqueued cmd failed/timeout"));
|
||||
if (mConfig.serialDebug) {
|
||||
if (mConfig->serial.debug) {
|
||||
DPRINT(DBG_INFO, F("(#") + String(iv->id) + ") ");
|
||||
DPRINTLN(DBG_INFO, F("no Payload received! (retransmits: ") + String(mPayload.getRetransmits(iv)) + ")");
|
||||
}
|
||||
|
@ -201,13 +196,13 @@ void app::loop(void) {
|
|||
mPayload.request(iv);
|
||||
|
||||
yield();
|
||||
if (mConfig.serialDebug) {
|
||||
if (mConfig->serial.debug) {
|
||||
DPRINTLN(DBG_DEBUG, F("app:loop WiFi WiFi.status ") + String(WiFi.status()));
|
||||
DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") Requesting Inv SN ") + String(iv->serial.u64, HEX));
|
||||
DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") Requesting Inv SN ") + String(iv->config->serial.u64, HEX));
|
||||
}
|
||||
|
||||
if (iv->devControlRequest) {
|
||||
if (mConfig.serialDebug)
|
||||
if (mConfig->serial.debug)
|
||||
DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") Devcontrol request ") + String(iv->devControlCmd) + F(" power limit ") + String(iv->powerLimit[0]));
|
||||
mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit);
|
||||
mPayload.setTxCmd(iv, iv->devControlCmd);
|
||||
|
@ -221,7 +216,7 @@ void app::loop(void) {
|
|||
mRxTicker = 0;
|
||||
}
|
||||
}
|
||||
} else if (mConfig.serialDebug)
|
||||
} else if (mConfig->serial.debug)
|
||||
DPRINTLN(DBG_WARN, F("Time not set or it is night time, therefore no communication to the inverter!"));
|
||||
yield();
|
||||
|
||||
|
@ -284,130 +279,13 @@ void app::resetSystem(void) {
|
|||
memset(&mStat, 0, sizeof(statistics_t));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void app::loadDefaultConfig(void) {
|
||||
memset(&mSysConfig, 0, sizeof(sysConfig_t));
|
||||
memset(&mConfig, 0, sizeof(config_t));
|
||||
snprintf(mVersion, 12, "%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
|
||||
|
||||
snprintf(mSysConfig.deviceName, DEVNAME_LEN, "%s", DEF_DEVICE_NAME);
|
||||
|
||||
// wifi
|
||||
snprintf(mSysConfig.stationSsid, SSID_LEN, "%s", FB_WIFI_SSID);
|
||||
snprintf(mSysConfig.stationPwd, PWD_LEN, "%s", FB_WIFI_PWD);
|
||||
|
||||
// password
|
||||
snprintf(mConfig.password, PWD_LEN, "%s", GUI_DEF_PASSWORD);
|
||||
|
||||
// nrf24
|
||||
mConfig.sendInterval = SEND_INTERVAL;
|
||||
mConfig.maxRetransPerPyld = DEF_MAX_RETRANS_PER_PYLD;
|
||||
mConfig.pinCs = DEF_CS_PIN;
|
||||
mConfig.pinCe = DEF_CE_PIN;
|
||||
mConfig.pinIrq = DEF_IRQ_PIN;
|
||||
mConfig.amplifierPower = DEF_AMPLIFIERPOWER & 0x03;
|
||||
|
||||
// status LED
|
||||
mConfig.led.led0 = DEF_LED0_PIN;
|
||||
mConfig.led.led1 = DEF_LED1_PIN;
|
||||
|
||||
// ntp
|
||||
snprintf(mConfig.ntpAddr, NTP_ADDR_LEN, "%s", DEF_NTP_SERVER_NAME);
|
||||
mConfig.ntpPort = DEF_NTP_PORT;
|
||||
|
||||
// Latitude + Longitude
|
||||
mConfig.sunLat = 0.0;
|
||||
mConfig.sunLon = 0.0;
|
||||
mConfig.sunDisNightCom = false;
|
||||
|
||||
// mqtt
|
||||
snprintf(mConfig.mqtt.broker, MQTT_ADDR_LEN, "%s", DEF_MQTT_BROKER);
|
||||
mConfig.mqtt.port = DEF_MQTT_PORT;
|
||||
snprintf(mConfig.mqtt.user, MQTT_USER_LEN, "%s", DEF_MQTT_USER);
|
||||
snprintf(mConfig.mqtt.pwd, MQTT_PWD_LEN, "%s", DEF_MQTT_PWD);
|
||||
snprintf(mConfig.mqtt.topic, MQTT_TOPIC_LEN, "%s", DEF_MQTT_TOPIC);
|
||||
|
||||
// serial
|
||||
mConfig.serialInterval = SERIAL_INTERVAL;
|
||||
mConfig.serialShowIv = false;
|
||||
mConfig.serialDebug = false;
|
||||
|
||||
// Disclaimer
|
||||
mConfig.disclaimer = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void app::loadEEpconfig(void) {
|
||||
DPRINTLN(DBG_INFO, F("loadEEpconfig"));
|
||||
|
||||
if (mWifiSettingsValid)
|
||||
mEep->read(ADDR_CFG_SYS, (uint8_t *)&mSysConfig, CFG_SYS_LEN);
|
||||
if (mSettingsValid) {
|
||||
mEep->read(ADDR_CFG, (uint8_t *)&mConfig, CFG_LEN);
|
||||
|
||||
mSendTicker = mConfig.sendInterval;
|
||||
mSerialTicker = 0;
|
||||
|
||||
// inverter
|
||||
uint64_t invSerial;
|
||||
char name[MAX_NAME_LENGTH + 1] = {0};
|
||||
uint16_t modPwr[4];
|
||||
Inverter<> *iv;
|
||||
for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) {
|
||||
mEep->read(ADDR_INV_ADDR + (i * 8), &invSerial);
|
||||
mEep->read(ADDR_INV_NAME + (i * MAX_NAME_LENGTH), name, MAX_NAME_LENGTH);
|
||||
mEep->read(ADDR_INV_CH_PWR + (i * 2 * 4), modPwr, 4);
|
||||
if (0ULL != invSerial) {
|
||||
iv = mSys->addInverter(name, invSerial, modPwr);
|
||||
if (NULL != iv) { // will run once on every dtu boot
|
||||
for (uint8_t j = 0; j < 4; j++) {
|
||||
mEep->read(ADDR_INV_CH_NAME + (i * 4 * MAX_NAME_LENGTH) + j * MAX_NAME_LENGTH, iv->chName[j], MAX_NAME_LENGTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) {
|
||||
iv = mSys->getInverterByPos(i, false);
|
||||
if (NULL != iv)
|
||||
mPayload.reset(iv, mUtcTimestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void app::saveValues(void) {
|
||||
DPRINTLN(DBG_VERBOSE, F("app::saveValues"));
|
||||
|
||||
mEep->write(ADDR_CFG_SYS, (uint8_t *)&mSysConfig, CFG_SYS_LEN);
|
||||
mEep->write(ADDR_CFG, (uint8_t *)&mConfig, CFG_LEN);
|
||||
Inverter<> *iv;
|
||||
for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) {
|
||||
iv = mSys->getInverterByPos(i, false);
|
||||
mEep->write(ADDR_INV_ADDR + (i * 8), iv->serial.u64);
|
||||
mEep->write(ADDR_INV_NAME + (i * MAX_NAME_LENGTH), iv->name, MAX_NAME_LENGTH);
|
||||
// max channel power / name
|
||||
for (uint8_t j = 0; j < 4; j++) {
|
||||
mEep->write(ADDR_INV_CH_PWR + (i * 2 * 4) + (j * 2), iv->chMaxPwr[j]);
|
||||
mEep->write(ADDR_INV_CH_NAME + (i * 4 * MAX_NAME_LENGTH) + j * MAX_NAME_LENGTH, iv->chName[j], MAX_NAME_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
updateCrc();
|
||||
|
||||
// update sun
|
||||
mLatestSunTimestamp = 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void app::setupMqtt(void) {
|
||||
if (mSettingsValid) {
|
||||
if (mConfig.mqtt.broker[0] > 0)
|
||||
if (mConfig->mqtt.broker[0] > 0)
|
||||
mMqttActive = true;
|
||||
|
||||
if(mMqttActive)
|
||||
mMqtt.setup(&mConfig.mqtt, mSysConfig.deviceName, mVersion, mSys, &mUtcTimestamp);
|
||||
}
|
||||
mMqtt.setup(&mConfig->mqtt, mConfig->sys.deviceName, mVersion, mSys, &mUtcTimestamp);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -417,26 +295,26 @@ void app::setupLed(void) {
|
|||
* PIN ---- |<----- 3.3V
|
||||
*
|
||||
* */
|
||||
if(mConfig.led.led0 != 0xff) {
|
||||
pinMode(mConfig.led.led0, OUTPUT);
|
||||
digitalWrite(mConfig.led.led0, HIGH); // LED off
|
||||
if(mConfig->led.led0 != 0xff) {
|
||||
pinMode(mConfig->led.led0, OUTPUT);
|
||||
digitalWrite(mConfig->led.led0, HIGH); // LED off
|
||||
}
|
||||
if(mConfig.led.led1 != 0xff) {
|
||||
pinMode(mConfig.led.led1, OUTPUT);
|
||||
digitalWrite(mConfig.led.led1, HIGH); // LED off
|
||||
if(mConfig->led.led1 != 0xff) {
|
||||
pinMode(mConfig->led.led1, OUTPUT);
|
||||
digitalWrite(mConfig->led.led1, HIGH); // LED off
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void app::updateLed(void) {
|
||||
if(mConfig.led.led0 != 0xff) {
|
||||
if(mConfig->led.led0 != 0xff) {
|
||||
Inverter<> *iv = mSys->getInverterByPos(0);
|
||||
if (NULL != iv) {
|
||||
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||
if(iv->isProducing(mUtcTimestamp, rec))
|
||||
digitalWrite(mConfig.led.led0, LOW); // LED on
|
||||
digitalWrite(mConfig->led.led0, LOW); // LED on
|
||||
else
|
||||
digitalWrite(mConfig.led.led0, HIGH); // LED off
|
||||
digitalWrite(mConfig->led.led0, HIGH); // LED off
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
93
src/app.h
93
src/app.h
|
@ -7,15 +7,12 @@
|
|||
#define __APP_H__
|
||||
|
||||
#include "utils/dbg.h"
|
||||
#include "Arduino.h"
|
||||
|
||||
|
||||
#include <queue>
|
||||
#include <Arduino.h>
|
||||
#include <RF24.h>
|
||||
#include <RF24_config.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include "config/eep.h"
|
||||
#include "config/settings.h"
|
||||
#include "defines.h"
|
||||
#include "utils/crc.h"
|
||||
#include "utils/ahoyTimer.h"
|
||||
|
@ -42,7 +39,7 @@ class web;
|
|||
|
||||
class app {
|
||||
public:
|
||||
app();
|
||||
app() {}
|
||||
~app() {}
|
||||
|
||||
void setup(uint32_t timeout);
|
||||
|
@ -55,9 +52,17 @@ class app {
|
|||
void scanAvailNetworks(void);
|
||||
void getAvailNetworks(JsonObject obj);
|
||||
|
||||
void saveSettings(void) {
|
||||
DPRINTLN(DBG_INFO, "a");
|
||||
mSettings.saveSettings();
|
||||
}
|
||||
|
||||
bool eraseSettings(bool eraseWifi = false) {
|
||||
return mSettings.eraseSettings(eraseWifi);
|
||||
}
|
||||
|
||||
uint8_t getIrqPin(void) {
|
||||
return mConfig.pinIrq;
|
||||
return mConfig->nrf.pinIrq;
|
||||
}
|
||||
|
||||
uint64_t Serial2u64(const char *val) {
|
||||
|
@ -122,26 +127,8 @@ class app {
|
|||
return mLatestSunTimestamp;
|
||||
}
|
||||
|
||||
void eraseSettings(bool all = false) {
|
||||
//DPRINTLN(DBG_VERBOSE, F("main.h:eraseSettings"));
|
||||
uint8_t buf[64];
|
||||
uint16_t addr = (all) ? ADDR_START : ADDR_START_SETTINGS;
|
||||
uint16_t end;
|
||||
|
||||
memset(buf, 0xff, 64);
|
||||
do {
|
||||
end = addr + 64;
|
||||
if(end > (ADDR_SETTINGS_CRC + 2))
|
||||
end = (ADDR_SETTINGS_CRC + 2);
|
||||
DPRINTLN(DBG_DEBUG, F("erase: 0x") + String(addr, HEX) + " - 0x" + String(end, HEX));
|
||||
mEep->write(addr, buf, (end-addr));
|
||||
addr = end;
|
||||
} while(addr < (ADDR_SETTINGS_CRC + 2));
|
||||
mEep->commit();
|
||||
}
|
||||
|
||||
inline bool mqttIsConnected(void) { return mMqtt.isConnected(); }
|
||||
inline bool getSettingsValid(void) { return mSettingsValid; }
|
||||
inline bool getSettingsValid(void) { return mSettings.getValid(); }
|
||||
inline bool getRebootRequestState(void) { return mShowRebootRequest; }
|
||||
inline uint32_t getMqttTxCnt(void) { return mMqtt.getTxCnt(); }
|
||||
|
||||
|
@ -151,57 +138,12 @@ class app {
|
|||
|
||||
private:
|
||||
void resetSystem(void);
|
||||
void loadDefaultConfig(void);
|
||||
void loadEEpconfig(void);
|
||||
|
||||
void setupMqtt(void);
|
||||
|
||||
void setupLed(void);
|
||||
void updateLed(void);
|
||||
|
||||
void processPayload(bool retransmit);
|
||||
|
||||
inline uint16_t buildEEpCrc(uint32_t start, uint32_t length) {
|
||||
DPRINTLN(DBG_VERBOSE, F("main.h:buildEEpCrc"));
|
||||
uint8_t buf[32];
|
||||
uint16_t crc = 0xffff;
|
||||
uint8_t len;
|
||||
|
||||
while(length > 0) {
|
||||
len = (length < 32) ? length : 32;
|
||||
mEep->read(start, buf, len);
|
||||
crc = ah::crc16(buf, len, crc);
|
||||
start += len;
|
||||
length -= len;
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
void updateCrc(void) {
|
||||
DPRINTLN(DBG_VERBOSE, F("app::updateCrc"));
|
||||
uint16_t crc;
|
||||
|
||||
crc = buildEEpCrc(ADDR_START, ADDR_WIFI_CRC);
|
||||
DPRINTLN(DBG_DEBUG, F("new Wifi CRC: ") + String(crc, HEX));
|
||||
mEep->write(ADDR_WIFI_CRC, crc);
|
||||
|
||||
crc = buildEEpCrc(ADDR_START_SETTINGS, ((ADDR_NEXT) - (ADDR_START_SETTINGS)));
|
||||
DPRINTLN(DBG_DEBUG, F("new Settings CRC: ") + String(crc, HEX));
|
||||
mEep->write(ADDR_SETTINGS_CRC, crc);
|
||||
|
||||
mEep->commit();
|
||||
}
|
||||
|
||||
bool checkEEpCrc(uint32_t start, uint32_t length, uint32_t crcPos) {
|
||||
DPRINTLN(DBG_VERBOSE, F("main.h:checkEEpCrc"));
|
||||
DPRINTLN(DBG_DEBUG, F("start: ") + String(start) + F(", length: ") + String(length));
|
||||
uint16_t crcRd, crcCheck;
|
||||
crcCheck = buildEEpCrc(start, length);
|
||||
mEep->read(crcPos, &crcRd);
|
||||
DPRINTLN(DBG_DEBUG, "CRC RD: " + String(crcRd, HEX) + " CRC CALC: " + String(crcCheck, HEX));
|
||||
return (crcCheck == crcRd);
|
||||
}
|
||||
|
||||
void stats(void) {
|
||||
DPRINTLN(DBG_VERBOSE, F("main.h:stats"));
|
||||
#ifdef ESP8266
|
||||
|
@ -228,11 +170,6 @@ class app {
|
|||
uint32_t mNtpRefreshTicker;
|
||||
uint32_t mNtpRefreshInterval;
|
||||
|
||||
|
||||
bool mWifiSettingsValid;
|
||||
bool mSettingsValid;
|
||||
|
||||
eep *mEep;
|
||||
uint32_t mUtcTimestamp;
|
||||
bool mUpdateNtp;
|
||||
|
||||
|
@ -240,10 +177,10 @@ class app {
|
|||
|
||||
ahoywifi *mWifi;
|
||||
web *mWebInst;
|
||||
sysConfig_t mSysConfig;
|
||||
config_t mConfig;
|
||||
char mVersion[12];
|
||||
PayloadType mPayload;
|
||||
settings mSettings;
|
||||
settings_t *mConfig;
|
||||
|
||||
uint16_t mSendTicker;
|
||||
uint8_t mSendLastIvId;
|
||||
|
|
|
@ -25,9 +25,6 @@
|
|||
// If the next line is uncommented, Ahoy will stay in access point mode all the time
|
||||
//#define AP_ONLY
|
||||
|
||||
// protection of the GUI by password
|
||||
#define GUI_DEF_PASSWORD ""
|
||||
|
||||
// timeout for automatic logoff (20 minutes)
|
||||
#define LOGOUT_TIMEOUT (20 * 60 * 60)
|
||||
|
||||
|
@ -121,6 +118,11 @@
|
|||
// default MQTT topic
|
||||
#define DEF_MQTT_TOPIC "inverter"
|
||||
|
||||
// discovery prefix
|
||||
#define MQTT_DISCOVERY_PREFIX "homeassistant"
|
||||
|
||||
// reconnect delay
|
||||
#define MQTT_RECONNECT_DELAY 5000
|
||||
|
||||
#if __has_include("config_override.h")
|
||||
#include "config_override.h"
|
||||
|
|
161
src/config/eep.h
161
src/config/eep.h
|
@ -1,161 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 2022 Ahoy, https://www.mikrocontroller.net/topic/525778
|
||||
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef __EEP_H__
|
||||
#define __EEP_H__
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <EEPROM.h>
|
||||
#ifdef ESP32
|
||||
#include <nvs_flash.h>
|
||||
#endif
|
||||
|
||||
class eep {
|
||||
public:
|
||||
eep() {
|
||||
|
||||
#ifdef ESP32
|
||||
if(!EEPROM.begin(4096)) {
|
||||
nvs_flash_init();
|
||||
EEPROM.begin(4096);
|
||||
}
|
||||
#else
|
||||
EEPROM.begin(4096);
|
||||
#endif
|
||||
|
||||
}
|
||||
~eep() {
|
||||
EEPROM.end();
|
||||
}
|
||||
|
||||
void read(uint32_t addr, char *str, uint8_t length) {
|
||||
for(uint8_t i = 0; i < length; i ++) {
|
||||
*(str++) = (char)EEPROM.read(addr++);
|
||||
}
|
||||
}
|
||||
|
||||
void read(uint32_t addr, float *value) {
|
||||
uint8_t *p = (uint8_t*)value;
|
||||
for(uint8_t i = 0; i < 4; i ++) {
|
||||
*(p++) = (uint8_t)EEPROM.read(addr++);
|
||||
}
|
||||
}
|
||||
|
||||
void read(uint32_t addr, bool *value) {
|
||||
uint8_t intVal = 0x00;
|
||||
intVal = EEPROM.read(addr++);
|
||||
*value = (intVal == 0x01);
|
||||
}
|
||||
|
||||
void read(uint32_t addr, uint8_t *value) {
|
||||
*value = (EEPROM.read(addr++));
|
||||
}
|
||||
|
||||
void read(uint32_t addr, uint8_t data[], uint16_t length) {
|
||||
for(uint16_t i = 0; i < length; i ++) {
|
||||
*(data++) = EEPROM.read(addr++);
|
||||
}
|
||||
}
|
||||
|
||||
void read(uint32_t addr, uint16_t *value) {
|
||||
*value = (EEPROM.read(addr++) << 8);
|
||||
*value |= (EEPROM.read(addr++));
|
||||
}
|
||||
|
||||
void read(uint32_t addr, uint16_t data[], uint16_t length) {
|
||||
for(uint16_t i = 0; i < length; i ++) {
|
||||
*(data) = (EEPROM.read(addr++) << 8);
|
||||
*(data++) |= (EEPROM.read(addr++));
|
||||
}
|
||||
}
|
||||
|
||||
void read(uint32_t addr, uint32_t *value) {
|
||||
*value = (EEPROM.read(addr++) << 24);
|
||||
*value |= (EEPROM.read(addr++) << 16);
|
||||
*value |= (EEPROM.read(addr++) << 8);
|
||||
*value |= (EEPROM.read(addr++));
|
||||
}
|
||||
|
||||
void read(uint32_t addr, uint64_t *value) {
|
||||
read(addr, (uint32_t *)value);
|
||||
*value <<= 32;
|
||||
uint32_t tmp;
|
||||
read(addr+4, &tmp);
|
||||
*value |= tmp;
|
||||
/**value = (EEPROM.read(addr++) << 56);
|
||||
*value |= (EEPROM.read(addr++) << 48);
|
||||
*value |= (EEPROM.read(addr++) << 40);
|
||||
*value |= (EEPROM.read(addr++) << 32);
|
||||
*value |= (EEPROM.read(addr++) << 24);
|
||||
*value |= (EEPROM.read(addr++) << 16);
|
||||
*value |= (EEPROM.read(addr++) << 8);
|
||||
*value |= (EEPROM.read(addr++));*/
|
||||
}
|
||||
|
||||
void write(uint32_t addr, const char *str, uint8_t length) {
|
||||
for(uint8_t i = 0; i < length; i ++) {
|
||||
EEPROM.write(addr++, str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void write(uint32_t addr, uint8_t data[], uint16_t length) {
|
||||
for(uint16_t i = 0; i < length; i ++) {
|
||||
EEPROM.write(addr++, data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void write(uint32_t addr, float value) {
|
||||
uint8_t *p = (uint8_t*)&value;
|
||||
for(uint8_t i = 0; i < 4; i ++) {
|
||||
EEPROM.write(addr++, p[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void write(uint32_t addr, bool value) {
|
||||
uint8_t intVal = (value) ? 0x01 : 0x00;
|
||||
EEPROM.write(addr++, intVal);
|
||||
}
|
||||
|
||||
void write(uint32_t addr, uint8_t value) {
|
||||
EEPROM.write(addr++, value);
|
||||
}
|
||||
|
||||
void write(uint32_t addr, uint16_t value) {
|
||||
EEPROM.write(addr++, (value >> 8) & 0xff);
|
||||
EEPROM.write(addr++, (value ) & 0xff);
|
||||
}
|
||||
|
||||
|
||||
void write(uint32_t addr, uint16_t data[], uint16_t length) {
|
||||
for(uint16_t i = 0; i < length; i ++) {
|
||||
EEPROM.write(addr++, (data[i] >> 8) & 0xff);
|
||||
EEPROM.write(addr++, (data[i] ) & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
void write(uint32_t addr, uint32_t value) {
|
||||
EEPROM.write(addr++, (value >> 24) & 0xff);
|
||||
EEPROM.write(addr++, (value >> 16) & 0xff);
|
||||
EEPROM.write(addr++, (value >> 8) & 0xff);
|
||||
EEPROM.write(addr++, (value ) & 0xff);
|
||||
}
|
||||
|
||||
void write(uint32_t addr, uint64_t value) {
|
||||
EEPROM.write(addr++, (value >> 56) & 0xff);
|
||||
EEPROM.write(addr++, (value >> 48) & 0xff);
|
||||
EEPROM.write(addr++, (value >> 40) & 0xff);
|
||||
EEPROM.write(addr++, (value >> 32) & 0xff);
|
||||
EEPROM.write(addr++, (value >> 24) & 0xff);
|
||||
EEPROM.write(addr++, (value >> 16) & 0xff);
|
||||
EEPROM.write(addr++, (value >> 8) & 0xff);
|
||||
EEPROM.write(addr++, (value ) & 0xff);
|
||||
}
|
||||
|
||||
void commit(void) {
|
||||
EEPROM.commit();
|
||||
}
|
||||
};
|
||||
|
||||
#endif /*__EEP_H__*/
|
407
src/config/settings.h
Normal file
407
src/config/settings.h
Normal file
|
@ -0,0 +1,407 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 2022 Ahoy, https://ahoydtu.de
|
||||
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef __SETTINGS_H__
|
||||
#define __SETTINGS_H__
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <LittleFS.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include "../utils/dbg.h"
|
||||
#include "../defines.h"
|
||||
|
||||
/**
|
||||
* More info:
|
||||
* https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html#flash-layout
|
||||
* */
|
||||
|
||||
typedef struct {
|
||||
uint8_t ip[4]; // ip address
|
||||
uint8_t mask[4]; // sub mask
|
||||
uint8_t dns1[4]; // dns 1
|
||||
uint8_t dns2[4]; // dns 2
|
||||
uint8_t gateway[4]; // standard gateway
|
||||
} cfgIp_t;
|
||||
|
||||
typedef struct {
|
||||
char deviceName[DEVNAME_LEN];
|
||||
char adminPwd[PWD_LEN];
|
||||
|
||||
// wifi
|
||||
char stationSsid[SSID_LEN];
|
||||
char stationPwd[PWD_LEN];
|
||||
|
||||
cfgIp_t ip;
|
||||
} cfgSys_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t sendInterval;
|
||||
uint8_t maxRetransPerPyld;
|
||||
uint8_t pinCs;
|
||||
uint8_t pinCe;
|
||||
uint8_t pinIrq;
|
||||
uint8_t amplifierPower;
|
||||
} cfgNrf24_t;
|
||||
|
||||
typedef struct {
|
||||
char addr[NTP_ADDR_LEN];
|
||||
uint16_t port;
|
||||
} cfgNtp_t;
|
||||
|
||||
typedef struct {
|
||||
float lat;
|
||||
float lon;
|
||||
bool disNightCom; // disable night communication
|
||||
} cfgSun_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t interval;
|
||||
bool showIv;
|
||||
bool debug;
|
||||
} cfgSerial_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t led0; // first LED pin
|
||||
uint8_t led1; // second LED pin
|
||||
} cfgLed_t;
|
||||
|
||||
typedef struct {
|
||||
char broker[MQTT_ADDR_LEN];
|
||||
uint16_t port;
|
||||
char user[MQTT_USER_LEN];
|
||||
char pwd[MQTT_PWD_LEN];
|
||||
char topic[MQTT_TOPIC_LEN];
|
||||
} cfgMqtt_t;
|
||||
|
||||
typedef struct {
|
||||
bool enabled;
|
||||
char name[MAX_NAME_LENGTH];
|
||||
serial_u serial;
|
||||
uint16_t chMaxPwr[4];
|
||||
char chName[4][MAX_NAME_LENGTH];
|
||||
} cfgIv_t;
|
||||
|
||||
typedef struct {
|
||||
bool enabled;
|
||||
cfgIv_t iv[MAX_NUM_INVERTERS];
|
||||
} cfgInst_t;
|
||||
|
||||
typedef struct {
|
||||
cfgSys_t sys;
|
||||
cfgNrf24_t nrf;
|
||||
cfgNtp_t ntp;
|
||||
cfgSun_t sun;
|
||||
cfgSerial_t serial;
|
||||
cfgMqtt_t mqtt;
|
||||
cfgLed_t led;
|
||||
cfgInst_t inst;
|
||||
} settings_t;
|
||||
|
||||
class settings {
|
||||
public:
|
||||
settings() {}
|
||||
|
||||
void setup() {
|
||||
DPRINTLN(DBG_INFO, F("Initializing FS .."));
|
||||
|
||||
mValid = false;
|
||||
|
||||
LittleFSConfig cfg;
|
||||
cfg.setAutoFormat(false);
|
||||
LittleFS.setConfig(cfg);
|
||||
|
||||
if(!LittleFS.begin()) {
|
||||
DPRINTLN(DBG_INFO, F(".. format .."));
|
||||
LittleFS.format();
|
||||
if(LittleFS.begin())
|
||||
DPRINTLN(DBG_INFO, F(".. success"));
|
||||
else
|
||||
DPRINTLN(DBG_INFO, F(".. failed"));
|
||||
|
||||
}
|
||||
else
|
||||
DPRINTLN(DBG_INFO, F(" .. done"));
|
||||
|
||||
readSettings();
|
||||
}
|
||||
|
||||
// should be used before OTA
|
||||
void stop() {
|
||||
LittleFS.end();
|
||||
DPRINTLN(DBG_INFO, F("FS stopped"));
|
||||
}
|
||||
|
||||
void getPtr(settings_t *&cfg) {
|
||||
cfg = &mCfg;
|
||||
}
|
||||
|
||||
bool getValid(void) {
|
||||
return mValid;
|
||||
}
|
||||
|
||||
void getInfo(uint32_t *used, uint32_t *size) {
|
||||
FSInfo info;
|
||||
LittleFS.info(info);
|
||||
*used = info.usedBytes;
|
||||
*size = info.totalBytes;
|
||||
|
||||
DPRINTLN(DBG_INFO, F("-- FILESYSTEM INFO --"));
|
||||
DPRINTLN(DBG_INFO, String(info.usedBytes) + F(" of ") + String(info.totalBytes) + F(" used"));
|
||||
}
|
||||
|
||||
void readSettings(void) {
|
||||
loadDefaults();
|
||||
File fp = LittleFS.open("/settings.json", "r");
|
||||
if(!fp)
|
||||
DPRINTLN(DBG_WARN, F("failed to load json, using default config"));
|
||||
else {
|
||||
DynamicJsonDocument json(8192);
|
||||
DeserializationError err = deserializeJson(json, fp);
|
||||
if(!err) {
|
||||
mValid = true;
|
||||
JsonObject root = json.to<JsonObject>();
|
||||
jsonWifi(root["wifi"]);
|
||||
jsonNrf(root["nrf"]);
|
||||
jsonNtp(root["ntp"]);
|
||||
jsonSun(root["sun"]);
|
||||
jsonSerial(root["serial"]);
|
||||
jsonMqtt(root["mqtt"]);
|
||||
jsonLed(root["led"]);
|
||||
jsonInst(root["inst"]);
|
||||
}
|
||||
else {
|
||||
Serial.println(F("failed to parse json, using default config"));
|
||||
}
|
||||
|
||||
fp.close();
|
||||
}
|
||||
}
|
||||
|
||||
bool saveSettings(void) {
|
||||
DPRINTLN(DBG_INFO, F("save settings"));
|
||||
File fp = LittleFS.open("/settings.json", "w");
|
||||
if(!fp) {
|
||||
DPRINTLN(DBG_ERROR, F("can't open settings file!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
DynamicJsonDocument json(8192);
|
||||
JsonObject root = json.to<JsonObject>();
|
||||
jsonWifi(root["wifi"], true);
|
||||
jsonNrf(root["nrf"], true);
|
||||
jsonNtp(root["ntp"], true);
|
||||
jsonSun(root["sun"], true);
|
||||
jsonSerial(root["serial"], true);
|
||||
jsonMqtt(root["mqtt"], true);
|
||||
jsonLed(root["led"], true);
|
||||
jsonInst(root["inst"], true);
|
||||
|
||||
if(0 == serializeJson(root, fp)) {
|
||||
DPRINTLN(DBG_ERROR, F("can't write settings file!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool eraseSettings(bool eraseWifi = false) {
|
||||
loadDefaults(eraseWifi);
|
||||
return saveSettings();
|
||||
}
|
||||
|
||||
String ip2Str(uint8_t ip[]) {
|
||||
return String(ip[0]) + F(".")
|
||||
+ String(ip[1]) + F(".")
|
||||
+ String(ip[2]) + F(".")
|
||||
+ String(ip[3]);
|
||||
}
|
||||
|
||||
void ip2Arr(uint8_t ip[], const char *ipStr) {
|
||||
char *tmp = new char[strlen(ipStr)];
|
||||
strncpy(tmp, ipStr, strlen(ipStr));
|
||||
char *p = strtok(tmp, ".");
|
||||
uint8_t i = 0;
|
||||
while(NULL != p) {
|
||||
ip[i++] = atoi(p);
|
||||
p = strtok(NULL, ".");
|
||||
}
|
||||
delete[] tmp;
|
||||
}
|
||||
|
||||
private:
|
||||
void loadDefaults(bool wifi = true) {
|
||||
DPRINTLN(DBG_INFO, F("loadDefaults"));
|
||||
|
||||
memset(&mCfg, 0, sizeof(settings_t));
|
||||
snprintf(mCfg.sys.stationSsid, SSID_LEN, FB_WIFI_SSID);
|
||||
snprintf(mCfg.sys.stationPwd, PWD_LEN, FB_WIFI_PWD);
|
||||
snprintf(mCfg.sys.deviceName, DEVNAME_LEN, DEF_DEVICE_NAME);
|
||||
|
||||
mCfg.nrf.sendInterval = SEND_INTERVAL;
|
||||
mCfg.nrf.maxRetransPerPyld = DEF_MAX_RETRANS_PER_PYLD;
|
||||
mCfg.nrf.pinCs = DEF_CS_PIN;
|
||||
mCfg.nrf.pinCe = DEF_CE_PIN;
|
||||
mCfg.nrf.pinIrq = DEF_IRQ_PIN;
|
||||
mCfg.nrf.amplifierPower = DEF_AMPLIFIERPOWER & 0x03;
|
||||
|
||||
snprintf(mCfg.ntp.addr, NTP_ADDR_LEN, "%s", DEF_NTP_SERVER_NAME);
|
||||
mCfg.ntp.port = DEF_NTP_PORT;
|
||||
|
||||
mCfg.sun.lat = 0.0;
|
||||
mCfg.sun.lon = 0.0;
|
||||
mCfg.sun.disNightCom = false;
|
||||
|
||||
mCfg.serial.interval = SERIAL_INTERVAL;
|
||||
mCfg.serial.showIv = false;
|
||||
mCfg.serial.debug = false;
|
||||
|
||||
mCfg.mqtt.port = DEF_MQTT_PORT;
|
||||
snprintf(mCfg.mqtt.broker, MQTT_ADDR_LEN, "%s", DEF_MQTT_BROKER);
|
||||
snprintf(mCfg.mqtt.user, MQTT_USER_LEN, "%s", DEF_MQTT_USER);
|
||||
snprintf(mCfg.mqtt.pwd, MQTT_PWD_LEN, "%s", DEF_MQTT_PWD);
|
||||
snprintf(mCfg.mqtt.topic, MQTT_TOPIC_LEN, "%s", DEF_MQTT_TOPIC);
|
||||
|
||||
mCfg.led.led0 = DEF_LED0_PIN;
|
||||
mCfg.led.led1 = DEF_LED1_PIN;
|
||||
}
|
||||
|
||||
void jsonWifi(JsonObject obj, bool set = false) {
|
||||
if(set) {
|
||||
obj[F("ssid")] = mCfg.sys.stationSsid;
|
||||
obj[F("pwd")] = mCfg.sys.stationPwd;
|
||||
obj[F("dev")] = mCfg.sys.deviceName;
|
||||
obj[F("adm")] = mCfg.sys.adminPwd;
|
||||
obj[F("ip")] = ip2Str(mCfg.sys.ip.ip);
|
||||
obj[F("mask")] = ip2Str(mCfg.sys.ip.mask);
|
||||
obj[F("dns1")] = ip2Str(mCfg.sys.ip.dns1);
|
||||
obj[F("dns2")] = ip2Str(mCfg.sys.ip.dns2);
|
||||
obj[F("gtwy")] = ip2Str(mCfg.sys.ip.gateway);
|
||||
} else {
|
||||
snprintf(mCfg.sys.stationSsid, SSID_LEN, "%s", obj[F("ssid")].as<const char*>());
|
||||
snprintf(mCfg.sys.stationPwd, PWD_LEN, "%s", obj[F("pwd")].as<const char*>());
|
||||
snprintf(mCfg.sys.deviceName, DEVNAME_LEN, "%s", obj[F("dev")].as<const char*>());
|
||||
snprintf(mCfg.sys.adminPwd, PWD_LEN, "%s", obj[F("adm")].as<const char*>());
|
||||
ip2Arr(mCfg.sys.ip.ip, obj[F("ip")]);
|
||||
ip2Arr(mCfg.sys.ip.mask, obj[F("mask")]);
|
||||
ip2Arr(mCfg.sys.ip.dns1, obj[F("dns1")]);
|
||||
ip2Arr(mCfg.sys.ip.dns2, obj[F("dns2")]);
|
||||
ip2Arr(mCfg.sys.ip.gateway, obj[F("gtwy")]);
|
||||
}
|
||||
}
|
||||
|
||||
void jsonNrf(JsonObject obj, bool set = false) {
|
||||
if(set) {
|
||||
obj[F("intvl")] = mCfg.nrf.sendInterval;
|
||||
obj[F("maxRetry")] = mCfg.nrf.maxRetransPerPyld;
|
||||
obj[F("cs")] = mCfg.nrf.pinCs;
|
||||
obj[F("ce")] = mCfg.nrf.pinCe;
|
||||
obj[F("irq")] = mCfg.nrf.pinIrq;
|
||||
obj[F("pwr")] = mCfg.nrf.amplifierPower;
|
||||
} else {
|
||||
mCfg.nrf.sendInterval = obj[F("intvl")];
|
||||
mCfg.nrf.maxRetransPerPyld = obj[F("maxRetry")];
|
||||
mCfg.nrf.pinCs = obj[F("cs")];
|
||||
mCfg.nrf.pinCe = obj[F("ce")];
|
||||
mCfg.nrf.pinIrq = obj[F("irq")];
|
||||
mCfg.nrf.amplifierPower = obj[F("pwr")];
|
||||
}
|
||||
}
|
||||
|
||||
void jsonNtp(JsonObject obj, bool set = false) {
|
||||
if(set) {
|
||||
obj[F("addr")] = mCfg.ntp.addr;
|
||||
obj[F("port")] = mCfg.ntp.port;
|
||||
} else {
|
||||
snprintf(mCfg.ntp.addr, NTP_ADDR_LEN, "%s", obj[F("addr")].as<const char*>());
|
||||
mCfg.ntp.port = obj[F("port")];
|
||||
}
|
||||
}
|
||||
|
||||
void jsonSun(JsonObject obj, bool set = false) {
|
||||
if(set) {
|
||||
obj[F("lat")] = mCfg.sun.lat;
|
||||
obj[F("lon")] = mCfg.sun.lon;
|
||||
obj[F("dis")] = mCfg.sun.disNightCom;
|
||||
} else {
|
||||
mCfg.sun.lat = obj[F("lat")];
|
||||
mCfg.sun.lon = obj[F("lon")];
|
||||
mCfg.sun.disNightCom = obj[F("dis")];
|
||||
}
|
||||
}
|
||||
|
||||
void jsonSerial(JsonObject obj, bool set = false) {
|
||||
if(set) {
|
||||
obj[F("intvl")] = mCfg.serial.interval;
|
||||
obj[F("show")] = mCfg.serial.showIv;
|
||||
obj[F("debug")] = mCfg.serial.debug;
|
||||
} else {
|
||||
mCfg.serial.interval = obj[F("intvl")];
|
||||
mCfg.serial.showIv = obj[F("show")];
|
||||
mCfg.serial.debug = obj[F("debug")];
|
||||
}
|
||||
}
|
||||
|
||||
void jsonMqtt(JsonObject obj, bool set = false) {
|
||||
if(set) {
|
||||
obj[F("broker")] = mCfg.mqtt.broker;
|
||||
obj[F("port")] = mCfg.mqtt.port;
|
||||
obj[F("user")] = mCfg.mqtt.user;
|
||||
obj[F("pwd")] = mCfg.mqtt.pwd;
|
||||
obj[F("topic")] = mCfg.mqtt.topic;
|
||||
} else {
|
||||
mCfg.mqtt.port = obj[F("port")];
|
||||
snprintf(mCfg.mqtt.broker, MQTT_ADDR_LEN, "%s", obj[F("broker")].as<const char*>());
|
||||
snprintf(mCfg.mqtt.user, MQTT_USER_LEN, "%s", obj[F("user")].as<const char*>());
|
||||
snprintf(mCfg.mqtt.pwd, MQTT_PWD_LEN, "%s", obj[F("pwd")].as<const char*>());
|
||||
snprintf(mCfg.mqtt.topic, MQTT_TOPIC_LEN, "%s", obj[F("topic")].as<const char*>());
|
||||
}
|
||||
}
|
||||
|
||||
void jsonLed(JsonObject obj, bool set = false) {
|
||||
if(set) {
|
||||
obj["0"] = mCfg.led.led0;
|
||||
obj["1"] = mCfg.led.led1;
|
||||
} else {
|
||||
mCfg.led.led0 = obj["0"];
|
||||
mCfg.led.led1 = obj["1"];
|
||||
}
|
||||
}
|
||||
|
||||
void jsonInst(JsonObject obj, bool set = false) {
|
||||
if(set) {
|
||||
obj["en"] = mCfg.inst.enabled;
|
||||
} else {
|
||||
mCfg.inst.enabled = obj["en"];
|
||||
}
|
||||
for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) {
|
||||
jsonIv(obj["iv"][i], mCfg.inst.iv[i], set);
|
||||
}
|
||||
}
|
||||
|
||||
void jsonIv(JsonObject obj, cfgIv_t cfg, bool set = false) {
|
||||
if(set) {
|
||||
obj["en"] = cfg.enabled;
|
||||
obj["name"] = cfg.name;
|
||||
obj["serial"] = cfg.serial.u64;
|
||||
for(uint8_t i = 0; i < 4; i++) {
|
||||
obj["chPwr"][i] = cfg.chMaxPwr[i];
|
||||
obj["chName"][i] = cfg.chName[i];
|
||||
}
|
||||
} else {
|
||||
cfg.enabled = obj["en"];
|
||||
snprintf(cfg.name, MAX_NAME_LENGTH, "%s", obj[F("name")].as<const char*>());
|
||||
cfg.serial.u64 = obj["serial"];
|
||||
for(uint8_t i = 0; i < 4; i++) {
|
||||
cfg.chMaxPwr[i] = obj["chPwr"][i];
|
||||
snprintf(cfg.chName[i], MAX_NAME_LENGTH, "%s", obj["chName"][i].as<const char*>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
settings_t mCfg;
|
||||
bool mValid;
|
||||
};
|
||||
|
||||
#endif /*__SETTINGS_H__*/
|
150
src/defines.h
150
src/defines.h
|
@ -13,7 +13,7 @@
|
|||
//-------------------------------------
|
||||
#define VERSION_MAJOR 0
|
||||
#define VERSION_MINOR 5
|
||||
#define VERSION_PATCH 35
|
||||
#define VERSION_PATCH 36
|
||||
|
||||
//-------------------------------------
|
||||
typedef struct {
|
||||
|
@ -63,6 +63,11 @@ typedef enum {
|
|||
RelativPersistent = 257UL // 0x0101
|
||||
} PowerLimitControlType;
|
||||
|
||||
union serial_u {
|
||||
uint64_t u64;
|
||||
uint8_t b[8];
|
||||
};
|
||||
|
||||
#define MIN_SERIAL_INTERVAL 5
|
||||
#define MIN_SEND_INTERVAL 15
|
||||
#define MIN_MQTT_INTERVAL 60
|
||||
|
@ -78,116 +83,14 @@ typedef enum {
|
|||
#define SSID_LEN 32
|
||||
#define PWD_LEN 64
|
||||
#define DEVNAME_LEN 16
|
||||
#define CRC_LEN 2 // uint16_t
|
||||
#define DISCLAIMER_LEN 1
|
||||
#define STATIC_IP_LEN 16 // 4x uint32_t
|
||||
#define STATUS_LED_LEN 2 // 2x uint8_t
|
||||
|
||||
#define INV_ADDR_LEN MAX_NUM_INVERTERS * 8 // uint64_t
|
||||
#define INV_NAME_LEN MAX_NUM_INVERTERS * MAX_NAME_LENGTH // char[]
|
||||
#define INV_CH_CH_PWR_LEN MAX_NUM_INVERTERS * 2 * 4 // uint16_t (4 channels)
|
||||
#define INV_CH_CH_NAME_LEN MAX_NUM_INVERTERS * MAX_NAME_LENGTH * 4 // (4 channels)
|
||||
#define INV_INTERVAL_LEN 2 // uint16_t
|
||||
#define INV_MAX_RTRY_LEN 1 // uint8_t
|
||||
#define INV_ENABLED_LEN 1 // uint8_t
|
||||
|
||||
#define CFG_SUN_LEN 9 // 2x float(4+4) + bool(1)
|
||||
|
||||
#define NTP_ADDR_LEN 32 // DNS Name
|
||||
|
||||
#define MQTT_ADDR_LEN 32 // DNS Name
|
||||
#define MQTT_USER_LEN 16
|
||||
#define MQTT_PWD_LEN 32
|
||||
#define MQTT_TOPIC_LEN 32
|
||||
#define MQTT_DISCOVERY_PREFIX "homeassistant"
|
||||
#define MQTT_TOPIC_LEN 64
|
||||
|
||||
#define MQTT_MAX_PACKET_SIZE 384
|
||||
#define MQTT_RECONNECT_DELAY 5000
|
||||
|
||||
#pragma pack(push) // push current alignment to stack
|
||||
#pragma pack(1) // set alignment to 1 byte boundary
|
||||
typedef struct {
|
||||
char broker[MQTT_ADDR_LEN];
|
||||
uint16_t port;
|
||||
char user[MQTT_USER_LEN];
|
||||
char pwd[MQTT_PWD_LEN];
|
||||
char topic[MQTT_TOPIC_LEN];
|
||||
} mqttConfig_t;
|
||||
#pragma pack(pop) // restore original alignment from stack
|
||||
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
typedef struct {
|
||||
char deviceName[DEVNAME_LEN];
|
||||
|
||||
// wifi
|
||||
char stationSsid[SSID_LEN];
|
||||
char stationPwd[PWD_LEN];
|
||||
} sysConfig_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
typedef struct {
|
||||
uint8_t ip[4]; // ip address
|
||||
uint8_t mask[4]; // sub mask
|
||||
uint8_t dns[4]; // dns
|
||||
uint8_t gateway[4]; // standard gateway
|
||||
} staticIp_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
typedef struct {
|
||||
uint8_t led0; // first led pin
|
||||
uint8_t led1; // second led pin
|
||||
} statusLed_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
typedef struct {
|
||||
// protection
|
||||
char password[PWD_LEN];
|
||||
|
||||
// nrf24
|
||||
uint16_t sendInterval;
|
||||
uint8_t maxRetransPerPyld;
|
||||
uint8_t pinCs;
|
||||
uint8_t pinCe;
|
||||
uint8_t pinIrq;
|
||||
uint8_t amplifierPower;
|
||||
|
||||
// Disclaimer
|
||||
bool disclaimer;
|
||||
|
||||
// ntp
|
||||
char ntpAddr[NTP_ADDR_LEN];
|
||||
uint16_t ntpPort;
|
||||
|
||||
// mqtt
|
||||
mqttConfig_t mqtt;
|
||||
|
||||
// sun
|
||||
float sunLat;
|
||||
float sunLon;
|
||||
bool sunDisNightCom; // disable night communication
|
||||
|
||||
// serial
|
||||
uint16_t serialInterval;
|
||||
bool serialShowIv;
|
||||
bool serialDebug;
|
||||
|
||||
// static ip
|
||||
staticIp_t staticIp;
|
||||
|
||||
// status LED(s)
|
||||
statusLed_t led;
|
||||
} config_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t rxFail;
|
||||
|
@ -196,41 +99,4 @@ typedef struct {
|
|||
uint32_t frmCnt;
|
||||
} statistics_t;
|
||||
|
||||
|
||||
#define CFG_MQTT_LEN MQTT_ADDR_LEN + 2 + MQTT_USER_LEN + MQTT_PWD_LEN +MQTT_TOPIC_LEN
|
||||
#define CFG_SYS_LEN DEVNAME_LEN + SSID_LEN + PWD_LEN
|
||||
#define CFG_LEN PWD_LEN + 7 + DISCLAIMER_LEN + NTP_ADDR_LEN + 2 + CFG_MQTT_LEN + CFG_SUN_LEN + 4 + STATIC_IP_LEN + STATUS_LED_LEN
|
||||
|
||||
#define ADDR_START 0
|
||||
#define ADDR_CFG_SYS ADDR_START
|
||||
#define ADDR_WIFI_CRC ADDR_CFG_SYS + CFG_SYS_LEN
|
||||
#define ADDR_START_SETTINGS ADDR_WIFI_CRC + CRC_LEN
|
||||
|
||||
#define ADDR_CFG ADDR_START_SETTINGS
|
||||
#define ADDR_CFG_INVERTER ADDR_CFG + CFG_LEN
|
||||
|
||||
#define ADDR_INV_ADDR ADDR_CFG_INVERTER
|
||||
#define ADDR_INV_NAME ADDR_INV_ADDR + INV_ADDR_LEN
|
||||
#define ADDR_INV_CH_PWR ADDR_INV_NAME + INV_NAME_LEN
|
||||
#define ADDR_INV_CH_NAME ADDR_INV_CH_PWR + INV_CH_CH_PWR_LEN
|
||||
#define ADDR_INV_INTERVAL ADDR_INV_CH_NAME + INV_CH_CH_NAME_LEN
|
||||
#define ADDR_INV_MAX_RTRY ADDR_INV_INTERVAL + INV_INTERVAL_LEN
|
||||
#define ADDR_INV_ENABLED ADDR_INV_MAX_RTRY + INV_MAX_RTRY_LEN
|
||||
|
||||
#define ADDR_NEXT ADDR_INV_MAX_RTRY + INV_ENABLED_LEN
|
||||
|
||||
|
||||
#define ADDR_SETTINGS_CRC ADDR_NEXT + 2
|
||||
|
||||
#if(ADDR_SETTINGS_CRC <= ADDR_NEXT)
|
||||
#pragma error "address overlap! (ADDR_SETTINGS_CRC="+ ADDR_SETTINGS_CRC +", ADDR_NEXT="+ ADDR_NEXT +")"
|
||||
#endif
|
||||
|
||||
#if(ADDR_SETTINGS_CRC >= 4096 - CRC_LEN)
|
||||
#pragma error "EEPROM size exceeded! (ADDR_SETTINGS_CRC="+ ADDR_SETTINGS_CRC +", CRC_LEN="+ CRC_LEN +")"
|
||||
#pragma error "Configure less inverters? (MAX_NUM_INVERTERS=" + MAX_NUM_INVERTERS +")"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif /*__DEFINES_H__*/
|
||||
|
|
|
@ -9,13 +9,6 @@
|
|||
#include "../utils/dbg.h"
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
union serial_u {
|
||||
uint64_t u64;
|
||||
uint8_t b[8];
|
||||
};
|
||||
|
||||
|
||||
// units
|
||||
enum {UNIT_V = 0, UNIT_A, UNIT_W, UNIT_WH, UNIT_KWH, UNIT_HZ, UNIT_C, UNIT_PCT, UNIT_VAR, UNIT_NONE};
|
||||
const char* const units[] = {"V", "A", "W", "Wh", "kWh", "Hz", "°C", "%", "var", ""};
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "hmDefines.h"
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include "../config/settings.h"
|
||||
|
||||
/**
|
||||
* For values which are of interest and not transmitted by the inverter can be
|
||||
|
@ -104,8 +105,8 @@ const calcFunc_t<T> calcFunctions[] = {
|
|||
template <class REC_TYP>
|
||||
class Inverter {
|
||||
public:
|
||||
cfgIv_t *config; // stored settings
|
||||
uint8_t id; // unique id
|
||||
char name[MAX_NAME_LENGTH]; // human readable name, eg. "HM-600.1"
|
||||
uint8_t type; // integer which refers to inverter type
|
||||
uint16_t alarmMesIndex; // Last recorded Alarm Message Index
|
||||
uint16_t fwVersion; // Firmware Version from Info Command Request
|
||||
|
@ -113,15 +114,12 @@ class Inverter {
|
|||
float actPowerLimit; // actual power limit
|
||||
uint8_t devControlCmd; // carries the requested cmd
|
||||
bool devControlRequest; // true if change needed
|
||||
serial_u serial; // serial number as on barcode
|
||||
serial_u radioId; // id converted to modbus
|
||||
uint8_t channels; // number of PV channels (1-4)
|
||||
record_t<REC_TYP> recordMeas; // structure for measured values
|
||||
record_t<REC_TYP> recordInfo; // structure for info values
|
||||
record_t<REC_TYP> recordConfig; // structure for system config values
|
||||
record_t<REC_TYP> recordAlarm; // structure for alarm values
|
||||
uint16_t chMaxPwr[4]; // maximum power of the modules (Wp)
|
||||
char chName[4][MAX_NAME_LENGTH]; // human readable name for channels
|
||||
String lastAlarmMsg;
|
||||
bool initialized; // needed to check if the inverter was correctly added (ESP32 specific - union types are never null)
|
||||
|
||||
|
@ -185,8 +183,6 @@ class Inverter {
|
|||
initAssignment(&recordConfig, SystemConfigPara);
|
||||
initAssignment(&recordAlarm, AlarmData);
|
||||
toRadioId();
|
||||
memset(name, 0, MAX_NAME_LENGTH);
|
||||
memset(chName, 0, MAX_NAME_LENGTH * 4);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
|
@ -484,10 +480,10 @@ class Inverter {
|
|||
void toRadioId(void) {
|
||||
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:toRadioId"));
|
||||
radioId.u64 = 0ULL;
|
||||
radioId.b[4] = serial.b[0];
|
||||
radioId.b[3] = serial.b[1];
|
||||
radioId.b[2] = serial.b[2];
|
||||
radioId.b[1] = serial.b[3];
|
||||
radioId.b[4] = config->serial.b[0];
|
||||
radioId.b[3] = config->serial.b[1];
|
||||
radioId.b[2] = config->serial.b[2];
|
||||
radioId.b[1] = config->serial.b[3];
|
||||
radioId.b[0] = 0x01;
|
||||
}
|
||||
};
|
||||
|
@ -583,8 +579,8 @@ static T calcIrradiation(Inverter<> *iv, uint8_t arg0) {
|
|||
if(NULL != iv) {
|
||||
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||
uint8_t pos = iv->getPosByChFld(arg0, FLD_PDC, rec);
|
||||
if(iv->chMaxPwr[arg0-1] > 0)
|
||||
return iv->getValue(pos, rec) / iv->chMaxPwr[arg0-1] * 100.0f;
|
||||
if(iv->config->chMaxPwr[arg0-1] > 0)
|
||||
return iv->getValue(pos, rec) / iv->config->chMaxPwr[arg0-1] * 100.0f;
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,18 @@ class HmSystem {
|
|||
Radio.setup(&BufCtrl, ampPwr, irqPin, cePin, csPin);
|
||||
}
|
||||
|
||||
INVERTERTYPE *addInverter(const char *name, uint64_t serial, uint16_t chMaxPwr[]) {
|
||||
void addInverters(cfgInst_t *config) {
|
||||
Inverter<> *iv;
|
||||
for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) {
|
||||
if (0ULL != config->iv[i].serial.u64) {
|
||||
iv = addInverter(&config->iv[i]);
|
||||
if (NULL != iv)
|
||||
DPRINTLN(DBG_INFO, "added inverter " + String(iv->config->serial.u64, HEX));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INVERTERTYPE *addInverter(cfgIv_t *config) {
|
||||
DPRINTLN(DBG_VERBOSE, F("hmSystem.h:addInverter"));
|
||||
if(MAX_INVERTER <= mNumInv) {
|
||||
DPRINT(DBG_WARN, F("max number of inverters reached!"));
|
||||
|
@ -45,18 +56,17 @@ class HmSystem {
|
|||
}
|
||||
INVERTERTYPE *p = &mInverter[mNumInv];
|
||||
p->id = mNumInv;
|
||||
p->serial.u64 = serial;
|
||||
memcpy(p->chMaxPwr, chMaxPwr, (4*2));
|
||||
DPRINT(DBG_VERBOSE, "SERIAL: " + String(p->serial.b[5], HEX));
|
||||
DPRINTLN(DBG_VERBOSE, " " + String(p->serial.b[4], HEX));
|
||||
if(p->serial.b[5] == 0x11) {
|
||||
switch(p->serial.b[4]) {
|
||||
p->config = config;
|
||||
DPRINT(DBG_VERBOSE, "SERIAL: " + String(p->config->serial.b[5], HEX));
|
||||
DPRINTLN(DBG_VERBOSE, " " + String(p->config->serial.b[4], HEX));
|
||||
if(p->config->serial.b[5] == 0x11) {
|
||||
switch(p->config->serial.b[4]) {
|
||||
case 0x21: p->type = INV_TYPE_1CH; break;
|
||||
case 0x41: p->type = INV_TYPE_2CH; break;
|
||||
case 0x61: p->type = INV_TYPE_4CH; break;
|
||||
default:
|
||||
DPRINT(DBG_ERROR, F("unknown inverter type: 11"));
|
||||
DPRINTLN(DBG_ERROR, String(p->serial.b[4], HEX));
|
||||
DPRINTLN(DBG_ERROR, String(p->config->serial.b[4], HEX));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -64,8 +74,6 @@ class HmSystem {
|
|||
DPRINTLN(DBG_ERROR, F("inverter type can't be detected!"));
|
||||
|
||||
p->init();
|
||||
uint8_t len = (uint8_t)strlen(name);
|
||||
strncpy(p->name, name, (len > MAX_NAME_LENGTH) ? MAX_NAME_LENGTH : len);
|
||||
|
||||
mNumInv ++;
|
||||
return p;
|
||||
|
@ -76,10 +84,10 @@ class HmSystem {
|
|||
INVERTERTYPE *p;
|
||||
for(uint8_t i = 0; i < mNumInv; i++) {
|
||||
p = &mInverter[i];
|
||||
if((p->serial.b[3] == buf[0])
|
||||
&& (p->serial.b[2] == buf[1])
|
||||
&& (p->serial.b[1] == buf[2])
|
||||
&& (p->serial.b[0] == buf[3]))
|
||||
if((p->config->serial.b[3] == buf[0])
|
||||
&& (p->config->serial.b[2] == buf[1])
|
||||
&& (p->config->serial.b[1] == buf[2])
|
||||
&& (p->config->serial.b[0] == buf[3]))
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
|
@ -89,7 +97,7 @@ class HmSystem {
|
|||
DPRINTLN(DBG_VERBOSE, F("hmSystem.h:getInverterByPos"));
|
||||
if(pos >= MAX_INVERTER)
|
||||
return NULL;
|
||||
else if((mInverter[pos].initialized && mInverter[pos].serial.u64 != 0ULL) || false == check)
|
||||
else if((mInverter[pos].initialized && mInverter[pos].config->serial.u64 != 0ULL) || false == check)
|
||||
return &mInverter[pos];
|
||||
else
|
||||
return NULL;
|
||||
|
|
|
@ -10,12 +10,13 @@
|
|||
|
||||
[platformio]
|
||||
src_dir = .
|
||||
include_dir = .
|
||||
|
||||
[env]
|
||||
framework = arduino
|
||||
board_build.filesystem = littlefs
|
||||
|
||||
build_flags =
|
||||
-include "config.h"
|
||||
;build_flags =
|
||||
; ;;;;; Possible Debug options ;;;;;;
|
||||
; https://docs.platformio.org/en/latest/platforms/espressif8266.html#debug-level
|
||||
;-DDEBUG_ESP_PORT=Serial
|
||||
|
@ -43,6 +44,7 @@ lib_deps =
|
|||
;esp8266/SPI
|
||||
;esp8266/Ticker
|
||||
|
||||
|
||||
[env:esp8266-release]
|
||||
platform = espressif8266
|
||||
board = esp12e
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 2022 Ahoy, https://www.mikrocontroller.net/topic/525778
|
||||
// 2022 Ahoy, https://ahoydtu.de
|
||||
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 2022 Ahoy, https://www.mikrocontroller.net/topic/525778
|
||||
// 2022 Ahoy, https://ahoydtu.de
|
||||
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@
|
|||
});
|
||||
document.getElementById("scroll").addEventListener("click", function() {
|
||||
mAutoScroll = !mAutoScroll;
|
||||
this.value = (mAutoScroll) ? "autoscroll" : "manual scoll";
|
||||
this.value = (mAutoScroll) ? "autoscroll" : "manual scroll";
|
||||
});
|
||||
|
||||
if (!!window.EventSource) {
|
||||
|
|
|
@ -67,8 +67,10 @@
|
|||
<input type="text" name="ipAddr" class="text" maxlength="15" />
|
||||
<label for="ipMask">Submask</label>
|
||||
<input type="text" name="ipMask" class="text" maxlength="15" />
|
||||
<label for="ipDns">DNS</label>
|
||||
<input type="text" name="ipDns" class="text" maxlength="15" />
|
||||
<label for="ipDns1">DNS 1</label>
|
||||
<input type="text" name="ipDns1" class="text" maxlength="15" />
|
||||
<label for="ipDns2">DNS 2</label>
|
||||
<input type="text" name="ipDns2" class="text" maxlength="15" />
|
||||
<label for="ipGateway">Gateway</label>
|
||||
<input type="text" name="ipGateway" class="text" maxlength="15" />
|
||||
</fieldset>
|
||||
|
@ -332,7 +334,7 @@
|
|||
}
|
||||
|
||||
function parseStaticIp(obj) {
|
||||
for(var i of [["ipAddr", "ip"], ["ipMask", "mask"], ["ipDns", "dns"], ["ipGateway", "gateway"]])
|
||||
for(var i of [["ipAddr", "ip"], ["ipMask", "mask"], ["ipDns1", "dns1"], ["ipDns2", "dns2"], ["ipGateway", "gateway"]])
|
||||
if(null != obj[i[1]])
|
||||
document.getElementsByName(i[0])[0].value = obj[i[1]];
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 2022 Ahoy, https://www.mikrocontroller.net/topic/525778
|
||||
// 2022 Ahoy, https://ahoydtu.de
|
||||
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
@ -21,9 +21,9 @@
|
|||
#include "../utils/ahoyTimer.h"
|
||||
#include "../config/config.h"
|
||||
#include <PubSubClient.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include "../defines.h"
|
||||
#include "../hm/hmSystem.h"
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
template<class HMSYSTEM>
|
||||
class mqtt {
|
||||
|
@ -34,18 +34,16 @@ class mqtt {
|
|||
|
||||
mLastReconnect = 0;
|
||||
mTxCnt = 0;
|
||||
|
||||
memset(mDevName, 0, DEVNAME_LEN);
|
||||
}
|
||||
|
||||
~mqtt() { }
|
||||
|
||||
void setup(mqttConfig_t *cfg, const char *devname, const char *version, HMSYSTEM *sys, uint32_t *utcTs) {
|
||||
void setup(cfgMqtt_t *cfg, const char *devName, const char *version, HMSYSTEM *sys, uint32_t *utcTs) {
|
||||
DPRINTLN(DBG_VERBOSE, F("mqtt.h:setup"));
|
||||
mAddressSet = true;
|
||||
|
||||
snprintf(mDevName, DEVNAME_LEN, "%s", devname);
|
||||
mCfg = cfg;
|
||||
mDevName = devName;
|
||||
mSys = sys;
|
||||
mUtcTimestamp = utcTs;
|
||||
|
||||
|
@ -55,7 +53,7 @@ class mqtt {
|
|||
setCallback(std::bind(&mqtt<HMSYSTEM>::cbMqtt, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
|
||||
sendMsg("version", version);
|
||||
sendMsg("device", devname);
|
||||
sendMsg("device", devName);
|
||||
sendMsg("uptime", "0");
|
||||
}
|
||||
|
||||
|
@ -76,8 +74,8 @@ class mqtt {
|
|||
void sendMsg(const char *topic, const char *msg) {
|
||||
//DPRINTLN(DBG_VERBOSE, F("mqtt.h:sendMsg"));
|
||||
if(mAddressSet) {
|
||||
char top[64];
|
||||
snprintf(top, 64, "%s/%s", mCfg->topic, topic);
|
||||
char top[66];
|
||||
snprintf(top, 66, "%s/%s", mCfg->topic, topic);
|
||||
sendMsg2(top, msg, false);
|
||||
}
|
||||
}
|
||||
|
@ -118,22 +116,22 @@ class mqtt {
|
|||
if (NULL != iv) {
|
||||
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||
DynamicJsonDocument deviceDoc(128);
|
||||
deviceDoc["name"] = iv->name;
|
||||
deviceDoc["ids"] = String(iv->serial.u64, HEX);
|
||||
deviceDoc["name"] = iv->config->name;
|
||||
deviceDoc["ids"] = String(iv->config->serial.u64, HEX);
|
||||
deviceDoc["cu"] = F("http://") + String(WiFi.localIP().toString());
|
||||
deviceDoc["mf"] = "Hoymiles";
|
||||
deviceDoc["mdl"] = iv->name;
|
||||
deviceDoc["mdl"] = iv->config->name;
|
||||
JsonObject deviceObj = deviceDoc.as<JsonObject>();
|
||||
DynamicJsonDocument doc(384);
|
||||
|
||||
for (uint8_t i = 0; i < rec->length; i++) {
|
||||
if (rec->assign[i].ch == CH0) {
|
||||
snprintf(name, 32, "%s %s", iv->name, iv->getFieldName(i, rec));
|
||||
snprintf(name, 32, "%s %s", iv->config->name, iv->getFieldName(i, rec));
|
||||
} else {
|
||||
snprintf(name, 32, "%s CH%d %s", iv->name, rec->assign[i].ch, iv->getFieldName(i, rec));
|
||||
snprintf(name, 32, "%s CH%d %s", iv->config->name, rec->assign[i].ch, iv->getFieldName(i, rec));
|
||||
}
|
||||
snprintf(stateTopic, 64, "%s/%s/ch%d/%s", topic, iv->name, rec->assign[i].ch, iv->getFieldName(i, rec));
|
||||
snprintf(discoveryTopic, 64, "%s/sensor/%s/ch%d_%s/config", MQTT_DISCOVERY_PREFIX, iv->name, rec->assign[i].ch, iv->getFieldName(i, rec));
|
||||
snprintf(stateTopic, 64, "%s/%s/ch%d/%s", topic, iv->config->name, rec->assign[i].ch, iv->getFieldName(i, rec));
|
||||
snprintf(discoveryTopic, 64, "%s/sensor/%s/ch%d_%s/config", MQTT_DISCOVERY_PREFIX, iv->config->name, rec->assign[i].ch, iv->getFieldName(i, rec));
|
||||
snprintf(uniq_id, 32, "ch%d_%s", rec->assign[i].ch, iv->getFieldName(i, rec));
|
||||
const char *devCls = getFieldDeviceClass(rec->assign[i].fieldId);
|
||||
const char *stateCls = getFieldStateClass(rec->assign[i].fieldId);
|
||||
|
@ -141,7 +139,7 @@ class mqtt {
|
|||
doc["name"] = name;
|
||||
doc["stat_t"] = stateTopic;
|
||||
doc["unit_of_meas"] = iv->getUnit(i, rec);
|
||||
doc["uniq_id"] = String(iv->serial.u64, HEX) + "_" + uniq_id;
|
||||
doc["uniq_id"] = String(iv->config->serial.u64, HEX) + "_" + uniq_id;
|
||||
doc["dev"] = deviceObj;
|
||||
doc["exp_aft"] = MQTT_INTERVAL + 5; // add 5 sec if connection is bad or ESP too slow @TODO: stimmt das wirklich als expire!?
|
||||
if (devCls != NULL)
|
||||
|
@ -248,7 +246,7 @@ class mqtt {
|
|||
if (MQTT_STATUS_AVAIL_PROD == status)
|
||||
status = MQTT_STATUS_AVAIL_NOT_PROD;
|
||||
}
|
||||
snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/available_text", iv->name);
|
||||
snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/available_text", iv->config->name);
|
||||
snprintf(val, 40, "%s%s%s%s",
|
||||
(status == MQTT_STATUS_NOT_AVAIL_NOT_PROD) ? "not yet " : "",
|
||||
"available and ",
|
||||
|
@ -257,11 +255,11 @@ class mqtt {
|
|||
);
|
||||
sendMsg(topic, val);
|
||||
|
||||
snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/available", iv->name);
|
||||
snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/available", iv->config->name);
|
||||
snprintf(val, 40, "%d", status);
|
||||
sendMsg(topic, val);
|
||||
|
||||
snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/last_success", iv->name);
|
||||
snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/last_success", iv->config->name);
|
||||
snprintf(val, 40, "%i", iv->getLastTs(rec) * 1000);
|
||||
sendMsg(topic, val);
|
||||
}
|
||||
|
@ -269,7 +267,7 @@ class mqtt {
|
|||
// data
|
||||
if(iv->isAvailable(*mUtcTimestamp, rec)) {
|
||||
for (uint8_t i = 0; i < rec->length; i++) {
|
||||
snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/ch%d/%s", iv->name, rec->assign[i].ch, fields[rec->assign[i].fieldId]);
|
||||
snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/ch%d/%s", iv->config->name, rec->assign[i].ch, fields[rec->assign[i].fieldId]);
|
||||
snprintf(val, 40, "%.3f", iv->getValue(i, rec));
|
||||
sendMsg(topic, val);
|
||||
|
||||
|
@ -435,8 +433,8 @@ class mqtt {
|
|||
uint32_t *mUtcTimestamp;
|
||||
|
||||
bool mAddressSet;
|
||||
mqttConfig_t *mCfg;
|
||||
char mDevName[DEVNAME_LEN];
|
||||
cfgMqtt_t *mCfg;
|
||||
const char *mDevName;
|
||||
uint32_t mLastReconnect;
|
||||
uint32_t mTxCnt;
|
||||
std::queue<uint8_t> mSendList;
|
||||
|
|
104
src/web/web.cpp
104
src/web/web.cpp
|
@ -26,15 +26,14 @@
|
|||
const char* const pinArgNames[] = {"pinCs", "pinCe", "pinIrq", "pinLed0", "pinLed1"};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
web::web(app *main, sysConfig_t *sysCfg, config_t *config, statistics_t *stat, char version[]) {
|
||||
web::web(app *main, settings_t *config, statistics_t *stat, char version[]) {
|
||||
mMain = main;
|
||||
mSysCfg = sysCfg;
|
||||
mConfig = config;
|
||||
mStat = stat;
|
||||
mVersion = version;
|
||||
mWeb = new AsyncWebServer(80);
|
||||
mEvts = new AsyncEventSource("/events");
|
||||
mApi = new webApi(mWeb, main, sysCfg, config, stat, version);
|
||||
mApi = new webApi(mWeb, main, config, stat, version);
|
||||
|
||||
mProtected = true;
|
||||
mLogoutTimeout = 0;
|
||||
|
@ -151,7 +150,7 @@ void web::onLogin(AsyncWebServerRequest *request) {
|
|||
DPRINTLN(DBG_VERBOSE, F("onLogin"));
|
||||
|
||||
if(request->args() > 0) {
|
||||
if(String(request->arg("pwd")) == String(mConfig->password)) {
|
||||
if(String(request->arg("pwd")) == String(mConfig->sys.adminPwd)) {
|
||||
mProtected = false;
|
||||
request->redirect("/");
|
||||
}
|
||||
|
@ -260,7 +259,7 @@ void web::showErase(AsyncWebServerRequest *request) {
|
|||
}
|
||||
|
||||
DPRINTLN(DBG_VERBOSE, F("showErase"));
|
||||
mMain->eraseSettings();
|
||||
mMain->eraseSettings(false);
|
||||
onReboot(request);
|
||||
}
|
||||
|
||||
|
@ -277,9 +276,11 @@ void web::showFactoryRst(AsyncWebServerRequest *request) {
|
|||
int refresh = 3;
|
||||
if(request->args() > 0) {
|
||||
if(request->arg("reset").toInt() == 1) {
|
||||
mMain->eraseSettings(true);
|
||||
content = F("factory reset: success\n\nrebooting ... ");
|
||||
refresh = 10;
|
||||
if(mMain->eraseSettings(true))
|
||||
content = F("factory reset: success\n\nrebooting ... ");
|
||||
else
|
||||
content = F("factory reset: failed\n\nrebooting ... ");
|
||||
}
|
||||
else {
|
||||
content = F("factory reset: aborted");
|
||||
|
@ -328,48 +329,52 @@ void web::showSave(AsyncWebServerRequest *request) {
|
|||
|
||||
// general
|
||||
if(request->arg("ssid") != "")
|
||||
request->arg("ssid").toCharArray(mSysCfg->stationSsid, SSID_LEN);
|
||||
request->arg("ssid").toCharArray(mConfig->sys.stationSsid, SSID_LEN);
|
||||
if(request->arg("pwd") != "{PWD}")
|
||||
request->arg("pwd").toCharArray(mSysCfg->stationPwd, PWD_LEN);
|
||||
request->arg("pwd").toCharArray(mConfig->sys.stationPwd, PWD_LEN);
|
||||
if(request->arg("device") != "")
|
||||
request->arg("device").toCharArray(mSysCfg->deviceName, DEVNAME_LEN);
|
||||
request->arg("device").toCharArray(mConfig->sys.deviceName, DEVNAME_LEN);
|
||||
if(request->arg("adminpwd") != "{PWD}") {
|
||||
request->arg("adminpwd").toCharArray(mConfig->password, PWD_LEN);
|
||||
mProtected = (strlen(mConfig->password) > 0);
|
||||
request->arg("adminpwd").toCharArray(mConfig->sys.adminPwd, PWD_LEN);
|
||||
mProtected = (strlen(mConfig->sys.adminPwd) > 0);
|
||||
}
|
||||
|
||||
|
||||
// static ip
|
||||
if(request->arg("ipAddr") != "") {
|
||||
request->arg("ipAddr").toCharArray(buf, SSID_LEN);
|
||||
ip2Arr(mConfig->staticIp.ip, buf);
|
||||
ip2Arr(mConfig->sys.ip.ip, buf);
|
||||
if(request->arg("ipMask") != "") {
|
||||
request->arg("ipMask").toCharArray(buf, SSID_LEN);
|
||||
ip2Arr(mConfig->staticIp.mask, buf);
|
||||
ip2Arr(mConfig->sys.ip.mask, buf);
|
||||
}
|
||||
if(request->arg("ipDns") != "") {
|
||||
request->arg("ipDns").toCharArray(buf, SSID_LEN);
|
||||
ip2Arr(mConfig->staticIp.dns, buf);
|
||||
if(request->arg("ipDns1") != "") {
|
||||
request->arg("ipDns1").toCharArray(buf, SSID_LEN);
|
||||
ip2Arr(mConfig->sys.ip.dns1, buf);
|
||||
}
|
||||
if(request->arg("ipDns2") != "") {
|
||||
request->arg("ipDns2").toCharArray(buf, SSID_LEN);
|
||||
ip2Arr(mConfig->sys.ip.dns2, buf);
|
||||
}
|
||||
if(request->arg("ipGateway") != "") {
|
||||
request->arg("ipGateway").toCharArray(buf, SSID_LEN);
|
||||
ip2Arr(mConfig->staticIp.gateway, buf);
|
||||
ip2Arr(mConfig->sys.ip.gateway, buf);
|
||||
}
|
||||
}
|
||||
else
|
||||
memset(&mConfig->staticIp, 0, sizeof(staticIp_t));
|
||||
memset(&mConfig->sys.ip.ip, 0, 4);
|
||||
|
||||
|
||||
// inverter
|
||||
Inverter<> *iv;
|
||||
/*Inverter<> *iv;
|
||||
for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) {
|
||||
iv = mMain->mSys->getInverterByPos(i, false);
|
||||
// address
|
||||
request->arg("inv" + String(i) + "Addr").toCharArray(buf, 20);
|
||||
if(strlen(buf) == 0)
|
||||
memset(buf, 0, 20);
|
||||
iv->serial.u64 = mMain->Serial2u64(buf);
|
||||
switch(iv->serial.b[4]) {
|
||||
iv->config->serial.u64 = mMain->Serial2u64(buf);
|
||||
switch(iv->config->serial.b[4]) {
|
||||
case 0x21: iv->type = INV_TYPE_1CH; iv->channels = 1; break;
|
||||
case 0x41: iv->type = INV_TYPE_2CH; iv->channels = 2; break;
|
||||
case 0x61: iv->type = INV_TYPE_4CH; iv->channels = 4; break;
|
||||
|
@ -377,59 +382,53 @@ void web::showSave(AsyncWebServerRequest *request) {
|
|||
}
|
||||
|
||||
// name
|
||||
request->arg("inv" + String(i) + "Name").toCharArray(iv->name, MAX_NAME_LENGTH);
|
||||
request->arg("inv" + String(i) + "Name").toCharArray(iv->config->name, MAX_NAME_LENGTH);
|
||||
|
||||
// max channel power / name
|
||||
for(uint8_t j = 0; j < 4; j++) {
|
||||
iv->chMaxPwr[j] = request->arg("inv" + String(i) + "ModPwr" + String(j)).toInt() & 0xffff;
|
||||
request->arg("inv" + String(i) + "ModName" + String(j)).toCharArray(iv->chName[j], MAX_NAME_LENGTH);
|
||||
iv->config->chMaxPwr[j] = request->arg("inv" + String(i) + "ModPwr" + String(j)).toInt() & 0xffff;
|
||||
request->arg("inv" + String(i) + "ModName" + String(j)).toCharArray(iv->config->chName[j], MAX_NAME_LENGTH);
|
||||
}
|
||||
iv->initialized = true;
|
||||
}
|
||||
}*/
|
||||
if(request->arg("invInterval") != "")
|
||||
mConfig->sendInterval = request->arg("invInterval").toInt();
|
||||
mConfig->nrf.sendInterval = request->arg("invInterval").toInt();
|
||||
if(request->arg("invRetry") != "")
|
||||
mConfig->maxRetransPerPyld = request->arg("invRetry").toInt();
|
||||
|
||||
// Disclaimer
|
||||
if(request->arg("disclaimer") != "")
|
||||
mConfig->disclaimer = strcmp("true", request->arg("disclaimer").c_str()) == 0 ? true : false;
|
||||
DPRINTLN(DBG_INFO, request->arg("disclaimer").c_str());
|
||||
mConfig->nrf.maxRetransPerPyld = request->arg("invRetry").toInt();
|
||||
|
||||
// pinout
|
||||
uint8_t pin;
|
||||
for(uint8_t i = 0; i < 5; i ++) {
|
||||
pin = request->arg(String(pinArgNames[i])).toInt();
|
||||
switch(i) {
|
||||
default: mConfig->pinCs = ((pin != 0xff) ? pin : DEF_CS_PIN); break;
|
||||
case 1: mConfig->pinCe = ((pin != 0xff) ? pin : DEF_CE_PIN); break;
|
||||
case 2: mConfig->pinIrq = ((pin != 0xff) ? pin : DEF_IRQ_PIN); break;
|
||||
default: mConfig->nrf.pinCs = ((pin != 0xff) ? pin : DEF_CS_PIN); break;
|
||||
case 1: mConfig->nrf.pinCe = ((pin != 0xff) ? pin : DEF_CE_PIN); break;
|
||||
case 2: mConfig->nrf.pinIrq = ((pin != 0xff) ? pin : DEF_IRQ_PIN); break;
|
||||
case 3: mConfig->led.led0 = pin; break;
|
||||
case 4: mConfig->led.led1 = pin; break;
|
||||
}
|
||||
}
|
||||
|
||||
// nrf24 amplifier power
|
||||
mConfig->amplifierPower = request->arg("rf24Power").toInt() & 0x03;
|
||||
mConfig->nrf.amplifierPower = request->arg("rf24Power").toInt() & 0x03;
|
||||
|
||||
// ntp
|
||||
if(request->arg("ntpAddr") != "") {
|
||||
request->arg("ntpAddr").toCharArray(mConfig->ntpAddr, NTP_ADDR_LEN);
|
||||
mConfig->ntpPort = request->arg("ntpPort").toInt() & 0xffff;
|
||||
request->arg("ntpAddr").toCharArray(mConfig->ntp.addr, NTP_ADDR_LEN);
|
||||
mConfig->ntp.port = request->arg("ntpPort").toInt() & 0xffff;
|
||||
}
|
||||
|
||||
// sun
|
||||
if(request->arg("sunLat") == "" || (request->arg("sunLon") == "")) {
|
||||
mConfig->sunLat = 0.0;
|
||||
mConfig->sunLon = 0.0;
|
||||
mConfig->sunDisNightCom = false;
|
||||
mConfig->sun.lat = 0.0;
|
||||
mConfig->sun.lon = 0.0;
|
||||
mConfig->sun.disNightCom = false;
|
||||
} else {
|
||||
mConfig->sunLat = request->arg("sunLat").toFloat();
|
||||
mConfig->sunLon = request->arg("sunLon").toFloat();
|
||||
mConfig->sunDisNightCom = (request->arg("sunDisNightCom") == "on");
|
||||
mConfig->sun.lat = request->arg("sunLat").toFloat();
|
||||
mConfig->sun.lon = request->arg("sunLon").toFloat();
|
||||
mConfig->sun.disNightCom = (request->arg("sunDisNightCom") == "on");
|
||||
}
|
||||
|
||||
|
||||
// mqtt
|
||||
if(request->arg("mqttAddr") != "") {
|
||||
String addr = request->arg("mqttAddr");
|
||||
|
@ -444,15 +443,14 @@ void web::showSave(AsyncWebServerRequest *request) {
|
|||
|
||||
// serial console
|
||||
if(request->arg("serIntvl") != "") {
|
||||
mConfig->serialInterval = request->arg("serIntvl").toInt() & 0xffff;
|
||||
mConfig->serial.interval = request->arg("serIntvl").toInt() & 0xffff;
|
||||
|
||||
mConfig->serialDebug = (request->arg("serDbg") == "on");
|
||||
mConfig->serialShowIv = (request->arg("serEn") == "on");
|
||||
mConfig->serial.debug = (request->arg("serDbg") == "on");
|
||||
mConfig->serial.showIv = (request->arg("serEn") == "on");
|
||||
// Needed to log TX buffers to serial console
|
||||
mMain->mSys->Radio.mSerialDebug = mConfig->serialDebug;
|
||||
mMain->mSys->Radio.mSerialDebug = mConfig->serial.debug;
|
||||
}
|
||||
|
||||
mMain->saveValues();
|
||||
mMain->saveSettings();
|
||||
|
||||
if(request->arg("reboot") == "on")
|
||||
onReboot(request);
|
||||
|
@ -701,7 +699,7 @@ void web::showMetrics(void) {
|
|||
String metrics;
|
||||
char headline[80];
|
||||
|
||||
snprintf(headline, 80, "ahoy_solar_info{version=\"%s\",image=\"\",devicename=\"%s\"} 1", mVersion, mSysCfg->deviceName);
|
||||
snprintf(headline, 80, "ahoy_solar_info{version=\"%s\",image=\"\",devicename=\"%s\"} 1", mVersion, mconfig->sys.deviceName);
|
||||
metrics += "# TYPE ahoy_solar_info gauge\n" + String(headline) + "\n";
|
||||
|
||||
for(uint8_t id = 0; id < mMain->mSys->getNumInverters(); id++) {
|
||||
|
|
|
@ -24,7 +24,7 @@ class webApi;
|
|||
|
||||
class web {
|
||||
public:
|
||||
web(app *main, sysConfig_t *sysCfg, config_t *config, statistics_t *stat, char version[]);
|
||||
web(app *main, settings_t *config, statistics_t *stat, char version[]);
|
||||
~web() {}
|
||||
|
||||
void setup(void);
|
||||
|
@ -85,8 +85,7 @@ class web {
|
|||
bool mProtected;
|
||||
uint32_t mLogoutTimeout;
|
||||
|
||||
config_t *mConfig;
|
||||
sysConfig_t *mSysCfg;
|
||||
settings_t *mConfig;
|
||||
statistics_t *mStat;
|
||||
char *mVersion;
|
||||
app *mMain;
|
||||
|
|
|
@ -11,10 +11,9 @@
|
|||
#include "webApi.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
webApi::webApi(AsyncWebServer *srv, app *app, sysConfig_t *sysCfg, config_t *config, statistics_t *stat, char version[]) {
|
||||
webApi::webApi(AsyncWebServer *srv, app *app, settings_t *config, statistics_t *stat, char version[]) {
|
||||
mSrv = srv;
|
||||
mApp = app;
|
||||
mSysCfg = sysCfg;
|
||||
mConfig = config;
|
||||
mStat = stat;
|
||||
mVersion = version;
|
||||
|
@ -143,8 +142,8 @@ void webApi::onDwnldSetup(AsyncWebServerRequest *request) {
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
void webApi::getSysInfo(JsonObject obj) {
|
||||
obj[F("ssid")] = mSysCfg->stationSsid;
|
||||
obj[F("device_name")] = mSysCfg->deviceName;
|
||||
obj[F("ssid")] = mConfig->sys.stationSsid;
|
||||
obj[F("device_name")] = mConfig->sys.deviceName;
|
||||
obj[F("version")] = String(mVersion);
|
||||
obj[F("build")] = String(AUTO_GIT_HASH);
|
||||
obj[F("ts_uptime")] = mApp->getUptime();
|
||||
|
@ -153,8 +152,7 @@ void webApi::getSysInfo(JsonObject obj) {
|
|||
obj[F("ts_sunset")] = mApp->getSunset();
|
||||
obj[F("ts_sun_upd")] = mApp->getLatestSunTimestamp();
|
||||
obj[F("wifi_rssi")] = WiFi.RSSI();
|
||||
obj[F("disclaimer")] = mConfig->disclaimer;
|
||||
obj[F("pwd_set")] = (strlen(mConfig->password) > 0);
|
||||
obj[F("pwd_set")] = (strlen(mConfig->sys.adminPwd) > 0);
|
||||
#if defined(ESP32)
|
||||
obj[F("esp_type")] = F("ESP32");
|
||||
#else
|
||||
|
@ -221,19 +219,19 @@ void webApi::getInverterList(JsonObject obj) {
|
|||
if(NULL != iv) {
|
||||
JsonObject obj2 = invArr.createNestedObject();
|
||||
obj2[F("id")] = i;
|
||||
obj2[F("name")] = String(iv->name);
|
||||
obj2[F("serial")] = String(iv->serial.u64, HEX);
|
||||
obj2[F("name")] = String(iv->config->name);
|
||||
obj2[F("serial")] = String(iv->config->serial.u64, HEX);
|
||||
obj2[F("channels")] = iv->channels;
|
||||
obj2[F("version")] = String(iv->fwVersion);
|
||||
|
||||
for(uint8_t j = 0; j < iv->channels; j ++) {
|
||||
obj2[F("ch_max_power")][j] = iv->chMaxPwr[j];
|
||||
obj2[F("ch_name")][j] = iv->chName[j];
|
||||
obj2[F("ch_max_power")][j] = iv->config->chMaxPwr[j];
|
||||
obj2[F("ch_name")][j] = iv->config->chName[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
obj[F("interval")] = String(mConfig->sendInterval);
|
||||
obj[F("retries")] = String(mConfig->maxRetransPerPyld);
|
||||
obj[F("interval")] = String(mConfig->nrf.sendInterval);
|
||||
obj[F("retries")] = String(mConfig->nrf.maxRetransPerPyld);
|
||||
obj[F("max_num_inverters")] = MAX_NUM_INVERTERS;
|
||||
}
|
||||
|
||||
|
@ -250,23 +248,23 @@ void webApi::getMqtt(JsonObject obj) {
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
void webApi::getNtp(JsonObject obj) {
|
||||
obj[F("addr")] = String(mConfig->ntpAddr);
|
||||
obj[F("port")] = String(mConfig->ntpPort);
|
||||
obj[F("addr")] = String(mConfig->ntp.addr);
|
||||
obj[F("port")] = String(mConfig->ntp.port);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void webApi::getSun(JsonObject obj) {
|
||||
obj[F("lat")] = mConfig->sunLat ? String(mConfig->sunLat, 5) : "";
|
||||
obj[F("lon")] = mConfig->sunLat ? String(mConfig->sunLon, 5) : "";
|
||||
obj[F("disnightcom")] = mConfig->sunDisNightCom;
|
||||
obj[F("lat")] = mConfig->sun.lat ? String(mConfig->sun.lat, 5) : "";
|
||||
obj[F("lon")] = mConfig->sun.lat ? String(mConfig->sun.lon, 5) : "";
|
||||
obj[F("disnightcom")] = mConfig->sun.disNightCom;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void webApi::getPinout(JsonObject obj) {
|
||||
obj[F("cs")] = mConfig->pinCs;
|
||||
obj[F("ce")] = mConfig->pinCe;
|
||||
obj[F("irq")] = mConfig->pinIrq;
|
||||
obj[F("cs")] = mConfig->nrf.pinCs;
|
||||
obj[F("ce")] = mConfig->nrf.pinCe;
|
||||
obj[F("irq")] = mConfig->nrf.pinIrq;
|
||||
obj[F("led0")] = mConfig->led.led0;
|
||||
obj[F("led1")] = mConfig->led.led1;
|
||||
}
|
||||
|
@ -274,25 +272,26 @@ void webApi::getPinout(JsonObject obj) {
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
void webApi::getRadio(JsonObject obj) {
|
||||
obj[F("power_level")] = mConfig->amplifierPower;
|
||||
obj[F("power_level")] = mConfig->nrf.amplifierPower;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void webApi::getSerial(JsonObject obj) {
|
||||
obj[F("interval")] = (uint16_t)mConfig->serialInterval;
|
||||
obj[F("show_live_data")] = mConfig->serialShowIv;
|
||||
obj[F("debug")] = mConfig->serialDebug;
|
||||
obj[F("interval")] = (uint16_t)mConfig->serial.interval;
|
||||
obj[F("show_live_data")] = mConfig->serial.showIv;
|
||||
obj[F("debug")] = mConfig->serial.debug;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void webApi::getStaticIp(JsonObject obj) {
|
||||
if(mConfig->staticIp.ip[0] != 0) {
|
||||
obj[F("ip")] = ip2String(mConfig->staticIp.ip);
|
||||
obj[F("mask")] = ip2String(mConfig->staticIp.mask);
|
||||
obj[F("dns")] = ip2String(mConfig->staticIp.dns);
|
||||
obj[F("gateway")] = ip2String(mConfig->staticIp.gateway);
|
||||
if(mConfig->sys.ip.ip[0] != 0) {
|
||||
obj[F("ip")] = ip2String(mConfig->sys.ip.ip);
|
||||
obj[F("mask")] = ip2String(mConfig->sys.ip.mask);
|
||||
obj[F("dns1")] = ip2String(mConfig->sys.ip.dns1);
|
||||
obj[F("dns2")] = ip2String(mConfig->sys.ip.dns2);
|
||||
obj[F("gateway")] = ip2String(mConfig->sys.ip.gateway);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -314,7 +313,7 @@ void webApi::getMenu(JsonObject obj) {
|
|||
obj["link"][6] = "/update";
|
||||
obj["name"][7] = "System";
|
||||
obj["link"][7] = "/system";
|
||||
if(strlen(mConfig->password) > 0) {
|
||||
if(strlen(mConfig->sys.adminPwd) > 0) {
|
||||
obj["name"][8] = "-";
|
||||
obj["name"][9] = "Logout";
|
||||
obj["link"][9] = "/logout";
|
||||
|
@ -327,7 +326,7 @@ void webApi::getIndex(JsonObject obj) {
|
|||
getMenu(obj.createNestedObject(F("menu")));
|
||||
getSysInfo(obj.createNestedObject(F("system")));
|
||||
getStatistics(obj.createNestedObject(F("statistics")));
|
||||
obj["refresh_interval"] = mConfig->sendInterval;
|
||||
obj["refresh_interval"] = mConfig->nrf.sendInterval;
|
||||
|
||||
JsonArray inv = obj.createNestedArray(F("inverter"));
|
||||
Inverter<> *iv;
|
||||
|
@ -337,7 +336,7 @@ void webApi::getIndex(JsonObject obj) {
|
|||
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||
JsonObject invObj = inv.createNestedObject();
|
||||
invObj[F("id")] = i;
|
||||
invObj[F("name")] = String(iv->name);
|
||||
invObj[F("name")] = String(iv->config->name);
|
||||
invObj[F("version")] = String(iv->fwVersion);
|
||||
invObj[F("is_avail")] = iv->isAvailable(mApp->getTimestamp(), rec);
|
||||
invObj[F("is_producing")] = iv->isProducing(mApp->getTimestamp(), rec);
|
||||
|
@ -387,7 +386,7 @@ void webApi::getLive(JsonObject obj) {
|
|||
getMenu(obj.createNestedObject(F("menu")));
|
||||
getSysInfo(obj.createNestedObject(F("system")));
|
||||
JsonArray invArr = obj.createNestedArray(F("inverter"));
|
||||
obj["refresh_interval"] = mConfig->sendInterval;
|
||||
obj["refresh_interval"] = mConfig->nrf.sendInterval;
|
||||
|
||||
uint8_t list[] = {FLD_UAC, FLD_IAC, FLD_PAC, FLD_F, FLD_PF, FLD_T, FLD_YT, FLD_YD, FLD_PDC, FLD_EFF, FLD_Q};
|
||||
|
||||
|
@ -398,7 +397,7 @@ void webApi::getLive(JsonObject obj) {
|
|||
if(NULL != iv) {
|
||||
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||
JsonObject obj2 = invArr.createNestedObject();
|
||||
obj2[F("name")] = String(iv->name);
|
||||
obj2[F("name")] = String(iv->config->name);
|
||||
obj2[F("channels")] = iv->channels;
|
||||
obj2[F("power_limit_read")] = round3(iv->actPowerLimit);
|
||||
obj2[F("last_alarm")] = String(iv->lastAlarmMsg);
|
||||
|
@ -415,7 +414,7 @@ void webApi::getLive(JsonObject obj) {
|
|||
}
|
||||
|
||||
for(uint8_t j = 1; j <= iv->channels; j ++) {
|
||||
obj2[F("ch_names")][j] = String(iv->chName[j-1]);
|
||||
obj2[F("ch_names")][j] = String(iv->config->chName[j-1]);
|
||||
JsonArray cur = ch.createNestedArray();
|
||||
for (uint8_t k = 0; k < 6; k++) {
|
||||
switch(k) {
|
||||
|
|
|
@ -16,7 +16,7 @@ class app;
|
|||
|
||||
class webApi {
|
||||
public:
|
||||
webApi(AsyncWebServer *srv, app *app, sysConfig_t *sysCfg, config_t *config, statistics_t *stat, char version[]);
|
||||
webApi(AsyncWebServer *srv, app *app, settings_t *config, statistics_t *stat, char version[]);
|
||||
|
||||
void setup(void);
|
||||
void loop(void);
|
||||
|
@ -72,8 +72,7 @@ class webApi {
|
|||
AsyncWebServer *mSrv;
|
||||
app *mApp;
|
||||
|
||||
config_t *mConfig;
|
||||
sysConfig_t *mSysCfg;
|
||||
settings_t *mConfig;
|
||||
statistics_t *mStat;
|
||||
char *mVersion;
|
||||
|
||||
|
|
|
@ -16,9 +16,7 @@
|
|||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
ahoywifi::ahoywifi(app *main, sysConfig_t *sysCfg, config_t *config) {
|
||||
mMain = main;
|
||||
mSysCfg = sysCfg;
|
||||
ahoywifi::ahoywifi(settings_t *config) {
|
||||
mConfig = config;
|
||||
|
||||
mDns = new DNSServer();
|
||||
|
@ -34,18 +32,17 @@ ahoywifi::ahoywifi(app *main, sysConfig_t *sysCfg, config_t *config) {
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ahoywifi::setup(uint32_t timeout, bool settingValid) {
|
||||
|
||||
#ifdef FB_WIFI_OVERRIDDEN
|
||||
mStationWifiIsDef = false;
|
||||
#else
|
||||
mStationWifiIsDef = (strncmp(mSysCfg->stationSsid, FB_WIFI_SSID, 14) == 0);
|
||||
mStationWifiIsDef = (strncmp(mConfig->sys.stationSsid, FB_WIFI_SSID, 14) == 0);
|
||||
#endif
|
||||
|
||||
mWifiStationTimeout = timeout;
|
||||
#ifndef AP_ONLY
|
||||
if(false == mApActive)
|
||||
mApActive = (mStationWifiIsDef) ? true : setupStation(mWifiStationTimeout);
|
||||
#endif
|
||||
|
||||
if(!settingValid) {
|
||||
DPRINTLN(DBG_WARN, F("your settings are not valid! check [IP]/setup"));
|
||||
mApActive = true;
|
||||
|
@ -58,7 +55,7 @@ void ahoywifi::setup(uint32_t timeout, bool settingValid) {
|
|||
DPRINTLN(DBG_INFO, F("Welcome to AHOY!"));
|
||||
DPRINT(DBG_INFO, F("\npoint your browser to http://"));
|
||||
if(mApActive)
|
||||
DBGPRINTLN(F("192.168.1.1"));
|
||||
DBGPRINTLN(F("192.168.4.1"));
|
||||
else
|
||||
DBGPRINTLN(WiFi.localIP().toString());
|
||||
DPRINTLN(DBG_INFO, F("to configure your device"));
|
||||
|
@ -142,20 +139,21 @@ bool ahoywifi::setupStation(uint32_t timeout) {
|
|||
}
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
if(mConfig->staticIp.ip[0] != 0) {
|
||||
IPAddress ip(mConfig->staticIp.ip);
|
||||
IPAddress mask(mConfig->staticIp.mask);
|
||||
IPAddress dns(mConfig->staticIp.dns);
|
||||
IPAddress gateway(mConfig->staticIp.gateway);
|
||||
if(!WiFi.config(ip, gateway, mask, dns))
|
||||
if(mConfig->sys.ip.ip[0] != 0) {
|
||||
IPAddress ip(mConfig->sys.ip.ip);
|
||||
IPAddress mask(mConfig->sys.ip.mask);
|
||||
IPAddress dns1(mConfig->sys.ip.dns1);
|
||||
IPAddress dns2(mConfig->sys.ip.dns2);
|
||||
IPAddress gateway(mConfig->sys.ip.gateway);
|
||||
if(!WiFi.config(ip, gateway, mask, dns1, dns2))
|
||||
DPRINTLN(DBG_ERROR, F("failed to set static IP!"));
|
||||
}
|
||||
WiFi.begin(mSysCfg->stationSsid, mSysCfg->stationPwd);
|
||||
if(String(mSysCfg->deviceName) != "")
|
||||
WiFi.hostname(mSysCfg->deviceName);
|
||||
WiFi.begin(mConfig->sys.stationSsid, mConfig->sys.stationPwd);
|
||||
if(String(mConfig->sys.deviceName) != "")
|
||||
WiFi.hostname(mConfig->sys.deviceName);
|
||||
|
||||
delay(2000);
|
||||
DPRINTLN(DBG_INFO, F("connect to network '") + String(mSysCfg->stationSsid) + F("' ..."));
|
||||
DPRINTLN(DBG_INFO, F("connect to network '") + String(mConfig->sys.stationSsid) + F("' ..."));
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(100);
|
||||
if(cnt % 40 == 0)
|
||||
|
@ -197,8 +195,8 @@ time_t ahoywifi::getNtpTime(void) {
|
|||
uint8_t buf[NTP_PACKET_SIZE];
|
||||
uint8_t retry = 0;
|
||||
|
||||
WiFi.hostByName(mConfig->ntpAddr, timeServer);
|
||||
mUdp->begin(mConfig->ntpPort);
|
||||
WiFi.hostByName(mConfig->ntp.addr, timeServer);
|
||||
mUdp->begin(mConfig->ntp.port);
|
||||
|
||||
sendNTPpacket(timeServer);
|
||||
|
||||
|
|
|
@ -7,21 +7,19 @@
|
|||
#define __AHOYWIFI_H__
|
||||
|
||||
#include "../utils/dbg.h"
|
||||
|
||||
// NTP
|
||||
#include <Arduino.h>
|
||||
#include <WiFiUdp.h>
|
||||
#include <TimeLib.h>
|
||||
#include <DNSServer.h>
|
||||
#include "ESPAsyncWebServer.h"
|
||||
|
||||
#include "../defines.h"
|
||||
|
||||
#include "../app.h"
|
||||
#include "../config/settings.h"
|
||||
|
||||
class app;
|
||||
|
||||
class ahoywifi {
|
||||
public:
|
||||
ahoywifi(app *main, sysConfig_t *sysCfg, config_t *config);
|
||||
ahoywifi(settings_t *config);
|
||||
~ahoywifi() {}
|
||||
|
||||
void setup(uint32_t timeout, bool settingValid);
|
||||
|
@ -36,9 +34,7 @@ class ahoywifi {
|
|||
private:
|
||||
void sendNTPpacket(IPAddress& address);
|
||||
|
||||
config_t *mConfig;
|
||||
sysConfig_t *mSysCfg;
|
||||
app *mMain;
|
||||
settings_t *mConfig;
|
||||
|
||||
DNSServer *mDns;
|
||||
WiFiUDP *mUdp; // for time server
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue