Thanks to the easy-to-use Feather system, we can quickly craft a working demo with lights and a relay. Grab a NeoPixel FeatherWing and a Relay FeatherWing (there's three types of Relay 'wings, use any which one you like).
We'll connect the NeoPixel data line to ESP pin #2 and the relay signal to #13 (you can change these pins around, except NeoPixel can't be on pin #16). You can either 'freewire' these boards together and just make sure you get the power and ground pins...
Or use a Featherwing Doubler + stacking headers on the ESP8266, and then stack the NeoPixel wing on top of it. Then put the relay board on the side
Then just make sure you cut/solder the trace on the bottom of each wing so that it is connected to the digital control pin specified above
Test Wings
You may want to go through the tutorials for both relay and NeoPixel wing to make sure they're working on the pins you want! That way you wont have to debug both the Alexa/WeMo code as well as your hardware
Full Demo Code
Now upload this sketch:
// SPDX-FileCopyrightText: 2019 Brent Rubell for Adafruit Industries // // SPDX-License-Identifier: MIT #include <Arduino.h> #include <Adafruit_NeoPixel.h> #include <ESP8266WiFi.h> #include "fauxmoESP.h" #define WIFI_SSID "wifi_ssid" #define WIFI_PASS "wifi_pass" #define SERIAL_BAUDRATE 115200 fauxmoESP fauxmo; #define RELAY_PIN 13 #define NEOPIX_PIN 2 Adafruit_NeoPixel strip = Adafruit_NeoPixel(40, NEOPIX_PIN, NEO_GRB + NEO_KHZ800); volatile boolean neopixel_state = false; // off by default! uint32_t Wheel(byte WheelPos); // function prototype // ----------------------------------------------------------------------------- // Wifi // ----------------------------------------------------------------------------- void wifiSetup() { // Set WIFI module to STA mode WiFi.mode(WIFI_STA); // Connect Serial.printf("[WIFI] Connecting to %s ", WIFI_SSID); WiFi.begin(WIFI_SSID, WIFI_PASS); // Wait while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(100); } Serial.println(); // Connected! Serial.printf("[WIFI] STATION Mode, SSID: %s, IP address: %s\n", WiFi.SSID().c_str(), WiFi.localIP().toString().c_str()); } void setup() { strip.begin(); strip.setBrightness(20); strip.show(); // Initialize all pixels to 'off' pinMode(RELAY_PIN, OUTPUT); digitalWrite(RELAY_PIN, LOW); // Init serial port and clean garbage Serial.begin(SERIAL_BAUDRATE); Serial.println(); Serial.println(); Serial.println("FauxMo demo sketch"); Serial.println("After connection, ask Alexa/Echo to 'turn pixels on' or 'off' or 'turn relay on' or 'off'"); // Wifi wifiSetup(); // for gen3 devices or above fauxmo.setPort(80); fauxmo.enable(true); // Fauxmo fauxmo.addDevice("relay"); fauxmo.addDevice("pixels"); fauxmo.onSetState([](unsigned char device_id, const char *device_name, bool state, unsigned char value) { Serial.printf("[MAIN] %s state: %s\n", device_name, state ? "ON" : "OFF"); if ((strcmp(device_name, "pixels") == 0)) { // this just sets a variable that the main loop() does something about if (state) { neopixel_state = true; } else { neopixel_state = false; } } if ((strcmp(device_name, "relay") == 0)) { // adjust the relay immediately! if (state) { digitalWrite(RELAY_PIN, HIGH); } else { digitalWrite(RELAY_PIN, LOW); } } }); } uint8_t j = 0; // color swirl incrementer void loop() { fauxmo.handle(); if (neopixel_state) { for (int16_t i = 0; i < strip.numPixels(); i++) { strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255)); } strip.show(); j++; delay(20); } else { for (int16_t i = 0; i < strip.numPixels(); i++) { strip.setPixelColor(i, 0); } strip.show(); } } // Input a value 0 to 255 to get a color value. // The colours are a transition r - g - b - back to r. uint32_t Wheel(byte WheelPos) { if (WheelPos < 85) { return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0); } else if (WheelPos < 170) { WheelPos -= 85; return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3); } else { WheelPos -= 170; return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3); } }
Since there's two devices we'll show two ways of using the call-back function to do what you want.
The callback
The way the code works is that when a new command is received, the fauxmo.onSetState([](unsigned char device_id, const char * device_name, bool state, unsigned char value)
function is called with the name as a character array and then a boolean with true/false depending on whether the device should be on or off.
The state boolean is easy to deal with. For the character array, you'll want to use strcmp which will do a string comparison for you. If the strings are identical, it will return 0.
Thus to test if you got a relay command, the line if ( (strcmp(device_name, "relay") == 0) )
will test to see if that's the device requested!
In-line control (Relay)
Once you know what string is sent, the code can do something simple based on the state variable. For example, just turn a pin on or off!
if ( (strcmp(device_name, "relay") == 0) ) { // adjust the relay immediately! if (state) { digitalWrite(RELAY_PIN, HIGH); } else { digitalWrite(RELAY_PIN, LOW); } }
External Flag control (NeoPixels)
For NeoPixels, we want to have the pixels do a rainbow swirl in loop so that we aren't in the callback for more than a millisecond. Rather than halt the callback to do pixel management, we set an external volatile variable. It's key that we indicate it is volatile because that tells the ESP8266 "hey, this variable will change in a callback or interrupt so don't assume it's the same value it was a second ago"
volatile boolean neopixel_state = false; // off by default! ... if ( (strcmp(device_name, "pixels") == 0) ) { // this just sets a variable that the main loop() does something about if (state) { neopixel_state = true; } else { neopixel_state = false; } }
Then in the main loop() code, we can test to see if neopixel_state is true or false. If it's true, it should continue with the color swirl output. The swirl code is from the rainbow() NeoPixel example, by the way, it just sets each pixel to an equidistant color on the color wheel.
if (neopixel_state) { for(int16_t i=0; i< strip.numPixels(); i++) { strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255)); } strip.show(); j++; delay(20); }
If it's false, turn off all the pixels
else { for(int16_t i=0; i< strip.numPixels(); i++) { strip.setPixelColor(i, 0); } strip.show(); }
Now that you've got it working - try other devices like servos, motors, IR or RF remote controls, etc! Maybe call the device "party" and then you can tell Alexa to "turn the party on"?
Text editor powered by tinymce.