MqttClient.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. #include <MqttClient.h>
  2. #include <TokenIterator.h>
  3. #include <UrlTokenBindings.h>
  4. #include <IntParsing.h>
  5. #include <ArduinoJson.h>
  6. #include <WiFiClient.h>
  7. MqttClient::MqttClient(Settings& settings, MiLightClient*& milightClient)
  8. : milightClient(milightClient),
  9. settings(settings),
  10. lastConnectAttempt(0)
  11. {
  12. String strDomain = settings.mqttServer();
  13. this->domain = new char[strDomain.length() + 1];
  14. strcpy(this->domain, strDomain.c_str());
  15. this->mqttClient = new PubSubClient(tcpClient);
  16. }
  17. MqttClient::~MqttClient() {
  18. mqttClient->disconnect();
  19. delete this->domain;
  20. }
  21. void MqttClient::begin() {
  22. #ifdef MQTT_DEBUG
  23. printf_P(
  24. PSTR("MqttClient - Connecting to: %s\nparsed:%s:%u\n"),
  25. settings._mqttServer.c_str(),
  26. settings.mqttServer().c_str(),
  27. settings.mqttPort()
  28. );
  29. #endif
  30. mqttClient->setServer(this->domain, settings.mqttPort());
  31. mqttClient->setCallback(
  32. [this](char* topic, byte* payload, int length) {
  33. this->publishCallback(topic, payload, length);
  34. }
  35. );
  36. reconnect();
  37. }
  38. bool MqttClient::connect() {
  39. char nameBuffer[30];
  40. sprintf_P(nameBuffer, PSTR("milight-hub-%u"), ESP.getChipId());
  41. #ifdef MQTT_DEBUG
  42. Serial.println(F("MqttClient - connecting"));
  43. #endif
  44. if (settings.mqttUsername.length() > 0) {
  45. return mqttClient->connect(
  46. nameBuffer,
  47. settings.mqttUsername.c_str(),
  48. settings.mqttPassword.c_str()
  49. );
  50. } else {
  51. return mqttClient->connect(nameBuffer);
  52. }
  53. }
  54. void MqttClient::reconnect() {
  55. if (lastConnectAttempt > 0 && (millis() - lastConnectAttempt) < MQTT_CONNECTION_ATTEMPT_FREQUENCY) {
  56. return;
  57. }
  58. if (! mqttClient->connected()) {
  59. if (connect()) {
  60. subscribe();
  61. #ifdef MQTT_DEBUG
  62. Serial.println(F("MqttClient - Successfully connected to MQTT server"));
  63. #endif
  64. } else {
  65. Serial.println(F("ERROR: Failed to connect to MQTT server"));
  66. }
  67. }
  68. lastConnectAttempt = millis();
  69. }
  70. void MqttClient::handleClient() {
  71. reconnect();
  72. mqttClient->loop();
  73. }
  74. void MqttClient::subscribe() {
  75. String topic = settings.mqttTopicPattern;
  76. topic.replace(":device_id", "+");
  77. topic.replace(":group_id", "+");
  78. topic.replace(":device_type", "+");
  79. #ifdef MQTT_DEBUG
  80. printf_P(PSTR("MqttClient - subscribing to topic: %s\n"), topic.c_str());
  81. #endif
  82. mqttClient->subscribe(topic.c_str());
  83. }
  84. void MqttClient::publishCallback(char* topic, byte* payload, int length) {
  85. uint16_t deviceId = 0;
  86. uint8_t groupId = 0;
  87. MiLightRadioConfig* config = &MilightRgbCctConfig;
  88. char cstrPayload[length + 1];
  89. cstrPayload[length] = 0;
  90. memcpy(cstrPayload, payload, sizeof(byte)*length);
  91. #ifdef MQTT_DEBUG
  92. printf_P(PSTR("MqttClient - Got message on topic: %s\n%s\n"), topic, cstrPayload);
  93. #endif
  94. char topicPattern[settings.mqttTopicPattern.length()];
  95. strcpy(topicPattern, settings.mqttTopicPattern.c_str());
  96. TokenIterator patternIterator(topicPattern, settings.mqttTopicPattern.length(), '/');
  97. TokenIterator topicIterator(topic, strlen(topic), '/');
  98. UrlTokenBindings tokenBindings(patternIterator, topicIterator);
  99. if (tokenBindings.hasBinding("device_id")) {
  100. deviceId = parseInt<uint16_t>(tokenBindings.get("device_id"));
  101. }
  102. if (tokenBindings.hasBinding("group_id")) {
  103. groupId = parseInt<uint16_t>(tokenBindings.get("group_id"));
  104. }
  105. if (tokenBindings.hasBinding("device_type")) {
  106. config = MiLightRadioConfig::fromString(tokenBindings.get("device_type"));
  107. }
  108. StaticJsonBuffer<400> buffer;
  109. JsonObject& obj = buffer.parseObject(cstrPayload);
  110. #ifdef MQTT_DEBUG
  111. printf_P(PSTR("MqttClient - device %04X, group %u\n"), deviceId, groupId);
  112. #endif
  113. milightClient->prepare(*config, deviceId, groupId);
  114. milightClient->update(obj);
  115. }