基于Amazon Echo 和 Raspberry Pi 的自动窗帘控制

来源:互联网 发布:河北广电 东方网络 编辑:程序博客网 时间:2024/04/27 19:09

作者 | Fortware

责编 | 薄荷茶

微信公众号ID | csdn_iot


本指南说明如何整合电动窗帘轨道,Raspberry Pi 和 Amazon Echo,以便您可以请求Alexa打开窗帘。


一旦完成,你应该可以说:“Alexa,请打开窗帘”和“Alexa,关闭窗帘”。


步骤一
设计概述


本设计由以下几个部分组成:


  1. 将电动窗帘轨道与Raspberry Pi集成

  2. 编写一个Python脚本来打开和关闭窗帘

  3. 编写 Amazon skill,让您的 Echo 与 Raspberry Pi 进行通信


我使用以下组件:


  1. 一个 Amazon Echo

  2. 一个电动窗帘轨道,https://www.amazon.co.uk/gp/product/B013X0BZF2

  3. 连接 Raspberry Pi GPIO 的水晶头网线

  4. 一块 Raspberry Pi 开发板

  5. 与Raspberry Pi GPIO整合所需的组件(我从Proto-Pic订购),包括 Raspberry Pi GPIO 转接口(2x13)、带状排线、3个型号为 BC547 的 NPN 晶体管、3个1K电阻、1块合适的单面洞洞板、适量导线


步骤二
整合电动窗帘轨道和 Raspberry Pi



我购买的窗帘轨道带两个控制器 - 有线和无线。 我没有碰到无线的,选择将 Raspberry Pi 与有线控制器整合。


一旦拆卸,您可以看到有线的控制器由四个开关组成(见电路图)-通过跟踪电线,您可以看到按钮将三根电线连接到地(第四根导线)。标示为 'open' 的短电线导致电机单向启动; 标记为 'close' 的短电线使电机以其他方式驱动。标有 'stop' (按停止按钮引起)的短线使电机停止。


切掉水晶头网线的一端并剥去外皮。


将原始控制器插头的背面与水晶头网线进行比较,以确定导线线序(在图中,原始控制线为白色;水晶头网线为灰色)。使用四根线; 两个不需要。 通过短路打开,关闭和停止接地线的电线,确认您有正确的电线。 窗帘导轨应打开,关闭并停止。


导线和接地之间的电势是5V - 我认为这是一个电阻上拉的的逻辑输入,接地时切换到低电平。


与 Raspberry Pi GPIO 集成相对简单。 任何基本的晶体管都可以用作开关来临时接地每根线,从而模拟开关按压。


图中给出了一个示例电路。 注意电线应确保 Raspberry Pi 和窗帘共地(Raspberry PI 6号引脚)。


我使用标准BJT晶体管 - NPN BC547和1K电阻将晶体管的基极连接到 Raspberry Pi。


我连接到物理引脚11,15和22号,映射到BCM格式的GPIO引脚17,22和25,更多关于物理和逻辑引脚之间的关系参考:https://projects.drogon.net/raspberry-pi/wiringpi/pins/


步骤三
编写打开或关闭窗帘的 Python 脚本


Raspberry Pi具有非常灵活的通用输入/输出端口 - 简称为GPIO。 有关使用Raspberry Pi GPIO 有许多很好的指导和文档。


还有一个优秀的的图书馆,可用于Python和C,这使得驱动GPIO非常简单 - Wiring Pi。原始页面位于:http://wiringpi.com/


在http://raspi.tv/how-to-install-wiringpi2-for-python-on-the-raspberry-pi你可以找到一组有用的安装说明。


一旦安装完成,以下代码应使窗帘打开和关闭,每次更改之间有两秒的间隙。 该代码通过将GPIO引脚置为高电平0.5s来模拟按钮,提高晶体管的基极电压,从而允许电流在集电极和发射极之间流动 - 将电线短路到地。


import RPi.GPIO as GPIO

import time

GPIO.setmode(GPIO.BCM)

openPin=17

closePin=25

stopPin=22

GPIO.setup(openPin, GPIO.OUT)

GPIO.setup(closePin, GPIO.OUT)

GPIO.setup(stopPin, GPIO.OUT)

time.sleep(2)

while (1==1) :

  print "Opening\n"

  GPIO.output(openPin, GPIO.HIGH)

  time.sleep(0.5)

  GPIO.output(openPin, GPIO.LOW)

  time.sleep(2)

  print "Stopping\n"

  GPIO.output(openPin, GPIO.HIGH)

  time.sleep(0.5)

  GPIO.output(openPin, GPIO.LOW)

  time.sleep(2)

  print "Stopping\n"

  GPIO.output(stopPin, GPIO.HIGH)

  time.sleep(0.5)

  GPIO.output(stopPin, GPIO.LOW)

  time.sleep(2)

  print "Closing\n"

  GPIO.output(closePin, GPIO.HIGH)

  time.sleep(0.5)

  GPIO.output(closePin, GPIO.LOW)

  time.sleep(2)

  print "Stopping\n"

  GPIO.output(stopPin, GPIO.HIGH)

  time.sleep(0.5)    

  GPIO.output(stopPin, GPIO.LOW)

  time.sleep(2)


步骤四
编写 Amazon Skill 与 Raspberry Pi 进行通信

询问Alexa


理想情况下,我们可以要求Alexa打开窗帘。但是我现在不知道Echo上提供的语音接口是否可以使用该类型的请求。所以,我们会说:'Alexa,请让窗帘打开'。然后“Alexa,请让窗帘关闭”。


有三个步骤:


  1. 在 Raspberry Pi 上创建本地脚本,并在路由器上实现端口转发

  2. 在亚马逊开发者网站上创建一个 Alexa skill

  3. 创建Amazon AWS Lambda代理


值得欣慰的是,关于此方案前人已经有一些优秀的分享,因此我从以下链接收益颇丰:https://www.instructables.com/id/Control-Raspberry-Pi-GPIO-With-Amazon-Echo-and-Pyt/


该指南说明了如何在Amazon开发人员网站上创建一个 skill,指出 Amazon 使用ngrok(ssl为http代理)生成输出,然后使用名为Flask-Ask的库在Raspberry Pi上处理请求。 ngrok必不可少,因为开发者网站只会通过ssl发送请求 - Flask-ask监听http。


ngrok作为一个临时代理很出色,但除非您要支付年费,否则每次重新启动您的pi上的ngrok客户端时,您需要修改指向 Amazon 脚本的URL 。


另一种方法是在Amazon AWS上创建一个基本代理,然后可以将请求重定向到您的Pi(假设您已经在防火墙上配置端口转发以允许请求)。


我使用了Matt创建的代理:https://forums.developer.amazon.com/questions/8155/how-to-use-aws-lambda-as-a-proxy-for-non-ssl-serve.html


感谢 Matt !


步骤五
创建本地脚本并在路由器上实现端口转发


在 Raspberry Pi 创建以下脚本:


from flask import Flask

from flask_ask import Ask, statement, convert_errors import RPi.GPIO as GPIO import logging import time

GPIO.setmode(GPIO.BCM)

openPin=17

closePin=25

stopPin=22

GPIO.setup(openPin, GPIO.OUT)

GPIO.setup(closePin, GPIO.OUT)

GPIO.setup(stopPin, GPIO.OUT)

app = Flask(__name__) ask = Ask(app, '/')

app.config['ASK_VERIFY_REQUESTS'] = False

app.config['ASK_APPLICATION_ID'] = 'Unique amazon skill reference''

logging.getLogger("flask_ask").setLevel(logging.DEBUG)

def openCurtains():

print 'Opening curtains'

GPIO.output(openPin, GPIO.HIGH)

time.sleep(0.5)

GPIO.output(openPin, GPIO.LOW)

time.sleep(5)

GPIO.output(stopPin, GPIO.HIGH)

time.sleep(0.5)

GPIO.output(stopPin, GPIO.LOW)

def closeCurtains():

print 'Closing curtains'

GPIO.output(closePin, GPIO.HIGH)

time.sleep(0.5)

GPIO.output(closePin, GPIO.LOW)

time.sleep(5)

GPIO.output(stopPin, GPIO.HIGH)

time.sleep(0.5)

GPIO.output(stopPin, GPIO.LOW)

@ask.intent('GPIOControlIntent', mapping={'status': 'status'})

def gpio_control(status):

if status in ['open', 'yield']: openCurtains() return statement('Good morning Hart Household')

if status in ['close', 'shield']: closeCurtains() return statement('Good evening Hart Household')

if __name__ == '__main__': app.run(host='IP address of Pi', port=5000, debug=True)


启动Pi运行进程。 在路由器上设置端口转发,以便发送到您的公共地址5000端口的请求转发到您的Pi的端口5000。 请注意,如果您的IP地址不是静态的,您可能需要订阅诸如DYNDNS之类的服务。


步骤六
在Amazon 开发者网站创建 Alexa Skill



让我们跟随Patrick的指引 - 从第4步开始:https://www.instructables.com/id/Control-Raspberry-Pi-GPIO-With-Amazon-Echo-and-Pyt/step4/AWS-Account/


Patrick 的第四步:创建一个 Amazon 开发者帐号。


Patrick 的第五步:创建一个新的skill,我使用了这个调用名字“窗帘”,这样Alexa就会回应“Alexa,问窗帘......”


请注意应用程序ID - 您需要将其粘贴到您编写的 Curtains 脚本中,再加上要编写的Lambda代理。


Patrick 的第六步:这里有一些微妙的变化,如截图所示。


意图很简单:


{

"intents": [{

"intent": "GPIOControlIntent",

"slots": [{

"name": "status",

"type": "GPIO_CONTROL"

}]

}]

}


slots值包含两种: open 和 close


调用更简单:


GPIOControlIntent to {status}


Patrick 的第七步:这是我们要使用 Lambda 代理而不是 Ngrok 的地方 - 看下一个阶段。


步骤七
创建 Amazon AWS Lambda 代理


建立 AWS 帐户和创建 lambda 函数的最佳指导可从 Amazon 获得 - https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/developing-an-alexa-skill-as-a-lambda-function


按照以下说明,直到您准备好将 node.js 代码输入到函数中。


然后使用来自 Matt 的代理:https://forums.developer.amazon.com/questions/8155/how-to-use-aws-lambda-as-a-proxy-for-non-ssl-serve.html。


(我在格式化代码的地方错过了一个 skill - 抱歉):


var http = require('http'); 

var URLParser = require('url');

console.log('Loading proxy function');

exports.handler = function (json, context)

{

try {

// A list of URL's to call for each applicationId

var handlers = { 'appId':'url', 'your amazon app id':'http://your router address:5000/' };

// Look up the url to call based on the appId

var url = handlers[json.session.application.applicationId];

if (!url) { context.fail("No url found for application id"); }

console.log('Trying url')

console.log(url)

var parts = URLParser.parse(url);

var post_data = JSON.stringify(json);

// An object of options to indicate where to post to

var post_options = { host: parts.hostname, port: (parts.port || 80), path: parts.path, method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': post_data.length } };

// Initiate the request to the HTTP endpoint

console.log(post_options)

var req = http.request(post_options,function(res) {

var body = "";

// Data may be chunked

res.on('data', function(chunk) { body += chunk; });

res.on('end', function() { // When data is done, finish the request

context.succeed(JSON.parse(body)); }); });

req.on('error', function(e) { context.fail('problem with request: ' + e.message); });

// Send the JSON data console.log('Sending data') req.write(post_data); req.end(); } catch (e) { context.fail("Exception: " + e); } };


我还将高级配置中的超时增加到7秒 - 否则,在窗帘完成5秒的活动之前,Lambda代理将超时。


步骤 八
整合与集成




复制Lambda ID - 您需要将其粘贴到Amazon开发中,指示Amazon将请求引导到您的新Lambda代理,将其转发到Raspberry Pi上 - 请参阅第1个屏幕截图。


从亚马逊开发者网站测试skill - 你应该看到第二个屏幕截图的响应。


如果它不起作用,请检查Lambda日志的调用错误和Raspberry Pi脚本输出的错误。


然后打开 Echo 的开发skill - 不要将其对外发送,否则您将失去对窗帘的控制。


坐下来享受自动化窗帘!

本文转载自 知乎,转载已经授权。

原文链接:https://zhuanlan.zhihu.com/p/28401612