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.

182 lines
5.0 KiB

6 years ago
6 years ago
6 years ago
6 years ago
  1. /*
  2. ALEXA MODULE
  3. Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #if ALEXA_SUPPORT
  6. #include <fauxmoESP.h>
  7. fauxmoESP alexa;
  8. #include <queue>
  9. typedef struct {
  10. unsigned char device_id;
  11. bool state;
  12. unsigned char value;
  13. } alexa_queue_element_t;
  14. static std::queue<alexa_queue_element_t> _alexa_queue;
  15. // -----------------------------------------------------------------------------
  16. // ALEXA
  17. // -----------------------------------------------------------------------------
  18. bool _alexaWebSocketOnKeyCheck(const char * key, JsonVariant& value) {
  19. return (strncmp(key, "alexa", 5) == 0);
  20. }
  21. void _alexaWebSocketOnConnected(JsonObject& root) {
  22. root["alexaEnabled"] = alexaEnabled();
  23. root["alexaName"] = getSetting("alexaName");
  24. }
  25. void _alexaConfigure() {
  26. alexa.enable(wifiConnected() && alexaEnabled());
  27. }
  28. #if WEB_SUPPORT
  29. bool _alexaBodyCallback(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) {
  30. return alexa.process(request->client(), request->method() == HTTP_GET, request->url(), String((char *)data));
  31. }
  32. bool _alexaRequestCallback(AsyncWebServerRequest *request) {
  33. String body = (request->hasParam("body", true)) ? request->getParam("body", true)->value() : String();
  34. return alexa.process(request->client(), request->method() == HTTP_GET, request->url(), body);
  35. }
  36. #endif
  37. #if BROKER_SUPPORT
  38. void _alexaBrokerCallback(const unsigned char type, const char * topic, unsigned char id, const char * payload) {
  39. // Only process status messages
  40. if (BROKER_MSG_TYPE_STATUS != type) return;
  41. unsigned char value = atoi(payload);
  42. if (strcmp(MQTT_TOPIC_CHANNEL, topic) == 0) {
  43. alexa.setState(id+1, value > 0, value);
  44. }
  45. if (strcmp(MQTT_TOPIC_RELAY, topic) == 0) {
  46. #if RELAY_PROVIDER == RELAY_PROVIDER_LIGHT
  47. if (id > 0) return;
  48. #endif
  49. alexa.setState(id, value, value > 0 ? 255 : 0);
  50. }
  51. }
  52. #endif // BROKER_SUPPORT
  53. // -----------------------------------------------------------------------------
  54. bool alexaEnabled() {
  55. return (getSetting("alexaEnabled", ALEXA_ENABLED).toInt() == 1);
  56. }
  57. void alexaSetup() {
  58. // Backwards compatibility
  59. moveSetting("fauxmoEnabled", "alexaEnabled");
  60. // Basic fauxmoESP configuration
  61. alexa.createServer(!WEB_SUPPORT);
  62. alexa.setPort(80);
  63. // Use custom alexa hostname if defined, device hostname otherwise
  64. String hostname = getSetting("alexaName", ALEXA_HOSTNAME);
  65. if (hostname.length() == 0) {
  66. hostname = getSetting("hostname");
  67. }
  68. // Lights
  69. #if RELAY_PROVIDER == RELAY_PROVIDER_LIGHT
  70. // Global switch
  71. alexa.addDevice(hostname.c_str());
  72. // For each channel
  73. for (unsigned char i = 1; i <= lightChannels(); i++) {
  74. alexa.addDevice((hostname + " " + i).c_str());
  75. }
  76. // Relays
  77. #else
  78. unsigned int relays = relayCount();
  79. if (relays == 1) {
  80. alexa.addDevice(hostname.c_str());
  81. } else {
  82. for (unsigned int i=1; i<=relays; i++) {
  83. alexa.addDevice((hostname + " " + i).c_str());
  84. }
  85. }
  86. #endif
  87. // Load & cache settings
  88. _alexaConfigure();
  89. // Websockets
  90. #if WEB_SUPPORT
  91. webBodyRegister(_alexaBodyCallback);
  92. webRequestRegister(_alexaRequestCallback);
  93. wsRegister()
  94. .onVisible([](JsonObject& root) { root["alexaVisible"] = 1; })
  95. .onConnected(_alexaWebSocketOnConnected)
  96. .onKeyCheck(_alexaWebSocketOnKeyCheck);
  97. #endif
  98. // Register wifi callback
  99. wifiRegister([](justwifi_messages_t code, char * parameter) {
  100. if ((MESSAGE_CONNECTED == code) || (MESSAGE_DISCONNECTED == code)) {
  101. _alexaConfigure();
  102. }
  103. });
  104. // Callback
  105. alexa.onSetState([&](unsigned char device_id, const char * name, bool state, unsigned char value) {
  106. alexa_queue_element_t element;
  107. element.device_id = device_id;
  108. element.state = state;
  109. element.value = value;
  110. _alexa_queue.push(element);
  111. });
  112. // Register main callbacks
  113. #if BROKER_SUPPORT
  114. brokerRegister(_alexaBrokerCallback);
  115. #endif
  116. espurnaRegisterReload(_alexaConfigure);
  117. espurnaRegisterLoop(alexaLoop);
  118. }
  119. void alexaLoop() {
  120. alexa.handle();
  121. while (!_alexa_queue.empty()) {
  122. alexa_queue_element_t element = _alexa_queue.front();
  123. DEBUG_MSG_P(PSTR("[ALEXA] Device #%u state: %s value: %d\n"), element.device_id, element.state ? "ON" : "OFF", element.value);
  124. #if RELAY_PROVIDER == RELAY_PROVIDER_LIGHT
  125. if (0 == element.device_id) {
  126. relayStatus(0, element.state);
  127. } else {
  128. lightState(element.device_id - 1, element.state);
  129. lightChannel(element.device_id - 1, element.value);
  130. lightUpdate(true, true);
  131. }
  132. #else
  133. relayStatus(element.device_id, element.state);
  134. #endif
  135. _alexa_queue.pop();
  136. }
  137. }
  138. #endif