Skip to content

Commit 3376b6a

Browse files
committed
-Ported to esp32. homie-esp8266 now supports architectures esp32 and esp8266.
-Successfully tested with M5Stick/Environment Sensor (https://docs.m5stack.com/#/en/core/m5stick, https://docs.m5stack.com/#/en/unit/env) on openHAB 2.4 / mosquitto 1.4.15. -For increased openhab2.4 compatibility $stats/interval is now set correctly and published on every stats update (see eclipse-archived/smarthome#6495). -On esp32 OTA and LED support are currently not working (future work needs to be done, see #FIXME comments).
1 parent 6079dcb commit 3376b6a

13 files changed

+193
-14
lines changed

library.properties

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ name=Homie
22
version=3.0.0
33
author=Marvin Roger
44
maintainer=Marvin Roger
5-
sentence=ESP8266 framework for Homie, a lightweight MQTT convention for the IoT
5+
sentence=ESP32/ESP8266 framework for Homie, a lightweight MQTT convention for the IoT
66
paragraph=Like this project? Please star it on GitHub!
77
category=Device Control
88
url=https://github.com/marvinroger/homie-esp8266
9-
architectures=esp8266
9+
architectures=esp32,esp8266

src/Homie.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,16 @@ HomieClass::HomieClass()
99
strlcpy(Interface::get().brand, DEFAULT_BRAND, MAX_BRAND_LENGTH);
1010
Interface::get().bootMode = HomieBootMode::UNDEFINED;
1111
Interface::get().configurationAp.secured = false;
12+
#ifdef ESP32
13+
//FIXME: led on ESP32
14+
Interface::get().led.enabled = false;
15+
//Interface::get().led.pin = LED_BUILTIN;
16+
//Interface::get().led.on = LOW;
17+
#elif defined(ESP8266)
1218
Interface::get().led.enabled = true;
1319
Interface::get().led.pin = LED_BUILTIN;
1420
Interface::get().led.on = LOW;
21+
#endif // ESP32
1522
Interface::get().reset.idle = true;
1623
Interface::get().reset.enabled = true;
1724
Interface::get().reset.triggerPin = DEFAULT_RESET_PIN;
@@ -332,6 +339,9 @@ Logger& HomieClass::getLogger() {
332339
return _logger;
333340
}
334341

342+
#ifdef ESP32
343+
//FIXME: implement for ESP32
344+
#elif defined(ESP8266)
335345
void HomieClass::prepareToSleep() {
336346
Interface::get().getLogger() << F("Flagged for sleep by sketch") << endl;
337347
if (Interface::get().ready) {
@@ -350,5 +360,7 @@ void HomieClass::doDeepSleep(uint32_t time_us, RFMode mode) {
350360
Serial.flush();
351361
ESP.deepSleep(time_us, mode);
352362
}
363+
#endif // ESP32
364+
353365

354366
HomieClass Homie;

src/Homie.hpp

+4
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,12 @@ class HomieClass {
6464
static const ConfigStruct& getConfiguration();
6565
AsyncMqttClient& getMqttClient();
6666
Logger& getLogger();
67+
#ifdef ESP32
68+
//FIXME implement on ESP32
69+
#elif defined(ESP8266)
6770
static void prepareToSleep();
6871
static void doDeepSleep(uint32_t time_us = 0, RFMode mode = RF_DEFAULT);
72+
#endif // ESP32
6973

7074
private:
7175
bool _setupCalled;

src/Homie/Boot/Boot.hpp

+4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22

33
#include "Arduino.h"
44

5+
#ifdef ESP32
6+
#include <WiFi.h>
7+
#elif defined(ESP8266)
58
#include <ESP8266WiFi.h>
9+
#endif // ESP32
610
#include "../../StreamingOperator.hpp"
711
#include "../Datatypes/Interface.hpp"
812
#include "../Constants.hpp"

src/Homie/Boot/BootConfig.cpp

+23
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,28 @@ void BootConfig::_generateNetworksJson() {
208208
JsonObject& jsonNetwork = generatedJsonBuffer.createObject();
209209
jsonNetwork["ssid"] = WiFi.SSID(network);
210210
jsonNetwork["rssi"] = WiFi.RSSI(network);
211+
#ifdef ESP32
212+
switch (WiFi.encryptionType(network)) {
213+
case (WIFI_AUTH_OPEN):
214+
jsonNetwork["encryption"] = "none";
215+
break;
216+
case (WIFI_AUTH_WEP):
217+
jsonNetwork["encryption"] = "wep";
218+
break;
219+
case (WIFI_AUTH_WPA_PSK):
220+
jsonNetwork["encryption"] = "wpa";
221+
break;
222+
case (WIFI_AUTH_WPA2_PSK):
223+
jsonNetwork["encryption"] = "wpa2";
224+
break;
225+
case (WIFI_AUTH_WPA_WPA2_PSK):
226+
//FIXME
227+
break;
228+
case (WIFI_AUTH_WPA2_ENTERPRISE):
229+
//FIXME
230+
break;
231+
}
232+
#elif defined(ESP8266)
211233
switch (WiFi.encryptionType(network)) {
212234
case ENC_TYPE_WEP:
213235
jsonNetwork["encryption"] = "wep";
@@ -225,6 +247,7 @@ void BootConfig::_generateNetworksJson() {
225247
jsonNetwork["encryption"] = "auto";
226248
break;
227249
}
250+
#endif // ESP32
228251

229252
networks.add(jsonNetwork);
230253
}

src/Homie/Boot/BootConfig.hpp

+7
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,16 @@
33
#include "Arduino.h"
44

55
#include <functional>
6+
#ifdef ESP32
7+
#include <WiFi.h>
8+
#include <HTTPClient.h>
9+
#include <AsyncTCP.h>
10+
#include <SPIFFS.h>
11+
#elif defined(ESP8266)
612
#include <ESP8266WiFi.h>
713
#include <ESP8266HTTPClient.h>
814
#include <ESPAsyncTCP.h>
15+
#endif // ESP32
916
#include <ESPAsyncWebServer.h>
1017
#include <DNSServer.h>
1118
#include <ArduinoJson.h>

src/Homie/Boot/BootNormal.cpp

+97-12
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
using namespace HomieInternals;
44

5+
#ifdef ESP32
56
BootNormal::BootNormal()
67
: Boot("normal")
78
, _mqttReconnectTimer(MQTT_RECONNECT_INITIAL_INTERVAL, MQTT_RECONNECT_MAX_BACKOFF)
@@ -21,17 +22,48 @@ BootNormal::BootNormal()
2122
, _mqttPayloadBuffer(nullptr)
2223
, _mqttTopicLevels(nullptr)
2324
, _mqttTopicLevelsCount(0) {
24-
strlcpy(_fwChecksum, ESP.getSketchMD5().c_str(), sizeof(_fwChecksum));
25+
//FIXME: getSketchMD5 not implemented / boot loop on ESP32
26+
//TODO: Remove Update.h from BootNormal.cpp, change status codes to https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/ota.html
27+
strcpy(_fwChecksum, "00000000000000000000000000000000");
2528
_fwChecksum[sizeof(_fwChecksum) - 1] = '\0';
2629
}
30+
#elif defined(ESP8266)
31+
BootNormal::BootNormal()
32+
: Boot("normal")
33+
, _mqttReconnectTimer(MQTT_RECONNECT_INITIAL_INTERVAL, MQTT_RECONNECT_MAX_BACKOFF)
34+
, _setupFunctionCalled(false)
35+
, _mqttConnectNotified(false)
36+
, _mqttDisconnectNotified(true)
37+
, _otaOngoing(false)
38+
, _flaggedForReboot(false)
39+
, _mqttOfflineMessageId(0)
40+
, _otaIsBase64(false)
41+
, _otaBase64Pads(0)
42+
, _otaSizeTotal(0)
43+
, _otaSizeDone(0)
44+
, _mqttTopic(nullptr)
45+
, _mqttClientId(nullptr)
46+
, _mqttWillTopic(nullptr)
47+
, _mqttPayloadBuffer(nullptr)
48+
, _mqttTopicLevels(nullptr)
49+
, _mqttTopicLevelsCount(0) {
50+
strlcpy(_fwChecksum, ESP.getSketchMD5().c_str(), sizeof(_fwChecksum));
51+
_fwChecksum[sizeof(_fwChecksum) - 1] = '\0';
52+
}
53+
#endif // ESP32
54+
2755

2856
BootNormal::~BootNormal() {
2957
}
3058

3159
void BootNormal::setup() {
3260
Boot::setup();
3361

62+
#ifdef ESP32
63+
//FIXME
64+
#elif defined(ESP8266)
3465
Update.runAsync(true);
66+
#endif // ESP32
3567

3668
_statsTimer.setInterval(Interface::get().getConfig().get().deviceStatsInterval * 1000);
3769

@@ -53,8 +85,13 @@ void BootNormal::setup() {
5385
}
5486
_mqttTopic = std::unique_ptr<char[]>(new char[baseTopicLength + longestSubtopicLength]);
5587

88+
#ifdef ESP32
89+
_wifiGotIpHandler = WiFi.onEvent(std::bind(&BootNormal::_onWifiGotIp, this, std::placeholders::_1, std::placeholders::_2), WiFiEvent_t::SYSTEM_EVENT_STA_GOT_IP);
90+
_wifiDisconnectedHandler = WiFi.onEvent(std::bind(&BootNormal::_onWifiDisconnected, this, std::placeholders::_1, std::placeholders::_2), WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED);
91+
#elif defined(ESP8266)
5692
_wifiGotIpHandler = WiFi.onStationModeGotIP(std::bind(&BootNormal::_onWifiGotIp, this, std::placeholders::_1));
5793
_wifiDisconnectedHandler = WiFi.onStationModeDisconnected(std::bind(&BootNormal::_onWifiDisconnected, this, std::placeholders::_1));
94+
#endif // ESP32
5895

5996
Interface::get().getMqttClient().onConnect(std::bind(&BootNormal::_onMqttConnected, this));
6097
Interface::get().getMqttClient().onDisconnect(std::bind(&BootNormal::_onMqttDisconnected, this, std::placeholders::_1));
@@ -144,10 +181,15 @@ void BootNormal::loop() {
144181
}
145182

146183
if (_statsTimer.check()) {
184+
char statsIntervalStr[3 + 1];
185+
itoa(Interface::get().getConfig().get().deviceStatsInterval, statsIntervalStr, 10);
186+
Interface::get().getLogger() << F("〽 Sending statistics...") << endl;
187+
Interface::get().getLogger() << F(" • Interval: ") << statsIntervalStr << F("s") << endl;
188+
uint16_t intervalPacketId = Interface::get().getMqttClient().publish(_prefixMqttTopic(PSTR("/$stats/interval")), 1, true, statsIntervalStr);
189+
147190
uint8_t quality = Helpers::rssiToPercentage(WiFi.RSSI());
148191
char qualityStr[3 + 1];
149192
itoa(quality, qualityStr, 10);
150-
Interface::get().getLogger() << F("〽 Sending statistics...") << endl;
151193
Interface::get().getLogger() << F(" • Wi-Fi signal quality: ") << qualityStr << F("%") << endl;
152194
uint16_t signalPacketId = Interface::get().getMqttClient().publish(_prefixMqttTopic(PSTR("/$stats/signal")), 1, true, qualityStr);
153195

@@ -157,7 +199,7 @@ void BootNormal::loop() {
157199
Interface::get().getLogger() << F(" • Uptime: ") << uptimeStr << F("s") << endl;
158200
uint16_t uptimePacketId = Interface::get().getMqttClient().publish(_prefixMqttTopic(PSTR("/$stats/uptime")), 1, true, uptimeStr);
159201

160-
if (signalPacketId != 0 && uptimePacketId != 0) _statsTimer.tick();
202+
if (intervalPacketId != 0 && signalPacketId != 0 && uptimePacketId != 0) _statsTimer.tick();
161203
}
162204

163205
Interface::get().loopFunction();
@@ -204,10 +246,14 @@ void BootNormal::_endOtaUpdate(bool success, uint8_t update_error) {
204246
switch (update_error) {
205247
case UPDATE_ERROR_SIZE: // new firmware size is zero
206248
case UPDATE_ERROR_MAGIC_BYTE: // new firmware does not have 0xE9 in first byte
249+
#ifdef ESP32
250+
//FIXME
251+
#elif defined(ESP8266)
207252
case UPDATE_ERROR_NEW_FLASH_CONFIG: // bad new flash config (does not match flash ID)
208253
code = 400; // 400 Bad Request
209254
info.concat(F("BAD_FIRMWARE"));
210255
break;
256+
#endif //ESP32
211257
case UPDATE_ERROR_MD5:
212258
code = 400; // 400 Bad Request
213259
info.concat(F("BAD_CHECKSUM"));
@@ -246,7 +292,11 @@ void BootNormal::_wifiConnect() {
246292

247293
if (WiFi.getMode() != WIFI_STA) WiFi.mode(WIFI_STA);
248294

295+
#ifdef ESP32
296+
WiFi.setHostname(Interface::get().getConfig().get().deviceId);
297+
#elif defined(ESP8266)
249298
WiFi.hostname(Interface::get().getConfig().get().deviceId);
299+
#endif // ESP32
250300
if (strcmp_P(Interface::get().getConfig().get().wifi.ip, PSTR("")) != 0) { // on _validateConfigWifi there is a requirement for mask and gateway
251301
IPAddress convertedIp;
252302
convertedIp.fromString(Interface::get().getConfig().get().wifi.ip);
@@ -283,32 +333,63 @@ void BootNormal::_wifiConnect() {
283333
}
284334
}
285335

286-
void BootNormal::_onWifiGotIp(const WiFiEventStationModeGotIP& event) {
336+
#ifdef ESP32
337+
void BootNormal::_onWifiGotIp(WiFiEvent_t event, WiFiEventInfo_t info) {
287338
if (Interface::get().led.enabled) Interface::get().getBlinker().stop();
288-
Interface::get().getLogger() << F("✔ Wi-Fi connected, IP: ") << event.ip << endl;
339+
Interface::get().getLogger() << F("✔ Wi-Fi connected, IP: ") << IPAddress(info.got_ip.ip_info.ip.addr) << endl;
289340
Interface::get().getLogger() << F("Triggering WIFI_CONNECTED event...") << endl;
290341
Interface::get().event.type = HomieEventType::WIFI_CONNECTED;
291-
Interface::get().event.ip = event.ip;
292-
Interface::get().event.mask = event.mask;
293-
Interface::get().event.gateway = event.gw;
342+
Interface::get().event.ip = IPAddress(info.got_ip.ip_info.ip.addr);
343+
Interface::get().event.mask = IPAddress(info.got_ip.ip_info.netmask.addr);
344+
Interface::get().event.gateway = IPAddress(info.got_ip.ip_info.gw.addr);
294345
Interface::get().eventHandler(Interface::get().event);
295346
MDNS.begin(Interface::get().getConfig().get().deviceId);
296347

297348
_mqttConnect();
298349
}
299-
300-
void BootNormal::_onWifiDisconnected(const WiFiEventStationModeDisconnected& event) {
350+
#elif defined(ESP8266)
351+
void BootNormal::_onWifiGotIp(const WiFiEventStationModeGotIP& event) {
352+
if (Interface::get().led.enabled) Interface::get().getBlinker().stop();
353+
Interface::get().getLogger() << F("✔ Wi-Fi connected, IP: ") << event.ip << endl;
354+
Interface::get().getLogger() << F("Triggering WIFI_CONNECTED event...") << endl;
355+
Interface::get().event.type = HomieEventType::WIFI_CONNECTED;
356+
Interface::get().event.ip = event.ip;
357+
Interface::get().event.mask = event.mask;
358+
Interface::get().event.gateway = event.gw;
359+
Interface::get().eventHandler(Interface::get().event);
360+
MDNS.begin(Interface::get().getConfig().get().deviceId);
361+
362+
_mqttConnect();
363+
}
364+
#endif // ESP32
365+
366+
#ifdef ESP32
367+
void BootNormal::_onWifiDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) {
301368
Interface::get().ready = false;
302369
if (Interface::get().led.enabled) Interface::get().getBlinker().start(LED_WIFI_DELAY);
303370
_statsTimer.reset();
304371
Interface::get().getLogger() << F("✖ Wi-Fi disconnected") << endl;
305372
Interface::get().getLogger() << F("Triggering WIFI_DISCONNECTED event...") << endl;
306373
Interface::get().event.type = HomieEventType::WIFI_DISCONNECTED;
307-
Interface::get().event.wifiReason = event.reason;
374+
//Interface::get().event.wifiReason = info.disconnected.reason;
308375
Interface::get().eventHandler(Interface::get().event);
309376

310377
_wifiConnect();
311378
}
379+
#elif defined(ESP8266)
380+
void BootNormal::_onWifiDisconnected(const WiFiEventStationModeDisconnected& event) {
381+
Interface::get().ready = false;
382+
if (Interface::get().led.enabled) Interface::get().getBlinker().start(LED_WIFI_DELAY);
383+
_statsTimer.reset();
384+
Interface::get().getLogger() << F("✖ Wi-Fi disconnected") << endl;
385+
Interface::get().getLogger() << F("Triggering WIFI_DISCONNECTED event...") << endl;
386+
Interface::get().event.type = HomieEventType::WIFI_DISCONNECTED;
387+
Interface::get().event.wifiReason = event.reason;
388+
Interface::get().eventHandler(Interface::get().event);
389+
390+
_wifiConnect();
391+
}
392+
#endif // ESP32
312393

313394
void BootNormal::_mqttConnect() {
314395
if (!Interface::get().disable) {
@@ -366,7 +447,7 @@ void BootNormal::_advertise() {
366447
break;
367448
case AdvertisementProgress::GlobalStep::PUB_STATS_INTERVAL:
368449
char statsIntervalStr[3 + 1];
369-
itoa(STATS_SEND_INTERVAL_SEC / 1000, statsIntervalStr, 10);
450+
itoa(Interface::get().getConfig().get().deviceStatsInterval, statsIntervalStr, 10);
370451
packetId = Interface::get().getMqttClient().publish(_prefixMqttTopic(PSTR("/$stats/interval")), 1, true, statsIntervalStr);
371452
if (packetId != 0) _advertisementProgress.globalStep = AdvertisementProgress::GlobalStep::PUB_FW_NAME;
372453
break;
@@ -383,7 +464,11 @@ void BootNormal::_advertise() {
383464
if (packetId != 0) _advertisementProgress.globalStep = AdvertisementProgress::GlobalStep::PUB_IMPLEMENTATION;
384465
break;
385466
case AdvertisementProgress::GlobalStep::PUB_IMPLEMENTATION:
467+
#ifdef ESP32
468+
packetId = Interface::get().getMqttClient().publish(_prefixMqttTopic(PSTR("/$implementation")), 1, true, "esp32");
469+
#elif defined(ESP8266)
386470
packetId = Interface::get().getMqttClient().publish(_prefixMqttTopic(PSTR("/$implementation")), 1, true, "esp8266");
471+
#endif // ESP32
387472
if (packetId != 0) _advertisementProgress.globalStep = AdvertisementProgress::GlobalStep::PUB_IMPLEMENTATION_CONFIG;
388473
break;
389474
case AdvertisementProgress::GlobalStep::PUB_IMPLEMENTATION_CONFIG:

src/Homie/Boot/BootNormal.hpp

+16
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,14 @@
44

55
#include <functional>
66
#include <libb64/cdecode.h>
7+
#ifdef ESP32
8+
#include <WiFi.h>
9+
#include <ESPmDNS.h>
10+
#include <Update.h>
11+
#elif defined(ESP8266)
712
#include <ESP8266WiFi.h>
813
#include <ESP8266mDNS.h>
14+
#endif // ESP32
915
#include <AsyncMqttClient.h>
1016
#include "../../HomieNode.hpp"
1117
#include "../../HomieRange.hpp"
@@ -82,8 +88,13 @@ class BootNormal : public Boot {
8288
Timer _statsTimer;
8389
ExponentialBackoffTimer _mqttReconnectTimer;
8490
bool _setupFunctionCalled;
91+
#ifdef ESP32
92+
WiFiEventId_t _wifiGotIpHandler;
93+
WiFiEventId_t _wifiDisconnectedHandler;
94+
#elif defined(ESP8266)
8595
WiFiEventHandler _wifiGotIpHandler;
8696
WiFiEventHandler _wifiDisconnectedHandler;
97+
#endif // ESP32
8798
bool _mqttConnectNotified;
8899
bool _mqttDisconnectNotified;
89100
bool _otaOngoing;
@@ -105,8 +116,13 @@ class BootNormal : public Boot {
105116
uint8_t _mqttTopicLevelsCount;
106117

107118
void _wifiConnect();
119+
#ifdef ESP32
120+
void _onWifiGotIp(WiFiEvent_t event, WiFiEventInfo_t info);
121+
void _onWifiDisconnected(WiFiEvent_t event, WiFiEventInfo_t info);
122+
#elif defined(ESP8266)
108123
void _onWifiGotIp(const WiFiEventStationModeGotIP& event);
109124
void _onWifiDisconnected(const WiFiEventStationModeDisconnected& event);
125+
#endif // ESP32
110126
void _mqttConnect();
111127
void _advertise();
112128
void _onMqttConnected();

src/Homie/Config.hpp

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
#include "Arduino.h"
44

55
#include <ArduinoJson.h>
6+
#ifdef ESP32
7+
#include <SPIFFS.h>
8+
#endif // ESP32
69
#include "FS.h"
710
#include "Datatypes/Interface.hpp"
811
#include "Datatypes/ConfigStruct.hpp"

0 commit comments

Comments
 (0)