Skip to content

Commit

Permalink
mqtt: refactoring & mdns autoconnect tweaks
Browse files Browse the repository at this point in the history
- generic mdns query function so we don't forget about the removeQuery()
- full handle mdns logic in the mqtt module, check for running mdns
instance and periodically poll for _mqtt._tcp service
- autoconnect only when MQTT is enabled *and* there is no server
- use mqtt::settings and mqtt::build namespaces for settings
- some refactoring for topic <-> setting application
- prefer const String& to const char* in topic generation
  • Loading branch information
mcspr committed Jun 23, 2021
1 parent 19f3214 commit 06fa5b1
Show file tree
Hide file tree
Showing 5 changed files with 437 additions and 205 deletions.
2 changes: 1 addition & 1 deletion code/espurna/homeassistant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ class SensorDiscovery : public Discovery {
json["uniq_id"] = uniqueId();

json["name"] = _ctx.name() + ' ' + name() + ' ' + localId();
json["stat_t"] = mqttTopic(magnitudeTopicIndex(_index).c_str(), false);
json["stat_t"] = mqttTopic(magnitudeTopicIndex(_index), false);
json["unit_of_meas"] = magnitudeUnits(_index);

json.printTo(_message);
Expand Down
87 changes: 51 additions & 36 deletions code/espurna/mdns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,12 @@ Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------

#include "mdns.h"

#include "mqtt.h"
#include "utils.h"

#if MDNS_SERVER_SUPPORT

#include <ESP8266mDNS.h>

#if MQTT_SUPPORT

void _mdnsFindMQTT() {
int count = MDNS.queryService("mqtt", "tcp");
DEBUG_MSG_P(PSTR("[MQTT] MQTT brokers found: %d\n"), count);
for (int i=0; i<count; i++) {
DEBUG_MSG_P(PSTR("[MQTT] Broker at %s:%d\n"), MDNS.IP(i).toString().c_str(), MDNS.port(i));
mqttSetBrokerIfNone(MDNS.IP(i), MDNS.port(i));
}
}

#endif

String _mdnsHostname() {
return getSetting("hostname", getIdentifier());
}
Expand All @@ -46,10 +31,58 @@ void _mdnsServerStart() {

// -----------------------------------------------------------------------------

// 2.7.x and older require MDNS.begin() when interface is UP
// issue tracker suggest doing begin() for each mode change, but...
// this does seem to imply pairing it with end() (aka close()),
// which will completely reset the MDNS object and require a setup once again.
// this does not seem to work reliably :/ only support STA for the time being
// 3.0.0 and newer only need to do MDNS.begin() once at setup()
// however, note that without begin() call it will immediatly crash b/c
// there are no sanity checks if it was actually called
constexpr bool MdnsOldCore {
#if defined(ARDUINO_ESP8266_RELEASE_2_7_2) \
|| defined(ARDUINO_ESP8266_RELEASE_2_7_3) \
|| defined(ARDUINO_ESP8266_RELEASE_2_7_4)
true
#else
false
#endif
};

// As of right now, this needs to be request -> response operation in the same block,
// so we don't end up using someone else's query results.
// `queryService()` 3rd arg is timeout, by default it blocks for MDNS_QUERYSERVICES_WAIT_TIME (1000)

// TODO: esp8266 allows async pyzeroconf-like API to have this running independently.
// In case something other than MQTT needs this, consider extending the API
// (and notice that RTOS SDK alternative would need to use mdns_query_* ESP-IDF API)
// TODO: both implementations also have separate queries for A and AAAA records :/

bool mdnsServiceQuery(const String& service, const String& protocol, MdnsServerQueryCallback callback) {
bool result { false };

auto found = MDNS.queryService(service, protocol);
for (decltype(found) n = 0; n < found; ++n) {
if (callback(MDNS.IP(n).toString(), MDNS.port(n))) {
result = true;
break;
}
}

MDNS.removeQuery();

return result;
}

bool mdnsRunning() {
return MDNS.isRunning();
}

void mdnsServerSetup() {
bool done { false };

MDNS.setHostname(_mdnsHostname());
if (!MdnsOldCore) {
_mdnsServerStart();
}

#if WEB_SUPPORT
{
Expand Down Expand Up @@ -93,29 +126,11 @@ void mdnsServerSetup() {
MDNS.update();
});

// 2.7.x and older require MDNS.begin() when interface is UP
// issue tracker suggest doing begin() for each mode change, but...
// this does seem to imply pairing it with end() (aka close()),
// which will completely reset the MDNS object and require a setup once again.
// this does not seem to work reliably :/ only support STA for the time being
// 3.0.0 and newer only need to do MDNS.begin() once at setup()
const static bool OldCore {
(esp8266::coreVersionNumeric() >= 20702000) && (esp8266::coreVersionNumeric() <= 20703003) };

wifiRegister([](wifi::Event event) {
#if MQTT_SUPPORT
if (event == wifi::Event::StationConnected) {
_mdnsFindMQTT();
}
#endif
if (OldCore && (event == wifi::Event::StationConnected) && !MDNS.isRunning()) {
if (MdnsOldCore && (event == wifi::Event::StationConnected) && !MDNS.isRunning()) {
_mdnsServerStart();
}
});

if (!OldCore) {
_mdnsServerStart();
}
}

#endif // MDNS_SERVER_SUPPORT
4 changes: 4 additions & 0 deletions code/espurna/mdns.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@ Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>

#include "espurna.h"

using MdnsServerQueryCallback = bool(*)(String&& server, uint16_t port);

bool mdnsRunning();
bool mdnsServiceQuery(const String& service, const String& protocol, MdnsServerQueryCallback callback);
void mdnsServerSetup();
Loading

0 comments on commit 06fa5b1

Please sign in to comment.