a1f4e57a21
* Update back end to add MQTT and WebSocket support * Update demo project to demonstrate MQTT and WebSockets * Update documentation to describe newly added and modified functionallity * Introduce separate MQTT pub/sub, HTTP get/post and WebSocket rx/tx classes * Significant reanaming - more accurate class names * Use PROGMEM_WWW as default * Update README documenting PROGMEM_WWW as default * Update README with API changes
156 lines
5.2 KiB
C++
156 lines
5.2 KiB
C++
#include <MqttSettingsService.h>
|
|
|
|
/**
|
|
* Retains a copy of the cstr provided in the pointer provided using dynamic allocation.
|
|
*
|
|
* Frees the pointer before allocation and leaves it as nullptr if cstr == nullptr.
|
|
*/
|
|
static char* retainCstr(const char* cstr, char** ptr) {
|
|
// free up previously retained value if exists
|
|
free(*ptr);
|
|
*ptr = nullptr;
|
|
|
|
// dynamically allocate and copy cstr (if non null)
|
|
if (cstr != nullptr) {
|
|
*ptr = (char*)malloc(strlen(cstr) + 1);
|
|
strcpy(*ptr, cstr);
|
|
}
|
|
|
|
// return reference to pointer for convenience
|
|
return *ptr;
|
|
}
|
|
|
|
MqttSettingsService::MqttSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) :
|
|
_httpEndpoint(MqttSettings::serialize,
|
|
MqttSettings::deserialize,
|
|
this,
|
|
server,
|
|
MQTT_SETTINGS_SERVICE_PATH,
|
|
securityManager),
|
|
_fsPersistence(MqttSettings::serialize, MqttSettings::deserialize, this, fs, MQTT_SETTINGS_FILE) {
|
|
#ifdef ESP32
|
|
WiFi.onEvent(
|
|
std::bind(&MqttSettingsService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2),
|
|
WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED);
|
|
WiFi.onEvent(std::bind(&MqttSettingsService::onStationModeGotIP, this, std::placeholders::_1, std::placeholders::_2),
|
|
WiFiEvent_t::SYSTEM_EVENT_STA_GOT_IP);
|
|
#elif defined(ESP8266)
|
|
_onStationModeDisconnectedHandler = WiFi.onStationModeDisconnected(
|
|
std::bind(&MqttSettingsService::onStationModeDisconnected, this, std::placeholders::_1));
|
|
_onStationModeGotIPHandler =
|
|
WiFi.onStationModeGotIP(std::bind(&MqttSettingsService::onStationModeGotIP, this, std::placeholders::_1));
|
|
#endif
|
|
_mqttClient.onConnect(std::bind(&MqttSettingsService::onMqttConnect, this, std::placeholders::_1));
|
|
_mqttClient.onDisconnect(std::bind(&MqttSettingsService::onMqttDisconnect, this, std::placeholders::_1));
|
|
addUpdateHandler([&](String originId) { onConfigUpdated(); }, false);
|
|
}
|
|
|
|
MqttSettingsService::~MqttSettingsService() {
|
|
}
|
|
|
|
void MqttSettingsService::begin() {
|
|
_fsPersistence.readFromFS();
|
|
}
|
|
|
|
void MqttSettingsService::loop() {
|
|
if (_reconfigureMqtt || (_disconnectedAt && (unsigned long)(millis() - _disconnectedAt) >= MQTT_RECONNECTION_DELAY)) {
|
|
// reconfigure MQTT client
|
|
configureMqtt();
|
|
|
|
// clear the reconnection flags
|
|
_reconfigureMqtt = false;
|
|
_disconnectedAt = 0;
|
|
}
|
|
}
|
|
|
|
bool MqttSettingsService::isEnabled() {
|
|
return _state.enabled;
|
|
}
|
|
|
|
bool MqttSettingsService::isConnected() {
|
|
return _mqttClient.connected();
|
|
}
|
|
|
|
const char* MqttSettingsService::getClientId() {
|
|
return _mqttClient.getClientId();
|
|
}
|
|
|
|
AsyncMqttClientDisconnectReason MqttSettingsService::getDisconnectReason() {
|
|
return _disconnectReason;
|
|
}
|
|
|
|
AsyncMqttClient* MqttSettingsService::getMqttClient() {
|
|
return &_mqttClient;
|
|
}
|
|
|
|
void MqttSettingsService::onMqttConnect(bool sessionPresent) {
|
|
Serial.print("Connected to MQTT, ");
|
|
Serial.print(sessionPresent ? "with" : "without");
|
|
Serial.println(" persistent session");
|
|
}
|
|
|
|
void MqttSettingsService::onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
|
|
Serial.print("Disconnected from MQTT reason: ");
|
|
Serial.println((uint8_t)reason);
|
|
_disconnectReason = reason;
|
|
_disconnectedAt = millis();
|
|
}
|
|
|
|
void MqttSettingsService::onConfigUpdated() {
|
|
_reconfigureMqtt = true;
|
|
_disconnectedAt = 0;
|
|
}
|
|
|
|
#ifdef ESP32
|
|
void MqttSettingsService::onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info) {
|
|
if (_state.enabled) {
|
|
Serial.println("WiFi connection dropped, starting MQTT client.");
|
|
onConfigUpdated();
|
|
}
|
|
}
|
|
|
|
void MqttSettingsService::onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) {
|
|
if (_state.enabled) {
|
|
Serial.println("WiFi connection dropped, stopping MQTT client.");
|
|
onConfigUpdated();
|
|
}
|
|
}
|
|
#elif defined(ESP8266)
|
|
void MqttSettingsService::onStationModeGotIP(const WiFiEventStationModeGotIP& event) {
|
|
if (_state.enabled) {
|
|
Serial.println("WiFi connection dropped, starting MQTT client.");
|
|
onConfigUpdated();
|
|
}
|
|
}
|
|
|
|
void MqttSettingsService::onStationModeDisconnected(const WiFiEventStationModeDisconnected& event) {
|
|
if (_state.enabled) {
|
|
Serial.println("WiFi connection dropped, stopping MQTT client.");
|
|
onConfigUpdated();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void MqttSettingsService::configureMqtt() {
|
|
// disconnect if currently connected
|
|
_mqttClient.disconnect();
|
|
|
|
// only connect if WiFi is connected and MQTT is enabled
|
|
if (_state.enabled && WiFi.isConnected()) {
|
|
Serial.println("Connecting to MQTT...");
|
|
_mqttClient.setServer(retainCstr(_state.host.c_str(), &_retainedHost), _state.port);
|
|
if (_state.username.length() > 0) {
|
|
_mqttClient.setCredentials(
|
|
retainCstr(_state.username.c_str(), &_retainedUsername),
|
|
retainCstr(_state.password.length() > 0 ? _state.password.c_str() : nullptr, &_retainedPassword));
|
|
} else {
|
|
_mqttClient.setCredentials(retainCstr(nullptr, &_retainedUsername), retainCstr(nullptr, &_retainedPassword));
|
|
}
|
|
_mqttClient.setClientId(retainCstr(_state.clientId.c_str(), &_retainedClientId));
|
|
_mqttClient.setKeepAlive(_state.keepAlive);
|
|
_mqttClient.setCleanSession(_state.cleanSession);
|
|
_mqttClient.setMaxTopicLength(_state.maxTopicLength);
|
|
_mqttClient.connect();
|
|
}
|
|
}
|