diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ee604d..83e18e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,7 @@ file(GLOB SRCFILES networkDevices/EthLan8720Device.cpp networkDevices/ClientSyncW5500.cpp networkDevices/espMqttClientW5500.cpp + networkDevices/IPConfiguration.cpp QueryCommand.h NukiWrapper.cpp NukiOpenerWrapper.cpp diff --git a/Config.h b/Config.h index fb1ed2d..ba97eb0 100644 --- a/Config.h +++ b/Config.h @@ -1,6 +1,6 @@ #pragma once -#define NUKI_HUB_VERSION "8.15" +#define NUKI_HUB_VERSION "8.16-pre-1" #define MQTT_QOS_LEVEL 1 #define MQTT_CLEAN_SESSIONS false diff --git a/Network.cpp b/Network.cpp index 69b79d7..5e3a63e 100644 --- a/Network.cpp +++ b/Network.cpp @@ -32,6 +32,8 @@ Network::Network(Preferences *preferences, const String& maintenancePathPrefix) void Network::setupDevice() { + _ipConfiguration = new IPConfiguration(_preferences); + int hardwareDetect = _preferences->getInt(preference_network_hardware); int hardwareDetectGpio = _preferences->getInt(preference_network_hardware_gpio); @@ -93,19 +95,19 @@ void Network::setupDevice() switch (_networkDeviceType) { case NetworkDeviceType::W5500: - _device = new W5500Device(_hostname, _preferences, hardwareDetect); + _device = new W5500Device(_hostname, _preferences, _ipConfiguration, hardwareDetect); break; case NetworkDeviceType::Olimex_LAN8720: - _device = new EthLan8720Device(_hostname, _preferences, "Olimex (LAN8720)", ETH_PHY_ADDR, 12, ETH_PHY_MDC, ETH_PHY_MDIO, ETH_PHY_TYPE, ETH_CLOCK_GPIO17_OUT); + _device = new EthLan8720Device(_hostname, _preferences, _ipConfiguration, "Olimex (LAN8720)", ETH_PHY_ADDR, 12, ETH_PHY_MDC, ETH_PHY_MDIO, ETH_PHY_TYPE, ETH_CLOCK_GPIO17_OUT); break; case NetworkDeviceType::WT32_LAN8720: - _device = new EthLan8720Device(_hostname, _preferences, "WT32-ETH01", 1, 16); + _device = new EthLan8720Device(_hostname, _preferences, _ipConfiguration, "WT32-ETH01", 1, 16); break; case NetworkDeviceType::WiFi: - _device = new WifiDevice(_hostname, _preferences); + _device = new WifiDevice(_hostname, _preferences, _ipConfiguration); break; default: - _device = new WifiDevice(_hostname, _preferences); + _device = new WifiDevice(_hostname, _preferences, _ipConfiguration); break; } diff --git a/Network.h b/Network.h index 0a81a1a..e1894f6 100644 --- a/Network.h +++ b/Network.h @@ -5,6 +5,7 @@ #include #include "networkDevices/NetworkDevice.h" #include "MqttReceiver.h" +#include "networkDevices/IPConfiguration.h" enum class NetworkDeviceType { @@ -92,6 +93,7 @@ private: static Network* _inst; Preferences* _preferences; + IPConfiguration* _ipConfiguration = nullptr; String _hostname; char _hostnameArr[101] = {0}; NetworkDevice* _device = nullptr; diff --git a/PreferencesKeys.h b/PreferencesKeys.h index 0403cb7..4aed7cb 100644 --- a/PreferencesKeys.h +++ b/PreferencesKeys.h @@ -19,6 +19,11 @@ #define preference_mqtt_crt "mqttcrt" #define preference_mqtt_key "mqttkey" #define preference_mqtt_hass_discovery "hassdiscovery" +#define preference_ip_dhcp_enabled "dhcpena" +#define preference_ip_address "ipaddr" +#define preference_ip_subnet "ipsub" +#define preference_ip_gateway "ipgtw" +#define preference_ip_dns_server "dnssrv" #define preference_network_hardware "nwhw" #define preference_network_hardware_gpio "nwhwdt" #define preference_rssi_publish_interval "rssipb" @@ -51,7 +56,20 @@ class DebugPreferences private: std::vector _keys = { - preference_started_before, preference_deviceId, preference_mqtt_broker, preference_mqtt_broker_port, preference_mqtt_user, preference_mqtt_password, preference_mqtt_log_enabled, preference_lock_enabled, preference_mqtt_lock_path, preference_opener_enabled, preference_mqtt_opener_path, preference_lock_max_keypad_code_count, preference_opener_max_keypad_code_count, preference_mqtt_ca, preference_mqtt_crt, preference_mqtt_key, preference_mqtt_hass_discovery, preference_network_hardware, preference_network_hardware_gpio, preference_rssi_publish_interval, preference_hostname, preference_network_timeout, preference_restart_on_disconnect, preference_restart_timer, preference_restart_ble_beacon_lost, preference_query_interval_lockstate, preference_query_interval_configuration, preference_query_interval_battery, preference_query_interval_keypad, preference_keypad_control_enabled, preference_register_as_app, preference_command_nr_of_retries, preference_command_retry_delay, preference_cred_user, preference_cred_password, preference_publish_authdata, preference_gpio_locking_enabled, preference_publish_debug_info, preference_presence_detection_timeout, preference_has_mac_saved, preference_has_mac_byte_0, preference_has_mac_byte_1, preference_has_mac_byte_2, + preference_started_before, preference_deviceId, preference_mqtt_broker, preference_mqtt_broker_port, + preference_mqtt_user, preference_mqtt_password, preference_mqtt_log_enabled, preference_lock_enabled, + preference_mqtt_lock_path, preference_opener_enabled, preference_mqtt_opener_path, + preference_lock_max_keypad_code_count, preference_opener_max_keypad_code_count, preference_mqtt_ca, + preference_mqtt_crt, preference_mqtt_key, preference_mqtt_hass_discovery, + preference_ip_dhcp_enabled, preference_ip_address, preference_ip_subnet, preference_ip_gateway, preference_ip_dns_server, + preference_network_hardware, preference_network_hardware_gpio, preference_rssi_publish_interval, + preference_hostname, preference_network_timeout, preference_restart_on_disconnect, + preference_restart_timer, preference_restart_ble_beacon_lost, preference_query_interval_lockstate, + preference_query_interval_configuration, preference_query_interval_battery, preference_query_interval_keypad, + preference_keypad_control_enabled, preference_register_as_app, preference_command_nr_of_retries, + preference_command_retry_delay, preference_cred_user, preference_cred_password, preference_publish_authdata, + preference_gpio_locking_enabled, preference_publish_debug_info, preference_presence_detection_timeout, + preference_has_mac_saved, preference_has_mac_byte_0, preference_has_mac_byte_1, preference_has_mac_byte_2, }; std::vector _redact = { @@ -62,7 +80,7 @@ private: std::vector _boolPrefs = { preference_started_before, preference_mqtt_log_enabled, preference_lock_enabled, preference_opener_enabled, - preference_restart_on_disconnect, preference_keypad_control_enabled, preference_register_as_app, + preference_restart_on_disconnect, preference_keypad_control_enabled, preference_register_as_app, preference_ip_dhcp_enabled, preference_publish_authdata, preference_gpio_locking_enabled, preference_has_mac_saved, preference_publish_debug_info }; diff --git a/WebCfgServer.cpp b/WebCfgServer.cpp index 4a43b5f..7919bfe 100644 --- a/WebCfgServer.cpp +++ b/WebCfgServer.cpp @@ -32,6 +32,19 @@ WebCfgServer::WebCfgServer(NukiWrapper* nuki, NukiOpenerWrapper* nukiOpener, Net const char *pass = str.c_str(); memcpy(&_credPassword, pass, str.length()); } + + _pinsConfigured = true; + + if(_nuki != nullptr) + { + _pinsConfigured = _pinsConfigured && _nuki->isPinSet(); + } + if(_nukiOpener != nullptr) + { + _pinsConfigured = _pinsConfigured && _nukiOpener->isPinSet(); + } + + _brokerConfigured = _preferences->getString(preference_mqtt_broker).length() > 0 && _preferences->getInt(preference_mqtt_broker_port) > 0; } void WebCfgServer::initialize() @@ -327,6 +340,31 @@ bool WebCfgServer::processArgs(String& message) _preferences->putBool(preference_mqtt_log_enabled, (value == "1")); configChanged = true; } + else if(key == "DHCPENA") + { + _preferences->putBool(preference_ip_dhcp_enabled, (value == "1")); + configChanged = true; + } + else if(key == "IPADDR") + { + _preferences->putString(preference_ip_address, value); + configChanged = true; + } + else if(key == "IPSUB") + { + _preferences->putString(preference_ip_subnet, value); + configChanged = true; + } + else if(key == "IPGTW") + { + _preferences->putString(preference_ip_gateway, value); + configChanged = true; + } + else if(key == "DNSSRV") + { + _preferences->putString(preference_ip_dns_server, value); + configChanged = true; + } else if(key == "LSTINT") { _preferences->putInt(preference_query_interval_lockstate, value.toInt()); @@ -519,13 +557,13 @@ void WebCfgServer::buildHtml(String& response) response.concat("

"); response.concat("

MQTT and Network Configuration

"); - buildNavigationButton(response, "Edit", "/mqttconfig"); + buildNavigationButton(response, "Edit", "/mqttconfig", _brokerConfigured ? "" : "(!) Please configure MQTT broker"); response.concat("

NUKI Configuration

"); buildNavigationButton(response, "Edit", "/nukicfg"); response.concat("

Credentials

"); - buildNavigationButton(response, "Edit", "/cred"); + buildNavigationButton(response, "Edit", "/cred", _pinsConfigured ? "" : "(!) Please configure PIN"); response.concat("

Firmware update

"); buildNavigationButton(response, "Open", "/ota"); @@ -656,7 +694,16 @@ void WebCfgServer::buildMqttConfigHtml(String &response) printInputField(response, "RSTTMR", "Restart timer (minutes; -1 to disable)", _preferences->getInt(preference_restart_timer), 10); printCheckBox(response, "MQTTLOG", "Enable MQTT logging", _preferences->getBool(preference_mqtt_log_enabled)); response.concat(""); - response.concat("* If no encryption is configured for the MQTT broker, leave empty. Only supported for WiFi connections.
"); + response.concat("* If no encryption is configured for the MQTT broker, leave empty. Only supported for WiFi connections.

"); + + response.concat("

IP Address assignment

"); + response.concat(""); + printCheckBox(response, "DHCPENA", "Enable DHCP", _preferences->getBool(preference_ip_dhcp_enabled)); + printInputField(response, "IPADDR", "Static IP address", _preferences->getString(preference_ip_address).c_str(), 15); + printInputField(response, "IPSUB", "Subnet", _preferences->getString(preference_ip_subnet).c_str(), 15); + printInputField(response, "IPGTW", "Default gateway", _preferences->getString(preference_ip_gateway).c_str(), 15); + printInputField(response, "DNSSRV", "DNS Server", _preferences->getString(preference_ip_dns_server).c_str(), 15); + response.concat("
"); response.concat("
"); response.concat(""); @@ -983,14 +1030,15 @@ void WebCfgServer::printDropDown(String &response, const char *token, const char response.concat(""); } -void WebCfgServer::buildNavigationButton(String &response, const char *caption, const char *targetPath) +void WebCfgServer::buildNavigationButton(String &response, const char *caption, const char *targetPath, const char* labelText) { response.concat("
"); response.concat(""); + response.concat(" "); + response.concat(labelText); response.concat("
"); } diff --git a/WebCfgServer.h b/WebCfgServer.h index ec05e06..be8deab 100644 --- a/WebCfgServer.h +++ b/WebCfgServer.h @@ -52,7 +52,7 @@ private: void printCheckBox(String& response, const char* token, const char* description, const bool value); void printTextarea(String& response, const char *token, const char *description, const char *value, const size_t& maxLength, const bool& enabled = true, const bool& showLengthRestriction = false); void printDropDown(String &response, const char *token, const char *description, const String preselectedValue, std::vector> options); - void buildNavigationButton(String& response, const char* caption, const char* targetPath); + void buildNavigationButton(String& response, const char* caption, const char* targetPath, const char* labelText = ""); const std::vector> getNetworkDetectionOptions() const; const std::vector> getNetworkGpioOptions() const; @@ -74,6 +74,8 @@ private: char _credUser[31] = {0}; char _credPassword[31] = {0}; bool _allowRestartToPortal = false; + bool _pinsConfigured = false; + bool _brokerConfigured = false; uint32_t _transferredSize = 0; unsigned long _otaStartTs = 0; String _hostname; diff --git a/networkDevices/EthLan8720Device.cpp b/networkDevices/EthLan8720Device.cpp index d586d84..24c0684 100644 --- a/networkDevices/EthLan8720Device.cpp +++ b/networkDevices/EthLan8720Device.cpp @@ -10,8 +10,8 @@ #include "espMqttClient.h" #include "../RestartReason.h" -EthLan8720Device::EthLan8720Device(const String& hostname, Preferences* preferences, const std::string& deviceName, uint8_t phy_addr, int power, int mdc, int mdio, eth_phy_type_t ethtype, eth_clock_mode_t clock_mode, bool use_mac_from_efuse) -: NetworkDevice(hostname), +EthLan8720Device::EthLan8720Device(const String& hostname, Preferences* preferences, const IPConfiguration* ipConfiguration, const std::string& deviceName, uint8_t phy_addr, int power, int mdc, int mdio, eth_phy_type_t ethtype, eth_clock_mode_t clock_mode, bool use_mac_from_efuse) +: NetworkDevice(hostname, ipConfiguration), _deviceName(deviceName), _phy_addr(phy_addr), _power(power), @@ -73,6 +73,10 @@ void EthLan8720Device::initialize() WiFi.setHostname(_hostname.c_str()); _hardwareInitialized = ETH.begin(_phy_addr, _power, _mdc, _mdio, _type, _clock_mode, _use_mac_from_efuse); ETH.setHostname(_hostname.c_str()); + if(!_ipConfiguration->dhcpEnabled()) + { + ETH.config(_ipConfiguration->ipAddress(), _ipConfiguration->defaultGateway(), _ipConfiguration->subnet(), _ipConfiguration->dnsServer()); + } if(_restartOnDisconnect) { diff --git a/networkDevices/EthLan8720Device.h b/networkDevices/EthLan8720Device.h index 7d39b48..cc8d92e 100644 --- a/networkDevices/EthLan8720Device.h +++ b/networkDevices/EthLan8720Device.h @@ -13,6 +13,7 @@ class EthLan8720Device : public NetworkDevice public: EthLan8720Device(const String& hostname, Preferences* preferences, + const IPConfiguration* ipConfiguration, const std::string& deviceName, uint8_t phy_addr = ETH_PHY_ADDR, int power = ETH_PHY_POWER, diff --git a/networkDevices/IPConfiguration.cpp b/networkDevices/IPConfiguration.cpp new file mode 100644 index 0000000..70eeb19 --- /dev/null +++ b/networkDevices/IPConfiguration.cpp @@ -0,0 +1,56 @@ +#include "IPConfiguration.h" +#include "../PreferencesKeys.h" +#include "../Logger.h" + +IPConfiguration::IPConfiguration(Preferences *preferences) +: _preferences(preferences) +{ + if(_preferences->getString(preference_ip_address).length() <= 0) + { + Log->println("IP address empty, falling back to DHCP."); + _preferences->putBool(preference_ip_dhcp_enabled, true); + } + + _ipAddress.fromString(_preferences->getString(preference_ip_address)); + _subnet.fromString(_preferences->getString(preference_ip_subnet)); + _gateway.fromString(_preferences->getString(preference_ip_gateway)); + _dnsServer.fromString(_preferences->getString(preference_ip_dns_server)); + + Log->print(F("IP configuration: ")); + if(dhcpEnabled()) + { + Log->println(F("DHCP")); + } + else + { + Log->print(F("IP address: ")); Log->print(ipAddress()); + Log->print(F(", Subnet: ")); Log->print(subnet()); + Log->print(F(", Gateway: ")); Log->print(defaultGateway()); + Log->print(F(", DNS: ")); Log->println(dnsServer()); + } +} + +bool IPConfiguration::dhcpEnabled() const +{ + return _preferences->getBool(preference_ip_dhcp_enabled); +} + +const IPAddress IPConfiguration::ipAddress() const +{ + return _ipAddress; +} + +const IPAddress IPConfiguration::subnet() const +{ + return _subnet; +} + +const IPAddress IPConfiguration::defaultGateway() const +{ + return _gateway; +} + +const IPAddress IPConfiguration::dnsServer() const +{ + return _dnsServer; +} diff --git a/networkDevices/IPConfiguration.h b/networkDevices/IPConfiguration.h new file mode 100644 index 0000000..13329a7 --- /dev/null +++ b/networkDevices/IPConfiguration.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +class IPConfiguration +{ +public: + explicit IPConfiguration(Preferences* preferences); + + bool dhcpEnabled() const; + const IPAddress ipAddress() const; + const IPAddress subnet() const; + const IPAddress defaultGateway() const; + const IPAddress dnsServer() const; + +private: + Preferences* _preferences = nullptr; + + IPAddress _ipAddress; + IPAddress _subnet; + IPAddress _gateway; + IPAddress _dnsServer; +}; + diff --git a/networkDevices/NetworkDevice.h b/networkDevices/NetworkDevice.h index 907e18e..b73b058 100644 --- a/networkDevices/NetworkDevice.h +++ b/networkDevices/NetworkDevice.h @@ -2,6 +2,7 @@ #include "MqttClient.h" #include "MqttClientSetup.h" +#include "IPConfiguration.h" enum class ReconnectStatus { @@ -13,8 +14,9 @@ enum class ReconnectStatus class NetworkDevice { public: - explicit NetworkDevice(const String& hostname) - : _hostname(hostname) + explicit NetworkDevice(const String& hostname, const IPConfiguration* ipConfiguration) + : _hostname(hostname), + _ipConfiguration(ipConfiguration) {} virtual const String deviceName() const = 0; @@ -49,4 +51,5 @@ public: protected: const uint16_t _mqttMaxBufferSize = 6144; const String _hostname; + const IPConfiguration* _ipConfiguration = nullptr; }; \ No newline at end of file diff --git a/networkDevices/W5500Device.cpp b/networkDevices/W5500Device.cpp index 06c0f62..6d4e517 100644 --- a/networkDevices/W5500Device.cpp +++ b/networkDevices/W5500Device.cpp @@ -6,8 +6,8 @@ #include "../Logger.h" #include "../MqttTopics.h" -W5500Device::W5500Device(const String &hostname, Preferences* preferences, int variant) -: NetworkDevice(hostname), +W5500Device::W5500Device(const String &hostname, Preferences* preferences, const IPConfiguration* ipConfiguration, int variant) +: NetworkDevice(hostname, ipConfiguration), _preferences(preferences), _variant((W5500Variant)variant) { @@ -117,8 +117,19 @@ ReconnectStatus W5500Device::reconnect() { _hasDHCPAddress = true; dhcpRetryCnt = 1000; - Log->print(F(" DHCP assigned IP ")); - Log->println(Ethernet.localIP()); + if(_ipConfiguration->dhcpEnabled()) + { + Log->print(F(" DHCP assigned IP ")); + Log->println(Ethernet.localIP()); + } + } + + if(!_ipConfiguration->dhcpEnabled()) + { + Ethernet.setLocalIP(_ipConfiguration->ipAddress()); + Ethernet.setSubnetMask(_ipConfiguration->subnet()); + Ethernet.setGatewayIP(_ipConfiguration->defaultGateway()); + Ethernet.setDnsServerIP(_ipConfiguration->dnsServer()); } } diff --git a/networkDevices/W5500Device.h b/networkDevices/W5500Device.h index 14290d0..8fa330a 100644 --- a/networkDevices/W5500Device.h +++ b/networkDevices/W5500Device.h @@ -15,7 +15,7 @@ enum class W5500Variant class W5500Device : public NetworkDevice { public: - explicit W5500Device(const String& hostname, Preferences* _preferences, int variant); + explicit W5500Device(const String& hostname, Preferences* _preferences, const IPConfiguration* ipConfiguration, int variant); ~W5500Device(); const String deviceName() const override; diff --git a/networkDevices/WifiDevice.cpp b/networkDevices/WifiDevice.cpp index ce906d0..5ad4df6 100644 --- a/networkDevices/WifiDevice.cpp +++ b/networkDevices/WifiDevice.cpp @@ -8,8 +8,8 @@ RTC_NOINIT_ATTR char WiFiDevice_reconfdetect[17]; -WifiDevice::WifiDevice(const String& hostname, Preferences* _preferences) -: NetworkDevice(hostname) +WifiDevice::WifiDevice(const String& hostname, Preferences* _preferences, const IPConfiguration* ipConfiguration) +: NetworkDevice(hostname, ipConfiguration) { _startAp = strcmp(WiFiDevice_reconfdetect, "reconfigure_wifi") == 0; @@ -69,6 +69,11 @@ void WifiDevice::initialize() _wm.setMenu(wm_menu); _wm.setHostname(_hostname); + if(!_ipConfiguration->dhcpEnabled()) + { + _wm.setSTAStaticIPConfig(_ipConfiguration->ipAddress(), _ipConfiguration->defaultGateway(), _ipConfiguration->subnet(), _ipConfiguration->dnsServer()); + } + _wm.setAPCallback(clearRtcInitVar); bool res = false; diff --git a/networkDevices/WifiDevice.h b/networkDevices/WifiDevice.h index e787703..3c04220 100644 --- a/networkDevices/WifiDevice.h +++ b/networkDevices/WifiDevice.h @@ -6,11 +6,12 @@ #include "NetworkDevice.h" #include "WiFiManager.h" #include "espMqttClient.h" +#include "IPConfiguration.h" class WifiDevice : public NetworkDevice { public: - WifiDevice(const String& hostname, Preferences* _preferences); + WifiDevice(const String& hostname, Preferences* _preferences, const IPConfiguration* ipConfiguration); const String deviceName() const override;