HomeAssistantDiscoveryClient.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. #include <HomeAssistantDiscoveryClient.h>
  2. HomeAssistantDiscoveryClient::HomeAssistantDiscoveryClient(Settings& settings, MqttClient* mqttClient)
  3. : settings(settings)
  4. , mqttClient(mqttClient)
  5. { }
  6. void HomeAssistantDiscoveryClient::sendDiscoverableDevices(const std::map<String, BulbId>& aliases) {
  7. #ifdef MQTT_DEBUG
  8. Serial.println(F("HomeAssistantDiscoveryClient: Sending discoverable devices..."));
  9. #endif
  10. for (auto itr = aliases.begin(); itr != aliases.end(); ++itr) {
  11. addConfig(itr->first.c_str(), itr->second);
  12. }
  13. }
  14. void HomeAssistantDiscoveryClient::removeConfig(const char* alias, const BulbId& bulbId) {
  15. // Remove by publishing an empty message
  16. String topic = buildTopic(bulbId);
  17. mqttClient->send(topic.c_str(), "", true);
  18. }
  19. void HomeAssistantDiscoveryClient::addConfig(const char* alias, const BulbId& bulbId) {
  20. String topic = buildTopic(bulbId);
  21. DynamicJsonDocument config(1024);
  22. config[F("schema")] = F("json");
  23. config[F("name")] = alias;
  24. config[F("command_topic")] = bindTopicVariables(settings.mqttTopicPattern, alias, bulbId);
  25. config[F("state_topic")] = bindTopicVariables(settings.mqttStateTopicPattern, alias, bulbId);
  26. // HomeAssistant only supports simple client availability
  27. if (settings.mqttClientStatusTopic.length() > 0 && settings.simpleMqttClientStatus) {
  28. config[F("availability_topic")] = settings.mqttClientStatusTopic;
  29. config[F("payload_available")] = F("connected");
  30. config[F("payload_not_available")] = F("disconnected");
  31. }
  32. // Configure supported commands based on the bulb type
  33. // All supported bulbs support brightness and night mode
  34. config[F("brightness")] = true;
  35. config[F("effect")] = true;
  36. JsonArray effects = config.createNestedArray(F("effect_list"));
  37. effects.add(F("night_mode"));
  38. // These bulbs support RGB color
  39. switch (bulbId.deviceType) {
  40. case REMOTE_TYPE_FUT089:
  41. case REMOTE_TYPE_RGB:
  42. case REMOTE_TYPE_RGB_CCT:
  43. case REMOTE_TYPE_RGBW:
  44. config[F("rgb")] = true;
  45. break;
  46. default:
  47. break; //nothing
  48. }
  49. // These bulbs support adjustable white values
  50. switch (bulbId.deviceType) {
  51. case REMOTE_TYPE_CCT:
  52. case REMOTE_TYPE_FUT089:
  53. case REMOTE_TYPE_FUT091:
  54. case REMOTE_TYPE_RGB_CCT:
  55. config[F("color_temp")] = true;
  56. break;
  57. default:
  58. break; //nothing
  59. }
  60. // These bulbs support switching between rgb/white, and have a "white_mode" command
  61. switch (bulbId.deviceType) {
  62. case REMOTE_TYPE_FUT089:
  63. case REMOTE_TYPE_RGB_CCT:
  64. case REMOTE_TYPE_RGBW:
  65. effects.add(F("white_mode"));
  66. break;
  67. default:
  68. break; //nothing
  69. }
  70. String message;
  71. serializeJson(config, message);
  72. #ifdef MQTT_DEBUG
  73. Serial.printf_P(PSTR("HomeAssistantDiscoveryClient: adding discoverable device: %s...\n"), alias);
  74. Serial.printf_P(PSTR(" topic: %s\nconfig: %s\n"), topic.c_str(), message.c_str());
  75. #endif
  76. mqttClient->send(topic.c_str(), message.c_str(), true);
  77. }
  78. // Topic syntax:
  79. // <discovery_prefix>/<component>/[<node_id>/]<object_id>/config
  80. //
  81. // source: https://www.home-assistant.io/docs/mqtt/discovery/
  82. String HomeAssistantDiscoveryClient::buildTopic(const BulbId& bulbId) {
  83. String topic = settings.homeAssistantDiscoveryPrefix;
  84. // Don't require the user to entier a "/" (or break things if they do)
  85. if (! topic.endsWith("/")) {
  86. topic += "/";
  87. }
  88. topic += "light/";
  89. // Use a static ID that doesn't depend on configuration.
  90. topic += "milight_hub_" + (ESP.getChipId());
  91. // make the object ID based on the actual parameters rather than the alias.
  92. topic += "/";
  93. topic += MiLightRemoteTypeHelpers::remoteTypeToString(bulbId.deviceType);
  94. topic += "_0x";
  95. topic += String(bulbId.deviceId, HEX);
  96. topic += "_";
  97. topic += bulbId.groupId;
  98. topic += "/config";
  99. return topic;
  100. }
  101. String HomeAssistantDiscoveryClient::bindTopicVariables(const String& topic, const char* alias, const BulbId& bulbId) {
  102. String boundTopic = topic;
  103. boundTopic.replace(":device_alias", alias);
  104. boundTopic.replace(":device_id", String("0x") + String(bulbId.deviceId, HEX));
  105. boundTopic.replace(":hex_device_id", String("0x") + String(bulbId.deviceId, HEX));
  106. boundTopic.replace(":dec_device_id", String(bulbId.deviceId));
  107. boundTopic.replace(":device_type", MiLightRemoteTypeHelpers::remoteTypeToString(bulbId.deviceType));
  108. boundTopic.replace(":group_id", String(bulbId.groupId));
  109. return boundTopic;
  110. }