Skip to content

Commit

Permalink
Merge pull request #132 from technyon/move-epsMqttClient-to-network-task
Browse files Browse the repository at this point in the history
Move eps mqtt client to network task
  • Loading branch information
technyon authored Mar 3, 2023
2 parents de057b8 + 9f78b2e commit e32647d
Show file tree
Hide file tree
Showing 32 changed files with 612 additions and 178 deletions.
2 changes: 1 addition & 1 deletion Config.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once

#define NUKI_HUB_VERSION "8.12-pre-1"
#define NUKI_HUB_VERSION "8.12-pre-11"

#define MQTT_QOS_LEVEL 1
#define MQTT_CLEAN_SESSIONS false
71 changes: 37 additions & 34 deletions Network.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,53 +56,55 @@ void Network::setupDevice()
}
else
{
if(hardwareDetect == 1)
Log->print(F("Network device: "));
switch (hardwareDetect)
{
Log->println(F("W5500 hardware is disabled, using Wifi."));
_networkDeviceType = NetworkDeviceType::WiFi;
}
else if(hardwareDetect == 2)
{
Log->print(F("Using PIN "));
Log->print(hardwareDetectGpio);
Log->println(F(" for network device selection"));
case 1:
Log->println(F("Wifi only"));
_networkDeviceType = NetworkDeviceType::WiFi;
break;
case 2:
Log->print(F("Using PIN "));
Log->print(hardwareDetectGpio);
Log->println(F(" for network device selection"));

pinMode(hardwareDetectGpio, INPUT_PULLUP);
_networkDeviceType = digitalRead(hardwareDetectGpio) == HIGH ? NetworkDeviceType::WiFi : NetworkDeviceType::W5500;
}
else if(hardwareDetect == 3)
{
Log->println(F("W5500 on M5Stack Atom POE"));
_networkDeviceType = NetworkDeviceType::W5500;
}
else if(hardwareDetect == 4)
{
Log->println(F("Olimex ESP32-POE / ESP-POE-ISO"));
_networkDeviceType = NetworkDeviceType::LAN8720;
}
else
{
Log->println(F("Unknown hardware selected, falling back to Wifi."));
_networkDeviceType = NetworkDeviceType::WiFi;
pinMode(hardwareDetectGpio, INPUT_PULLUP);
_networkDeviceType = digitalRead(hardwareDetectGpio) == HIGH ? NetworkDeviceType::WiFi : NetworkDeviceType::W5500;
break;
case 3:
Log->println(F("W5500 on M5Stack Atom POE"));
_networkDeviceType = NetworkDeviceType::W5500;
break;
case 4:
Log->println(F("Olimex ESP32-POE / ESP-POE-ISO"));
_networkDeviceType = NetworkDeviceType::Olimex_LAN8720;
break;
case 5:
Log->println(F("WT32-ETH01"));
_networkDeviceType = NetworkDeviceType::WT32_LAN8720;
break;
default:
Log->println(F("Unknown hardware selected, falling back to Wifi."));
_networkDeviceType = NetworkDeviceType::WiFi;
break;
}
}

switch(_networkDeviceType)
switch (_networkDeviceType)
{
case NetworkDeviceType::W5500:
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);
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);
break;
case NetworkDeviceType::WT32_LAN8720:
_device = new EthLan8720Device(_hostname, _preferences, "WT32-ETH01", 1, 16);
break;
case NetworkDeviceType::WiFi:
Log->println(F("Network device: Builtin WiFi"));
_device = new WifiDevice(_hostname, _preferences);
break;
default:
Log->println(F("Unknown network device type, defaulting to WiFi"));
_device = new WifiDevice(_hostname, _preferences);
break;
}
Expand Down Expand Up @@ -357,7 +359,8 @@ bool Network::reconnect()

while(!_connectReplyReceived && millis() < timeout)
{
delay(200);
delay(50);
_device->update();
if(_keepAliveCallback != nullptr)
{
_keepAliveCallback();
Expand Down
3 changes: 2 additions & 1 deletion Network.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ enum class NetworkDeviceType
{
WiFi,
W5500,
LAN8720
Olimex_LAN8720,
WT32_LAN8720
};

#define JSON_BUFFER_SIZE 1024
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ As an alternative to Wifi, the following ESP32 modules with wired ethernet are s
[M5Stack Atom POE](https://docs.m5stack.com/en/atom/atom_poe)<br>
[Olimex ESP32-POE](https://www.olimex.com/Products/IoT/ESP32/ESP32-POE/open-source-hardware)<br>
[Olimex ESP32-POE-ISO](https://www.olimex.com/Products/IoT/ESP32/ESP32-POE-ISO/open-source-hardware)<br>
[WT32-ETH01](http://www.wireless-tag.com/portfolio/wt32-eth01/)<br>

## Installation

Expand All @@ -34,7 +35,10 @@ https://github.com/technyon/nuki_hub/releases
The firmware uses the Wifi Manager to configure the WiFi network. Power up the ESP32, a new Access Point should appear. Connect to this access point and in a browser navigate to "192.168.4.1". Use the web interface configure your Wifi network.

After configuring the Wifi, the ESP should automatically connect to your network. Use the web interface to setup the MQTT broker; just navigate to the IP-Address assigned to the ESP32 via DHCP (often found in the web interface of the internet router).<br>
To configure MQTT, enter the adress of your MQTT broker and eventually a username and a password if required. The firmware supports SSL encryption for MQTT, however most people and especially home users don't use this. In that case leave all fields about "MQTT SSL" blank.
To configure MQTT, enter the adress of your MQTT broker and eventually a username and a password if required. The firmware supports SSL encryption for MQTT, however most people and especially home users don't use this. In that case leave all fields about "MQTT SSL" blank.<br>
If a PIN has been configured using the smartphone app, it's recommended to supply this PIN to NUKI Hub.
Certain functionality is not available without configuring the PIN, like changing the config or keypad coded.
To do so, navigate to "Credentials" in the web interface. This will only supply the PIN to NUK Hub, it will on no way reconfigure the PIN on the lock.

## Pairing

Expand Down
11 changes: 10 additions & 1 deletion WebCfgServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,14 @@ void WebCfgServer::buildInfoHtml(String &response)
response.concat(esp_get_free_heap_size());
response.concat("\n");

response.concat("Stack watermarks: nw: ");
response.concat(uxTaskGetStackHighWaterMark(networkTaskHandle));
response.concat(", nuki: ");
response.concat(uxTaskGetStackHighWaterMark(nukiTaskHandle));
response.concat(", pd: ");
response.concat(uxTaskGetStackHighWaterMark(presenceDetectionTaskHandle));
response.concat("\n");

response.concat("Restart reason FW: ");
response.concat(getRestartReason());
response.concat( "\n");
Expand Down Expand Up @@ -1105,10 +1113,11 @@ const std::vector<std::pair<String, String>> WebCfgServer::getNetworkDetectionOp
{
std::vector<std::pair<String, String>> options;

options.push_back(std::make_pair("1", "Disable W5500 (Wifi only)"));
options.push_back(std::make_pair("1", "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"));
options.push_back(std::make_pair("5", "WT32-ETH01"));

return options;
}
Expand Down
4 changes: 4 additions & 0 deletions WebCfgServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
#include "NukiOpenerWrapper.h"
#include "Ota.h"

extern TaskHandle_t networkTaskHandle;
extern TaskHandle_t nukiTaskHandle;
extern TaskHandle_t presenceDetectionTaskHandle;

enum class TokenType
{
None,
Expand Down
30 changes: 24 additions & 6 deletions lib/espMqttClient/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ espMqttClientAsync()
```

Instantiate a new espMqttClient or espMqttSecure object.
On ESP32, two optional parameters are available: `espMqttClient(uint8_t priority = 1, uint8_t core = 1)`. This will change the priority of the MQTT client task and the core on which it runs (higher priority = more cpu-time).
On ESP32, three optional parameters are available: `espMqttClient(bool internalTask = true, uint8_t priority = 1, uint8_t core = 1)`. By default, espMqttclient creates its own task to manage TCP. By setting `internalTask` to false, no task will be created and you will be responsible yourself to call `espMqttClient.loop()`. `priority` changes the priority of the MQTT client task and the core on which it runs (higher priority = more cpu-time).

For the asynchronous version, use `espMqttClientAsync`.

Expand Down Expand Up @@ -150,6 +150,15 @@ Set the server.
- **`host`**: Host of the server, expects a null-terminated char array (c-string)
- **`port`**: Port of the server

```cpp
espMqttClient& setTimeout(uint16_t timeout)
```
Set the timeout for packets that need acknowledgement. Defaults to 10 seconds.
When no acknowledgement has been received from the broker after sending a packet, the client will retransmit **all** the packets in the queue.
* **`timeout`**: Timeout in seconds
#### Options for TLS connections
All common options from WiFiClientSecure to setup an encrypted connection are made available. These include:
Expand Down Expand Up @@ -312,17 +321,19 @@ Publish a packet with a callback for payload handling. Return the packet ID (or
The callback has the following signature: `size_t callback(uint8_t* data, size_t maxSize, size_t index)`. When the library needs payload data, the callback will be invoked. It is the callback's job to write data indo `data` with a maximum of `maxSize` bytes, according the `index` and return the amount of bytes written.
```cpp
void clearQueue()
void clearQueue(bool deleteSessionData = false)
```

When disconnected, clears all queued messages.
Keep in mind that this also deletes any session data and therefore is no MQTT compliant.
Clears all queued messages.
Keep in mind that this may also delete any session data and therefore is not MQTT compliant.

- **`deleteSessionData`**: When true, delete all outgoing messages. Not MQTT compliant!

```cpp
void loop()
```

This is the worker function of the MQTT client. For ESP8266 you must call this function in the Arduino loop. For ESP32 this function is only used internally and is not available in the API.
This is the worker function of the MQTT client. For ESP8266 you must call this function in the Arduino loop. For ESP32 you have to call this function yourself **only if you have disabled the internal task** (see the constructors).

```cpp
const char* getClientId() const
Expand Down Expand Up @@ -361,12 +372,19 @@ Set this to 1 if you use the async version on ESP8266. For the regular client th
### EMC_ALLOW_NOT_CONNECTED_PUBLISH 1

By default, you can publish when the client is not connected. If you don't want this, set this to 0.
Regardless of this setting, after you called `disconnect()`, no messages can be published until fully disconnected.

### EMC_WAIT_FOR_CONNACK 1

espMqttClient waits for the CONNACK (connection acknowledge) packet before starting to send other packets.
The MQTT specification allows to start sending before the broker acknowledges the connection but some brokers
don't allow this (AWS for example doesn't).

### EMC_CLIENTID_LENGTH 18 + 1

The (maximum) length of the client ID. (Keep in mind that this is a c-string. You need to have 1 position available for the null-termination.)

### EMC_TASK_STACK_SIZE 5000
### EMC_TASK_STACK_SIZE 5120

Only used on ESP32. Sets the stack size (in words) of the MQTT client worker task.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <ESP8266WiFi.h>
#include <Ticker.h>

#include <espMqttClient.h>

#define WIFI_SSID "yourSSID"
Expand All @@ -11,7 +12,8 @@
WiFiEventHandler wifiConnectHandler;
WiFiEventHandler wifiDisconnectHandler;
espMqttClient mqttClient;
Ticker reconnectTimer;
bool reconnectMqtt = false;
uint32_t lastReconnect = 0;

size_t fetchPayload(uint8_t* dest, size_t len, size_t index) {
Serial.printf("filling buffer at index %zu\n", index);
Expand All @@ -35,7 +37,13 @@ void connectToWiFi() {

void connectToMqtt() {
Serial.println("Connecting to MQTT...");
mqttClient.connect();
if (!mqttClient.connect()) {
reconnectMqtt = true;
lastReconnect = millis();
Serial.println("Connecting failed.");
} else {
reconnectMqtt = false;
}
}

void onWiFiConnect(const WiFiEventStationModeGotIP& event) {
Expand All @@ -45,8 +53,6 @@ void onWiFiConnect(const WiFiEventStationModeGotIP& event) {

void onWiFiDisconnect(const WiFiEventStationModeDisconnected& event) {
Serial.println("Disconnected from Wi-Fi.");
reconnectTimer.detach(); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
reconnectTimer.once(5, connectToWiFi);
}

void onMqttConnect(bool sessionPresent) {
Expand All @@ -60,7 +66,8 @@ void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason) {
Serial.printf("Disconnected from MQTT: %u.\n", static_cast<uint8_t>(reason));

if (WiFi.isConnected()) {
reconnectTimer.once(5, connectToMqtt);
reconnectMqtt = true;
lastReconnect = millis();
}
}

Expand All @@ -75,6 +82,8 @@ void setup() {
Serial.println();
Serial.println();

WiFi.setAutoConnect(false);
WiFi.setAutoReconnect(true);
wifiConnectHandler = WiFi.onStationModeGotIP(onWiFiConnect);
wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWiFiDisconnect);

Expand All @@ -87,5 +96,10 @@ void setup() {
}

void loop() {
static uint32_t currentMillis = millis();

mqttClient.loop();
if (reconnectMqtt && currentMillis - lastReconnect > 5000) {
connectToMqtt();
}
}
Loading

0 comments on commit e32647d

Please sign in to comment.