由于 Mote 是为家庭照明设计的,比如低架或者低架照明,自动化控制开启了许多可能性。
幸运的是,苹果的 Homekit API 已经有一个名为 homebridge 的扩展开源项目,一个 Node.js 库及一些有用的插件,用于控制从 RGB LED 灯(如 Mote)到 Sonos 扬声器甚至是 Xbox One 的所有内容。
虽然,苹果不久将发布一个家庭应用程序(与 iOS 10 一起),以允许您控制启用 Homekit 的设备,但还有其他一些应用程序允许您执行相同的操作。我们最喜欢的就是 Hesperus,它提供了一个干净、直观的界面,可以用各种设备和计划动作设置场景。
(更新:苹果公司现在已经发布了他们的家庭应用程序,我们可以证实,它适用于我们下面描述的 Mote API)
在这里,我们将介绍如何设置 Flask API 来控制 Mote,如何安装、配置 Homebridge 和 homebridge-better-http-rgb 插件,以及如何使用 Hesperus 应用程序和 Siri 来控制 Mote。
我们需要一些 Python 库( Mote 和 Flask 库),所以现在就开始安装这些库,然后再开始阅读代码。
如果你在 Raspberry Pi 上设置这个,我们推荐使用这个方式,那么你可以使用下面的命令来安装 Mote 库:
curl https://get.pimoroni.com/mote | bash
如果您不使用 Raspberry Pi,那么您可以使用 Python 软件包安装程序 pip 来安装 Mote 库。
sudo pip install mote
我们还需要安装 Flask 库,我们也可以使用 pip 来安装它。 键入以下内容来安装 Flask:
sudo pip install flask
我们将于接收来自 Hesperus 和 Siri 的信息的 homebridge 插件,称为homebridge-better-http-rgb。它使用一系列结点,将命令转发到 RGB LED 灯。我们的 Flask API 将定义这些结点,并使用它们来开关 Mote LED,控制它们的亮度并控制它们的色调。
由 homebridge-better-http-rgb 定义的结点是 on
、off
、status
(灯光是否打开)、brightness
,并使用 set
设置色调。brightness` 和
set结点,当没有后续值调用时,将分别返回当前设置的亮度或色调。否则,可以将值传递到这些结点,例如,
brightness/50将亮度设置为 50%,或者用
set/FF0000`` 设置为红色。
Flask 是一个用于构建 Web 应用程序的超级小 Python 库,也可以用来构建简单的 API(应用程序编程接口),让您以编程方式控制事物,无论它们是物理设备还是 Web 服务。
我们的 Flask API 大概有100行,所以我们会逐一浏览一下,看看它们都做了什么。
首先,我们需要导入一些我们将用于 API 的东西:
from colorsys import hsv_to_rgb, rgb_to_hsv
from mote import Mote
from flask import Flask, jsonify, make_response
colorsys
函数 hsv_to_rgb
和 rgb_to_hsv
将用于互换 HSV 和 RGB 颜色(稍后更多)。我们需要 Mote 类来控制 Mote,以及 Flask 类和 jsonify
和 make_response
函数来构建我们的 API。
在最上面,我们有一些样板代码,它们设置了我们的代码所需的一些东西,来初始化 Flask 应用程序并为 Mote 设置一些参数。
app = Flask(__name__)
mote = Mote()
mote.configure_channel(1, 16, False)
mote.configure_channel(2, 16, False)
mote.configure_channel(3, 16, False)
mote.configure_channel(4, 16, False)
colour = 'FFFFFF'
status = 0
我们将控制器的四个通道分别配置为 16 像素,然后创建 colour
和 status
变量,稍后我们将使用这些颜色和状态,对于颜色显示默认的白色,对于状态为 0
或关闭。
我们其余的大部分代码都是由各种函数组成的,我们可以将这些功能分解为与控制 Mote 相关的功能,以及 Flask 用来创建 API 结点的功能。
先来看看Mote的功能。
因为我们的 homebridge 期望颜色是十六进制的,而且 Mote 期望颜色是 RGB,所以我们有一些相互转换的轻微复杂的任务。 colorsys
库具有互换 HSV 和 RGB 值的功能,但不幸的是没有函数来进行十六进制值互相转换。 所以,我们将写一个简单的函数来将十六进制转换为RGB。
def hex_to_rgb(value):
value = value.lstrip('#')
length = len(value)
return tuple(int(value[i:i + length / 3], 16) for i in range(0, length, length / 3))
接下来,我们有几个开关 Mote 的函数。mote_on
函数接受一个参数 - c
- 颜色作为十六进制值。然后使用我们刚刚写的 hex_to_rgb
函数从十六进制颜色 c
中获取 r
,g
和 b
值,并将所有条的所有像素设置为该颜色。此功能将用于开启 Mote,并在开启时更改 Mote 的颜色。
def mote_on(c):
r, g, b = hex_to_rgb(c)
for channel in range(4):
for pixel in range(16):
mote.set_pixel(channel + 1, pixel, r, g, b)
mote.show()
return True
我们的 mote_off
函数是一个简单的函数,可以关闭所有的像素。
def mote_off():
mote.clear()
mote.show()
return True
其余功能与 API 本身相关,并定义 homebridge-better-http-rgb 插件将使用的端点。就像 API 惯例一样,我们所有的端点都将从 /mote/api/v1.0/
开始,告诉我们 API 的名字,指定它的确是一个 API,而不是一个网页,以及提供的版本号 一旦开发出更新的版本,就具有了遗留支持的手段。
我们要定义的第一个端点是 /mote/api/v1.0/status
, /mote/api/v1.0/on
和 /mote/api/v1.0/off
。 状态端点允许 API 返回 Mote 的状态 - 无论它是打开还是关闭 - 所以我们将使用状态变量,即关闭时为 0 或开启时为 1,并将其设置为 get_status
函数的一部分。
def get_status():
global status
for channel in range(4):
for pixel in range(16):
if mote.get_pixel(channel + 1, pixel) != (0, 0, 0):
status = 1
else:
status = 0
return status
我们的函数将状态定义为一个全局变量,所以它的状态持续在所有代码中,在函数内部和外部。 然后循环遍历所有通道上的所有像素,然后检查它们是否打开或关闭。 如果它们是打开的,则状态设置为1,否则状态设置为0。
我们将在 set_status
函数中使用我们刚刚在第一个路由中写入的那个函数。 在 Flask中,端点被封装在一个 @ app.route
装饰器中,该装饰器将其定义为 URL 路由。
@app.route('/mote/api/v1.0/<string:st>', methods=['GET'])
def set_status(st):
global status, colour
if st == 'on':
status = 1
mote_on(colour)
elif st == 'off':
status = 0
mote_off()
elif st == 'status':
status = get_status()
return jsonify({'status': status, 'colour': colour})
我们的 app.route
装饰器将URL结构定义为 '/mote/api/v1.0/ <string:st>'
。第一部分 - /mote/api/v1.0/
- 对我们所有的 URL 端点都是通用的。<string:st>
部分是一个巧妙的小技巧,Flask 用来获取 URL 的一部分,并将其直接赋值给一个变量,甚至可以让你设置什么类型,在这种情况下,一个名为 st 的字符串我们也使用 methods = ['GET']
指定这个 URL 将发送一个 get 请求。
set_status 函数从 URL 中传递 st 变量,然后根据 st 是否处于开启,关闭或状态,进行相应的操作。如果st等于'on',则使用当前设置的全局颜色调用 mote_on 函数,状态全局设置为 1,如果等于 off,则调用 mote_off 函数,状态设置为 0
。如果 st 等于 'status'
,那么我们调用我们的 get_status 函数。
最后,我们返回 JSON 格式的状态和颜色,使用 jsonify 函数,传递一个具有适当的键和值的字典。当一个 get 请求被发送到这个URL路由时,JSON-ified 字典将被返回,而不是正常情况下的 HTML 页面。
homebridge-better-http-rgb 指定 /set
端点将返回当前设置的颜色。我们将编写一个简单的路由函数,返回全局颜色值,并以与我们写的最后一条路由相同的 JSON 格式返回。
@app.route('/mote/api/v1.0/set', methods=['GET'])
def get_colour():
global colour
return jsonify({'status': status, 'colour': colour})
再次,我们使用 @app.route
装饰器将 URL 设置为 “/mote/api/v1.0/set”
,并指定它将发送一个 get 请求。访问 URL 时调用的 get_colour 函数,仅返回包含状态和颜色的 JSON 查询字典。
我们还需要一个 set_colour 函数来设置颜色! 它用十六进制颜色扩展/设置路线,例如 FF0000 红色。
@app.route('/mote/api/v1.0/set/<string:c>', methods=['GET'])
def set_colour(c):
global status, colour
colour = c
if status != 0:
mote_on(colour)
status = 1
return jsonify({'status': status, 'colour': colour})
为了完成本书的工作,我们将使用 Flask 的 @app.errorhandler
装饰器来优雅地处理 404 未找到的错误。
@app.errorhandler(404)
def not_found(error):
return make_response(jsonify({'error': 'Not found'}), 404)
在Flask应用程序中,首先在命令行运行应用程序时运行主函数。除了使用 app.run(host ='0.0.0.0',debug = True)
实际运行应用程序外,我们还将调用 mote_off()
函数在脚本首次运行时将 Mote 关闭。
if __name__ == '__main__':
mote_off()
app.run(host='0.0.0.0', debug=True)
现在我们已经编写了我们的 API,我们可以测试端点按预期工作。 整个代码在下面,所以将其复制并保存在一个名为 mote_api.py
的文件中。
from colorsys import hsv_to_rgb, rgb_to_hsv
from mote import Mote
from flask import Flask, jsonify, make_response
app = Flask(__name__)
mote = Mote()
mote.configure_channel(1, 16, False)
mote.configure_channel(2, 16, False)
mote.configure_channel(3, 16, False)
mote.configure_channel(4, 16, False)
colour = 'FFFFFF'
status = 0
def hex_to_rgb(value):
value = value.lstrip('#')
length = len(value)
return tuple(int(value[i:i + length / 3], 16) for i in range(0, length, length / 3))
def mote_on(c):
r, g, b = hex_to_rgb(c)
for channel in range(4):
for pixel in range(16):
mote.set_pixel(channel + 1, pixel, r, g, b)
mote.show()
return True
def mote_off():
mote.clear()
mote.show()
return True
def get_status():
global status
for channel in range(4):
for pixel in range(16):
if mote.get_pixel(channel + 1, pixel) != (0, 0, 0):
status = 1
return status
@app.route('/mote/api/v1.0/<string:st>', methods=['GET'])
def set_status(st):
global status, colour
if st == 'on':
status = 1
mote_on(colour)
elif st == 'off':
status = 0
mote_off()
elif st == 'status':
status = get_status()
return jsonify({'status': status, 'colour': colour})
@app.route('/mote/api/v1.0/set', methods=['GET'])
def get_colour():
global colour
return jsonify({'status': status, 'colour': colour})
@app.route('/mote/api/v1.0/set/<string:c>', methods=['GET'])
def set_colour(c):
global status, colour
colour = c
if status != 0:
mote_on(colour)
status = 1
return jsonify({'status': status, 'colour': colour})
@app.errorhandler(404)
def not_found(error):
return make_response(jsonify({'error': 'Not found'}), 404)
if __name__ == '__main__':
mote_off()
app.run(host='0.0.0.0', debug=True)
打开一个终端并输入 python mote_api.py
。
然后,打开另一个终端窗口或选项卡,然后输入以下内容来测试我们的API是否按预期工作。
curl -i http://127.0.0.1:5000/mote/api/v1.0/on
这应该只是把你的 Mote 打开!您还应该能够在另一台机器上远程执行此操作,将 URL 的 127.0.0.1 部分替换为运行 API 的机器的 IP 地址。 你也应该能够在你的网页浏览器中做到这一点,而不是在终端上使用 curl
。
尝试输入以下内容将 Mote 条的颜色更改为红色。
curl -i http://127.0.0.1:5000/mote/api/v1.0/set/FF0000
homebridge-better-http-rgb
下一步是在运行 Mote API 的机器上设置 homebridge 和 homebridge-better-http-rgb 来完成这个循环。 homebridge 和 homebridge-better-http-rgb 插件提供了将 Mote 添加为可以通过像 Hesperus 这样的应用程序进行控制的 Homekit 设备的方法,并将命令发送到我们的 API,然后发送到 Mote 条带。
以下说明假定您使用的是运行 Raspbian Jessie 最新版本的 Raspberry Pi 3,但经过一些修改,您应该可以在 Mac,Windows PC 或其他 Linux 机器上运行所有程序。
打开一个终端,输入以下内容升级到 Node.js 的最新版本:
sudo apt-get update
sudo apt-get upgrade
curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
sudo apt-get install -y nodejs
在安装 Homebridge 之前,我们需要先安装一些依赖:
sudo apt-get install libavahi-compat-libdnssd-dev
然后安装 homebridge 和 homebridge-better-http-rgb 插件:
sudo npm install -g --unsafe-perm homebridge
sudo npm install -g --unsafe-perm homebridge-better-http-rgb
现在所有东西都已经安装好了,我们还需要做更多的事情来正确配置 Homebridge。homebridge 是通过一个.json文件来配置的,它必须放在 /home/pi/.homebridge/
目录下。 我们现在创建这个目录:
mkdir /home/pi/.homebridge
我们的配置文件如下所示:
{
"bridge": {
"name": "Homebridge",
"username": "CC:22:3D:E3:CE:32",
"port": 51826,
"pin": "031-45-155"
},
"description": "Homebridge",
"accessories": [
{
"accessory": "HTTP-RGB",
"name": "Mote",
"switch": {
"status": "http://127.0.0.1:5000/mote/api/v1.0/status",
"powerOn": "http://127.0.0.1:5000/mote/api/v1.0/on",
"powerOff": "http://127.0.0.1:5000/mote/api/v1.0/off"
},
"brightness": {
"status": "http://127.0.0.1:5000/mote/api/v1.0/brightness",
"url": "http://127.0.0.1:5000/mote/api/v1.0/brightness/%s"
},
"color": {
"status": "http://127.0.0.1:5000/mote/api/v1.0/set",
"url": "http://127.0.0.1:5000/mote/api/v1.0/set/%s",
"brightness": true
}
}
],
"platforms": []
}
复制粘贴,并在我们刚刚创建的 /home/pi/.homebridge/
目录中,保存为 config.json
。
您可以将 bridge name 和 description 更改为任何您想要的名称,以及我们称为 “Mote” 的 accessory 名称。username, port 和 pin 都是样板值,可以保留原样。
如果在以后的日子,您想要使用其他 Homebridge 插件添加其他配件,那么您可以将它们添加为 accessories
列表中的新配件。
现在所有的东西都已经建立好了,我们将首先启动 Mote API,然后再启动 Homebridge。
假设您的 Mote API 被称为 mote_api.py
并位于 /home/pi/
中,请输入以下命令启动它:
python /home/pi/mote_api.py
您将看到几行信息,告诉您 Flask 应用程序的状态,包括其运行的IP地址和端口。
现在,打开另一个终端选项卡或窗口,然后输入 homebridge
启动家庭网桥。
您将看到几行确认 Mote 附件已成功加载,并且在您的 iPhone 上配置 Homekit 应用程序时可以输入代码。 不需要编写这段代码,因为它和我们之前在配置文件中配置的代码一样。
接着,打开我们的 Homekit(家庭)应用程序,手动输入我们在 Homebridge 中定义的 PIN 码:
031-45-155
就可以在应用中看到我们的 Mote。
另外一个好处就是现在我们已经有了 Homekit 的 Mote,我们可以用 Siri 来控制它。我们可以使用我们在配置文件中,给定的 Mote 附件的名字(在我们的例子中是“Mote”)来控制它。
如果您启用了 “嗨,Siri”,请尝试说 “嘿,Siri。开启Mote。”,或者按住 home 键启动 Siri 并说“打开 Mote”。
有一点灵活性,所以你也应该可以说 “开启 Mote”,“打开灯”,也许还有其他一些措辞。
你也可以说 “将亮度设置为25%”,或者 “将 Mote 设置为红色”。
如果您有Apple Watch,那么您也可以使用Siri来控制您的家庭设备。随着苹果添加到 OS X 的 Siri,你也应该能够很快用你的 Mac 来控制它们。
我们仅用一个Mote控制器进行了基本设置,但是您可以轻松扩展此功能,或者在同一个 Pi 上使用其他 Mote 控制器,并扩展 API 端点以在 URL 中包含控制器编号,或者使用其他 Pis 和控制器在单独的IP地址。您也可以修改 API,以单独控制每个控制器上的每个条。
一个简单的方式来鼓励你的 Mote API,当你打开或关闭你的 Mote 时,包括一个简短的淡入淡出,使它打开或关闭时看起来不那么刺耳。
而且,当然,Homebridge 的美妙之处在于,您可以轻松添加更多的插件和配件,以便通过触发一个动作,启动您的 Sonos 播放流畅的爵士乐,并将灯光打开。
原文链接:https://learn.pimoroni.com/tutorial/sandyj/using-mote-with-homekit-and-siri
观光\评论区