diff --git a/.gitignore b/.gitignore index 89b7ea7f..da27a66d 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ tools/esp8266/binaries *.ipch tools/esp8266/.vscode/extensions.json .DS_Store +.vscode diff --git a/tools/esp8266/app.cpp b/tools/esp8266/app.cpp index 0e558bf1..273d258b 100644 --- a/tools/esp8266/app.cpp +++ b/tools/esp8266/app.cpp @@ -4,236 +4,68 @@ //----------------------------------------------------------------------------- #include "app.h" - -#include "favicon.h" -#include "html/h/index_html.h" -#include "html/h/setup_html.h" -#include "html/h/hoymiles_html.h" #include - //----------------------------------------------------------------------------- -app::app() : Main() { - DPRINTLN(DBG_VERBOSE, F("app::app():Main")); - mSendTicker = 0xffff; - mSendInterval = SEND_INTERVAL; - mMqttTicker = 0xffff; - mMqttInterval = MQTT_INTERVAL; - mSerialTicker = 0xffff; - mSerialInterval = SERIAL_INTERVAL; - mMqttActive = false; - - mTicker = 0; - mRxTicker = 0; +app::app() { + DPRINTLN(DBG_VERBOSE, F("app::app")); + mEep = new eep(); + Serial.begin(115200); - mSendLastIvId = 0; + mWifi = new wifi(this, &mSysConfig, &mConfig); - mShowRebootRequest = false; + mWebInst = new web(this, &mSysConfig, &mConfig, mVersion); + mWebInst->setup(); - mSerialValues = true; - mSerialDebug = false; - - memset(mPayload, 0, (MAX_NUM_INVERTERS * sizeof(invPayload_t))); - mRxFailed = 0; - mRxSuccess = 0; - mFrameCnt = 0; - mLastPacketId = 0x00; + resetSystem(); + loadDefaultConfig(); mSys = new HmSystemType(); } -//----------------------------------------------------------------------------- -app::~app(void) { - -} - - //----------------------------------------------------------------------------- void app::setup(uint32_t timeout) { DPRINTLN(DBG_VERBOSE, F("app::setup")); - Main::setup(timeout); - - mWeb->on("/", std::bind(&app::showIndex, this)); - mWeb->on("/favicon.ico", std::bind(&app::showFavicon, this)); - mWeb->on("/setup", std::bind(&app::showSetup, this)); - mWeb->on("/save", std::bind(&app::showSave, this)); - mWeb->on("/erase", std::bind(&app::showErase, this)); - mWeb->on("/cmdstat", std::bind(&app::showStatistics, this)); - mWeb->on("/hoymiles", std::bind(&app::showHoymiles, this)); - mWeb->on("/livedata", std::bind(&app::showLiveData, this)); - mWeb->on("/json", std::bind(&app::showJSON, this)); - mWeb->on("/api",HTTP_POST, std::bind(&app::webapi, this)); - - if(mSettingsValid) { - mEep->read(ADDR_INV_INTERVAL, &mSendInterval); - if(mSendInterval < MIN_SEND_INTERVAL) - mSendInterval = MIN_SEND_INTERVAL; - mSendTicker = mSendInterval; - - // 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) { - mEep->read(ADDR_INV_PWR_LIM + (i * 2),(uint16_t *)&(iv->powerLimit[0])); - if (iv->powerLimit[0] != 0xffff) { // only set it, if it is changed by user. Default value in the html setup page is -1 = 0xffff - iv->powerLimit[1] = 0x0001; // set the limit as persistent - iv->devControlCmd = ActivePowerContr; // set active power limit - iv->devControlRequest = true; // set to true to update the active power limit from setup html page - DPRINTLN(DBG_INFO, F("add inverter: ") + String(name) + ", SN: " + String(invSerial, HEX) + ", Power Limit: " + String(iv->powerLimit[0])); - } - 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); - } - } + mWifiSettingsValid = checkEEpCrc(ADDR_START, ADDR_WIFI_CRC, ADDR_WIFI_CRC); + mSettingsValid = checkEEpCrc(ADDR_START_SETTINGS, ((ADDR_NEXT)-(ADDR_START_SETTINGS)), ADDR_SETTINGS_CRC); + loadEEpconfig(); - mMqttInterval += mSendInterval; - } - } - - mEep->read(ADDR_INV_MAX_RTRY, &mMaxRetransPerPyld); - if(0 == mMaxRetransPerPyld) - mMaxRetransPerPyld = DEF_MAX_RETRANS_PER_PYLD; - - // pinout - mEep->read(ADDR_PINOUT, &mSys->Radio.pinCs); - mEep->read(ADDR_PINOUT+1, &mSys->Radio.pinCe); - mEep->read(ADDR_PINOUT+2, &mSys->Radio.pinIrq); - if(mSys->Radio.pinCs == mSys->Radio.pinCe) { - mSys->Radio.pinCs = RF24_CS_PIN; - mSys->Radio.pinCe = RF24_CE_PIN; - mSys->Radio.pinIrq = RF24_IRQ_PIN; - } + mWifi->setup(timeout, mWifiSettingsValid); - // nrf24 amplifier power - mEep->read(ADDR_RF24_AMP_PWR, &mSys->Radio.AmplifierPower); - - // serial console - uint8_t tmp; - mEep->read(ADDR_SER_INTERVAL, &mSerialInterval); - if(mSerialInterval < MIN_SERIAL_INTERVAL) - mSerialInterval = MIN_SERIAL_INTERVAL; - mEep->read(ADDR_SER_ENABLE, &tmp); - mSerialValues = (tmp == 0x01); - mEep->read(ADDR_SER_DEBUG, &tmp); - mSerialDebug = (tmp == 0x01); - mSys->Radio.mSerialDebug = mSerialDebug; - - // ntp - char ntpAddr[NTP_ADDR_LEN]; - uint16_t ntpPort; - mEep->read(ADDR_NTP_ADDR, ntpAddr, NTP_ADDR_LEN); - mEep->read(ADDR_NTP_PORT, &ntpPort); - // TODO set ntpAddr & ntpPort in main - - // mqtt - uint16_t mqttPort; - char mqttAddr[MQTT_ADDR_LEN]; - char mqttUser[MQTT_USER_LEN]; - char mqttPwd[MQTT_PWD_LEN]; - char mqttTopic[MQTT_TOPIC_LEN]; - char mqttDevName[DEVNAME_LEN]; - mEep->read(ADDR_MQTT_ADDR, mqttAddr, MQTT_ADDR_LEN); - mEep->read(ADDR_MQTT_USER, mqttUser, MQTT_USER_LEN); - mEep->read(ADDR_MQTT_PWD, mqttPwd, MQTT_PWD_LEN); - mEep->read(ADDR_MQTT_TOPIC, mqttTopic, MQTT_TOPIC_LEN); - mEep->read(ADDR_DEVNAME, mqttDevName, DEVNAME_LEN); - //mEep->read(ADDR_MQTT_INTERVAL, &mMqttInterval); - mEep->read(ADDR_MQTT_PORT, &mqttPort); - - if(mqttAddr[0] > 0) { - mMqttActive = true; - if(mMqttInterval < MIN_MQTT_INTERVAL) - mMqttInterval = MIN_MQTT_INTERVAL; - } - else - mMqttInterval = 0xffff; - - if(0 == mqttPort) - mqttPort = 1883; + #ifndef AP_ONLY + setupMqtt(); + #endif + mSys->setup(&mConfig); +} - mMqtt.setup(mqttAddr, mqttTopic, mqttUser, mqttPwd, mqttDevName, mqttPort); - mMqtt.mClient->setCallback(std::bind(&app::cbMqtt, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); - mMqttTicker = 0; +//----------------------------------------------------------------------------- +void app::loop(void) { + DPRINTLN(DBG_VERBOSE, F("app::loop")); -#ifdef __MQTT_TEST__ - // für mqtt test - mMqttTicker = mMqttInterval -10; -#endif - mSerialTicker = 0; + bool apActive = mWifi->loop(); + mWebInst->loop(); - if(mqttAddr[0] > 0) { - char topic[30]; - mMqtt.sendMsg("device", mqttDevName); - mMqtt.sendMsg("version", mVersion); - for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) { - iv = mSys->getInverterByPos(i); - if(NULL != iv) { - for(uint8_t i = 0; i < 4; i++) { - if(0 != iv->chName[i][0]) { - snprintf(topic, 30, "%s/ch%d/%s", iv->name, i+1, "name"); - mMqtt.sendMsg(topic, iv->chName[i]); - yield(); - } - } - } + if(checkTicker(&mUptimeTicker, mUptimeInterval)) { + mUptimeSecs++; + if(0 != mTimestamp) + mTimestamp++; + else { + if(!apActive) { + mTimestamp = mWifi->getNtpTime(); + DPRINTLN(DBG_INFO, "[NTP]: " + getDateTimeStr(mTimestamp)); } } } - else { - DPRINTLN(DBG_DEBUG, F("CRC pos: ") + String(ADDR_SETTINGS_CRC)); - DPRINTLN(DBG_DEBUG, F("NXT pos: ") + String(ADDR_NEXT)); - DPRINTLN(DBG_INFO, F("Settings not valid, erasing ...")); - eraseSettings(); - saveValues(false); - delay(100); - DPRINTLN(DBG_INFO, F("... restarting ...")); - delay(100); - ESP.restart(); - } - - mSys->setup(); - if(!mWifiSettingsValid) - DPRINTLN(DBG_WARN, F("your settings are not valid! check [IP]/setup")); - else { - DPRINTLN(DBG_INFO, F("\n\n----------------------------------------")); - DPRINTLN(DBG_INFO, F("Welcome to AHOY!")); - DPRINT(DBG_INFO, F("\npoint your browser to http://")); - if(mApActive) - DBGPRINTLN(F("192.168.1.1")); - else - DBGPRINTLN(WiFi.localIP()); - DPRINTLN(DBG_INFO, F("to configure your device")); - DPRINTLN(DBG_INFO, F("----------------------------------------\n")); - } -} - - -//----------------------------------------------------------------------------- -void app::loop(void) { - DPRINTLN(DBG_VERBOSE, F("app::loop")); - Main::loop(); mSys->Radio.loop(); yield(); if(checkTicker(&mRxTicker, 5)) { - //DPRINTLN(DBG_VERBOSE, F("app_loops =") + String(app_loops)); - app_loops=0; - DPRINT(DBG_VERBOSE, F("a")); - bool rxRdy = mSys->Radio.switchRxCh(); if(!mSys->BufCtrl.empty()) { @@ -242,7 +74,7 @@ void app::loop(void) { if(mSys->Radio.checkPaketCrc(p->packet, &len, p->rxCh)) { // process buffer only on first occurrence - if(mSerialDebug) { + if(mConfig.serialDebug) { DPRINT(DBG_INFO, "RX " + String(len) + "B Ch" + String(p->rxCh) + " | "); mSys->Radio.dumpBuf(NULL, p->packet, len); } @@ -349,7 +181,7 @@ void app::loop(void) { mMqtt.loop(); if(checkTicker(&mTicker, 1000)) { - if((++mMqttTicker >= mMqttInterval) && (mMqttInterval != 0xffff)) { + if((++mMqttTicker >= mMqttInterval) && (mMqttInterval != 0xffff) && mMqttActive) { mMqttTicker = 0; mMqtt.isConnected(true); char topic[30], val[10]; @@ -367,11 +199,11 @@ void app::loop(void) { } } snprintf(val, 10, "%ld", millis()/1000); - + #ifndef __MQTT_NO_DISCOVERCONFIG__ // MQTTDiscoveryConfig nur wenn nicht abgeschaltet. sendMqttDiscoveryConfig(); -#endif +#endif mMqtt.sendMsg("uptime", val); #ifdef __MQTT_TEST__ @@ -380,8 +212,8 @@ void app::loop(void) { #endif } - if(mSerialValues) { - if(++mSerialTicker >= mSerialInterval) { + if(mConfig.serialShowIv) { + if(++mSerialTicker >= mConfig.serialInterval) { mSerialTicker = 0; char topic[30], val[10]; for(uint8_t id = 0; id < mSys->getNumInverters(); id++) { @@ -404,15 +236,15 @@ void app::loop(void) { } } - if(++mSendTicker >= mSendInterval) { + if(++mSendTicker >= mConfig.sendInterval) { mSendTicker = 0; if(0 != mTimestamp) { - if(mSerialDebug) + if(mConfig.serialDebug) DPRINTLN(DBG_DEBUG, F("Free heap: 0x") + String(ESP.getFreeHeap(), HEX)); if(!mSys->BufCtrl.empty()) { - if(mSerialDebug) + if(mConfig.serialDebug) DPRINTLN(DBG_DEBUG, F("recbuf not empty! #") + String(mSys->BufCtrl.getFill())); } @@ -431,7 +263,7 @@ void app::loop(void) { if(!mPayload[iv->id].complete) { mRxFailed++; - if(mSerialDebug) { + if(mConfig.serialDebug) { DPRINT(DBG_INFO, F("Inverter #") + String(iv->id) + " "); DPRINTLN(DBG_INFO, F("no Payload received! (retransmits: ") + String(mPayload[iv->id].retransmits) + ")"); } @@ -446,11 +278,11 @@ void app::loop(void) { mPayload[iv->id].ts = mTimestamp; yield(); - if(mSerialDebug) + if(mConfig.serialDebug) DPRINTLN(DBG_DEBUG, F("app:loop WiFi WiFi.status ") + String(WiFi.status()) ); DPRINTLN(DBG_INFO, F("Requesting Inverter SN ") + String(iv->serial.u64, HEX)); if(iv->devControlRequest && iv->powerLimit[0] > 0){ // prevent to "switch off" - if(mSerialDebug) + if(mConfig.serialDebug) DPRINTLN(DBG_INFO, F("Devcontrol request ") + String(iv->devControlCmd) + F(" power limit ") + String(iv->powerLimit[0])); mSys->Radio.sendControlPacket(iv->radioId.u64,iv->devControlCmd ,iv->powerLimit); } else { @@ -459,7 +291,7 @@ void app::loop(void) { } } } - else if(mSerialDebug) + else if(mConfig.serialDebug) DPRINTLN(DBG_WARN, F("time not set, can't request inverter!")); yield(); } @@ -514,12 +346,12 @@ void app::processPayload(bool retransmit) { if(!buildPayload(iv->id)) { if(mPayload[iv->id].requested) { if(retransmit) { - if(mPayload[iv->id].retransmits < mMaxRetransPerPyld) { + if(mPayload[iv->id].retransmits < mConfig.maxRetransPerPyld) { mPayload[iv->id].retransmits++; if(mPayload[iv->id].maxPackId != 0) { for(uint8_t i = 0; i < (mPayload[iv->id].maxPackId-1); i ++) { if(mPayload[iv->id].len[i] == 0) { - if(mSerialDebug) + if(mConfig.serialDebug) DPRINTLN(DBG_ERROR, F("while retrieving data: Frame ") + String(i+1) + F(" missing: Request Retransmit")); mSys->Radio.sendCmdPacket(iv->radioId.u64, TX_REQ_INFO, (SINGLE_FRAME+i), true); break; // only retransmit one frame per loop @@ -528,7 +360,7 @@ void app::processPayload(bool retransmit) { } } else { - if(mSerialDebug) + if(mConfig.serialDebug) DPRINTLN(DBG_ERROR, F("while retrieving data: last frame missing: Request Retransmit")); if(0x00 != mLastPacketId) mSys->Radio.sendCmdPacket(iv->radioId.u64, TX_REQ_INFO, mLastPacketId, true); @@ -551,7 +383,7 @@ void app::processPayload(bool retransmit) { yield(); } offs-=2; - if(mSerialDebug) { + if(mConfig.serialDebug) { DPRINT(DBG_INFO, F("Payload (") + String(offs) + "): "); mSys->Radio.dumpBuf(NULL, payload, offs); } @@ -586,168 +418,6 @@ void app::processPayload(bool retransmit) { } -//----------------------------------------------------------------------------- -void app::showIndex(void) { - DPRINTLN(DBG_VERBOSE, F("app::showIndex")); - String html = FPSTR(index_html); - html.replace(F("{DEVICE}"), mDeviceName); - html.replace(F("{VERSION}"), mVersion); - html.replace(F("{TS}"), String(mSendInterval) + " "); - html.replace(F("{JS_TS}"), String(mSendInterval * 1000)); - html.replace(F("{BUILD}"), String(AUTO_GIT_HASH)); - mWeb->send(200, "text/html", html); -} - - -//----------------------------------------------------------------------------- -void app::showSetup(void) { - DPRINTLN(DBG_VERBOSE, F("app::showSetup")); - // overrides same method in main.cpp - - String html = FPSTR(setup_html); - html.replace(F("{SSID}"), mStationSsid); - // PWD will be left at the default value (for protection) - // -> the PWD will only be changed if it does not match the placeholder "{PWD}" - - html.replace(F("{DEVICE}"), String(mDeviceName)); - html.replace(F("{VERSION}"), String(mVersion)); - if(mApActive) - html.replace(F("{IP}"), String(F("http://192.168.1.1"))); - else - html.replace(F("{IP}"), ("http://" + String(WiFi.localIP().toString()))); - - String inv; - uint64_t invSerial; - char name[MAX_NAME_LENGTH + 1] = {0}; - uint16_t modPwr[4]; - uint16_t invActivePowerLimit = -1; - 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); - mEep->read(ADDR_INV_PWR_LIM + (i * 2),(uint16_t *) &invActivePowerLimit); - inv += F("

Inverter ") + String(i) + "

"; - - inv += F(""); - inv += F(""); - - inv += F(""); - inv += F(""; - - inv += F(""); - inv += F(""; - - - inv += F(""); - for(uint8_t j = 0; j < 4; j++) { - inv += F(""); - } - inv += F("
"); - for(uint8_t j = 0; j < 4; j++) { - mEep->read(ADDR_INV_CH_NAME + (i * 4 * MAX_NAME_LENGTH) + j * MAX_NAME_LENGTH, name, MAX_NAME_LENGTH); - inv += F(""; - } - } - html.replace(F("{INVERTERS}"), String(inv)); - - - // pinout - String pinout; - for(uint8_t i = 0; i < 3; i++) { - pinout += F(""); - pinout += F(""); - } - html.replace(F("{PINOUT}"), String(pinout)); - - - // nrf24l01+ - String rf24; - for(uint8_t i = 0; i <= 3; i++) { - rf24 += F(""); - } - html.replace(F("{RF24}"), String(rf24)); - - - if(mSettingsValid) { - html.replace(F("{INV_INTVL}"), String(mSendInterval)); - html.replace(F("{INV_RETRIES}"), String(mMaxRetransPerPyld)); - - uint8_t tmp; - mEep->read(ADDR_SER_ENABLE, &tmp); - html.replace(F("{SER_INTVL}"), String(mSerialInterval)); - html.replace(F("{SER_VAL_CB}"), (tmp == 0x01) ? "checked" : ""); - mEep->read(ADDR_SER_DEBUG, &tmp); - html.replace(F("{SER_DBG_CB}"), (tmp == 0x01) ? "checked" : ""); - - char ntpAddr[NTP_ADDR_LEN] = {0}; - uint16_t ntpPort; - mEep->read(ADDR_NTP_ADDR, ntpAddr, NTP_ADDR_LEN); - mEep->read(ADDR_NTP_PORT, &ntpPort); - html.replace(F("{NTP_ADDR}"), String(ntpAddr)); - html.replace(F("{NTP_PORT}"), String(ntpPort)); - - char mqttAddr[MQTT_ADDR_LEN] = {0}; - uint16_t mqttPort; - mEep->read(ADDR_MQTT_ADDR, mqttAddr, MQTT_ADDR_LEN); - mEep->read(ADDR_MQTT_PORT, &mqttPort); - - html.replace(F("{MQTT_ADDR}"), String(mqttAddr)); - html.replace(F("{MQTT_PORT}"), String(mMqtt.getPort())); - html.replace(F("{MQTT_USER}"), String(mMqtt.getUser())); - html.replace(F("{MQTT_PWD}"), String(mMqtt.getPwd())); - html.replace(F("{MQTT_TOPIC}"), String(mMqtt.getTopic())); - html.replace(F("{MQTT_INTVL}"), String(mMqttInterval)); - } - - mWeb->send(200, F("text/html"), html); -} - - -//----------------------------------------------------------------------------- -void app::showSave(void) { - DPRINTLN(DBG_VERBOSE, F("app::showSave")); - saveValues(true); -} - - -//----------------------------------------------------------------------------- -void app::showErase() { - DPRINTLN(DBG_VERBOSE, F("app::showErase")); - eraseSettings(); - showReboot(); -} - //----------------------------------------------------------------------------- void app::cbMqtt(char* topic, byte* payload, unsigned int length) { // callback handling on subscribed devcontrol topic @@ -820,10 +490,8 @@ void app::cbMqtt(char* topic, byte* payload, unsigned int length) { } - //----------------------------------------------------------------------------- -void app::showStatistics(void) { - DPRINTLN(DBG_VERBOSE, F("app::showStatistics")); +String app::getStatistics(void) { String content = F("Receive success: ") + String(mRxSuccess) + "\n"; content += F("Receive fail: ") + String(mRxFailed) + "\n"; content += F("Frames received: ") + String(mFrameCnt) + "\n"; @@ -868,7 +536,7 @@ void app::showStatistics(void) { content += F("not "); content += F("connected\n"); - mWeb->send(200, F("text/plain"), content); + return content; } //----------------------------------------------------------------------------- @@ -885,22 +553,6 @@ void app::webapi(void) { // ToDo mSys->InfoCmd = payload["cmd"]; DPRINTLN(DBG_INFO, F("Will make tx-request 0x15 with subcmd ") + String(mSys->InfoCmd)); } - if (payload["tx_request"] == (uint8_t)TX_REQ_DEVCONTROL){ - if(payload["cmd"] == (uint8_t)ActivePowerContr){ - uint8_t iv_id = payload["inverter"]; - if (iv_id >= 0 && iv_id <= MAX_NUM_INVERTERS){ - Inverter<> *iv = this->mSys->getInverterByPos(iv_id); - uint16_t webapiPayload = payload["payload"]; - if (webapiPayload > 0 && webapiPayload < 10000){ - iv->devControlCmd = ActivePowerContr; - iv->powerLimit[0] = webapiPayload; - iv->powerLimit[1] = 0x0000; // if power limit is set via external interface --> set it temporay - DPRINTLN(DBG_INFO, F("Power limit for inverter ") + String(iv->id) + F(" set to ") + String(iv->powerLimit[0]) + F("W via REST API") ); - iv->devControlRequest = true; - } - } - } - } mWeb->send ( 200, "text/json", "{success:true}" ); } @@ -998,13 +650,13 @@ void app::showLiveData(void) { #endif } } - mWeb->send(200, F("text/html"), modHtml); + return modHtml; } //----------------------------------------------------------------------------- -void app::showJSON(void) { - DPRINTLN(DBG_VERBOSE, F("app::showJSON")); +String app::getJson(void) { + DPRINTLN(DBG_VERBOSE, F("app::showJson")); String modJson; modJson = F("{\n"); @@ -1024,139 +676,17 @@ void app::showJSON(void) { } modJson += F("\"json_ts\": \"") + String(getDateTimeStr(mTimestamp)) + F("\"\n}\n"); - // mWeb->send(200, F("text/json"), modJson); - mWeb->send(200, F("application/json"), modJson); // the preferred content-type (https://stackoverflow.com/questions/22406077/what-is-the-exact-difference-between-content-type-text-json-and-application-jso) + return modJson; } //----------------------------------------------------------------------------- -void app::saveValues(bool webSend = true) { - DPRINTLN(DBG_VERBOSE, F("app::saveValues")); - Main::saveValues(false); // general configuration - - if(mWeb->args() > 0) { - char buf[20] = {0}; - uint8_t i = 0; - uint16_t interval; - uint16_t activepowerlimit=-1; - - // inverter - serial_u addr; - for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) { - // address - mWeb->arg("inv" + String(i) + "Addr").toCharArray(buf, 20); - if(strlen(buf) == 0) - memset(buf, 0, 20); - addr.u64 = Serial2u64(buf); - mEep->write(ADDR_INV_ADDR + (i * 8), addr.u64); - - // active power limit - activepowerlimit = mWeb->arg("inv" + String(i) + "ActivePowerLimit").toInt(); - if (activepowerlimit != 0xffff && activepowerlimit > 0) { - mEep->write(ADDR_INV_PWR_LIM + i * 2,activepowerlimit); - } - - // name - mWeb->arg("inv" + String(i) + "Name").toCharArray(buf, 20); - mEep->write(ADDR_INV_NAME + (i * MAX_NAME_LENGTH), buf, MAX_NAME_LENGTH); - - // max channel power / name - for(uint8_t j = 0; j < 4; j++) { - uint16_t pwr = mWeb->arg("inv" + String(i) + "ModPwr" + String(j)).toInt(); - mEep->write(ADDR_INV_CH_PWR + (i * 2 * 4) + (j*2), pwr); - memset(buf, 0, 20); - mWeb->arg("inv" + String(i) + "ModName" + String(j)).toCharArray(buf, 20); - mEep->write(ADDR_INV_CH_NAME + (i * 4 * MAX_NAME_LENGTH) + j * MAX_NAME_LENGTH, buf, MAX_NAME_LENGTH); - } - } - - interval = mWeb->arg("invInterval").toInt(); - mEep->write(ADDR_INV_INTERVAL, interval); - i = mWeb->arg("invRetry").toInt(); - mEep->write(ADDR_INV_MAX_RTRY, i); - - - // pinout - for(uint8_t i = 0; i < 3; i ++) { - uint8_t pin = mWeb->arg(String(pinArgNames[i])).toInt(); - mEep->write(ADDR_PINOUT + i, pin); - } - - - // nrf24 amplifier power - mSys->Radio.AmplifierPower = mWeb->arg("rf24Power").toInt() & 0x03; - mEep->write(ADDR_RF24_AMP_PWR, mSys->Radio.AmplifierPower); - - // ntp - char ntpAddr[NTP_ADDR_LEN] = {0}; - uint16_t ntpPort; - mWeb->arg("ntpAddr").toCharArray(ntpAddr, NTP_ADDR_LEN); - ntpPort = mWeb->arg("ntpPort").toInt(); - mEep->write(ADDR_NTP_ADDR, ntpAddr, NTP_ADDR_LEN); - mEep->write(ADDR_NTP_PORT, ntpPort); - - // mqtt - char mqttAddr[MQTT_ADDR_LEN] = {0}; - uint16_t mqttPort; - char mqttUser[MQTT_USER_LEN]; - char mqttPwd[MQTT_PWD_LEN]; - char mqttTopic[MQTT_TOPIC_LEN]; - mWeb->arg("mqttAddr").toCharArray(mqttAddr, MQTT_ADDR_LEN); - mWeb->arg("mqttUser").toCharArray(mqttUser, MQTT_USER_LEN); - mWeb->arg("mqttPwd").toCharArray(mqttPwd, MQTT_PWD_LEN); - mWeb->arg("mqttTopic").toCharArray(mqttTopic, MQTT_TOPIC_LEN); - //interval = mWeb->arg("mqttIntvl").toInt(); - mqttPort = mWeb->arg("mqttPort").toInt(); - mEep->write(ADDR_MQTT_ADDR, mqttAddr, MQTT_ADDR_LEN); - mEep->write(ADDR_MQTT_PORT, mqttPort); - mEep->write(ADDR_MQTT_USER, mqttUser, MQTT_USER_LEN); - mEep->write(ADDR_MQTT_PWD, mqttPwd, MQTT_PWD_LEN); - mEep->write(ADDR_MQTT_TOPIC, mqttTopic, MQTT_TOPIC_LEN); - //mEep->write(ADDR_MQTT_INTERVAL, interval); - - - // serial console - bool tmp; - interval = mWeb->arg("serIntvl").toInt(); - mEep->write(ADDR_SER_INTERVAL, interval); - tmp = (mWeb->arg("serEn") == "on"); - mEep->write(ADDR_SER_ENABLE, (uint8_t)((tmp) ? 0x01 : 0x00)); - mSerialDebug = (mWeb->arg("serDbg") == "on"); - mEep->write(ADDR_SER_DEBUG, (uint8_t)((mSerialDebug) ? 0x01 : 0x00)); - DPRINT(DBG_INFO, "Serial debug is "); - if(mSerialDebug) DPRINTLN(DBG_INFO, "on"); else DPRINTLN(DBG_INFO, "off"); - mSys->Radio.mSerialDebug = mSerialDebug; - - updateCrc(); - mEep->commit(); - if((mWeb->arg("reboot") == "on")) - showReboot(); - else { - mShowRebootRequest = true; - mWeb->send(200, F("text/html"), F("Setup saved" - "

saved

")); - } - } - else { - updateCrc(); - mEep->commit(); - mWeb->send(200, F("text/html"), F("Error" - "

Error while saving

")); - } +bool app::getWifiApActive(void) { + return mWifi->getApActive(); } //----------------------------------------------------------------------------- -void app::updateCrc(void) { - DPRINTLN(DBG_VERBOSE, F("app::updateCrc")); - Main::updateCrc(); - - uint16_t crc; - crc = buildEEpCrc(ADDR_START_SETTINGS, ((ADDR_NEXT) - (ADDR_START_SETTINGS))); - DPRINTLN(DBG_DEBUG, F("new CRC: ") + String(crc, HEX)); - mEep->write(ADDR_SETTINGS_CRC, crc); -} - void app::sendMqttDiscoveryConfig(void) { DPRINTLN(DBG_VERBOSE, F("app::sendMqttDiscoveryConfig")); @@ -1178,7 +708,7 @@ void app::sendMqttDiscoveryConfig(void) { } else { snprintf(name, 32, "%s CH%d %s", iv->name, iv->assign[i].ch, iv->getFieldName(i)); } - snprintf(stateTopic, 64, "%s/%s/ch%d/%s", mMqtt.getTopic(), iv->name, iv->assign[i].ch, iv->getFieldName(i)); + snprintf(stateTopic, 64, "%s/%s/ch%d/%s", mConfig.mqtt.topic, iv->name, iv->assign[i].ch, iv->getFieldName(i)); snprintf(discoveryTopic, 64, "%s/sensor/%s/ch%d_%s/config", MQTT_DISCOVERY_PREFIX, iv->name, iv->assign[i].ch, iv->getFieldName(i)); snprintf(uniq_id, 32, "ch%d_%s", iv->assign[i].ch, iv->getFieldName(i)); const char* devCls = getFieldDeviceClass(iv->assign[i].fieldId); @@ -1210,6 +740,8 @@ void app::sendMqttDiscoveryConfig(void) { } } + +//----------------------------------------------------------------------------- const char* app::getFieldDeviceClass(uint8_t fieldId) { uint8_t pos = 0; for(; pos < DEVICE_CLS_ASSIGN_LIST_LEN; pos++) { @@ -1219,6 +751,8 @@ const char* app::getFieldDeviceClass(uint8_t fieldId) { return (pos >= DEVICE_CLS_ASSIGN_LIST_LEN) ? NULL : deviceClasses[deviceFieldAssignment[pos].deviceClsId]; } + +//----------------------------------------------------------------------------- const char* app::getFieldStateClass(uint8_t fieldId) { uint8_t pos = 0; for(; pos < DEVICE_CLS_ASSIGN_LIST_LEN; pos++) { @@ -1227,3 +761,187 @@ const char* app::getFieldStateClass(uint8_t fieldId) { } return (pos >= DEVICE_CLS_ASSIGN_LIST_LEN) ? NULL : stateClasses[deviceFieldAssignment[pos].stateClsId]; } + + +//----------------------------------------------------------------------------- +void app::resetSystem(void) { + mUptimeSecs = 0; + mUptimeTicker = 0xffffffff; + mUptimeInterval = 1000; + +#ifdef AP_ONLY + mTimestamp = 1; +#else + mTimestamp = 0; +#endif + + mHeapStatCnt = 0; + + mSendTicker = 0xffff; + mMqttTicker = 0xffff; + mMqttInterval = MQTT_INTERVAL; + mSerialTicker = 0xffff; + mMqttActive = false; + + mTicker = 0; + mRxTicker = 0; + + mSendLastIvId = 0; + + mShowRebootRequest = false; + + + memset(mPayload, 0, (MAX_NUM_INVERTERS * sizeof(invPayload_t))); + mRxFailed = 0; + mRxSuccess = 0; + mFrameCnt = 0; + mLastPacketId = 0x00; +} + + +//----------------------------------------------------------------------------- +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); + + + // nrf24 + mConfig.sendInterval = SEND_INTERVAL; + mConfig.maxRetransPerPyld = DEF_MAX_RETRANS_PER_PYLD; + mConfig.pinCs = DEF_RF24_CS_PIN; + mConfig.pinCe = DEF_RF24_CE_PIN; + mConfig.pinIrq = DEF_RF24_IRQ_PIN; + mConfig.amplifierPower = DEF_AMPLIFIERPOWER & 0x03; + + // ntp + snprintf(mConfig.ntpAddr, NTP_ADDR_LEN, "%s", DEF_NTP_SERVER_NAME); + mConfig.ntpPort = DEF_NTP_PORT; + + // 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; +} + + +//----------------------------------------------------------------------------- +void app::loadEEpconfig(void) { + DPRINTLN(DBG_VERBOSE, F("app::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) { + mEep->read(ADDR_INV_PWR_LIM + (i * 2),(uint16_t *)&(iv->powerLimit[0])); + if (iv->powerLimit[0] != 0xffff) { // only set it, if it is changed by user. Default value in the html setup page is -1 = 0xffff + iv->powerLimit[1] = 0x0001; // set the limit as persistent + iv->devControlCmd = ActivePowerContr; // set active power limit + iv->devControlRequest = true; // set to true to update the active power limit from setup html page + DPRINTLN(DBG_INFO, F("add inverter: ") + String(name) + ", SN: " + String(invSerial, HEX) + ", Power Limit: " + String(iv->powerLimit[0])); + } + 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); + } + } + + // TODO: the original mqttinterval value is not needed any more + mMqttInterval += mConfig.sendInterval; + } + } + } +} + + +//----------------------------------------------------------------------------- +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); + if(NULL != iv) { + mEep->write(ADDR_INV_ADDR + (i * 8), iv->serial.u64); + mEep->write(ADDR_INV_PWR_LIM + i * 2, iv->powerLimit[0]); + 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(); + mEep->commit(); +} + + +//----------------------------------------------------------------------------- +void app::setupMqtt(void) { + if(mSettingsValid) { + if(mConfig.mqtt.broker[0] > 0) { + mMqttActive = true; + if(mMqttInterval < MIN_MQTT_INTERVAL) + mMqttInterval = MIN_MQTT_INTERVAL; + } + else + mMqttInterval = 0xffff; + + mMqttTicker = 0; + mMqtt.setup(&mConfig.mqtt, mSysConfig.deviceName); + mMqtt.setCallback(std::bind(&app::cbMqtt, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + + + if(mMqttActive) { + mMqtt.sendMsg("version", mVersion); + if(mMqtt.isConnected()) + mMqtt.sendMsg("device", mSysConfig.deviceName); + + /*char topic[30]; + for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) { + iv = mSys->getInverterByPos(i); + if(NULL != iv) { + for(uint8_t i = 0; i < 4; i++) { + if(0 != iv->chName[i][0]) { + snprintf(topic, 30, "%s/ch%d/%s", iv->name, i+1, "name"); + mMqtt.sendMsg(topic, iv->chName[i]); + yield(); + } + } + } + }*/ + } + } +} diff --git a/tools/esp8266/app.h b/tools/esp8266/app.h index 0014e68e..c81ba2f1 100644 --- a/tools/esp8266/app.h +++ b/tools/esp8266/app.h @@ -6,16 +6,23 @@ #ifndef __APP_H__ #define __APP_H__ -#include "main.h" +#include "dbg.h" +#include "Arduino.h" + + #include #include #include +#include "eep.h" #include "defines.h" +#include "crc.h" #include "CircularBuffer.h" #include "hmSystem.h" #include "mqtt.h" +#include "wifi.h" +#include "web.h" // hier läst sich das Verhalten der app in Bezug auf MQTT // durch PER-Conpiler defines anpassen @@ -25,7 +32,7 @@ #define __MQTT_NO_DISCOVERCONFIG__ // das versenden der MQTTDiscoveryConfig abschalten ( gehört eigentlich ins Setup ) typedef CircularBuffer BufferType; -typedef HmRadio RadioType; +typedef HmRadio RadioType; typedef Inverter InverterType; typedef HmSystem HmSystemType; @@ -49,43 +56,28 @@ typedef struct { } invPayload_t; -class app : public Main { +class wifi; +class web; + +class app { public: app(); - ~app(); + ~app() {} void setup(uint32_t timeout); void loop(void); void handleIntr(void); void cbMqtt(char* topic, byte* payload, unsigned int length); + void saveValues(void); + String getStatistics(void); + String getLiveData(void); + String getJson(void); + bool getWifiApActive(void); - uint8_t app_loops; uint8_t getIrqPin(void) { - return mSys->Radio.pinIrq; + return mConfig.pinIrq; } - private: - bool buildPayload(uint8_t id); - void processPayload(bool retransmit); - - void showFavicon(void); - void showIndex(void); - void showSetup(void); - void showSave(void); - void showErase(void); - void showStatistics(void); - void showHoymiles(void); - void showLiveData(void); - void showJSON(void); - void webapi(void); - - - void saveValues(bool webSend); - void updateCrc(void); - void sendMqttDiscoveryConfig(void); - const char* getFieldDeviceClass(uint8_t fieldId); - const char* getFieldStateClass(uint8_t fieldId); - uint64_t Serial2u64(const char *val) { char tmp[3] = {0}; uint64_t ret = 0ULL; @@ -101,12 +93,142 @@ class app : public Main { return ret; } - bool mShowRebootRequest; + String getDateTimeStr(time_t t) { + char str[20] = {0}; + if(0 == t) + sprintf(str, "n/a"); + else + sprintf(str, "%04d-%02d-%02d %02d:%02d:%02d", year(t), month(t), day(t), hour(t), minute(t), second(t)); + return String(str); + } + + inline uint32_t getUptime(void) { + return mUptimeSecs; + } + + inline uint32_t getTimestamp(void) { + return mTimestamp; + } + + void eraseSettings(bool all = false) { + //DPRINTLN(DBG_VERBOSE, F("main.h:eraseSettings")); + uint8_t buf[64] = {0}; + uint16_t addr = (all) ? ADDR_START : ADDR_START_SETTINGS; + uint16_t end; + 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 checkTicker(uint32_t *ticker, uint32_t interval) { + uint32_t mil = millis(); + if(mil >= *ticker) { + *ticker = mil + interval; + return true; + } + else if(mil < (*ticker - interval)) { + *ticker = mil + interval; + return true; + } + + return false; + } HmSystemType *mSys; + private: + void resetSystem(void); + void loadDefaultConfig(void); + void loadEEpconfig(void); + void setupMqtt(void); + + bool buildPayload(uint8_t id); + void processPayload(bool retransmit); + + void sendMqttDiscoveryConfig(void); + const char* getFieldDeviceClass(uint8_t fieldId); + const char* getFieldStateClass(uint8_t fieldId); + + 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 = 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")); + uint32_t free; + uint16_t max; + uint8_t frag; + ESP.getHeapStats(&free, &max, &frag); + DPRINT(DBG_VERBOSE, F("free: ") + String(free)); + DPRINT(DBG_VERBOSE, F(" - max: ") + String(max) + "%"); + DPRINTLN(DBG_VERBOSE, F(" - frag: ") + String(frag)); + } + + + uint32_t mUptimeTicker; + uint16_t mUptimeInterval; + uint32_t mUptimeSecs; + uint8_t mHeapStatCnt; + + + bool mWifiSettingsValid; + bool mSettingsValid; + + eep *mEep; + uint32_t mTimestamp; + + bool mShowRebootRequest; + + wifi *mWifi; + web *mWebInst; + sysConfig_t mSysConfig; + config_t mConfig; + char mVersion[12]; + uint16_t mSendTicker; - uint16_t mSendInterval; uint8_t mSendLastIvId; invPayload_t mPayload[MAX_NUM_INVERTERS]; @@ -114,12 +236,9 @@ class app : public Main { uint32_t mRxSuccess; uint32_t mFrameCnt; uint8_t mLastPacketId; - uint8_t mMaxRetransPerPyld; // timer uint32_t mTicker; - bool mSerialValues; - bool mSerialDebug; uint32_t mRxTicker; @@ -132,7 +251,6 @@ class app : public Main { // serial uint16_t mSerialTicker; - uint16_t mSerialInterval; }; #endif /*__APP_H__*/ diff --git a/tools/esp8266/config.h b/tools/esp8266/config.h index 9851caef..a022528e 100644 --- a/tools/esp8266/config.h +++ b/tools/esp8266/config.h @@ -31,6 +31,14 @@ // default device name #define DEF_DEVICE_NAME "AHOY-DTU" +// default pinout +#define DEF_RF24_CS_PIN 15 +#define DEF_RF24_CE_PIN 2 +#define DEF_RF24_IRQ_PIN 0 + +// default NRF24 power, possible values (0 - 3) +#define DEF_AMPLIFIERPOWER 2 + // number of packets hold in buffer #define PACKET_BUFFER_SIZE 30 @@ -38,13 +46,10 @@ #define MAX_NUM_INVERTERS 3 // default serial interval -#define SERIAL_INTERVAL 5 +#define SERIAL_INTERVAL 5 // default send interval -#define SEND_INTERVAL 30 - -// default mqtt interval -#define MQTT_INTERVAL 60 +#define SEND_INTERVAL 30 // maximum human readable inverter name length #define MAX_NAME_LENGTH 16 @@ -64,6 +69,30 @@ // threshold of minimum power on which the inverter is marked as inactive #define INACT_PWR_THRESH 3 +// default ntp server uri +#define DEF_NTP_SERVER_NAME "pool.ntp.org" + +// default ntp server port +#define DEF_NTP_PORT 8888 + +// default mqtt interval +#define MQTT_INTERVAL 60 + +// default MQTT broker uri +#define DEF_MQTT_BROKER "\0" + +// default MQTT port +#define DEF_MQTT_PORT 1883 + +// default MQTT user +#define DEF_MQTT_USER "\0" + +// default MQTT pwd +#define DEF_MQTT_PWD "\0" + +// default MQTT topic +#define DEF_MQTT_TOPIC "inverter" + // changes the style of "/setup" page, visualized = nicer #define LIVEDATA_VISUALIZED diff --git a/tools/esp8266/defines.h b/tools/esp8266/defines.h index f229e1da..ce21e996 100644 --- a/tools/esp8266/defines.h +++ b/tools/esp8266/defines.h @@ -8,20 +8,12 @@ #include "config.h" -//------------------------------------- -// PINOUT (Default, can be changed in setup) -//------------------------------------- -#define RF24_CS_PIN 15 -#define RF24_CE_PIN 2 -#define RF24_IRQ_PIN 0 - - //------------------------------------- // VERSION //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 5 -#define VERSION_PATCH 9 +#define VERSION_PATCH 11 //------------------------------------- @@ -111,18 +103,58 @@ typedef enum { #define SER_INTERVAL_LEN 2 // uint16_t -#define ADDR_START 0 -#define ADDR_SSID ADDR_START -#define ADDR_PWD ADDR_SSID + SSID_LEN -#define ADDR_DEVNAME ADDR_PWD + PWD_LEN -#define ADDR_WIFI_CRC ADDR_DEVNAME + DEVNAME_LEN -#define ADDR_START_SETTINGS ADDR_WIFI_CRC + CRC_LEN +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; + +typedef struct { + char deviceName[DEVNAME_LEN]; + + // wifi + char stationSsid[SSID_LEN]; + char stationPwd[PWD_LEN]; +} sysConfig_t; + +typedef struct { + // nrf24 + uint16_t sendInterval; + uint8_t maxRetransPerPyld; + uint8_t pinCs; + uint8_t pinCe; + uint8_t pinIrq; + uint8_t amplifierPower; + + // ntp + char ntpAddr[NTP_ADDR_LEN]; + uint16_t ntpPort; + + // mqtt + mqttConfig_t mqtt; + + // serial + uint16_t serialInterval; + bool serialShowIv; + bool serialDebug; +} config_t; + -#define ADDR_PINOUT ADDR_START_SETTINGS +#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 + 1 +#define CFG_LEN 7 + NTP_ADDR_LEN + 2 + CFG_MQTT_LEN + 4 -#define ADDR_RF24_AMP_PWR ADDR_PINOUT + PINOUT_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_RF24_AMP_PWR + RF24_AMP_PWR_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 @@ -130,31 +162,20 @@ typedef enum { #define ADDR_INV_MAX_RTRY ADDR_INV_INTERVAL + INV_INTERVAL_LEN #define ADDR_INV_PWR_LIM ADDR_INV_MAX_RTRY + INV_MAX_RTRY_LEN -#define ADDR_NTP_ADDR ADDR_INV_PWR_LIM + INV_PWR_LIM_LEN //Bugfix #125 -#define ADDR_NTP_PORT ADDR_NTP_ADDR + NTP_ADDR_LEN - -#define ADDR_MQTT_ADDR ADDR_NTP_PORT + NTP_PORT_LEN -#define ADDR_MQTT_USER ADDR_MQTT_ADDR + MQTT_ADDR_LEN -#define ADDR_MQTT_PWD ADDR_MQTT_USER + MQTT_USER_LEN -#define ADDR_MQTT_TOPIC ADDR_MQTT_PWD + MQTT_PWD_LEN -#define ADDR_MQTT_INTERVAL ADDR_MQTT_TOPIC + MQTT_TOPIC_LEN -#define ADDR_MQTT_PORT ADDR_MQTT_INTERVAL + MQTT_INTERVAL_LEN +#define ADDR_NEXT ADDR_INV_PWR_LIM + INV_PWR_LIM_LEN -#define ADDR_SER_ENABLE ADDR_MQTT_PORT + MQTT_PORT_LEN -#define ADDR_SER_DEBUG ADDR_SER_ENABLE + SER_ENABLE_LEN -#define ADDR_SER_INTERVAL ADDR_SER_DEBUG + SER_DEBUG_LEN -#define ADDR_NEXT ADDR_SER_INTERVAL + SER_INTERVAL_LEN -// #define ADDR_SETTINGS_CRC 950 #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 +")" +#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 +")" +#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__*/ diff --git a/tools/esp8266/eep.h b/tools/esp8266/eep.h index 52907d5b..b66d2cf7 100644 --- a/tools/esp8266/eep.h +++ b/tools/esp8266/eep.h @@ -130,7 +130,7 @@ class eep { EEPROM.write(addr++, (value ) & 0xff); } - void write(uint64_t addr, uint64_t value) { + 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); diff --git a/tools/esp8266/esp8266.cpp b/tools/esp8266/esp8266.cpp deleted file mode 100644 index 72caa280..00000000 --- a/tools/esp8266/esp8266.cpp +++ /dev/null @@ -1,30 +0,0 @@ -//----------------------------------------------------------------------------- -// 2022 Ahoy, https://www.mikrocontroller.net/topic/525778 -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ -//----------------------------------------------------------------------------- - -#include "dbg.h" -#include "app.h" -#include "config.h" - -app myApp; - -//----------------------------------------------------------------------------- -IRAM_ATTR void handleIntr(void) { - myApp.handleIntr(); -} - - -//----------------------------------------------------------------------------- -void setup() { - myApp.setup(WIFI_TRY_CONNECT_TIME); - - // TODO: move to HmRadio - attachInterrupt(digitalPinToInterrupt(myApp.getIrqPin()), handleIntr, FALLING); -} - - -//----------------------------------------------------------------------------- -void loop() { - myApp.loop(); -} diff --git a/tools/esp8266/hmInverter.h b/tools/esp8266/hmInverter.h index f7a50cf7..88b3356a 100644 --- a/tools/esp8266/hmInverter.h +++ b/tools/esp8266/hmInverter.h @@ -83,7 +83,7 @@ class Inverter { Inverter() { ts = 0; - powerLimit[0] = -1; // 65535 W Limit -> unlimited + powerLimit[0] = 0xffff; // 65535 W Limit -> unlimited powerLimit[1] = 0x0001; // 0x0000 --> set temporary , 0x0001 --> set persistent devControlRequest = false; devControlCmd = 0xff; diff --git a/tools/esp8266/hmRadio.h b/tools/esp8266/hmRadio.h index a5c6f863..957ace68 100644 --- a/tools/esp8266/hmRadio.h +++ b/tools/esp8266/hmRadio.h @@ -27,7 +27,7 @@ #define ALL_FRAMES 0x80 #define SINGLE_FRAME 0x81 -const char* const rf24AmpPower[] = {"MIN", "LOW", "HIGH", "MAX"}; +const char* const rf24AmpPowerNames[] = {"MIN", "LOW", "HIGH", "MAX"}; //----------------------------------------------------------------------------- @@ -55,7 +55,7 @@ const char* const rf24AmpPower[] = {"MIN", "LOW", "HIGH", "MAX"}; //----------------------------------------------------------------------------- // HM Radio class //----------------------------------------------------------------------------- -template +template class HmRadio { public: HmRadio() : mNrf24(CE_PIN, CS_PIN, SPI_SPEED) { @@ -73,11 +73,6 @@ class HmRadio { mRxChIdx = 0; // Start RX with 03 mRxLoopCnt = RF_LOOP_CNT; - pinCs = CS_PIN; - pinCe = CE_PIN; - pinIrq = IRQ_PIN; - - AmplifierPower = 1; mSendCnt = 0; mSerialDebug = false; @@ -85,13 +80,13 @@ class HmRadio { } ~HmRadio() {} - void setup(BUFFER *ctrl) { + void setup(config_t *config, BUFFER *ctrl) { DPRINTLN(DBG_VERBOSE, F("hmRadio.h:setup")); - pinMode(pinIrq, INPUT_PULLUP); + pinMode(config->pinIrq, INPUT_PULLUP); mBufCtrl = ctrl; - mNrf24.begin(pinCe, pinCs); + mNrf24.begin(config->pinCe, config->pinCs); mNrf24.setRetries(0, 0); mNrf24.setChannel(DEFAULT_RECV_CHANNEL); @@ -106,8 +101,8 @@ class HmRadio { // enable only receiving interrupts mNrf24.maskIRQ(true, true, false); - DPRINTLN(DBG_INFO, F("RF24 Amp Pwr: RF24_PA_") + String(rf24AmpPower[AmplifierPower])); - mNrf24.setPALevel(AmplifierPower & 0x03); + DPRINTLN(DBG_INFO, F("RF24 Amp Pwr: RF24_PA_") + String(rf24AmpPowerNames[config->amplifierPower])); + mNrf24.setPALevel(config->amplifierPower & 0x03); mNrf24.startListening(); DPRINTLN(DBG_INFO, F("Radio Config:")); @@ -277,11 +272,8 @@ class HmRadio { return mNrf24.isChipConnected(); } - uint8_t pinCs; - uint8_t pinCe; - uint8_t pinIrq; - uint8_t AmplifierPower; + uint32_t mSendCnt; bool mSerialDebug; diff --git a/tools/esp8266/hmSystem.h b/tools/esp8266/hmSystem.h index 3d7f7f2b..386484fa 100644 --- a/tools/esp8266/hmSystem.h +++ b/tools/esp8266/hmSystem.h @@ -30,9 +30,9 @@ class HmSystem { // TODO: cleanup } - void setup() { + void setup(config_t *config) { DPRINTLN(DBG_VERBOSE, F("hmSystem.h:setup")); - Radio.setup(&BufCtrl); + Radio.setup(config, &BufCtrl); } INVERTERTYPE *addInverter(const char *name, uint64_t serial, uint16_t chMaxPwr[]) { @@ -86,9 +86,9 @@ class HmSystem { return NULL; } - INVERTERTYPE *getInverterByPos(uint8_t pos) { + INVERTERTYPE *getInverterByPos(uint8_t pos, bool check = true) { DPRINTLN(DBG_VERBOSE, F("hmSystem.h:getInverterByPos")); - if(mInverter[pos].serial.u64 != 0ULL) + if((mInverter[pos].serial.u64 != 0ULL) || false == check) return &mInverter[pos]; else return NULL; diff --git a/tools/esp8266/html/convert.py b/tools/esp8266/html/convert.py index 4cbecb20..98027b2f 100755 --- a/tools/esp8266/html/convert.py +++ b/tools/esp8266/html/convert.py @@ -34,5 +34,5 @@ def convert2Header(inFile): convert2Header("index.html") convert2Header("setup.html") -convert2Header("hoymiles.html") +convert2Header("visualization.html") convert2Header("style.css") diff --git a/tools/esp8266/html/h/hoymiles_html.h b/tools/esp8266/html/h/hoymiles_html.h deleted file mode 100644 index 93beff78..00000000 --- a/tools/esp8266/html/h/hoymiles_html.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef __HOYMILES_HTML_H__ -#define __HOYMILES_HTML_H__ -const char hoymiles_html[] PROGMEM = "Index - {DEVICE}

AHOY - {DEVICE}

Every {TS}seconds the values are updated

© 2022

Home

AHOY :: {VERSION}

"; -#endif /*__HOYMILES_HTML_H__*/ diff --git a/tools/esp8266/html/h/index_html.h b/tools/esp8266/html/h/index_html.h index 6c4255bf..61dd0cce 100644 --- a/tools/esp8266/html/h/index_html.h +++ b/tools/esp8266/html/h/index_html.h @@ -1,4 +1,4 @@ #ifndef __INDEX_HTML_H__ #define __INDEX_HTML_H__ -const char index_html[] PROGMEM = "Index - {DEVICE}

AHOY - {DEVICE}

Visualization

Setup

Uptime:

Time:

Statistics:

Every {TS}seconds the values are updated

This project was started from this discussion. (Mikrocontroller.net)
New updates can be found on Github: https://github.com/grindylow/ahoy

Please report issues using the feature provided by Github

Discuss with us on Discord

Creative Commons - https://creativecommons.org/licenses/by-nc-sa/3.0/de/
Check the licenses which are published on https://github.com/grindylow/ahoyas well

© 2022

Update Firmware

AHOY :: {VERSION}

Reboot

Git SHA: {BUILD}

"; +const char index_html[] PROGMEM = "Index - {DEVICE}

AHOY - {DEVICE}

Visualization

Setup

Uptime:

Statistics:

Every {TS}seconds the values are updated

This project was started from this discussion. (Mikrocontroller.net)
New updates can be found on Github: https://github.com/grindylow/ahoy

Please report issues using the feature provided by Github

Discuss with us on Discord

Creative Commons - https://creativecommons.org/licenses/by-nc-sa/3.0/de/
Check the licenses which are published on https://github.com/grindylow/ahoyas well

© 2022

Update Firmware

AHOY :: {VERSION}

Reboot

Git SHA: {BUILD}

"; #endif /*__INDEX_HTML_H__*/ diff --git a/tools/esp8266/html/h/visualization_html.h b/tools/esp8266/html/h/visualization_html.h new file mode 100644 index 00000000..b70bc5b2 --- /dev/null +++ b/tools/esp8266/html/h/visualization_html.h @@ -0,0 +1,4 @@ +#ifndef __VISUALIZATION_HTML_H__ +#define __VISUALIZATION_HTML_H__ +const char visualization_html[] PROGMEM = "Index - {DEVICE}

AHOY - {DEVICE}

Every {TS}seconds the values are updated

© 2022

Home

AHOY :: {VERSION}

"; +#endif /*__VISUALIZATION_HTML_H__*/ diff --git a/tools/esp8266/html/index.html b/tools/esp8266/html/index.html index f0d2ffa8..d72ae6f3 100644 --- a/tools/esp8266/html/index.html +++ b/tools/esp8266/html/index.html @@ -6,10 +6,8 @@