- /*
-
- ALEXA MODULE
-
- Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
-
- */
-
- #include "alexa.h"
-
- #if ALEXA_SUPPORT
-
- #include <queue>
-
- #include "broker.h"
- #include "light.h"
- #include "relay.h"
- #include "rpc.h"
- #include "web.h"
- #include "ws.h"
-
- #include <fauxmoESP.h>
- #include <ArduinoJson.h>
-
- struct alexa_queue_element_t {
- unsigned char device_id;
- bool state;
- unsigned char value;
- };
-
- static std::queue<alexa_queue_element_t> _alexa_queue;
-
- fauxmoESP _alexa;
-
- // -----------------------------------------------------------------------------
- // ALEXA
- // -----------------------------------------------------------------------------
-
- bool _alexaWebSocketOnKeyCheck(const char * key, JsonVariant& value) {
- return (strncmp(key, "alexa", 5) == 0);
- }
-
- void _alexaWebSocketOnConnected(JsonObject& root) {
- root["alexaEnabled"] = alexaEnabled();
- root["alexaName"] = getSetting("alexaName");
- }
-
- void _alexaConfigure() {
- _alexa.enable(wifiConnected() && alexaEnabled());
- }
-
- #if WEB_SUPPORT
- bool _alexaBodyCallback(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) {
- return _alexa.process(request->client(), request->method() == HTTP_GET, request->url(), String((char *)data));
- }
-
- bool _alexaRequestCallback(AsyncWebServerRequest *request) {
- String body = (request->hasParam("body", true)) ? request->getParam("body", true)->value() : String();
- return _alexa.process(request->client(), request->method() == HTTP_GET, request->url(), body);
- }
- #endif
-
- void _alexaBrokerCallback(const String& topic, unsigned char id, unsigned int value) {
-
- // Only process status messages for switches and channels
- if (!topic.equals(MQTT_TOPIC_CHANNEL)
- && !topic.equals(MQTT_TOPIC_RELAY)) {
- return;
- }
-
- if (topic.equals(MQTT_TOPIC_CHANNEL)) {
- _alexa.setState(id + 1, value > 0, value);
- }
-
- if (topic.equals(MQTT_TOPIC_RELAY)) {
- #if RELAY_PROVIDER == RELAY_PROVIDER_LIGHT
- if (id > 0) return;
- #endif
- _alexa.setState(id, value, value > 0 ? 255 : 0);
- }
-
- }
-
- // -----------------------------------------------------------------------------
-
- bool alexaEnabled() {
- return getSetting("alexaEnabled", 1 == ALEXA_ENABLED);
- }
-
- void alexaLoop() {
-
- _alexa.handle();
-
- while (!_alexa_queue.empty()) {
-
- alexa_queue_element_t element = _alexa_queue.front();
- DEBUG_MSG_P(PSTR("[ALEXA] Device #%u state: %s value: %d\n"), element.device_id, element.state ? "ON" : "OFF", element.value);
-
- #if RELAY_PROVIDER == RELAY_PROVIDER_LIGHT
- if (0 == element.device_id) {
- relayStatus(0, element.state);
- } else {
- lightState(element.device_id - 1, element.state);
- lightChannel(element.device_id - 1, element.value);
- lightUpdate(true, true);
- }
- #else
- relayStatus(element.device_id, element.state);
- #endif
-
- _alexa_queue.pop();
- }
-
- }
-
- void alexaSetup() {
-
- // Backwards compatibility
- moveSetting("fauxmoEnabled", "alexaEnabled");
-
- // Basic fauxmoESP configuration
- _alexa.createServer(!WEB_SUPPORT);
- _alexa.setPort(80);
-
- // Use custom alexa hostname if defined, device hostname otherwise
- String hostname = getSetting("alexaName", ALEXA_HOSTNAME);
- if (hostname.length() == 0) {
- hostname = getSetting("hostname");
- }
-
- // Lights
- #if RELAY_PROVIDER == RELAY_PROVIDER_LIGHT
-
- // Global switch
- _alexa.addDevice(hostname.c_str());
-
- // For each channel
- for (unsigned char i = 1; i <= lightChannels(); i++) {
- _alexa.addDevice((hostname + " " + i).c_str());
- }
-
- // Relays
- #else
-
- unsigned int relays = relayCount();
- if (relays == 1) {
- _alexa.addDevice(hostname.c_str());
- } else {
- for (unsigned int i=1; i<=relays; i++) {
- _alexa.addDevice((hostname + " " + i).c_str());
- }
- }
-
- #endif
-
- // Load & cache settings
- _alexaConfigure();
-
- // Websockets
- #if WEB_SUPPORT
- webBodyRegister(_alexaBodyCallback);
- webRequestRegister(_alexaRequestCallback);
- wsRegister()
- .onVisible([](JsonObject& root) { root["alexaVisible"] = 1; })
- .onConnected(_alexaWebSocketOnConnected)
- .onKeyCheck(_alexaWebSocketOnKeyCheck);
- #endif
-
- // Register wifi callback
- wifiRegister([](justwifi_messages_t code, char * parameter) {
- if ((MESSAGE_CONNECTED == code) || (MESSAGE_DISCONNECTED == code)) {
- _alexaConfigure();
- }
- });
-
- // Callback
- _alexa.onSetState([&](unsigned char device_id, const char * name, bool state, unsigned char value) {
- alexa_queue_element_t element;
- element.device_id = device_id;
- element.state = state;
- element.value = value;
- _alexa_queue.push(element);
- });
-
- // Register main callbacks
- StatusBroker::Register(_alexaBrokerCallback);
- espurnaRegisterReload(_alexaConfigure);
- espurnaRegisterLoop(alexaLoop);
-
- }
-
- #endif
|