diff --git a/CMakeLists.txt b/CMakeLists.txt index bb9b70d..7ee604d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,6 +50,7 @@ file(GLOB SRCFILES networkDevices/NetworkDevice.h networkDevices/WifiDevice.cpp networkDevices/W5500Device.cpp + networkDevices/EthLan8720Device.cpp networkDevices/ClientSyncW5500.cpp networkDevices/espMqttClientW5500.cpp QueryCommand.h @@ -126,6 +127,7 @@ target_link_arduino_libraries(${PROJECT_NAME} Update DNSServer Preferences + Ethernet SPI ) diff --git a/Network.cpp b/Network.cpp index dea1506..13664b5 100644 --- a/Network.cpp +++ b/Network.cpp @@ -7,6 +7,7 @@ #include "Config.h" #include #include "RestartReason.h" +#include "networkDevices/EthLan8720Device.h" Network* Network::_inst = nullptr; unsigned long Network::_ignoreSubscriptionsTs = 0; @@ -74,6 +75,11 @@ void Network::setupDevice() Log->print(F("W5500 on M5Stack Atom POE")); _networkDeviceType = NetworkDeviceType::W5500; } + else if(hardwareDetect == 4) + { + Log->print(F("Olimex ESP32-POE / ESP-POE-ISO")); + _networkDeviceType = NetworkDeviceType::LAN8720; + } else { Log->println(F("Unknown hardware selected, falling back to Wifi.")); @@ -87,6 +93,10 @@ void Network::setupDevice() Log->println(F("Network device: W5500")); _device = new W5500Device(_hostname, _preferences, hardwareDetect); break; + case NetworkDeviceType::LAN8720: + Log->println(F("Network device: LAN8720")); + _device = new EthLan8720Device(_hostname, _preferences); + break; case NetworkDeviceType::WiFi: Log->println(F("Network device: Builtin WiFi")); _device = new WifiDevice(_hostname, _preferences); diff --git a/Network.h b/Network.h index 0f72e21..7b99131 100644 --- a/Network.h +++ b/Network.h @@ -9,7 +9,8 @@ enum class NetworkDeviceType { WiFi, - W5500 + W5500, + LAN8720 }; #define JSON_BUFFER_SIZE 1024 diff --git a/RestartReason.h b/RestartReason.h index 8da243d..5c7815d 100644 --- a/RestartReason.h +++ b/RestartReason.h @@ -9,6 +9,7 @@ enum class RestartReason NetworkTimeoutWatchdog, WifiInitFailed, ReconfigureWifi, + ReconfigureLAN8720, NetworkDeviceCriticalFailure, ConfigurationUpdated, RestartTimer, @@ -55,6 +56,8 @@ inline static String getRestartReason() return "WifiInitFailed"; case RestartReason::ReconfigureWifi: return "ReconfigureWifi"; + case RestartReason::ReconfigureLAN8720: + return "ReconfigureLAN8720"; case RestartReason::NetworkDeviceCriticalFailure: return "NetworkDeviceCriticalFailure"; case RestartReason::ConfigurationUpdated: diff --git a/WebCfgServer.cpp b/WebCfgServer.cpp index a4c2145..73bb2e7 100644 --- a/WebCfgServer.cpp +++ b/WebCfgServer.cpp @@ -1108,6 +1108,7 @@ const std::vector> WebCfgServer::getNetworkDetectionOp options.push_back(std::make_pair("1", "Disable W5500 (Wifi only)")); options.push_back(std::make_pair("2", "Detect W5500 (GPIO CS=5; SCK=18; MISO=19; MOSI=23; RST=33)")); options.push_back(std::make_pair("3", "M5Stack Atom POE (W5500)")); + options.push_back(std::make_pair("4", "Olimex ESP32-POE / ESP-POE-ISO")); return options; } diff --git a/networkDevices/EthLan8720Device.cpp b/networkDevices/EthLan8720Device.cpp new file mode 100644 index 0000000..41e226f --- /dev/null +++ b/networkDevices/EthLan8720Device.cpp @@ -0,0 +1,281 @@ +#define ETH_CLK_MODE ETH_CLOCK_GPIO17_OUT +#define ETH_PHY_POWER 12 + +#include +#include +#include "EthLan8720Device.h" +#include "../PreferencesKeys.h" +#include "../Logger.h" +#include "../MqttTopics.h" +#include "espMqttClient.h" +#include "../RestartReason.h" + +EthLan8720Device::EthLan8720Device(const String& hostname, Preferences* _preferences) +: NetworkDevice(hostname) +{ + _restartOnDisconnect = _preferences->getBool(preference_restart_on_disconnect); + + size_t caLength = _preferences->getString(preference_mqtt_ca,_ca,TLS_CA_MAX_SIZE); + size_t crtLength = _preferences->getString(preference_mqtt_crt,_cert,TLS_CERT_MAX_SIZE); + size_t keyLength = _preferences->getString(preference_mqtt_key,_key,TLS_KEY_MAX_SIZE); + + _useEncryption = caLength > 1; // length is 1 when empty + + if(_useEncryption) + { + Log->println(F("MQTT over TLS.")); + Log->println(_ca); + _mqttClientSecure = new espMqttClientSecure(); + _mqttClientSecure->setCACert(_ca); + if(crtLength > 1 && keyLength > 1) // length is 1 when empty + { + Log->println(F("MQTT with client certificate.")); + Log->println(_cert); + Log->println(_key); + _mqttClientSecure->setCertificate(_cert); + _mqttClientSecure->setPrivateKey(_key); + } + } else + { + Log->println(F("MQTT without TLS.")); + _mqttClient = new espMqttClient(); + } + + if(_preferences->getBool(preference_mqtt_log_enabled)) + { + _path = new char[200]; + memset(_path, 0, sizeof(_path)); + + String pathStr = _preferences->getString(preference_mqtt_lock_path); + pathStr.concat(mqtt_topic_log); + strcpy(_path, pathStr.c_str()); + Log = new MqttLogger(this, _path, MqttLoggerMode::MqttAndSerial); + } +} + +const String EthLan8720Device::deviceName() const +{ + return "LAN8720"; +} + +void EthLan8720Device::initialize() +{ + delay(250); + + _hardwareInitialized = ETH.begin(); + + if(_restartOnDisconnect) + { + WiFi.onEvent([&](WiFiEvent_t event, WiFiEventInfo_t info) + { + if(event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED) + { + onDisconnected(); + } + }); + } +} + +void EthLan8720Device::reconfigure() +{ + delay(200); + restartEsp(RestartReason::ReconfigureWifi); +} + +void EthLan8720Device::printError() +{ + Log->print(F("Free Heap: ")); + Log->println(ESP.getFreeHeap()); +} + +bool EthLan8720Device::supportsEncryption() +{ + return true; +} + +bool EthLan8720Device::isConnected() +{ + return ETH.linkUp(); +} + +ReconnectStatus EthLan8720Device::reconnect() +{ + delay(3000); + return isConnected() ? ReconnectStatus::Success : ReconnectStatus::Failure; +} + +void EthLan8720Device::update() +{ + +} + +void EthLan8720Device::onDisconnected() +{ + if(millis() > 60000) + { + restartEsp(RestartReason::RestartOnDisconnectWatchdog); + } +} + +int8_t EthLan8720Device::signalStrength() +{ + return -1; +} + +void EthLan8720Device::mqttSetClientId(const char *clientId) +{ + if(_useEncryption) + { + _mqttClientSecure->setClientId(clientId); + } + else + { + _mqttClient->setClientId(clientId); + } +} + +void EthLan8720Device::mqttSetCleanSession(bool cleanSession) +{ + if(_useEncryption) + { + _mqttClientSecure->setCleanSession(cleanSession); + } + else + { + _mqttClient->setCleanSession(cleanSession); + } +} + +uint16_t EthLan8720Device::mqttPublish(const char *topic, uint8_t qos, bool retain, const char *payload) +{ + if(_useEncryption) + { + return _mqttClientSecure->publish(topic, qos, retain, payload); + } + else + { + return _mqttClient->publish(topic, qos, retain, payload); + } +} + +uint16_t EthLan8720Device::mqttPublish(const char *topic, uint8_t qos, bool retain, const uint8_t *payload, size_t length) +{ + if(_useEncryption) + { + return _mqttClientSecure->publish(topic, qos, retain, payload, length); + } + else + { + return _mqttClient->publish(topic, qos, retain, payload, length); + } +} + +bool EthLan8720Device::mqttConnected() const +{ + if(_useEncryption) + { + return _mqttClientSecure->connected(); + } + else + { + return _mqttClient->connected(); + } +} + +void EthLan8720Device::mqttSetServer(const char *host, uint16_t port) +{ + if(_useEncryption) + { + _mqttClientSecure->setServer(host, port); + } + else + { + _mqttClient->setServer(host, port); + } +} + +bool EthLan8720Device::mqttConnect() +{ + if(_useEncryption) + { + return _mqttClientSecure->connect(); + } + else + { + return _mqttClient->connect(); + } +} + +bool EthLan8720Device::mqttDisonnect(bool force) +{ + if(_useEncryption) + { + return _mqttClientSecure->disconnect(force); + } + else + { + return _mqttClient->disconnect(force); + } +} + +void EthLan8720Device::mqttSetCredentials(const char *username, const char *password) +{ + if(_useEncryption) + { + _mqttClientSecure->setCredentials(username, password); + } + else + { + _mqttClient->setCredentials(username, password); + } +} + +void EthLan8720Device::mqttOnMessage(espMqttClientTypes::OnMessageCallback callback) +{ + if(_useEncryption) + { + _mqttClientSecure->onMessage(callback); + } + else + { + _mqttClient->onMessage(callback); + } +} + + +void EthLan8720Device::mqttOnConnect(espMqttClientTypes::OnConnectCallback callback) +{ + if(_useEncryption) + { + _mqttClientSecure->onConnect(callback); + } + else + { + _mqttClient->onConnect(callback); + } +} + +void EthLan8720Device::mqttOnDisconnect(espMqttClientTypes::OnDisconnectCallback callback) +{ + if(_useEncryption) + { + _mqttClientSecure->onDisconnect(callback); + } + else + { + _mqttClient->onDisconnect(callback); + } +} + + +uint16_t EthLan8720Device::mqttSubscribe(const char *topic, uint8_t qos) +{ + if(_useEncryption) + { + return _mqttClientSecure->subscribe(topic, qos); + } + else + { + return _mqttClient->subscribe(topic, qos); + } +} diff --git a/networkDevices/EthLan8720Device.h b/networkDevices/EthLan8720Device.h new file mode 100644 index 0000000..ad60793 --- /dev/null +++ b/networkDevices/EthLan8720Device.h @@ -0,0 +1,69 @@ +#pragma once + +#include +#include +#include +#include "NetworkDevice.h" +#include "espMqttClient.h" + +class EthLan8720Device : public NetworkDevice +{ +public: + EthLan8720Device(const String& hostname, Preferences* _preferences); + + const String deviceName() const override; + + virtual void initialize(); + virtual void reconfigure(); + virtual ReconnectStatus reconnect(); + virtual void printError(); + bool supportsEncryption() override; + + virtual void update(); + + virtual bool isConnected(); + + int8_t signalStrength() override; + + void mqttSetClientId(const char *clientId) override; + + void mqttSetCleanSession(bool cleanSession) override; + + uint16_t mqttPublish(const char *topic, uint8_t qos, bool retain, const char *payload) override; + + uint16_t mqttPublish(const char *topic, uint8_t qos, bool retain, const uint8_t *payload, size_t length) override; + + bool mqttConnected() const override; + + void mqttSetServer(const char *host, uint16_t port) override; + + bool mqttConnect() override; + + bool mqttDisonnect(bool force) override; + + void mqttSetCredentials(const char *username, const char *password) override; + + void mqttOnMessage(espMqttClientTypes::OnMessageCallback callback) override; + + void mqttOnConnect(espMqttClientTypes::OnConnectCallback callback) override; + + void mqttOnDisconnect(espMqttClientTypes::OnDisconnectCallback callback) override; + + uint16_t mqttSubscribe(const char *topic, uint8_t qos) override; + +private: + void onDisconnected(); + + espMqttClient* _mqttClient = nullptr; + espMqttClientSecure* _mqttClientSecure = nullptr; + + bool _restartOnDisconnect = false; + bool _startAp = false; + char* _path; + bool _useEncryption = false; + bool _hardwareInitialized = false; + + char _ca[TLS_CA_MAX_SIZE] = {0}; + char _cert[TLS_CERT_MAX_SIZE] = {0}; + char _key[TLS_KEY_MAX_SIZE] = {0}; +};