Fork of the espurna firmware for `mhsw` switches
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.

300 lines
7.9 KiB

6 years ago
6 years ago
  1. /*
  2. HOME ASSISTANT MODULE
  3. Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #if HOMEASSISTANT_SUPPORT
  6. #include <ArduinoJson.h>
  7. bool _haEnabled = false;
  8. bool _haSendFlag = false;
  9. // -----------------------------------------------------------------------------
  10. // SENSORS
  11. // -----------------------------------------------------------------------------
  12. #if SENSOR_SUPPORT
  13. void _haSendMagnitude(unsigned char i, JsonObject& config) {
  14. unsigned char type = magnitudeType(i);
  15. config["name"] = getSetting("hostname") + String(" ") + magnitudeTopic(type);
  16. config.set("platform", "mqtt");
  17. config["state_topic"] = mqttTopic(magnitudeTopicIndex(i).c_str(), false);
  18. config["unit_of_measurement"] = magnitudeUnits(type);
  19. }
  20. void _haSendMagnitudes() {
  21. for (unsigned char i=0; i<magnitudeCount(); i++) {
  22. String topic = getSetting("haPrefix", HOMEASSISTANT_PREFIX) +
  23. "/sensor/" +
  24. getSetting("hostname") + "_" + String(i) +
  25. "/config";
  26. String output;
  27. if (_haEnabled) {
  28. DynamicJsonBuffer jsonBuffer;
  29. JsonObject& config = jsonBuffer.createObject();
  30. _haSendMagnitude(i, config);
  31. config.printTo(output);
  32. }
  33. mqttSendRaw(topic.c_str(), output.c_str());
  34. mqttSend(MQTT_TOPIC_STATUS, MQTT_STATUS_ONLINE, true);
  35. }
  36. }
  37. #endif // SENSOR_SUPPORT
  38. // -----------------------------------------------------------------------------
  39. // SWITCHES & LIGHTS
  40. // -----------------------------------------------------------------------------
  41. void _haSendSwitch(unsigned char i, JsonObject& config) {
  42. String name = getSetting("hostname");
  43. if (relayCount() > 1) {
  44. name += String(" #") + String(i);
  45. }
  46. config.set("name", name);
  47. config.set("platform", "mqtt");
  48. if (relayCount()) {
  49. config["state_topic"] = mqttTopic(MQTT_TOPIC_RELAY, i, false);
  50. config["command_topic"] = mqttTopic(MQTT_TOPIC_RELAY, i, true);
  51. config["payload_on"] = String("1");
  52. config["payload_off"] = String("0");
  53. config["availability_topic"] = mqttTopic(MQTT_TOPIC_STATUS, false);
  54. config["payload_available"] = String("1");
  55. config["payload_not_available"] = String("0");
  56. }
  57. #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
  58. if (i == 0) {
  59. if (lightHasColor()) {
  60. config["brightness_state_topic"] = mqttTopic(MQTT_TOPIC_BRIGHTNESS, false);
  61. config["brightness_command_topic"] = mqttTopic(MQTT_TOPIC_BRIGHTNESS, true);
  62. config["rgb_state_topic"] = mqttTopic(MQTT_TOPIC_COLOR_RGB, false);
  63. config["rgb_command_topic"] = mqttTopic(MQTT_TOPIC_COLOR_RGB, true);
  64. config["color_temp_command_topic"] = mqttTopic(MQTT_TOPIC_MIRED, true);
  65. }
  66. if (lightChannels() > 3) {
  67. config["white_value_state_topic"] = mqttTopic(MQTT_TOPIC_CHANNEL, 3, false);
  68. config["white_value_command_topic"] = mqttTopic(MQTT_TOPIC_CHANNEL, 3, true);
  69. }
  70. }
  71. #endif // LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
  72. }
  73. void _haSendSwitches() {
  74. #if (LIGHT_PROVIDER != LIGHT_PROVIDER_NONE) || (defined(ITEAD_SLAMPHER))
  75. String type = String("light");
  76. #else
  77. String type = String("switch");
  78. #endif
  79. for (unsigned char i=0; i<relayCount(); i++) {
  80. String topic = getSetting("haPrefix", HOMEASSISTANT_PREFIX) +
  81. "/" + type +
  82. "/" + getSetting("hostname") + "_" + String(i) +
  83. "/config";
  84. String output;
  85. if (_haEnabled) {
  86. DynamicJsonBuffer jsonBuffer;
  87. JsonObject& config = jsonBuffer.createObject();
  88. _haSendSwitch(i, config);
  89. config.printTo(output);
  90. }
  91. mqttSendRaw(topic.c_str(), output.c_str());
  92. mqttSend(MQTT_TOPIC_STATUS, MQTT_STATUS_ONLINE, true);
  93. }
  94. }
  95. // -----------------------------------------------------------------------------
  96. String _haGetConfig() {
  97. String output;
  98. #if (LIGHT_PROVIDER != LIGHT_PROVIDER_NONE) || (defined(ITEAD_SLAMPHER))
  99. String type = String("light");
  100. #else
  101. String type = String("switch");
  102. #endif
  103. for (unsigned char i=0; i<relayCount(); i++) {
  104. DynamicJsonBuffer jsonBuffer;
  105. JsonObject& config = jsonBuffer.createObject();
  106. _haSendSwitch(i, config);
  107. output += type + ":\n";
  108. bool first = true;
  109. for (auto kv : config) {
  110. if (first) {
  111. output += " - ";
  112. first = false;
  113. } else {
  114. output += " ";
  115. }
  116. output += kv.key + String(": ") + kv.value.as<String>() + String("\n");
  117. }
  118. output += "\n";
  119. }
  120. #if SENSOR_SUPPORT
  121. for (unsigned char i=0; i<magnitudeCount(); i++) {
  122. DynamicJsonBuffer jsonBuffer;
  123. JsonObject& config = jsonBuffer.createObject();
  124. _haSendMagnitude(i, config);
  125. output += "sensor:\n";
  126. bool first = true;
  127. for (auto kv : config) {
  128. if (first) {
  129. output += " - ";
  130. first = false;
  131. } else {
  132. output += " ";
  133. }
  134. output += kv.key + String(": ") + kv.value.as<String>() + String("\n");
  135. }
  136. output += "\n";
  137. }
  138. #endif
  139. return output;
  140. }
  141. void _haSend() {
  142. // Pending message to send?
  143. if (!_haSendFlag) return;
  144. // Are we connected?
  145. if (!mqttConnected()) return;
  146. DEBUG_MSG_P(PSTR("[HA] Sending autodiscovery MQTT message\n"));
  147. // Send messages
  148. _haSendSwitches();
  149. #if SENSOR_SUPPORT
  150. _haSendMagnitudes();
  151. #endif
  152. _haSendFlag = false;
  153. }
  154. void _haConfigure() {
  155. bool enabled = getSetting("haEnabled", HOMEASSISTANT_ENABLED).toInt() == 1;
  156. _haSendFlag = (enabled != _haEnabled);
  157. _haEnabled = enabled;
  158. _haSend();
  159. }
  160. #if WEB_SUPPORT
  161. bool _haWebSocketOnReceive(const char * key, JsonVariant& value) {
  162. return (strncmp(key, "ha", 2) == 0);
  163. }
  164. void _haWebSocketOnSend(JsonObject& root) {
  165. root["haVisible"] = 1;
  166. root["haPrefix"] = getSetting("haPrefix", HOMEASSISTANT_PREFIX);
  167. root["haEnabled"] = getSetting("haEnabled", HOMEASSISTANT_ENABLED).toInt() == 1;
  168. }
  169. void _haWebSocketOnAction(uint32_t client_id, const char * action, JsonObject& data) {
  170. if (strcmp(action, "haconfig") == 0) {
  171. String output = _haGetConfig();
  172. output.replace(" ", "&nbsp;");
  173. output.replace("\n", "<br />");
  174. output = String("{\"haConfig\": \"") + output + String("\"}");
  175. wsSend(client_id, output.c_str());
  176. }
  177. }
  178. #endif
  179. #if TERMINAL_SUPPORT
  180. void _haInitCommands() {
  181. settingsRegisterCommand(F("HA.CONFIG"), [](Embedis* e) {
  182. DEBUG_MSG(_haGetConfig().c_str());
  183. DEBUG_MSG_P(PSTR("+OK\n"));
  184. });
  185. settingsRegisterCommand(F("HA.SEND"), [](Embedis* e) {
  186. setSetting("haEnabled", "1");
  187. _haConfigure();
  188. #if WEB_SUPPORT
  189. wsSend(_haWebSocketOnSend);
  190. #endif
  191. DEBUG_MSG_P(PSTR("+OK\n"));
  192. });
  193. settingsRegisterCommand(F("HA.CLEAR"), [](Embedis* e) {
  194. setSetting("haEnabled", "0");
  195. _haConfigure();
  196. #if WEB_SUPPORT
  197. wsSend(_haWebSocketOnSend);
  198. #endif
  199. DEBUG_MSG_P(PSTR("+OK\n"));
  200. });
  201. }
  202. #endif
  203. // -----------------------------------------------------------------------------
  204. void haSetup() {
  205. _haConfigure();
  206. #if WEB_SUPPORT
  207. wsOnSendRegister(_haWebSocketOnSend);
  208. wsOnAfterParseRegister(_haConfigure);
  209. wsOnActionRegister(_haWebSocketOnAction);
  210. wsOnReceiveRegister(_haWebSocketOnReceive);
  211. #endif
  212. // On MQTT connect check if we have something to send
  213. mqttRegister([](unsigned int type, const char * topic, const char * payload) {
  214. if (type == MQTT_CONNECT_EVENT) _haSend();
  215. });
  216. #if TERMINAL_SUPPORT
  217. _haInitCommands();
  218. #endif
  219. }
  220. #endif // HOMEASSISTANT_SUPPORT