From 677f7e56c84c3bb5f70efba14ccaecde37164a8f Mon Sep 17 00:00:00 2001 From: technyon Date: Tue, 26 Apr 2022 22:12:52 +0200 Subject: [PATCH] initial w5500 support --- CMakeLists.txt | 5 ++ Network.cpp | 119 ++++++++++++++++----------------- Network.h | 22 ++++-- Pins.h | 5 ++ WebCfgServer.cpp | 1 - main.cpp | 8 ++- networkDevices/NetworkDevice.h | 21 ++++++ networkDevices/W5500Device.cpp | 95 ++++++++++++++++++++++++++ networkDevices/W5500Device.h | 24 +++++++ networkDevices/WifiDevice.cpp | 62 +++++++++++++++++ networkDevices/WifiDevice.h | 23 +++++++ 11 files changed, 314 insertions(+), 71 deletions(-) create mode 100644 Pins.h create mode 100644 networkDevices/NetworkDevice.h create mode 100644 networkDevices/W5500Device.cpp create mode 100644 networkDevices/W5500Device.h create mode 100644 networkDevices/WifiDevice.cpp create mode 100644 networkDevices/WifiDevice.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b36074e..0a2b8cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,11 @@ include_directories(${PROJECT_NAME} file(GLOB SRCFILES # "Lib/FreeRTOS/src/*.c" # "Lib/FreeRTOS/src/*.cpp" + Pins.h Network.cpp + networkDevices/NetworkDevice.h + networkDevices/WifiDevice.cpp + networkDevices/W5500Device.cpp NukiWrapper.cpp MqttTopics.h WebCfgServer.cpp @@ -59,6 +63,7 @@ target_link_arduino_libraries(${PROJECT_NAME} DNSServer Preferences SPIFFS + Ethernet # esp32 # Wire # FS diff --git a/Network.cpp b/Network.cpp index 69dfc64..882d8ac 100644 --- a/Network.cpp +++ b/Network.cpp @@ -1,18 +1,21 @@ #include "Network.h" -#include "WiFi.h" #include // https://github.com/tzapu/WiFiManager #include "Arduino.h" #include "MqttTopics.h" #include "PreferencesKeys.h" +#include "Pins.h" Network* nwInst; -Network::Network(Preferences* preferences) -: _mqttClient(_wifiClient), - _preferences(preferences) +Network::Network(const NetworkDeviceType networkDevice, Preferences* preferences) +: _preferences(preferences), + _networkDeviceType(networkDevice) { nwInst = this; + _hostname = _preferences->getString(preference_hostname); + setupDevice(networkDevice); + _configTopics.reserve(5); _configTopics.push_back(mqtt_topic_config_button_enabled); _configTopics.push_back(mqtt_topic_config_led_enabled); @@ -21,53 +24,46 @@ Network::Network(Preferences* preferences) _configTopics.push_back(mqtt_topic_config_auto_lock); } +Network::~Network() +{ + if(_device != nullptr) + { + delete _device; + _device = nullptr; + } +} + +void Network::setupDevice(const NetworkDeviceType hardware) +{ + switch(hardware) + { + case NetworkDeviceType::W5500: + Serial.println(F("Network device: W5500")); + _device = new W5500Device(_hostname); + break; + case NetworkDeviceType::WiFi: + Serial.println(F("Network device: Builtin WiFi")); + _device = new WifiDevice(_hostname); + break; + default: + Serial.println(F("Unknown network device type, defaulting to WiFi")); + _device = new WifiDevice(_hostname); + break; + } +} + void Network::initialize() { - String hostname = _preferences->getString(preference_hostname); - if(hostname == "") + if(_hostname == "") { - hostname = "nukihub"; - _preferences->putString(preference_hostname, hostname); + _hostname = "nukihub"; + _preferences->putString(preference_hostname, _hostname); } - WiFi.mode(WIFI_STA); // explicitly set mode, esp defaults to STA+AP - // it is a good practice to make sure your code sets wifi mode how you want it. - - //WiFiManager, Local intialization. Once its business is done, there is no need to keep it around - WiFiManager wm; - - std::vector wm_menu; - wm_menu.push_back("wifi"); - wm_menu.push_back("exit"); - wm.setShowInfoUpdate(false); - wm.setMenu(wm_menu); - wm.setHostname(hostname); - - bool res = false; - - if(_cookie.isSet()) - { - Serial.println(F("Opening WiFi configuration portal.")); - _cookie.clear(); - res = wm.startConfigPortal(); - } - else - { - res = wm.autoConnect(); // password protected ap - } - - if(!res) { - Serial.println(F("Failed to connect. Wait for ESP restart.")); - delay(10000); - ESP.restart(); - } - else { - Serial.print(F("WiFi connected.")); - Serial.println(WiFi.localIP().toString()); - } + _device->initialize(); Serial.print(F("Host name: ")); - Serial.println(hostname); + Serial.println(_hostname); const char* brokerAddr = _preferences->getString(preference_mqtt_broker).c_str(); strcpy(_mqttBrokerAddr, brokerAddr); @@ -119,14 +115,13 @@ void Network::initialize() Serial.print(F(":")); Serial.println(port); - _mqttClient.setServer(_mqttBrokerAddr, port); - _mqttClient.setCallback(Network::onMqttDataReceivedCallback); + _device->mqttClient()->setServer(_mqttBrokerAddr, port); + _device->mqttClient()->setCallback(Network::onMqttDataReceivedCallback); } - bool Network::reconnect() { - while (!_mqttClient.connected() && millis() > _nextReconnect) + while (!_device->mqttClient()->connected() && millis() > _nextReconnect) { Serial.println(F("Attempting MQTT connection")); bool success = false; @@ -134,12 +129,12 @@ bool Network::reconnect() if(strlen(_mqttUser) == 0) { Serial.println(F("MQTT: Connecting without credentials")); - success = _mqttClient.connect(_preferences->getString(preference_hostname).c_str()); + success = _device->mqttClient()->connect(_preferences->getString(preference_hostname).c_str()); } else { Serial.print(F("MQTT: Connecting with user: ")); Serial.println(_mqttUser); - success = _mqttClient.connect(_preferences->getString(preference_hostname).c_str(), _mqttUser, _mqttPass); + success = _device->mqttClient()->connect(_preferences->getString(preference_hostname).c_str(), _mqttUser, _mqttPass); } @@ -157,7 +152,7 @@ bool Network::reconnect() else { Serial.print(F("MQTT connect failed, rc=")); - Serial.println(_mqttClient.state()); + Serial.println(_device->mqttClient()->state()); _mqttConnected = false; _nextReconnect = millis() + 5000; } @@ -167,13 +162,13 @@ bool Network::reconnect() void Network::update() { - if(!WiFi.isConnected()) + if(!_device->isConnected()) { - Serial.println(F("WiFi not connected")); + Serial.println(F("Network not connected")); vTaskDelay( 1000 / portTICK_PERIOD_MS); } - if(!_mqttClient.connected()) + if(!_device->mqttClient()->connected()) { bool success = reconnect(); if(!success) @@ -188,7 +183,7 @@ void Network::update() _presenceCsv = nullptr; } - _mqttClient.loop(); + _device->mqttClient()->loop(); } void Network::onMqttDataReceivedCallback(char *topic, byte *payload, unsigned int length) @@ -323,7 +318,7 @@ void Network::publishFloat(const char* topic, const float value, const uint8_t p dtostrf(value, 0, precision, str); char path[200] = {0}; buildMqttPath(topic, path); - _mqttClient.publish(path, str); + _device->mqttClient()->publish(path, str); } void Network::publishInt(const char *topic, const int value) @@ -333,7 +328,7 @@ void Network::publishInt(const char *topic, const int value) itoa(value, str, 10); char path[200] = {0}; buildMqttPath(topic, path); - _mqttClient.publish(path, str); + _device->mqttClient()->publish(path, str); } void Network::publishBool(const char *topic, const bool value) @@ -342,14 +337,14 @@ void Network::publishBool(const char *topic, const bool value) str[0] = value ? '1' : '0'; char path[200] = {0}; buildMqttPath(topic, path); - _mqttClient.publish(path, str); + _device->mqttClient()->publish(path, str); } void Network::publishString(const char *topic, const char *value) { char path[200] = {0}; buildMqttPath(topic, path); - _mqttClient.publish(path, value); + _device->mqttClient()->publish(path, value); } @@ -384,14 +379,12 @@ void Network::subscribe(const char *path) { char prefixedPath[500]; buildMqttPath(path, prefixedPath); - _mqttClient.subscribe(prefixedPath); + _device->mqttClient()->subscribe(prefixedPath); } void Network::restartAndConfigureWifi() { - _cookie.set(); - delay(200); - ESP.restart(); + _device->reconfigure(); } bool Network::comparePrefixedPath(const char *fullPath, const char *subPath) diff --git a/Network.h b/Network.h index b71a54b..e049e3e 100644 --- a/Network.h +++ b/Network.h @@ -1,20 +1,30 @@ #pragma once #include -#include +#include "networkDevices/NetworkDevice.h" +#include "networkDevices/WifiDevice.h" +#include "networkDevices/W5500Device.h" #include #include #include "NukiConstants.h" #include "SpiffsCookie.h" +enum class NetworkDeviceType +{ + WiFi, + W5500 +}; + class Network { public: - explicit Network(Preferences* preferences); - virtual ~Network() = default; + explicit Network(const NetworkDeviceType networkDevice, Preferences* preferences); + virtual ~Network(); void initialize(); void update(); + void setupDevice(const NetworkDeviceType hardware); + void initializeW5500(); bool isMqttConnected(); @@ -45,10 +55,10 @@ private: bool reconnect(); - PubSubClient _mqttClient; - WiFiClient _wifiClient; + NetworkDevice* _device = nullptr; Preferences* _preferences; - SpiffsCookie _cookie; + String _hostname; + NetworkDeviceType _networkDeviceType; bool _mqttConnected = false; diff --git a/Pins.h b/Pins.h new file mode 100644 index 0000000..df5d0c3 --- /dev/null +++ b/Pins.h @@ -0,0 +1,5 @@ +#pragma once + +#define NETWORK_SELECT 26 +#define ETHERNET_CS_PIN 5 +#define ETHERNET_RESET_PIN 33 diff --git a/WebCfgServer.cpp b/WebCfgServer.cpp index 98f3927..a85e308 100644 --- a/WebCfgServer.cpp +++ b/WebCfgServer.cpp @@ -1,5 +1,4 @@ #include "WebCfgServer.h" -#include #include "PreferencesKeys.h" #include "Version.h" diff --git a/main.cpp b/main.cpp index 4a89ec6..0379bd7 100644 --- a/main.cpp +++ b/main.cpp @@ -1,4 +1,5 @@ #include "Arduino.h" +#include "Pins.h" #include "NukiWrapper.h" #include "Network.h" #include "WebCfgServer.h" @@ -80,11 +81,16 @@ uint32_t getRandomId() void setup() { + pinMode(NETWORK_SELECT, INPUT_PULLUP); + Serial.begin(115200); + const NetworkDeviceType networkDevice = NetworkDeviceType::WiFi; +// const NetworkDeviceType networkDevice = digitalRead(NETWORK_SELECT) == HIGH ? NetworkDeviceType::WiFi : NetworkDeviceType::W5500; + preferences = new Preferences(); preferences->begin("nukihub", false); - network = new Network(preferences); + network = new Network(networkDevice, preferences); network->initialize(); uint32_t deviceId = preferences->getUInt(preference_deviceId); diff --git a/networkDevices/NetworkDevice.h b/networkDevices/NetworkDevice.h new file mode 100644 index 0000000..85d1a84 --- /dev/null +++ b/networkDevices/NetworkDevice.h @@ -0,0 +1,21 @@ +#pragma once + +#include "PubSubClient.h" + +class NetworkDevice +{ +public: + explicit NetworkDevice(const String& hostname) + : _hostname(hostname) + {} + + virtual PubSubClient* mqttClient() = 0; + + virtual void initialize() = 0; + virtual void reconfigure() = 0; + + virtual bool isConnected() = 0; + +protected: + const String _hostname; +}; \ No newline at end of file diff --git a/networkDevices/W5500Device.cpp b/networkDevices/W5500Device.cpp new file mode 100644 index 0000000..9d4219a --- /dev/null +++ b/networkDevices/W5500Device.cpp @@ -0,0 +1,95 @@ +#include "W5500Device.h" +#include "../Pins.h" + +W5500Device::W5500Device(const String &hostname) +: NetworkDevice(hostname) +{ +} + +W5500Device::~W5500Device() +{} + +void W5500Device::initialize() +{ + resetDevice(); + + Ethernet.init(ETHERNET_CS_PIN); + _ethClient = new EthernetClient(); + _mqttClient = new PubSubClient(*_ethClient); + + // start the Ethernet connection: + Serial.println(F("Initialize Ethernet with DHCP:")); + + int dhcpRetryCnt = 0; + + while(dhcpRetryCnt < 3) + { + Serial.print(F("DHCP connect try #")); + Serial.print(dhcpRetryCnt); + Serial.println(); + dhcpRetryCnt++; + + byte mac[] = {0xB0,0xCD,0xAE,0x0F,0xDE,0x10}; + + if (Ethernet.begin(mac, 1000, 1000) == 0) + { + Serial.println(F("Failed to configure Ethernet using DHCP")); + // Check for Ethernet hardware present + if (Ethernet.hardwareStatus() == EthernetNoHardware) + { + Serial.println(F("Ethernet module not found")); + delay(10000); + ESP.restart(); + } + if (Ethernet.linkStatus() == LinkOFF) + { + Serial.println(F("Ethernet cable is not connected.")); + } + + IPAddress ip; + ip.fromString("192.168.4.1"); + + IPAddress subnet; + subnet.fromString("255.255.255.0"); + + // try to congifure using IP address instead of DHCP: + Ethernet.begin(mac, ip); + Ethernet.setSubnetMask(subnet); + + delay(2000); + } + else + { + dhcpRetryCnt = 1000; + Serial.print(F(" DHCP assigned IP ")); + Serial.println(Ethernet.localIP()); + } + } +} + +void W5500Device::reconfigure() +{ + Serial.println(F("Reconfigure W5500 not implemented.")); +} + +void W5500Device::resetDevice() +{ + Serial.println(F("Resetting network hardware.")); + pinMode(ETHERNET_RESET_PIN, OUTPUT); + digitalWrite(ETHERNET_RESET_PIN, HIGH); + delay(250); + digitalWrite(ETHERNET_RESET_PIN, LOW); + delay(50); + digitalWrite(ETHERNET_RESET_PIN, HIGH); + delay(1500); +} + +PubSubClient *W5500Device::mqttClient() +{ + return _mqttClient; +} + +bool W5500Device::isConnected() +{ + return _ethClient->connected(); +} diff --git a/networkDevices/W5500Device.h b/networkDevices/W5500Device.h new file mode 100644 index 0000000..ef623e9 --- /dev/null +++ b/networkDevices/W5500Device.h @@ -0,0 +1,24 @@ +#pragma once + +#include "NetworkDevice.h" +#include + +class W5500Device : public NetworkDevice +{ +public: + explicit W5500Device(const String& hostname); + ~W5500Device(); + + virtual void initialize(); + virtual void reconfigure(); + + virtual bool isConnected(); + + virtual PubSubClient *mqttClient(); + +private: + void resetDevice(); + + EthernetClient* _ethClient = nullptr; + PubSubClient* _mqttClient = nullptr; +}; \ No newline at end of file diff --git a/networkDevices/WifiDevice.cpp b/networkDevices/WifiDevice.cpp new file mode 100644 index 0000000..42e5ac0 --- /dev/null +++ b/networkDevices/WifiDevice.cpp @@ -0,0 +1,62 @@ +#include +#include "WifiDevice.h" +#include "WiFiManager.h" + +WifiDevice::WifiDevice(const String& hostname) +: NetworkDevice(hostname), + _mqttClient(_wifiClient) +{} + +PubSubClient *WifiDevice::mqttClient() +{ + return &_mqttClient; +} + +void WifiDevice::initialize() +{ + WiFi.mode(WIFI_STA); // explicitly set mode, esp defaults to STA+AP + + WiFiManager wm; + + std::vector wm_menu; + wm_menu.push_back("wifi"); + wm_menu.push_back("exit"); + wm.setShowInfoUpdate(false); + wm.setMenu(wm_menu); + wm.setHostname(_hostname); + + bool res = false; + + if(_cookie.isSet()) + { + Serial.println(F("Opening WiFi configuration portal.")); + _cookie.clear(); + res = wm.startConfigPortal(); + } + else + { + res = wm.autoConnect(); // password protected ap + } + + if(!res) { + Serial.println(F("Failed to connect. Wait for ESP restart.")); + delay(10000); + ESP.restart(); + } + else { + Serial.print(F("WiFi connected: ")); + Serial.println(WiFi.localIP().toString()); + } +} + +void WifiDevice::reconfigure() +{ + _cookie.set(); + delay(200); + ESP.restart(); +} + +bool WifiDevice::isConnected() +{ + return WiFi.isConnected(); +} diff --git a/networkDevices/WifiDevice.h b/networkDevices/WifiDevice.h new file mode 100644 index 0000000..bf6e773 --- /dev/null +++ b/networkDevices/WifiDevice.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include "NetworkDevice.h" +#include "../SpiffsCookie.h" + +class WifiDevice : public NetworkDevice +{ +public: + WifiDevice(const String& hostname); + + virtual void initialize(); + virtual void reconfigure(); + + virtual bool isConnected(); + + virtual PubSubClient *mqttClient(); + +private: + WiFiClient _wifiClient; + PubSubClient _mqttClient; + SpiffsCookie _cookie; +};