- 28
Oct - 2017Home Automation, MicroPython
7 min | 16461#MicroPython: WeMos (ESP32) and Amazon Echo (Alexa) - Switching LED Colors!
Home Automation, MicroPython | 7 min | 16461
Table of contentShowI don’t have any Belkin WeMo system or Philips Hue light bulbs. However, I have two ESP32 running MicroPython (see my last article), and a W2812b LED strip, and I thought I should be able to say, "Echo/Alexa, turn on the kitchen light" or "Echo/Alexa, turn on the blue light" and It should work with this setup.
And... it works as you can see in this video!
If you are interesting in only using the code, then click here. Otherwise, you can read the complete story... ;)
Code: https://github.com/lemariva/uPyEcho If you’re not up to speed with MicroPython, Wipy see earlier articles in here.
State of the Art ;)
I started to search the web, and I found the "Alexa Skills" and the first repository was flask-ask. I tried to modified it, so that it runs using MicroPython, but there were too many dependencies that are still not implemented on MicroPython (and because of the size, there are not going to be implemented or should not be implemented), and that was not possible. Another problem was that the skill must run behind a public HTTPS server (HTTP should be enough, if it is only for you) or AWS Lambda. I thought some options would be to open a port on my router, or to use ngrok as proposed in the development amazon blog. I didn't like both ideas, the first one was too risky: an open port with a webserver on MicroPython listening to it, and the second one: there isn't any possibility to run ngrok on MicroPython, and it is again a bridge over the router, it was also too risky.
I looked forward the web again and I found the n8henrie/fauxmo repository. This is a great repository: it is a Python 3 (MicroPython is a lean and efficient implementation of the Python 3! -> Nice!) module that emulates Belkin WeMo devices for use with the Amazon Echo. That was, what I wanted. I looked to it closer, and I found that it uses libraries that need some dependencies that are not working on MicroPython (on ESP32) yet (update > may be using
import upip
andupip.install('<libraries>'
) works - I am going to publish an article soon).The n8henrie/fauxmo repository was forked from makermusings/fauxmo. I looked forward on the web and I found that there are a port of the makermusings/fauxmo to C++ for the ESP32 (fauxmoESP). But, I wanted to use MicroPython! Then, I cloned the makermusings/fauxmo library, and modified it. Now, it is working on the ESP32 (WeMos board - ESP-WROOM-32) running MicroPython.
How does it Work? Backgrounds on the Communication
I took Fig. 1 from Chris(derossi). This figure describes the complete communication. The Belkin WeMo devices advertise themselves on the network responding to searches, and define the details of their control interfaces. The Amazon Echo searches for the WeMo devices (UDP broadcast formatted as an HTTP request) and know about the WeMo API. To understand the communication, Chris(derossi) used Wireshark to sniff the traffic between the Amazon Echo and the Belkin devices. You can find more info about the tests here.
The Echo starts to search the network for new devices (UDP broadcast formatted as an HTTP request). In this case, the WeMos board emulates a WeMo device and responds to the requests of the Amazon Echo (UDP messages to the IP address and port that made the search request). Then, the Amazon Echo send HTTP GET request to the specific URLs that the WeMos responded, and the WeMos sends back the device description. The device description can be found in the original post of Chris(derossi) as well as details of the UDP broadcast and the HTTP GET requests. When you tell then the Echo to turn a device on or off, it sends an HTTP request (details again here) to the WeMos that includes a
<BinaryState>
element that contains a1
for turn on, or a0
for turn off. Then, the WeMos responds back with aHTTP/1.1 200 OK
to confirm that the operation has been executed.Fig. 1: Communication between Amazon Echo & WeMos (MicroPython) Micropython
I ported the original code of makermusings/fauxmo to work on MicroPython. MicroPython is a lean and efficient implementation of the Python 3 that includes a small subset of the Python standard library. I've introduced the following modifications
- MicroPython is an implementation of Python 3, the class was written for Python 2.7. Then, minor changes were made to run on Python 3.
- MicroPython supports
uselect.poll()
. That means, the classpoller
that waits for incoming data to be read works on MicroPython usinguselect.poll()
. On Python thepoll.register(fd[, eventmask])
registers afd
descriptor with the epoll object. On MicroPython thepoll.register(obj[, eventmask])
register anobj
with the epoll object. This is a main difference, while on Python, you need to register the socket’s file descriptorsocket.fileno()
, you have to register thesocket
object on MicroPython. Taking this in consideration- In the class
poller
, the methodsadd(...)
,remove(...)
andpoll(...)
were modified; - In the class
upnp_device
, thesockets(...)
method was added to return the socket object;
- In the class
socket.inet_aton(ip_string)
is not supported on MicroPython. Then, the following function was writtendef inet_aton(addr): ip_as_bytes = bytes(map(int, addr.split('.'))) return ip_as_bytes
dgb
function for debugging messages was added;- I've introduced one of the pull request to the code: The device description using json as
devices = [ {"description": "white lights", "port": 12345, "handler": rest_api_handler((255,255,255), 50)}, {"description": "red lights", "port": 12346, "handler": rest_api_handler((255,0,0), 50)}, {"description": "blue lights", "port": 12340, "handler": rest_api_handler((0,0,255), 50)}, ]
- The class
rest_api_handler(object)
was modified to introduce the WS2812b support; - Threading was also implemented. The main loop runs in a separated thread and reads the received data using polling.
- The garbage collector was needed to avoid full memory error. I think, MicroPython has still some memory leak problems yet;
- Some try and except clauses were added to the code (read the next topic!).
- The MicroPython version for ESP32 doesn't have a
time.gmtime()
or amachine.RTC()
. Using a ntp server and sockets, I've implemented some classes and functions in order to get the actual time (it is alpha release, it should be optimized!).
As you can see in the video and in the cover picture, I've combined the WeMos with the WS2812b LEDs. I've extended the WS2812b Python driver to support the WeMos board. The new version of the driver can be found here.
The device description in
main.py
includes three fields{"description": "blue lights", "port": 12340, "handler": rest_api_handler((0,0,255), 50)}
the first one
blue lights
corresponds to the device name; you are going to use this name every time you want to switch the device on or off. I mean, "echo, turn on/off theblue lights
". The second one,12340
is the port of each device. Amazon Echo is going to get the device configuration from, and send the commands to thishttp://wemos-ip:12340
address. The third argument is the handler, in this case I use the classrest_api_handler()
in which the constructur has two arguments:(0,0,255)
corresponds to the LED color in RGB format, and50
to the brightness. You can rewrite this class.A big limitation :(!!!
MicroPython has nowaday (Oct. 2017) problems with the number of parallel opened sockets. The maximum number is 8. Each socket has a socket’s file descriptor (a small integer) that identifies the socket object. The method
add(...)
of the classpoller
register the sockets to the epoll object. The fileno number increases up to 7, and if there is no free socket between 0 and 7, then overflows and replaces a still opened socket. I put some try and except clauses to avoid fatal errors. But, this results in a limitation.As a result, the maximal number of opened sockets limits the devices that you can register to a maximum of 5 (+ 1 for broadcasting, + 1 for responding with the devices description "setup.xml" = 7) . With a top of 3 devices, you are going to get some errors which are "excepted" but all of your devices are going to be recognized simultaneously. If you have more than 3, some of your devices are not going to be recognized (usually you get less than 3 recognized), you need to start the search of devices again, and if you have some luck you can find the rest of them. If you have less than 3 devices, you are not going to see any failure and all devices are going to be recognized simultaneously. It should be possible to optimize the code and solve this problem, or maybe it is possible to solve the maximal number of socket's file descriptors (bug report coming...).
Do it Yourself
You need the following Hardware & Software
And here are the steps that you should do to get the code working!
- Read the blog article: #Micropython: Getting Started! and install MicroPython on the WeMos board;
- Download the repository: uPyEcho;
- Modify the following lines in the
boot.py
- ssid_ =
<your ssid>
- wp2_pass =
<your wpa2 password>
- ssid_ =
- Modify if you want (or need) to, the following lines in the
main.py
file- The code line
ws2812_chain = WS2812(ledNumber=ledNumber, brightness=100)
defines the WS2812 LED strip. The argument
ledNumber
defines the size of the LED strip. In my case, I used 144 LEDs. - The code lines
devices = [ {"description": "white lights", "port": 12340, "handler": rest_api_handler((255,255,255), 50)}, ... ]
define the devices that are going to be found by Amazon Echo. As I said before, you can add up to 5 devices, but read again the section "A big limitation :(!!!". You need to define a name (e.g.
white lights
), a port (e.g.12340
), and a class (e.g.rest_api_handler
) that is used as a handler. If you want to use further therest_api_handler
class, you can select the LED color in RGB (e.g. white >(255,255,255)
), and the brightness of the LED stripin % (e.g.50
). The WS2812b class uses the SPI unit, and the pin 23 as data pin. Do not forget to connect the also the GND.
- The code line
- Upload the code, connect the LED strip and restart the board;
- Start a device search from Amazon Echo. You can use the Alexa application, or just say, "echo/alexa, search for new devices" and wait;
- Say, "echo/alexa, turn on the
<your device name>
", it should work, if not, leave a comment or write me.
Further Developments
Port this code to the Wipy 2.0. MicroPython on WiPy 2.0 doesn't not support multicast yet. I am going to write to the Wipy developers to see if it is possible to implement this. The line
self.ssock.setsockopt(usocket.IPPROTO_IP, usocket.IP_ADD_MEMBERSHIP, self.mreq)
doesn't not work on the Wipy 2.0 running the last version of MicroPython (Oct. 2017).
I've just bought the Wemos D1 Mini NodeMcu Lua WIFI ESP8266 Development Board. I'm going to test if the code works on the ESP8266 (it's another firmware file), and may be that could be the cheapest multi-output Alexa-enabled device on the planet!(UPDATE: The RAM is not enough to run MicroPython and the emulator code! :( )
More Interesting Links
We use cookies to improve our services. Read more about how we use cookies and how you can refuse them.
George 05.17.2018
Hello ,
I wanted to thank you for pointing me to wireshark.org/ on your page here: lemariva.com/blog/2017/10/micropython-wemos-and-amazon-echo-alexa I was not aware of how important it is to monitor my site and you got me to do that!
After some research, I found this super cool really free alternative mobile app. What these guys do is turn my phone into a monitor, so I get an instant message if my site is down: freewebsitemonitor [edited]
I think this is a really cool approach, and it saves me the money I paid for the monitoring in the past. They promise a forever-free app, so I thought since you got me to the first course, I would return the favor, so you can share this app on your page.