Implemented serveal global network functions which are independent of the medium (wifi / ethernet)

This commit is contained in:
Thomas Basler 2022-07-19 21:53:04 +02:00
parent 69959db93c
commit c022b8696b
9 changed files with 290 additions and 39 deletions

View File

@ -1,10 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include "NetworkSettings.h"
#include <Arduino.h> #include <Arduino.h>
#include <AsyncMqttClient.h> #include <AsyncMqttClient.h>
#include <Ticker.h> #include <Ticker.h>
#include <WiFi.h>
#include <memory> #include <memory>
class MqttSettingsClass { class MqttSettingsClass {
@ -19,7 +19,7 @@ public:
String getPrefix(); String getPrefix();
private: private:
void WiFiEvent(WiFiEvent_t event); void NetworkEvent(network_event event);
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason); void onMqttDisconnect(AsyncMqttClientDisconnectReason reason);
void onMqttConnect(bool sessionPresent); void onMqttConnect(bool sessionPresent);

View File

@ -4,6 +4,37 @@
#include <DNSServer.h> #include <DNSServer.h>
#include <WiFi.h> #include <WiFi.h>
#include <memory> #include <memory>
#include <vector>
enum class network_mode {
WiFi,
Ethernet,
Undefined
};
enum class network_event {
NETWORK_UNKNOWN,
NETWORK_START,
NETWORK_STOP,
NETWORK_CONNECTED,
NETWORK_DISCONNECTED,
NETWORK_GOT_IP,
NETWORK_LOST_IP,
NETWORK_EVENT_MAX
};
typedef std::function<void(network_event event)> NetworkEventCb;
typedef struct NetworkEventCbList {
NetworkEventCb cb;
network_event event;
NetworkEventCbList()
: cb(NULL)
, event(network_event::NETWORK_UNKNOWN)
{
}
} NetworkEventCbList_t;
class NetworkSettingsClass { class NetworkSettingsClass {
public: public:
@ -14,6 +45,18 @@ public:
void enableAdminMode(); void enableAdminMode();
String getApName(); String getApName();
IPAddress localIP();
IPAddress subnetMask();
IPAddress gatewayIP();
IPAddress dnsIP(uint8_t dns_no = 0);
String macAddress();
const char* getHostname();
bool isConnected();
network_mode NetworkMode();
bool onEvent(NetworkEventCb cbEvent, network_event event = network_event::NETWORK_EVENT_MAX);
void raiseEvent(network_event event);
private: private:
void setHostname(); void setHostname();
void setStaticIp(); void setStaticIp();
@ -30,6 +73,9 @@ private:
IPAddress apNetmask; IPAddress apNetmask;
std::unique_ptr<DNSServer> dnsServer; std::unique_ptr<DNSServer> dnsServer;
bool dnsServerStatus = false; bool dnsServerStatus = false;
network_mode _networkMode = network_mode::Undefined;
bool _ethConnected = false;
std::vector<NetworkEventCbList_t> _cbEventList;
}; };
extern NetworkSettingsClass NetworkSettings; extern NetworkSettingsClass NetworkSettings;

View File

@ -6,7 +6,7 @@
#include "ArduinoJson.h" #include "ArduinoJson.h"
#include "MqttPublishing.h" #include "MqttPublishing.h"
#include "MqttSettings.h" #include "MqttSettings.h"
#include "WiFiSettings.h" #include "NetworkSettings.h"
MqttHassPublishingClass MqttHassPublishing; MqttHassPublishingClass MqttHassPublishing;

View File

@ -4,6 +4,7 @@
*/ */
#include "MqttPublishing.h" #include "MqttPublishing.h"
#include "MqttSettings.h" #include "MqttSettings.h"
#include "NetworkSettings.h"
MqttPublishingClass MqttPublishing; MqttPublishingClass MqttPublishing;
@ -21,7 +22,7 @@ void MqttPublishingClass::loop()
if (millis() - _lastPublish > (config.Mqtt_PublishInterval * 1000)) { if (millis() - _lastPublish > (config.Mqtt_PublishInterval * 1000)) {
MqttSettings.publish("dtu/uptime", String(millis() / 1000)); MqttSettings.publish("dtu/uptime", String(millis() / 1000));
MqttSettings.publish("dtu/ip", WiFi.localIP().toString()); MqttSettings.publish("dtu/ip", NetworkSettings.localIP().toString());
// Loop all inverters // Loop all inverters
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) { for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {

View File

@ -7,22 +7,21 @@
#include "NetworkSettings.h" #include "NetworkSettings.h"
#include <AsyncMqttClient.h> #include <AsyncMqttClient.h>
#include <Ticker.h> #include <Ticker.h>
#include <WiFi.h>
MqttSettingsClass::MqttSettingsClass() MqttSettingsClass::MqttSettingsClass()
: mqttClient() : mqttClient()
{ {
} }
void MqttSettingsClass::WiFiEvent(WiFiEvent_t event) void MqttSettingsClass::NetworkEvent(network_event event)
{ {
switch (event) { switch (event) {
case SYSTEM_EVENT_STA_GOT_IP: case network_event::NETWORK_GOT_IP:
Serial.println(F("WiFi connected")); Serial.println(F("Network connected"));
performConnect(); performConnect();
break; break;
case SYSTEM_EVENT_STA_DISCONNECTED: case network_event::NETWORK_DISCONNECTED:
Serial.println(F("WiFi lost connection")); Serial.println(F("Network lost connection"));
mqttReconnectTimer.detach(); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi mqttReconnectTimer.detach(); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
break; break;
} }
@ -45,7 +44,7 @@ void MqttSettingsClass::onMqttDisconnect(AsyncMqttClientDisconnectReason reason)
void MqttSettingsClass::performConnect() void MqttSettingsClass::performConnect()
{ {
if (WiFi.isConnected() && Configuration.get().Mqtt_Enabled) { if (NetworkSettings.isConnected() && Configuration.get().Mqtt_Enabled) {
Serial.println(F("Connecting to MQTT...")); Serial.println(F("Connecting to MQTT..."));
CONFIG_T& config = Configuration.get(); CONFIG_T& config = Configuration.get();
mqttClient.setServer(config.Mqtt_Hostname, config.Mqtt_Port); mqttClient.setServer(config.Mqtt_Hostname, config.Mqtt_Port);
@ -103,7 +102,7 @@ void MqttSettingsClass::publishHass(String subtopic, String payload)
void MqttSettingsClass::init() void MqttSettingsClass::init()
{ {
using namespace std::placeholders; using namespace std::placeholders;
WiFi.onEvent(std::bind(&MqttSettingsClass::WiFiEvent, this, _1)); NetworkSettings.onEvent(std::bind(&MqttSettingsClass::NetworkEvent, this, _1));
mqttClient.onConnect(std::bind(&MqttSettingsClass::onMqttConnect, this, _1)); mqttClient.onConnect(std::bind(&MqttSettingsClass::onMqttConnect, this, _1));
mqttClient.onDisconnect(std::bind(&MqttSettingsClass::onMqttDisconnect, this, _1)); mqttClient.onDisconnect(std::bind(&MqttSettingsClass::onMqttDisconnect, this, _1));

View File

@ -31,36 +31,83 @@ void NetworkSettingsClass::NetworkEvent(WiFiEvent_t event)
#ifdef OPENDTU_ETHERNET #ifdef OPENDTU_ETHERNET
case ARDUINO_EVENT_ETH_START: case ARDUINO_EVENT_ETH_START:
Serial.println("ETH start"); Serial.println("ETH start");
ETH.setHostname("esp32-ethernet"); if (_networkMode == network_mode::Ethernet) {
raiseEvent(network_event::NETWORK_START);
}
break; break;
case ARDUINO_EVENT_ETH_STOP: case ARDUINO_EVENT_ETH_STOP:
Serial.println("ETH stop"); Serial.println("ETH stop");
if (_networkMode == network_mode::Ethernet) {
raiseEvent(network_event::NETWORK_STOP);
}
break; break;
case ARDUINO_EVENT_ETH_CONNECTED: case ARDUINO_EVENT_ETH_CONNECTED:
Serial.println("ETH connected"); Serial.println("ETH connected");
ETH.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE); _ethConnected = true;
raiseEvent(network_event::NETWORK_CONNECTED);
break; break;
case ARDUINO_EVENT_ETH_GOT_IP: case ARDUINO_EVENT_ETH_GOT_IP:
Serial.printf("ETH got IP: %s\n", ETH.localIP().toString().c_str()); Serial.printf("ETH got IP: %s\n", ETH.localIP().toString().c_str());
if (_networkMode == network_mode::Ethernet) {
raiseEvent(network_event::NETWORK_GOT_IP);
}
break; break;
case ARDUINO_EVENT_ETH_DISCONNECTED: case ARDUINO_EVENT_ETH_DISCONNECTED:
Serial.println("ETH disconnected"); Serial.println("ETH disconnected");
_ethConnected = false;
if (_networkMode == network_mode::Ethernet) {
raiseEvent(network_event::NETWORK_DISCONNECTED);
}
break; break;
#endif #endif
case ARDUINO_EVENT_WIFI_STA_CONNECTED: case ARDUINO_EVENT_WIFI_STA_CONNECTED:
Serial.println("WiFi connected"); Serial.println("WiFi connected");
if (_networkMode == network_mode::WiFi) {
raiseEvent(network_event::NETWORK_CONNECTED);
}
break; break;
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
Serial.println("WiFi disconnected"); Serial.println("WiFi disconnected");
if (_networkMode == network_mode::WiFi) {
WiFi.reconnect();
raiseEvent(network_event::NETWORK_DISCONNECTED);
}
break; break;
case ARDUINO_EVENT_WIFI_STA_GOT_IP: case ARDUINO_EVENT_WIFI_STA_GOT_IP:
Serial.printf("WiFi got ip: %s\n", WiFi.localIP().toString().c_str()); Serial.printf("WiFi got ip: %s\n", WiFi.localIP().toString().c_str());
if (_networkMode == network_mode::WiFi) {
raiseEvent(network_event::NETWORK_GOT_IP);
}
break; break;
default: default:
Serial.printf("Event: %d\n", event); Serial.printf("Event: %d\n", event);
} }
} }
bool NetworkSettingsClass::onEvent(NetworkEventCb cbEvent, network_event event)
{
if (!cbEvent) {
return pdFALSE;
}
NetworkEventCbList_t newEventHandler;
newEventHandler.cb = cbEvent;
newEventHandler.event = event;
_cbEventList.push_back(newEventHandler);
return true;
}
void NetworkSettingsClass::raiseEvent(network_event event)
{
for (uint32_t i = 0; i < _cbEventList.size(); i++) {
NetworkEventCbList_t entry = _cbEventList[i];
if (entry.cb) {
if (entry.event == event || entry.event == network_event::NETWORK_EVENT_MAX) {
entry.cb(event);
}
}
}
}
void NetworkSettingsClass::setupMode() void NetworkSettingsClass::setupMode()
{ {
if (adminEnabled) { if (adminEnabled) {
@ -74,7 +121,11 @@ void NetworkSettingsClass::setupMode()
} else { } else {
dnsServer->stop(); dnsServer->stop();
dnsServerStatus = false; dnsServerStatus = false;
if (_networkMode == network_mode::WiFi) {
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
} else {
WiFi.mode(WIFI_MODE_NULL);
}
} }
#ifdef OPENDTU_ETHERNET #ifdef OPENDTU_ETHERNET
ETH.begin(); ETH.begin();
@ -99,6 +150,26 @@ String NetworkSettingsClass::getApName()
void NetworkSettingsClass::loop() void NetworkSettingsClass::loop()
{ {
#ifdef OPENDTU_ETHERNET
if (_ethConnected) {
if (_networkMode != network_mode::Ethernet) {
// Do stuff when switching to Ethernet mode
Serial.println(F("Switch to Ethernet mode"));
_networkMode = network_mode::Ethernet;
WiFi.mode(WIFI_MODE_NULL);
setStaticIp();
setHostname();
}
} else
#endif
if (_networkMode != network_mode::WiFi) {
// Do stuff when switching to Ethernet mode
Serial.println(F("Switch to WiFi mode"));
_networkMode = network_mode::WiFi;
enableAdminMode();
applyConfig();
}
if (millis() - lastTimerCall > 1000) { if (millis() - lastTimerCall > 1000) {
adminTimeoutCounter++; adminTimeoutCounter++;
connectTimeoutTimer++; connectTimeoutTimer++;
@ -106,8 +177,8 @@ void NetworkSettingsClass::loop()
lastTimerCall = millis(); lastTimerCall = millis();
} }
if (adminEnabled) { if (adminEnabled) {
// Don't disable the admin mode when WiFi is not available // Don't disable the admin mode when network is not available
if (WiFi.status() != WL_CONNECTED) { if (!isConnected()) {
adminTimeoutCounter = 0; adminTimeoutCounter = 0;
} }
// If WiFi is connected to AP for more than ADMIN_TIMEOUT // If WiFi is connected to AP for more than ADMIN_TIMEOUT
@ -120,7 +191,7 @@ void NetworkSettingsClass::loop()
// It's nearly not possible to use the internal AP if the // It's nearly not possible to use the internal AP if the
// WiFi is searching for an AP. So disable searching afer // WiFi is searching for an AP. So disable searching afer
// WIFI_RECONNECT_TIMEOUT and repeat after WIFI_RECONNECT_REDO_TIMEOUT // WIFI_RECONNECT_TIMEOUT and repeat after WIFI_RECONNECT_REDO_TIMEOUT
if (WiFi.status() == WL_CONNECTED) { if (isConnected()) {
connectTimeoutTimer = 0; connectTimeoutTimer = 0;
connectRedoTimer = 0; connectRedoTimer = 0;
} else { } else {
@ -170,11 +241,22 @@ void NetworkSettingsClass::setHostname()
{ {
Serial.print(F("Setting Hostname... ")); Serial.print(F("Setting Hostname... "));
if (strcmp(Configuration.get().WiFi_Hostname, "")) { if (strcmp(Configuration.get().WiFi_Hostname, "")) {
if (_networkMode == network_mode::WiFi) {
if (WiFi.hostname(Configuration.get().WiFi_Hostname)) { if (WiFi.hostname(Configuration.get().WiFi_Hostname)) {
Serial.println(F("done")); Serial.println(F("done"));
} else { } else {
Serial.println(F("failed")); Serial.println(F("failed"));
} }
}
#ifdef OPENDTU_ETHERNET
else if (_networkMode == network_mode::Ethernet) {
if (ETH.setHostname(Configuration.get().WiFi_Hostname)) {
Serial.println(F("done"));
} else {
Serial.println(F("failed"));
}
}
#endif
} else { } else {
Serial.println(F("failed (Hostname empty)")); Serial.println(F("failed (Hostname empty)"));
} }
@ -182,6 +264,7 @@ void NetworkSettingsClass::setHostname()
void NetworkSettingsClass::setStaticIp() void NetworkSettingsClass::setStaticIp()
{ {
if (_networkMode == network_mode::WiFi) {
if (!Configuration.get().WiFi_Dhcp) { if (!Configuration.get().WiFi_Dhcp) {
Serial.print(F("Configuring WiFi STA static IP... ")); Serial.print(F("Configuring WiFi STA static IP... "));
WiFi.config( WiFi.config(
@ -192,6 +275,127 @@ void NetworkSettingsClass::setStaticIp()
IPAddress(Configuration.get().WiFi_Dns2)); IPAddress(Configuration.get().WiFi_Dns2));
Serial.println(F("done")); Serial.println(F("done"));
} }
}
#ifdef OPENDTU_ETHERNET
else if (_networkMode == network_mode::Ethernet) {
if (Configuration.get().WiFi_Dhcp) {
ETH.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE);
} else {
Serial.print(F("Configuring Ethernet static IP... "));
ETH.config(
IPAddress(Configuration.get().WiFi_Ip),
IPAddress(Configuration.get().WiFi_Gateway),
IPAddress(Configuration.get().WiFi_Netmask),
IPAddress(Configuration.get().WiFi_Dns1),
IPAddress(Configuration.get().WiFi_Dns2));
Serial.println(F("done"));
}
}
#endif
}
IPAddress NetworkSettingsClass::localIP()
{
switch (_networkMode) {
#ifdef OPENDTU_ETHERNET
case network_mode::Ethernet:
return ETH.localIP();
break;
#endif
case network_mode::WiFi:
return WiFi.localIP();
break;
default:
return INADDR_NONE;
}
}
IPAddress NetworkSettingsClass::subnetMask()
{
switch (_networkMode) {
#ifdef OPENDTU_ETHERNET
case network_mode::Ethernet:
return ETH.subnetMask();
break;
#endif
case network_mode::WiFi:
return WiFi.subnetMask();
break;
default:
return IPAddress(255, 255, 255, 0);
}
}
IPAddress NetworkSettingsClass::gatewayIP()
{
switch (_networkMode) {
#ifdef OPENDTU_ETHERNET
case network_mode::Ethernet:
return ETH.gatewayIP();
break;
#endif
case network_mode::WiFi:
return WiFi.gatewayIP();
break;
default:
return INADDR_NONE;
}
}
IPAddress NetworkSettingsClass::dnsIP(uint8_t dns_no)
{
switch (_networkMode) {
#ifdef OPENDTU_ETHERNET
case network_mode::Ethernet:
return ETH.dnsIP(dns_no);
break;
#endif
case network_mode::WiFi:
return WiFi.dnsIP(dns_no);
break;
default:
return INADDR_NONE;
}
}
String NetworkSettingsClass::macAddress()
{
switch (_networkMode) {
#ifdef OPENDTU_ETHERNET
case network_mode::Ethernet:
return ETH.macAddress();
break;
#endif
case network_mode::WiFi:
return WiFi.macAddress();
break;
default:
return String("");
}
}
const char* NetworkSettingsClass::getHostname()
{
#ifdef OPENDTU_ETHERNET
if (_networkMode == network_mode::Ethernet) {
return ETH.getHostname();
}
#endif
return WiFi.getHostname();
}
bool NetworkSettingsClass::isConnected()
{
#ifndef OPENDTU_ETHERNET
return WiFi.localIP()[0] != 0;
#else
return WiFi.localIP()[0] != 0 || ETH.localIP()[0] != 0;
#endif
}
network_mode NetworkSettingsClass::NetworkMode()
{
return _networkMode;
} }
NetworkSettingsClass NetworkSettings; NetworkSettingsClass NetworkSettings;

View File

@ -31,12 +31,12 @@ void WebApiNetworkClass::onNetworkStatus(AsyncWebServerRequest* request)
root[F("sta_status")] = ((WiFi.getMode() & WIFI_STA) != 0); root[F("sta_status")] = ((WiFi.getMode() & WIFI_STA) != 0);
root[F("sta_ssid")] = WiFi.SSID(); root[F("sta_ssid")] = WiFi.SSID();
root[F("sta_ip")] = WiFi.localIP().toString(); root[F("sta_ip")] = NetworkSettings.localIP().toString();
root[F("sta_netmask")] = WiFi.subnetMask().toString(); root[F("sta_netmask")] = NetworkSettings.subnetMask().toString();
root[F("sta_gateway")] = WiFi.gatewayIP().toString(); root[F("sta_gateway")] = NetworkSettings.gatewayIP().toString();
root[F("sta_dns1")] = WiFi.dnsIP(0).toString(); root[F("sta_dns1")] = NetworkSettings.dnsIP(0).toString();
root[F("sta_dns2")] = WiFi.dnsIP(1).toString(); root[F("sta_dns2")] = NetworkSettings.dnsIP(1).toString();
root[F("sta_mac")] = WiFi.macAddress(); root[F("sta_mac")] = NetworkSettings.macAddress();
root[F("sta_rssi")] = WiFi.RSSI(); root[F("sta_rssi")] = WiFi.RSSI();
root[F("ap_status")] = ((WiFi.getMode() & WIFI_AP) != 0); root[F("ap_status")] = ((WiFi.getMode() & WIFI_AP) != 0);
root[F("ap_ssid")] = NetworkSettings.getApName(); root[F("ap_ssid")] = NetworkSettings.getApName();

View File

@ -6,6 +6,7 @@
#include "ArduinoJson.h" #include "ArduinoJson.h"
#include "AsyncJson.h" #include "AsyncJson.h"
#include "Configuration.h" #include "Configuration.h"
#include "NetworkSettings.h"
#include <LittleFS.h> #include <LittleFS.h>
#include <ResetReason.h> #include <ResetReason.h>
@ -31,7 +32,7 @@ void WebApiSysstatusClass::onSystemStatus(AsyncWebServerRequest* request)
AsyncJsonResponse* response = new AsyncJsonResponse(); AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject root = response->getRoot(); JsonObject root = response->getRoot();
root[F("hostname")] = WiFi.getHostname(); root[F("hostname")] = NetworkSettings.getHostname();
root[F("sdkversion")] = ESP.getSdkVersion(); root[F("sdkversion")] = ESP.getSdkVersion();
root[F("cpufreq")] = ESP.getCpuFreqMHz(); root[F("cpufreq")] = ESP.getCpuFreqMHz();

View File

@ -54,7 +54,7 @@ void setup()
Serial.println(F("done")); Serial.println(F("done"));
// Initialize WiFi // Initialize WiFi
Serial.print(F("Initialize WiFi... ")); Serial.print(F("Initialize Network... "));
NetworkSettings.init(); NetworkSettings.init();
Serial.println(F("done")); Serial.println(F("done"));
NetworkSettings.applyConfig(); NetworkSettings.applyConfig();