當 Alexa 遇上 ESP8266 (一)
https://www.birdandgua.net/bird/2017/12/when_alexa_meets_esp8266-1/
去年的 AWS 的 re:Invent 上,我見識了 Alexa Voice service 的本事後深受震撼,我除了帶了幾顆 Echo 和 Echo Dot 回來研究外,也想著要用 ESP8266 來做可以讓 Alexa 控制的裝置。
其實回來之後沒多久我就做出來了,但這篇文章一直沒寫。等到我想寫文章、把寫好的程式再度拿出來看時,發現我所使用的 library 已經大幅更新,我原來寫的程式根本沒辦法 compile,只好整個砍掉重練。
時隔一年,這幾天正值 re:Invent 2017 進行中。今年因為種種因素我無法成行,就用這篇文章來紀念去年此時的這個 idea 和那時的熱血吧。
偽裝
要做一個讓 Alexa 可以控制的裝置有很多方法,但大部份的方法都要用到 AWS 的 IoT 或 serverless 服務,至少要寫一點 Lamda script 去處理 Alexa 跟裝置間的互動,或者要走 MQTT 透過 IFTTT 之類的服務來運作。一但用了 backend server 的服務,被控裝置的安裝就要處理註冊和認證等問題,操作上會變得很麻煩。
尋尋覓覓後,我發現有另一種更聰明的做法: 偽裝。
Alexa 支援一系列的智慧插座,可以用 Alexa 控制插座電源的開或關,而這其中最有名的就是 Belkin 出的 Wemo Switch。Wemo Switch 必需跟執行 Alexa 的 Echo 或 Echo Dot 位在同一個 WiFi 網路之下才能運作,因此就有人推測它們倆可能是在 LAN 上直接溝通,而不經過雲上的 server。
有一位很有名的 maker,Chris Derossi,利用 Wireshark這個老牌的 network sniffer 監聽 Echo 跟 Wemo Switch 之間的通訊後,解開了這個謎。Echo 跟 Wemo Switch 都沒有 Ethernet 接口,因此只能用 WiFi sniffer 來監聽。這張圖發表在他原來的部落格文章 Amazon Echo and Home Automation 中:
原來 Echo 跟 Wemo Switch 之間是這麼運作的:
- 當使用者第一次設定 Wemo Switch 時,要先對 Echo 喊 “Alexa, descover devices”。此時 Echo 會利用 UDP broadcast 送出一個 UPnP 的 SSDP 請求,SSDP 是 UPnP 控制器用來在網路上尋找裝置用的協定,它是一個 HTTP request,帶有一種叫 M-SEARCH 的 method,只有 header 沒有 body,送往 IPv4 的 multicast 地址 239.255.255.250:1900。
- 同一個網路上的 Wemo Switch 都聽得到 IP multicast。它們發現這個 HTTP request 是在叫自己後,就會回傳一個 HTTP response 給發出 IP multicast 的 Echo,裡面最重要的訊息是一個 URL。這個 URL 指向一個 XML 檔,用來描述裝置本身的屬性。這時的回覆會來自網路上的多個裝置,因為每個收到 IP multicast 的 Wemo switch 都會回答,所以網路會有一小段時間變得很吵。以上都還是走 UDP,所以不需建立連線。
- Echo 收到這些回覆的 URL 後,依序對每個裝置發出 HTTP request,讀取每個裝置的 XML 配置檔。這時的協定通訊協定改走 TCP,會先建立連線,傳送的資料也會變得可靠。
- 每個裝置用 HTTP response 回覆它們的設定檔,也是走 TCP。這個設定檔很長,是一個一百多行的 XML 檔,但其中只有一欄比較重要,就是這個裝置的 friendly name。Friendly name 就是我們幫每一個 Wemo Switch 取的名字,當我們要用 Alexa 的語音服務控制它時,叫的就是這個名字。
- 設定完成後,我們會在 Alexa 的 app 中看到它已經找到的裝置列表,此時就可以用語音控制每個 Wemo Switch 的開或關。
- 當使用者喊出語音指令且 Alexa 聽懂後,它會送出一個 HTTP request 給對應的裝置,裡面有一大串有的沒有的資料,甚至包含了整組包在 XML 裡的 SOAP 指令,但其實我們真正關心的就只是 <BinaryState> 這個 tag 而已,而這個 tag 只有 1 跟 0 兩個值。
- Wemo Switch 收到指令並確認動作後,會回應一個 HTTP response,這是一個固定內容的 acknowledgement。
- Echo 收到確認的回覆後,才會講 “OK”。
Chris Derossi 隨後在另一篇 post 中發佈了一支 Python 程式,用來模擬 Wemo Switch 並回應來自 Alexa 的這些訊息。這支程式叫 fauxmo,有點向 Wemo 致敬的味道。
當 Alexa 遇上 ESP8266 (一)的更多相关文章
- MVC遇上bootstrap后的ajax表单模型验证
MVC遇上bootstrap后的ajax表单验证 使用bootstrap后他由他自带的样式has-error,想要使用它就会比较麻烦,往常使用jqueyr.validate的话只有使用他自己的样式了, ...
- 敏捷遇上UML-需求分析及软件设计最佳实践(郑州站 2014-6-7)
邀请函: 尊敬的阁下:我们将在郑州为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实 ...
- 敏捷遇上UML—软创基地马年大会(广州站 2014-4-19)
我们将在广州为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实战技巧. 时间:2 ...
- 敏捷遇上UML——软创基地马年大会(深圳站 2014-3-15)
邀请函: 尊敬的阁下: 我们将在深圳为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实战 ...
- 初识genymotion安装遇上的VirtualBox问题
想必做过Android开发的都讨厌那慢如蜗牛的 eclipse原生Android模拟器吧! 光是启动这个模拟器都得花上两三分钟,慢慢的用起来手机来调试,但那毕竟不是长久之计,也确实不方便,后来知道了g ...
- SQL SERVER 2008 R2 SP1更新时,遇上共享功能更新失败解决方案
SQL SERVER 2008 R2 SP1更新时,遇上共享功能更新失败的问题,可作如下尝试: 更新失败后,在windows的[事件查看器→应用程序]中找到来源为MsiInstaller,事件ID为1 ...
- 当创业遇上O2O,新一批死亡名单,看完震惊了!
当创业遇上O2O,故事就开始了,总投入1.6亿.半年开7家便利店.会员猛增至10万……2015半年过去后,很多故事在后面变成了一场创业“事故”,是模式错误还是烧钱过度?这些项目的失败能给国内创业者带来 ...
- LoadRunner - 当DiscuzNT遇上了Loadrunner(下) (转发)
当DiscuzNT遇上了Loadrunner(下) 在之前的两篇文章中,基本上介绍了如何录制脚本和生成并发用户,同时还对测试报告中的几个图表做了简单的说明.今天这篇文章做为这个系列的最后一篇,将会介绍 ...
- LoadRunner - 当DiscuzNT遇上了Loadrunner(中) (转发)
当DiscuzNT遇上了Loadrunner(中) 在上文中,介绍了如果录制脚本和设置脚本执行次数.如果经过调试脚本能够正常工作的话,就可以设置并发用户数并进行压力测试了. 首先我们通过脚本编辑界面上 ...
随机推荐
- phpstudy 产生You don't have permission to access / on this server.解决
phpstudy配置好访问目录时候有时候会产生You don't have permission to access / on this server. 解决办法: 修改服务器httpd.conf配置 ...
- nodejs+expressjs+ws实现了websocket即时通讯,服务器和客户端互相通信
nodejs代码 // 导入WebSocket模块: const WebSocket = require('ws'); // 引用Server类: const WebSocketServer = We ...
- c#无边框窗体移动
[DllImport("user32.dll")]//拖动无窗体的控件 public static extern bool ReleaseCapture(); [DllImport ...
- 腾讯的产品思维 VS 阿里的终局思维
从成立到借壳上市,有赞用了5年多时间.这期间,它有好几次机会死掉,有很多的理由活不到今天,白鸦曾经说,每一次度过难关最关键都是靠团队的力量.谢天谢地,它活了下来. 那么,这个在To B领域敢打敢拼的团 ...
- Spinner的简单使用
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...
- springboot 学习之路 4(日志输出)
目录:[持续更新.....] spring 部分常用注解 spring boot 学习之路1(简单入门) spring boot 学习之路2(注解介绍) spring boot 学习之路3( 集成my ...
- 堆栈的应用——用JavaScript描述数据结构
栈(stack)又名堆栈,它是一种运算受限的线性表.其限制是仅允许在表的一端进行插入和删除运算.这一端被称为栈顶,相对地,把另一端称为栈底. 一.实现一个栈类Stack 基于堆栈的特性,可以用数组做线 ...
- [转载]Windows 2003 R2 SP2 VOL 企业版(简体中文)
Windows 2003 R2 SP2 VOL 企业版(简体中文) 要是这个的话,分享个电驴的下载连接吧(可以复制后用快车和迅雷直接下)32位版CD1:SHA1值:d0dd2782e9387328eb ...
- Linux用户抢占和内核抢占详解(概念, 实现和触发时机)--Linux进程的管理与调度(二十)
1 非抢占式和可抢占式内核 为了简化问题,我使用嵌入式实时系统uC/OS作为例子 首先要指出的是,uC/OS只有内核态,没有用户态,这和Linux不一样 多任务系统中, 内核负责管理各个任务, 或者说 ...
- 使用 boost.asio 简单实现 异步Socket 通信
客户端: class IPCClient { public: IPCClient(); ~IPCClient(); bool run(); private: bool connect(); bool ...