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.

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