Browse Source

add ethernet support, thx @fumanchi

(ahoyeth.h and ahoyeth.cpp are missing)
pull/1093/head
lumapu 2 years ago
parent
commit
1e1a21fa56
  1. 95
      src/app.cpp
  2. 29
      src/app.h
  3. 7
      src/appInterface.h
  4. 14
      src/config/config.h
  5. 20
      src/config/settings.h
  6. 2
      src/defines.h
  7. 44
      src/platformio.ini
  8. 17
      src/web/RestApi.h
  9. 8
      src/web/web.h
  10. 3
      src/wifi/ahoywifi.cpp
  11. 3
      src/wifi/ahoywifi.h

95
src/app.cpp

@ -3,12 +3,18 @@
// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed
//-----------------------------------------------------------------------------
#include "app.h"
#include <ArduinoJson.h>
#include "app.h"
#include "utils/sun.h"
//-----------------------------------------------------------------------------
app::app() : ah::Scheduler() {}
app::app()
: ah::Scheduler {},
mInnerLoopCb {nullptr} {
}
//-----------------------------------------------------------------------------
@ -24,6 +30,7 @@ void app::setup() {
mSettings.setup();
mSettings.getPtr(mConfig);
DPRINT(DBG_INFO, F("Settings valid: "));
DSERIAL.flush();
if (mSettings.getValid())
DBGPRINTLN(F("true"));
else
@ -31,17 +38,29 @@ void app::setup() {
mSys.enableDebug();
mSys.setup(mConfig->nrf.amplifierPower, mConfig->nrf.pinIrq, mConfig->nrf.pinCe, mConfig->nrf.pinCs, mConfig->nrf.pinSclk, mConfig->nrf.pinMosi, mConfig->nrf.pinMiso);
#if defined(AP_ONLY)
#ifdef ETHERNET
delay(1000);
DPRINT(DBG_INFO, F("mEth setup..."));
DSERIAL.flush();
mEth.setup(mConfig, &mTimestamp, [this](bool gotIp) { this->onNetwork(gotIp); }, [this](bool gotTime) { this->onNtpUpdate(gotTime); });
DBGPRINTLN(F("done..."));
DSERIAL.flush();
#endif // ETHERNET
#if !defined(ETHERNET)
#if defined(AP_ONLY)
mInnerLoopCb = std::bind(&app::loopStandard, this);
#else
mInnerLoopCb = std::bind(&app::loopWifi, this);
#endif
#endif /* !defined(ETHERNET) */
mWifi.setup(mConfig, &mTimestamp, std::bind(&app::onWifi, this, std::placeholders::_1));
#if !defined(ETHERNET)
mWifi.setup(mConfig, &mTimestamp, std::bind(&app::onNetwork, this, std::placeholders::_1));
#if !defined(AP_ONLY)
everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi), "wifiL");
#endif
#endif /* defined(ETHERNET) */
mSys.addInverters(&mConfig->inst);
@ -95,7 +114,8 @@ void app::setup() {
//-----------------------------------------------------------------------------
void app::loop(void) {
mInnerLoopCb();
if (mInnerLoopCb)
mInnerLoopCb();
}
//-----------------------------------------------------------------------------
@ -136,30 +156,38 @@ void app::loopStandard(void) {
mMqtt.loop();
}
#if !defined(ETHERNET)
//-----------------------------------------------------------------------------
void app::loopWifi(void) {
ah::Scheduler::loop();
yield();
}
#endif /* !defined(ETHERNET) */
//-----------------------------------------------------------------------------
void app::onWifi(bool gotIp) {
DPRINTLN(DBG_DEBUG, F("onWifi"));
void app::onNetwork(bool gotIp) {
DPRINTLN(DBG_DEBUG, F("onNetwork"));
ah::Scheduler::resetTicker();
regularTickers(); // reinstall regular tickers
if (gotIp) {
mInnerLoopCb = std::bind(&app::loopStandard, this);
every(std::bind(&app::tickSend, this), mConfig->nrf.sendInterval, "tSend");
mMqttReconnect = true;
mSunrise = 0; // needs to be set to 0, to reinstall sunrise and ivComm tickers!
once(std::bind(&app::tickNtpUpdate, this), 2, "ntp2");
#if !defined(ETHERNET)
if (WIFI_AP == WiFi.getMode()) {
mMqttEnabled = false;
everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi), "wifiL");
}
#endif /* !defined(ETHERNET) */
mInnerLoopCb = [this]() { this->loopStandard(); };
} else {
mInnerLoopCb = std::bind(&app::loopWifi, this);
#if defined(ETHERNET)
mInnerLoopCb = nullptr;
#else /* defined(ETHERNET) */
mInnerLoopCb = [this]() { this->loopWifi(); };
everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi), "wifiL");
#endif /* defined(ETHERNET) */
}
}
@ -176,8 +204,42 @@ void app::regularTickers(void) {
//-----------------------------------------------------------------------------
void app::tickNtpUpdate(void) {
uint32_t nxtTrig = 5; // default: check again in 5 sec
bool isOK = mWifi.getNtpTime();
bool isOK = false;
#if defined(ETHERNET)
if (!(isOK = mEth.updateNtpTime()))
once(std::bind(&app::tickNtpUpdate, this), nxtTrig, "ntp");
#else /* defined(ETHERNET) */
isOK = mWifi.getNtpTime();
if (isOK || mTimestamp != 0) {
this->updateNtp();
nxtTrig = isOK ? 43200 : 60; // depending on NTP update success check again in 12 h or in 1 min
}
once(std::bind(&app::tickNtpUpdate, this), nxtTrig, "ntp");
#endif /* defined(ETHERNET) */
// immediately start communicating
// @TODO: leads to reboot loops? not sure #674
if (isOK && mSendFirst) {
mSendFirst = false;
once(std::bind(&app::tickSend, this), 2, "senOn");
}
}
#if defined(ETHERNET)
void app::onNtpUpdate(bool gotTime)
{
uint32_t nxtTrig = 5; // default: check again in 5 sec
if (gotTime || mTimestamp != 0) {
this->updateNtp();
nxtTrig = gotTime ? 43200 : 60; // depending on NTP update success check again in 12 h or in 1 min
}
once(std::bind(&app::tickNtpUpdate, this), nxtTrig, "ntp");
}
#endif /* defined(ETHERNET) */
//-----------------------------------------------------------------------------
void app::updateNtp(void) {
if (mMqttReconnect && mMqttEnabled) {
mMqtt.tickerSecond();
everySec(std::bind(&PubMqttType::tickerSecond, &mMqtt), "mqttS");
@ -195,24 +257,13 @@ void app::tickNtpUpdate(void) {
}
}
nxtTrig = isOK ? 43200 : 60; // depending on NTP update success check again in 12 h or in 1 min
if ((mSunrise == 0) && (mConfig->sun.lat) && (mConfig->sun.lon)) {
mCalculatedTimezoneOffset = (int8_t)((mConfig->sun.lon >= 0 ? mConfig->sun.lon + 7.5 : mConfig->sun.lon - 7.5) / 15) * 3600;
tickCalcSunrise();
}
// immediately start communicating
// @TODO: leads to reboot loops? not sure #674
if (isOK && mSendFirst) {
mSendFirst = false;
once(std::bind(&app::tickSend, this), 2, "senOn");
}
mMqttReconnect = false;
}
once(std::bind(&app::tickNtpUpdate, this), nxtTrig, "ntp");
}
//-----------------------------------------------------------------------------
void app::tickCalcSunrise(void) {

29
src/app.h

@ -24,7 +24,11 @@
#include "utils/scheduler.h"
#include "web/RestApi.h"
#include "web/web.h"
#if defined(ETHERNET)
#include "eth/ahoyeth.h"
#else /* defined(ETHERNET) */
#include "wifi/ahoywifi.h"
#endif /* defined(ETHERNET) */
// convert degrees and radians for sun calculation
#define SIN(x) (sin(radians(x)))
@ -52,8 +56,10 @@ class app : public IApp, public ah::Scheduler {
void setup(void);
void loop(void);
void loopStandard(void);
#if !defined(ETHERNET)
void loopWifi(void);
void onWifi(bool gotIp);
#endif /* !defined(ETHERNET) */
void onNetwork(bool gotIp);
void regularTickers(void);
void handleIntr(void) {
@ -100,6 +106,7 @@ class app : public IApp, public ah::Scheduler {
return &mStat;
}
#if !defined(ETHERNET)
void scanAvailNetworks() {
mWifi.scanAvailNetworks();
}
@ -109,8 +116,9 @@ class app : public IApp, public ah::Scheduler {
}
void setOnUpdate() {
onWifi(false);
onNetwork(false);
}
#endif /* !defined(ETHERNET) */
void setRebootFlag() {
once(std::bind(&app::tickReboot, this), 3, "rboot");
@ -198,7 +206,13 @@ class app : public IApp, public ah::Scheduler {
DPRINT(DBG_DEBUG, F("setTimestamp: "));
DBGPRINTLN(String(newTime));
if(0 == newTime)
{
#if defined(ETHERNET)
mEth.updateNtpTime();
#else /* defined(ETHERNET) */
mWifi.getNtpTime();
#endif /* defined(ETHERNET) */
}
else
Scheduler::setTimestamp(newTime);
}
@ -226,7 +240,7 @@ class app : public IApp, public ah::Scheduler {
void tickReboot(void) {
DPRINTLN(DBG_INFO, F("Rebooting..."));
onWifi(false);
onNetwork(false);
ah::Scheduler::resetTicker();
WiFi.disconnect();
delay(200);
@ -243,6 +257,11 @@ class app : public IApp, public ah::Scheduler {
}
void tickNtpUpdate(void);
#if defined(ETHERNET)
void onNtpUpdate(bool gotTime);
#endif /* defined(ETHERNET) */
void updateNtp(void);
void tickCalcSunrise(void);
void tickIVCommunication(void);
void tickSun(void);
@ -271,7 +290,11 @@ class app : public IApp, public ah::Scheduler {
bool mShowRebootRequest;
bool mIVCommunicationOn;
#if defined(ETHERNET)
ahoyeth mEth;
#else /* defined(ETHERNET) */
ahoywifi mWifi;
#endif /* defined(ETHERNET) */
WebType mWeb;
RestApiType mApi;
PayloadType mPayload;

7
src/appInterface.h

@ -8,7 +8,9 @@
#include "defines.h"
#include "hm/hmSystem.h"
#if !defined(ETHERNET)
#include "ESPAsyncWebServer.h"
#endif /* defined(ETHERNET) */
// abstract interface to App. Make members of App accessible from child class
// like web or API without forward declaration
@ -18,15 +20,20 @@ class IApp {
virtual bool saveSettings(bool stopFs) = 0;
virtual bool readSettings(const char *path) = 0;
virtual bool eraseSettings(bool eraseWifi) = 0;
#if !defined(ETHERNET)
virtual bool getSavePending() = 0;
virtual bool getLastSaveSucceed() = 0;
virtual bool getShouldReboot() = 0;
virtual void setOnUpdate() = 0;
#endif /* defined(ETHERNET) */
virtual void setRebootFlag() = 0;
virtual const char *getVersion() = 0;
virtual statistics_t *getStatistics() = 0;
#if !defined(ETHERNET)
virtual void scanAvailNetworks() = 0;
virtual void getAvailNetworks(JsonObject obj) = 0;
#endif /* defined(ETHERNET) */
virtual uint32_t getUptime() = 0;
virtual uint32_t getTimestamp() = 0;

14
src/config/config.h

@ -32,12 +32,24 @@
// CONFIGURATION - COMPILE TIME
//-------------------------------------
// ethernet
#if defined(ETHERNET)
#define ETH_SPI_HOST SPI2_HOST
#define ETH_SPI_CLOCK_MHZ 25
#define ETH_INT_GPIO 4
#define ETH_MISO_GPIO 12
#define ETH_MOSI_GPIO 13
#define ETH_SCK_GPIO 14
#define ETH_CS_PIN 15
#else /* defined(ETHERNET) */
// time in seconds how long the station info (ssid + pwd) will be tried
#define WIFI_TRY_CONNECT_TIME 30
// time during the ESP will act as access point on connection failure (to
// station) in seconds
#define WIFI_AP_ACTIVE_TIME 60
#endif /* defined(ETHERNET) */
// default device name
#define DEF_DEVICE_NAME "AHOY-DTU"
@ -49,7 +61,7 @@
// to map its two HW SPIs anywhere and PCBs differ materially,
// so it has to be selected in the Web UI
#define DEF_CS_PIN 5
#define DEF_CE_PIN 4
#define DEF_CE_PIN 17
#define DEF_IRQ_PIN 16
#define DEF_MISO_PIN 19
#define DEF_MOSI_PIN 23

20
src/config/settings.h

@ -65,9 +65,14 @@ typedef struct {
uint16_t protectionMask;
bool darkMode;
#if defined(ETHERNET)
// ethernet
#else /* defined(ETHERNET) */
// wifi
char stationSsid[SSID_LEN];
char stationPwd[PWD_LEN];
#endif /* defined(ETHERNET) */
cfgIp_t ip;
} cfgSys_t;
@ -250,7 +255,7 @@ class settings {
root.shrinkToFit();
if(!err && (root.size() > 0)) {
mCfg.valid = true;
if(root.containsKey(F("wifi"))) jsonWifi(root[F("wifi")]);
if(root.containsKey(F("wifi"))) jsonNetwork(root[F("wifi")]);
if(root.containsKey(F("nrf"))) jsonNrf(root[F("nrf")]);
if(root.containsKey(F("ntp"))) jsonNtp(root[F("ntp")]);
if(root.containsKey(F("sun"))) jsonSun(root[F("sun")]);
@ -274,7 +279,7 @@ class settings {
DynamicJsonDocument json(MAX_ALLOWED_BUF_SIZE);
JsonObject root = json.to<JsonObject>();
jsonWifi(root.createNestedObject(F("wifi")), true);
jsonNetwork(root.createNestedObject(F("wifi")), true);
jsonNrf(root.createNestedObject(F("nrf")), true);
jsonNtp(root.createNestedObject(F("ntp")), true);
jsonSun(root.createNestedObject(F("sun")), true);
@ -338,13 +343,18 @@ class settings {
mCfg.sys.protectionMask = DEF_PROT_INDEX | DEF_PROT_LIVE | DEF_PROT_SERIAL | DEF_PROT_SETUP
| DEF_PROT_UPDATE | DEF_PROT_SYSTEM | DEF_PROT_API | DEF_PROT_MQTT;
mCfg.sys.darkMode = false;
// restore temp settings
#if defined(ETHERNET)
memcpy(&mCfg.sys, &tmp, sizeof(cfgSys_t));
#else /* defined(ETHERNET) */
if(keepWifi)
memcpy(&mCfg.sys, &tmp, sizeof(cfgSys_t));
else {
snprintf(mCfg.sys.stationSsid, SSID_LEN, FB_WIFI_SSID);
snprintf(mCfg.sys.stationPwd, PWD_LEN, FB_WIFI_PWD);
}
#endif /* defined(ETHERNET) */
snprintf(mCfg.sys.deviceName, DEVNAME_LEN, DEF_DEVICE_NAME);
@ -400,11 +410,13 @@ class settings {
mCfg.plugin.display.disp_dc = DEF_PIN_OFF;
}
void jsonWifi(JsonObject obj, bool set = false) {
void jsonNetwork(JsonObject obj, bool set = false) {
if(set) {
char buf[16];
#if !defined(ETHERNET)
obj[F("ssid")] = mCfg.sys.stationSsid;
obj[F("pwd")] = mCfg.sys.stationPwd;
#endif /* !defined(ETHERNET) */
obj[F("dev")] = mCfg.sys.deviceName;
obj[F("adm")] = mCfg.sys.adminPwd;
obj[F("prot_mask")] = mCfg.sys.protectionMask;
@ -415,8 +427,10 @@ class settings {
ah::ip2Char(mCfg.sys.ip.dns2, buf); obj[F("dns2")] = String(buf);
ah::ip2Char(mCfg.sys.ip.gateway, buf); obj[F("gtwy")] = String(buf);
} else {
#if !defined(ETHERNET)
getChar(obj, F("ssid"), mCfg.sys.stationSsid, SSID_LEN);
getChar(obj, F("pwd"), mCfg.sys.stationPwd, PWD_LEN);
#endif /* !defined(ETHERNET) */
getChar(obj, F("dev"), mCfg.sys.deviceName, DEVNAME_LEN);
getChar(obj, F("adm"), mCfg.sys.adminPwd, PWD_LEN);
getVal<uint16_t>(obj, F("prot_mask"), &mCfg.sys.protectionMask);

2
src/defines.h

@ -13,7 +13,7 @@
//-------------------------------------
#define VERSION_MAJOR 0
#define VERSION_MINOR 6
#define VERSION_PATCH 7
#define VERSION_PATCH 8
//-------------------------------------
typedef struct {

44
src/platformio.ini

@ -135,6 +135,50 @@ monitor_filters =
time ; Add timestamp with milliseconds for each new line
log2file ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory
[env:esp32-wroom32-ethernet-debug]
platform = espressif32
board = lolin_d32
lib_deps =
khoih-prog/AsyncWebServer_ESP32_W5500
khoih-prog/AsyncUDP_ESP32_W5500
nrf24/RF24
paulstoffregen/Time
https://github.com/bertmelis/espMqttClient#v1.3.3
bblanchon/ArduinoJson
https://github.com/JChristensen/Timezone
olikraus/U8g2
zinggjm/GxEPD2@^1.5.0
build_flags = -DETHERNET -DDEBUG_LEVEL=DBG_DEBUG -DDEBUG_ESP_CORE -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_OOM -DDEBUG_ESP_PORT=Serial -std=gnu++14
build_unflags = -std=gnu++11
build_type = debug
monitor_filters =
;default ; Remove typical terminal control codes from input
time ; Add timestamp with milliseconds for each new line
log2file ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory
;esp32_exception_decoder
[env:esp32-wroom32-ethernet-release]
platform = espressif32
board = esp32dev
lib_deps =
khoih-prog/AsyncWebServer_ESP32_W5500
khoih-prog/AsyncUDP_ESP32_W5500
nrf24/RF24
paulstoffregen/Time
https://github.com/bertmelis/espMqttClient#v1.3.3
bblanchon/ArduinoJson
https://github.com/JChristensen/Timezone
olikraus/U8g2
zinggjm/GxEPD2@^1.5.0
build_flags = -DETHERNET -DRELEASE -DLOG_LOCAL_LEVEL=ESP_LOG_INFO -DDEBUG_LEVEL=DBG_DEBUG -std=gnu++14
build_unflags = -std=gnu++11
monitor_filters =
;default ; Remove typical terminal control codes from input
;time ; Add timestamp with milliseconds for each new line
;log2file ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory
esp32_exception_decoder
[env:opendtufusionv1-release]
platform = espressif32
board = esp32-s3-devkitc-1

17
src/web/RestApi.h

@ -16,7 +16,11 @@
#include "../hm/hmSystem.h"
#include "../utils/helper.h"
#include "AsyncJson.h"
#if defined(ETHERNET)
#include "AsyncWebServer_ESP32_W5500.h"
#else /* defined(ETHERNET) */
#include "ESPAsyncWebServer.h"
#endif /* defined(ETHERNET) */
#if defined(F) && defined(ESP32)
#undef F
@ -88,8 +92,10 @@ class RestApi {
else if(path == "inverter/list") getInverterList(root);
else if(path == "index") getIndex(request, root);
else if(path == "setup") getSetup(request, root);
#if !defined(ETHERNET)
else if(path == "setup/networks") getNetworks(root);
else if(path == "live") getLive(request, root);
#endif /* !defined(ETHERNET) */
else if(path == "live") getLive(request,root);
else if(path == "record/info") getRecord(root, InverterDevInform_All);
else if(path == "record/alarm") getRecord(root, AlarmData);
else if(path == "record/config") getRecord(root, SystemConfigPara);
@ -204,7 +210,9 @@ class RestApi {
}
void getSysInfo(AsyncWebServerRequest *request, JsonObject obj) {
#if !defined(ETHERNET)
obj[F("ssid")] = mConfig->sys.stationSsid;
#endif /* !defined(ETHERNET) */
obj[F("device_name")] = mConfig->sys.deviceName;
obj[F("dark_mode")] = (bool)mConfig->sys.darkMode;
@ -494,9 +502,11 @@ class RestApi {
getDisplay(obj.createNestedObject(F("display")));
}
#if !defined(ETHERNET)
void getNetworks(JsonObject obj) {
mApp->getAvailNetworks(obj);
}
#endif /* !defined(ETHERNET) */
void getLive(AsyncWebServerRequest *request, JsonObject obj) {
getGeneric(request, obj.createNestedObject(F("generic")));
@ -587,9 +597,12 @@ class RestApi {
}
bool setSetup(JsonObject jsonIn, JsonObject jsonOut) {
#if !defined(ETHERNET)
if(F("scan_wifi") == jsonIn[F("cmd")])
mApp->scanAvailNetworks();
else if(F("set_time") == jsonIn[F("cmd")])
else
#endif /* !defined(ETHERNET) */
if(F("set_time") == jsonIn[F("cmd")])
mApp->setTimestamp(jsonIn[F("val")]);
else if(F("sync_ntp") == jsonIn[F("cmd")])
mApp->setTimestamp(0); // 0: update ntp flag

8
src/web/web.h

@ -16,7 +16,11 @@
#include "../appInterface.h"
#include "../hm/hmSystem.h"
#include "../utils/helper.h"
#if defined(ETHERNET)
#include "AsyncWebServer_ESP32_W5500.h"
#else /* defined(ETHERNET) */
#include "ESPAsyncWebServer.h"
#endif /* defined(ETHERNET) */
#include "html/h/api_js.h"
#include "html/h/colorBright_css.h"
#include "html/h/colorDark_css.h"
@ -144,7 +148,9 @@ class Web {
}
void showUpdate2(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
#if !defined(ETHERNET)
mApp->setOnUpdate();
#endif /* !defined(ETHERNET) */
if (!index) {
Serial.printf("Update Start: %s\n", filename.c_str());
@ -444,10 +450,12 @@ class Web {
char buf[20] = {0};
// general
#if !defined(ETHERNET)
if (request->arg("ssid") != "")
request->arg("ssid").toCharArray(mConfig->sys.stationSsid, SSID_LEN);
if (request->arg("pwd") != "{PWD}")
request->arg("pwd").toCharArray(mConfig->sys.stationPwd, PWD_LEN);
#endif /* !defined(ETHERNET) */
if (request->arg("device") != "")
request->arg("device").toCharArray(mConfig->sys.deviceName, DEVNAME_LEN);
mConfig->sys.darkMode = (request->arg("darkMode") == "on");

3
src/wifi/ahoywifi.cpp

@ -3,6 +3,7 @@
// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed
//-----------------------------------------------------------------------------
#if !defined(ETHERNET)
#if defined(ESP32) && defined(F)
#undef F
#define F(sl) (sl)
@ -414,3 +415,5 @@ void ahoywifi::welcome(String ip, String mode) {
DBGPRINTLN(F("to configure your device"));
DBGPRINTLN(F("--------------------------------\n"));
}
#endif /* !defined(ETHERNET) */

3
src/wifi/ahoywifi.h

@ -2,7 +2,7 @@
// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
//-----------------------------------------------------------------------------
#if !defined(ETHERNET)
#ifndef __AHOYWIFI_H__
#define __AHOYWIFI_H__
@ -75,3 +75,4 @@ class ahoywifi {
};
#endif /*__AHOYWIFI_H__*/
#endif /* !defined(ETHERNET) */

Loading…
Cancel
Save