diff --git a/CMakeLists.txt b/CMakeLists.txt index cbb03a9..c0c14e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,11 @@ project(nuki_hub CXX) set(LOG_LEVEL ARDUHAL_LOG_LEVEL_NONE) +# Length of char arrays to store certificates for MQTTS +add_compile_definitions(TLS_CA_MAX_SIZE=1500) +add_compile_definitions(TLS_CERT_MAX_SIZE=1500) +add_compile_definitions(TLS_KEY_MAX_SIZE=1800) + include_directories(${PROJECT_NAME} PRIVATE lib/Crc16 @@ -84,6 +89,7 @@ target_link_arduino_libraries(${PROJECT_NAME} PRIVATE core WiFi + WiFiClientSecure Update # WebServer DNSServer diff --git a/Network.cpp b/Network.cpp index 0339e76..91fb69b 100644 --- a/Network.cpp +++ b/Network.cpp @@ -42,11 +42,11 @@ void Network::setupDevice(const NetworkDeviceType hardware) break; case NetworkDeviceType::WiFi: Serial.println(F("Network device: Builtin WiFi")); - _device = new WifiDevice(_hostname); + _device = new WifiDevice(_hostname, _preferences); break; default: Serial.println(F("Unknown network device type, defaulting to WiFi")); - _device = new WifiDevice(_hostname); + _device = new WifiDevice(_hostname, _preferences); break; } } @@ -161,6 +161,8 @@ bool Network::reconnect() { Serial.print(F("MQTT connect failed, rc=")); Serial.println(_device->mqttClient()->state()); + _device->printError(); + _device->mqttClient()->disconnect(); _mqttConnected = false; _nextReconnect = millis() + 5000; } diff --git a/PreferencesKeys.h b/PreferencesKeys.h index 8e48fc1..56466db 100644 --- a/PreferencesKeys.h +++ b/PreferencesKeys.h @@ -10,6 +10,9 @@ #define preference_mqtt_lock_path "mqttpath" #define preference_opener_enabled "openerena" #define preference_mqtt_opener_path "mqttoppath" +#define preference_mqtt_ca "mqttca" +#define preference_mqtt_crt "mqttcrt" +#define preference_mqtt_key "mqttkey" #define preference_hostname "hostname" #define preference_network_timeout "nettmout" #define preference_query_interval_lockstate "lockStInterval" diff --git a/WebCfgServer.cpp b/WebCfgServer.cpp index f91ba9c..8771ada 100644 --- a/WebCfgServer.cpp +++ b/WebCfgServer.cpp @@ -189,6 +189,21 @@ bool WebCfgServer::processArgs(String& message) _preferences->putString(preference_mqtt_opener_path, value); configChanged = true; } + else if(key == "MQTTCA") + { + _preferences->putString(preference_mqtt_ca, value); + configChanged = true; + } + else if(key == "MQTTCRT") + { + _preferences->putString(preference_mqtt_crt, value); + configChanged = true; + } + else if(key == "MQTTKEY") + { + _preferences->putString(preference_mqtt_key, value); + configChanged = true; + } else if(key == "HOSTNAME") { _preferences->putString(preference_hostname, value); @@ -481,6 +496,9 @@ void WebCfgServer::buildMqttConfigHtml(String &response) printInputField(response, "MQTTPORT", "MQTT Broker port", _preferences->getInt(preference_mqtt_broker_port), 5); printInputField(response, "MQTTUSER", "MQTT User (# to clear)", _preferences->getString(preference_mqtt_user).c_str(), 30); printInputField(response, "MQTTPASS", "MQTT Password", "*", 30, true); + printTextarea(response, "MQTTCA", "MQTT SSL CA Certificate", _preferences->getString(preference_mqtt_ca).c_str(), TLS_CA_MAX_SIZE); + printTextarea(response, "MQTTCRT", "MQTT SSL Client Certificate", _preferences->getString(preference_mqtt_crt).c_str(), TLS_CERT_MAX_SIZE); + printTextarea(response, "MQTTKEY", "MQTT SSL Client Key", _preferences->getString(preference_mqtt_key).c_str(), TLS_KEY_MAX_SIZE); printInputField(response, "NETTIMEOUT", "Network Timeout until restart (seconds; -1 to disable)", _preferences->getInt(preference_network_timeout), 5); response.concat(""); response.concat("
"); @@ -624,6 +642,32 @@ void WebCfgServer::printCheckBox(String &response, const char *token, const char response.concat("/>"); } +void WebCfgServer::printTextarea(String& response, + const char *token, + const char *description, + const char *value, + const size_t maxLength) +{ + char maxLengthStr[20]; + + itoa(maxLength, maxLengthStr, 10); + + response.concat(""); + response.concat(""); + response.concat(description); + response.concat(""); + response.concat(""); + response.concat(" "); + response.concat(""); + response.concat(""); +} + void WebCfgServer::printParameter(String& response, const char *description, const char *value) { response.concat(""); diff --git a/WebCfgServer.h b/WebCfgServer.h index 38dd12b..b9bdd59 100644 --- a/WebCfgServer.h +++ b/WebCfgServer.h @@ -43,6 +43,7 @@ private: void printInputField(String& response, const char* token, const char* description, const char* value, const size_t maxLength, const bool isPassword = false); void printInputField(String& response, const char* token, const char* description, const int value, size_t maxLength); 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); void printParameter(String& response, const char* description, const char* value); diff --git a/networkDevices/NetworkDevice.h b/networkDevices/NetworkDevice.h index e1ec20c..7fc65bf 100644 --- a/networkDevices/NetworkDevice.h +++ b/networkDevices/NetworkDevice.h @@ -14,6 +14,7 @@ public: virtual void initialize() = 0; virtual bool reconnect() = 0; virtual void reconfigure() = 0; + virtual void printError() = 0; virtual void update() = 0; diff --git a/networkDevices/W5500Device.cpp b/networkDevices/W5500Device.cpp index 1041046..79bbc85 100644 --- a/networkDevices/W5500Device.cpp +++ b/networkDevices/W5500Device.cpp @@ -117,6 +117,13 @@ void W5500Device::resetDevice() nwDelay(1500); } + +void W5500Device::printError() +{ + Serial.print(F("Free Heap: ")); + Serial.println(ESP.getFreeHeap()); +} + PubSubClient *W5500Device::mqttClient() { return _mqttClient; diff --git a/networkDevices/W5500Device.h b/networkDevices/W5500Device.h index 6cd1bc5..9ba726d 100644 --- a/networkDevices/W5500Device.h +++ b/networkDevices/W5500Device.h @@ -13,6 +13,7 @@ public: virtual void initialize(); virtual bool reconnect(); virtual void reconfigure(); + virtual void printError(); virtual void update(); diff --git a/networkDevices/WifiDevice.cpp b/networkDevices/WifiDevice.cpp index 87633f1..3428e99 100644 --- a/networkDevices/WifiDevice.cpp +++ b/networkDevices/WifiDevice.cpp @@ -1,15 +1,41 @@ #include #include "WifiDevice.h" #include "WiFiManager.h" +#include "../PreferencesKeys.h" -WifiDevice::WifiDevice(const String& hostname) -: NetworkDevice(hostname), - _mqttClient(_wifiClient) -{} +WifiDevice::WifiDevice(const String& hostname, Preferences* _preferences) +: NetworkDevice(hostname) +{ + 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); + + if(caLength > 1) // length is 1 when empty + { + Serial.println(F("MQTT over TLS.")); + Serial.println(_ca); + _wifiClientSecure = new WiFiClientSecure(); + _wifiClientSecure->setCACert(_ca); + if(crtLength > 1 && keyLength > 1) // length is 1 when empty + { + Serial.println(F("MQTT with client certificate.")); + Serial.println(_cert); + Serial.println(_key); + _wifiClientSecure->setCertificate(_cert); + _wifiClientSecure->setPrivateKey(_key); + } + _mqttClient = new PubSubClient(*_wifiClientSecure); + } else + { + Serial.println(F("MQTT without TLS.")); + _wifiClient = new WiFiClient(); + _mqttClient = new PubSubClient(*_wifiClient); + } +} PubSubClient *WifiDevice::mqttClient() { - return &_mqttClient; + return _mqttClient; } void WifiDevice::initialize() @@ -48,7 +74,7 @@ void WifiDevice::initialize() Serial.println(WiFi.localIP().toString()); } - _mqttClient.setBufferSize(_mqttMaxBufferSize); + _mqttClient->setBufferSize(_mqttMaxBufferSize); } void WifiDevice::reconfigure() @@ -58,6 +84,18 @@ void WifiDevice::reconfigure() ESP.restart(); } +void WifiDevice::printError() +{ + if(_wifiClientSecure != nullptr) + { + char lastError[100]; + _wifiClientSecure->lastError(lastError,100); + Serial.println(lastError); + } + Serial.print(F("Free Heap: ")); + Serial.println(ESP.getFreeHeap()); +} + bool WifiDevice::isConnected() { return WiFi.isConnected(); diff --git a/networkDevices/WifiDevice.h b/networkDevices/WifiDevice.h index 4680210..27b6728 100644 --- a/networkDevices/WifiDevice.h +++ b/networkDevices/WifiDevice.h @@ -1,17 +1,20 @@ #pragma once #include +#include +#include #include "NetworkDevice.h" #include "../SpiffsCookie.h" class WifiDevice : public NetworkDevice { public: - WifiDevice(const String& hostname); + WifiDevice(const String& hostname, Preferences* _preferences); virtual void initialize(); virtual void reconfigure(); virtual bool reconnect(); + virtual void printError(); virtual void update(); @@ -20,7 +23,11 @@ public: virtual PubSubClient *mqttClient(); private: - WiFiClient _wifiClient; - PubSubClient _mqttClient; + WiFiClient* _wifiClient = nullptr; + WiFiClientSecure* _wifiClientSecure = nullptr; + PubSubClient* _mqttClient = nullptr; SpiffsCookie _cookie; + char _ca[TLS_CA_MAX_SIZE]; + char _cert[TLS_CERT_MAX_SIZE]; + char _key[TLS_KEY_MAX_SIZE]; };