Fork of the excellent esp8266-react - https://github.com/rjwats/esp8266-react
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

161 lines
5.4 KiB

  1. #include <MqttSettingsService.h>
  2. /**
  3. * Retains a copy of the cstr provided in the pointer provided using dynamic allocation.
  4. *
  5. * Frees the pointer before allocation and leaves it as nullptr if cstr == nullptr.
  6. */
  7. static char* retainCstr(const char* cstr, char** ptr) {
  8. // free up previously retained value if exists
  9. free(*ptr);
  10. *ptr = nullptr;
  11. // dynamically allocate and copy cstr (if non null)
  12. if (cstr != nullptr) {
  13. *ptr = (char*)malloc(strlen(cstr) + 1);
  14. strcpy(*ptr, cstr);
  15. }
  16. // return reference to pointer for convenience
  17. return *ptr;
  18. }
  19. MqttSettingsService::MqttSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) :
  20. _httpEndpoint(MqttSettings::read, MqttSettings::update, this, server, MQTT_SETTINGS_SERVICE_PATH, securityManager),
  21. _fsPersistence(MqttSettings::read, MqttSettings::update, this, fs, MQTT_SETTINGS_FILE),
  22. _retainedHost(nullptr),
  23. _retainedClientId(nullptr),
  24. _retainedUsername(nullptr),
  25. _retainedPassword(nullptr),
  26. _reconfigureMqtt(false),
  27. _disconnectedAt(0),
  28. _disconnectReason(AsyncMqttClientDisconnectReason::TCP_DISCONNECTED),
  29. _mqttClient() {
  30. #ifdef ESP32
  31. WiFi.onEvent(
  32. std::bind(&MqttSettingsService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2),
  33. WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED);
  34. WiFi.onEvent(std::bind(&MqttSettingsService::onStationModeGotIP, this, std::placeholders::_1, std::placeholders::_2),
  35. WiFiEvent_t::SYSTEM_EVENT_STA_GOT_IP);
  36. #elif defined(ESP8266)
  37. _onStationModeDisconnectedHandler = WiFi.onStationModeDisconnected(
  38. std::bind(&MqttSettingsService::onStationModeDisconnected, this, std::placeholders::_1));
  39. _onStationModeGotIPHandler =
  40. WiFi.onStationModeGotIP(std::bind(&MqttSettingsService::onStationModeGotIP, this, std::placeholders::_1));
  41. #endif
  42. _mqttClient.onConnect(std::bind(&MqttSettingsService::onMqttConnect, this, std::placeholders::_1));
  43. _mqttClient.onDisconnect(std::bind(&MqttSettingsService::onMqttDisconnect, this, std::placeholders::_1));
  44. addUpdateHandler([&](const String& originId) { onConfigUpdated(); }, false);
  45. }
  46. MqttSettingsService::~MqttSettingsService() {
  47. }
  48. void MqttSettingsService::begin() {
  49. _fsPersistence.readFromFS();
  50. }
  51. void MqttSettingsService::loop() {
  52. if (_reconfigureMqtt || (_disconnectedAt && (unsigned long)(millis() - _disconnectedAt) >= MQTT_RECONNECTION_DELAY)) {
  53. // reconfigure MQTT client
  54. configureMqtt();
  55. // clear the reconnection flags
  56. _reconfigureMqtt = false;
  57. _disconnectedAt = 0;
  58. }
  59. }
  60. bool MqttSettingsService::isEnabled() {
  61. return _state.enabled;
  62. }
  63. bool MqttSettingsService::isConnected() {
  64. return _mqttClient.connected();
  65. }
  66. const char* MqttSettingsService::getClientId() {
  67. return _mqttClient.getClientId();
  68. }
  69. AsyncMqttClientDisconnectReason MqttSettingsService::getDisconnectReason() {
  70. return _disconnectReason;
  71. }
  72. AsyncMqttClient* MqttSettingsService::getMqttClient() {
  73. return &_mqttClient;
  74. }
  75. void MqttSettingsService::onMqttConnect(bool sessionPresent) {
  76. Serial.print(F("Connected to MQTT, "));
  77. if (sessionPresent) {
  78. Serial.println(F("with persistent session"));
  79. } else {
  80. Serial.println(F("without persistent session"));
  81. }
  82. }
  83. void MqttSettingsService::onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
  84. Serial.print(F("Disconnected from MQTT reason: "));
  85. Serial.println((uint8_t)reason);
  86. _disconnectReason = reason;
  87. _disconnectedAt = millis();
  88. }
  89. void MqttSettingsService::onConfigUpdated() {
  90. _reconfigureMqtt = true;
  91. _disconnectedAt = 0;
  92. }
  93. #ifdef ESP32
  94. void MqttSettingsService::onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info) {
  95. if (_state.enabled) {
  96. Serial.println(F("WiFi connection dropped, starting MQTT client."));
  97. onConfigUpdated();
  98. }
  99. }
  100. void MqttSettingsService::onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) {
  101. if (_state.enabled) {
  102. Serial.println(F("WiFi connection dropped, stopping MQTT client."));
  103. onConfigUpdated();
  104. }
  105. }
  106. #elif defined(ESP8266)
  107. void MqttSettingsService::onStationModeGotIP(const WiFiEventStationModeGotIP& event) {
  108. if (_state.enabled) {
  109. Serial.println(F("WiFi connection dropped, starting MQTT client."));
  110. onConfigUpdated();
  111. }
  112. }
  113. void MqttSettingsService::onStationModeDisconnected(const WiFiEventStationModeDisconnected& event) {
  114. if (_state.enabled) {
  115. Serial.println(F("WiFi connection dropped, stopping MQTT client."));
  116. onConfigUpdated();
  117. }
  118. }
  119. #endif
  120. void MqttSettingsService::configureMqtt() {
  121. // disconnect if currently connected
  122. _mqttClient.disconnect();
  123. // only connect if WiFi is connected and MQTT is enabled
  124. if (_state.enabled && WiFi.isConnected()) {
  125. Serial.println(F("Connecting to MQTT..."));
  126. _mqttClient.setServer(retainCstr(_state.host.c_str(), &_retainedHost), _state.port);
  127. if (_state.username.length() > 0) {
  128. _mqttClient.setCredentials(
  129. retainCstr(_state.username.c_str(), &_retainedUsername),
  130. retainCstr(_state.password.length() > 0 ? _state.password.c_str() : nullptr, &_retainedPassword));
  131. } else {
  132. _mqttClient.setCredentials(retainCstr(nullptr, &_retainedUsername), retainCstr(nullptr, &_retainedPassword));
  133. }
  134. _mqttClient.setClientId(retainCstr(_state.clientId.c_str(), &_retainedClientId));
  135. _mqttClient.setKeepAlive(_state.keepAlive);
  136. _mqttClient.setCleanSession(_state.cleanSession);
  137. _mqttClient.setMaxTopicLength(_state.maxTopicLength);
  138. _mqttClient.connect();
  139. }
  140. }