使用 PYNQ 和 Zigbee 创建一个简单且可扩展的家庭自动化系统。
介绍
我们经常忘记 FPGA 可用于消费类应用,而不仅仅是工业、汽车、国防/航空航天等。对于诸如 Artix、Spartan 和 Zynq 7000 系列设备等 cist 优化范围内的设备尤其如此。
可编程逻辑和 SoC 提供了一系列起初可能并不明显的优势,包括
FPGA 在消费市场中的一种常见应用是家庭自动化。在家庭自动化系统中,通常有一个中央安全网关来管理设备和更广泛系统的连接。
对于这个项目,我们将演示连接到 ZigBee 控制灯系列的中央网关。
该项目的路线图是在稍后阶段将其与基于智能人工智能的数字锁连接,该数字锁将与网关通信并为解锁人员建立家庭设置。
家庭自动化、PYNQ 和 ZigBee
完全可以直接从 PYNQ 的 Juptyer 笔记本控制和自动化 ZigBee 设备。这有一些很大的好处,例如自定义用户界面,与其他家庭助理和自动化软件相比,这本身就非常独特。不仅如此,我们甚至可以利用这是一个 PYNQ 板这一事实,我们可以利用 PL 来进一步定制我们的应用程序。它非常适合家庭助理社区,令人惊讶的是它相对简单。让我们向您展示我们是如何做到的。
特色图片
方法总结
本节是对本项目中使用的方法进行总结。
PYNQ 框架运行和底层操作系统。PYNQ 框架的底层操作系统是 Ubuntu。稍后我们将利用它来安装 docker,然后安装 deCONZ 软件。
什么是 docker ?
简单地说,docker 是一种分发软件的好方法,可以减少多个虚拟机的开销。Docker 能够在所谓的“容器”中运行软件,容器是一个完全打包的软件,其中包括镜像、库和配置文件。由于容器将运行软件,因此我们不必担心兼容性问题,并且可以直接按预期运行,只需最少的干预。
为什么使用
Conbee II 使用制造商 Dresden Elektronik 提供的 deCONZ 软件来连接和控制设备。deCONZ 软件允许我们通过 Web 应用程序连接和控制设备。使这一切正常工作的原因是 deCONZ Web 应用程序具有内置的 REST API,我们可以从 Juypter Notebook 环境中进行接口!
先决条件 - 硬件
对于此演示将用于硬件:
Arty Z7 能够运行 PYNQ 框架并具有 USB 插槽。USB 插槽是必需的,因为我们将直接从 Arty Z7 本身使用 ConBee II USB 网关。
Conbee II 是一个很棒的小型 USB 记忆棒,可以连接智能设备,如灯、开关、插座和传感器。这个小棒适用于从 Windows 到 Ubuntu 的所有平台,我们将在 PYNQ 上安装它。
这个项目中的智能灯,是一个通用的蓝牙智能灯,您可以在线获取。您不必购买相同的,但一定要检查它是否与 Conbee II 兼容。可在此处找到兼容设备的完整列表:https ://phoscon.de/en/conbee2/compatible
设置 PYNQ
开始之前,我们需要从http://www.pynq.io/board.html 下载 PYNQ 映像,在撰写本文时 2.7 版是最新版本。在这里,我们将下载 PYNQ-Z1 图像,因为它与我们的 Arty Z7 板兼容。
下载后,我们需要将图像闪存到 SD 卡上。我们将使用 WinDisk32 软件来刷写镜像。注意 刷写 SD 卡会擦除所有内容。确保 SD 卡上没有任何内容。
刷机过程完成后。取出 SD 卡并将卡插入 Arty Z7,确保 Boot Jumper 设置为 SD。插入 Arty 并等待 Pynq 映像启动。
一旦 PYNQ 完成加载,我们需要找到我们的 IP 地址,输入以下命令。
ifconfig -a
找到我们的IP地址,应该在eth0接口下。这里我们的 IP 地址是 192.168.0.38。记下这一点,我们稍后将需要它。
设置 Docker 和 Docker-Compose
如方法摘要部分所述,我们将安装 Docker。首先,我们需要将当前用户添加到拨出组
sudo usermod -a G dialout $USER
接下来我们需要使用以下命令下载 docker 包:
sudo apt-get install docker.io
等待安装完成。完成后,我们需要安装 docker compose。Docker compose 是一个使用工具,它将帮助我们创建和修改我们的软件。
sudo apt-get install docker-compose
使用 docker compose 设置 DeConz
安装 docker-compose 后,我们接下来需要设置 deCONZ 容器/应用程序,这是与我们的 zigbee 设备进行交互和查找的软件。
导航到 /opt 文件夹:
cd /opt
接下来我们将创建一个新的 docker-compose.yaml 文件。
这是我们添加和配置容器的文件。
所以,回到创建 yaml 文件。
sudo nano docker-compose.yaml
确保保持缩进正确!
version: "3.2"
services:
deconz:
image: deconzcommunity/deconz:latest
privileged: true
container_name: deCONZ
network_mode: host
restart: always
volumes:
- type: bind
source: /opt/deconz
target: /opt/deCONZ
devices:
- /dev/ttyACM0
environment:
- TZ=Europe/London
- DECONZ_WEB_PORT=8090
- DECONZ_WS_PORT=443
- DEBUG_INFO=1
- DEBUG_APS=0
- DEBUG_ZCL=0
- DEBUG_ZDP=0
- DEBUG_OTAU=0
这一步将配置容器,以便下载最新版本的 deCONZ 软件并将我们的门户网站设置为端口 8090。这是关键,因为 PYNQ 使用 Jupyter 笔记本的门户网站,默认情况下使用端口 80 来访问网页和已打开额外的 9090 端口。这就是我们将 deCONZ 应用程序的端口设置为使用 8090 的原因。因为这不会干扰 Pynq Jupyter 的笔记本网络套接字。
保存 (CTR-S) 并关闭 (CTR-X) 配置。
接下来我们可以使用 docker-compose 启动 deCONZ 应用程序。输入以下命令:
sudo docker-compose up -d
这将下载 deCONZ 应用程序并在完成后自动启动容器。
当我们得到“Done”响应时,让我们做一个健全性检查,看看容器是否真的在运行。
sudo docker container ls
容器正在运行。
Conbee II 和 deCONZ 设置
现在在容器中运行 deCONZ 应用程序。我们可以使用以下说明打开 deCONZ 网络应用程序。
打开 Web 浏览器并输入 IP 和端口号 8090。在我们的实例中,我们的 IP 地址是 192.168.0.32,端口号是:192.168.0.32:8090。
这将打开 Phoscon 网络应用程序。从下图中我们可以看到我们的网关点击图标开始设置。
在下一页上,我们需要创建我们的登录凭据(见下图)。完成后单击下一步。
Phoscon 应用程序现在将要求您连接任何灯。您可以现在或以后连接您的灯。我们将连接我们的飞利浦 Hue GO 便携式灯。确保我们的灯已插入。单击搜索按钮。
从上图中我们可以看到,我们可以看到我们的 Lamp。如果您单击灯,您可以重命名它以便更容易识别灯。一旦检测到所有灯。单击无灯继续。不用担心已经检测到的灯会被记住。
在下一页上,我们可以创建一个新组来添加灯。下面是一个例子。
创建一个新组,编辑,管理灯光。
将我们的灯添加到组中。我们只有 1 盏灯要添加。单击绿色加号图标
单击保存并按箭头图标返回组页面。
将灯光添加到我们的自定义组中,我们可以控制它。请注意,在 webapp 和灯光下可能会有一些延迟。要有耐心。如果仍然存在问题,请考虑刷新页面、将设备移近或使用以下命令重新启动容器:
sudo docker container restart deCONZ
快速测试
单击灯光选项卡以调整亮度、颜色和饱和度。也可以使用下图中的图标更改色温。
设置 REST API
现在通过灯光设置,我们可以使用 Jupyter 的 Notebook 创建自己的界面。这相对容易。由于 deCONZ 应用程序有一个内置的 API,我们可以通过使用一些简单的 python 脚本来利用它。
打开一个新的 Web 浏览器并导航到 Jupyter 的笔记本页面。在我们的例子中是 192.168.0.32:80。这将打开熟悉的 jupyter 笔记本。
我们将创建一个新文件夹以保持一切整洁。我们将文件夹命名为 ConBee II,并在该文件夹中创建一个新的 python3 应用程序
REST API 通过发出请求来工作。
我们需要导入一些库来发出请求。
import requests
import json
接下来,我们需要创建一个请求以获取 API 密钥。在新单元格中输入:
URL = "http://192.168.0.38:8090/api"
device = {'devicetype': 'application'}
p = requests.post(URL, json=device)
pretty_json = json.loads(p.text)
print (json.dumps(pretty_json, indent=2))
运行上面的代码,我们会收到如下错误:
错误是未按下链接按钮。这是指身份验证检查。我们需要授权第三方应用程序。回到 Phoscon 应用程序并单击网关选项。
在高级设置下,单击验证应用程序。您将有 60 秒的时间重新运行上一步中的代码。如果在时间内完成,则使用 API 密钥成功。您现在已经成功验证了您的应用程序,并且可以开始使用 Jupyter 配置和控制设备。
在 Juypter 中控制我们的设备
现在要发出请求,我们需要提供我们的 API 密钥。例如,我们希望看到我们的灯光。
# 代表上一步的 API 密钥
r = requests.get(URL+"/D########9/lights")
pretty_json = json.loads(r.text)
print (json.dumps(pretty_json, indent=2))
上图向我们展示了 Philip Hue Lamp 和 ConBee II 设备
请使用命令查看完整列表。使用提供的链接:
https://dresden-elektronik.github.io/deconz-rest-doc/
可以修改的参数是“状态”类别下列出的参数:
这些参数需要请求 PUT 命令。例如,我们可以关闭我们的设备。
使用 Jupyter Notebook 创建自定义界面
既然我们知道如何控制我们的设备,接下来就是将它们集成到 Jupyter 的内置 GUI 创建工具中。我们将使用 ipywidgets 库。
import ipywidgets
让我们先来了解一下 Light 的一些基本控件。我们需要一个“开启开关”和一个“关闭开关”。没有任何开关,但我们可以使用按钮。下面的代码创建了一个将“on”值更改为 True 的按钮。
btn = widgets.Button(description='On')
display(btn)
def btn_eventhandler(obj):
data = {"on": True}
r = requests.put(URL+"/D78828C329/lights/1/state", json = data)
print("Lamp is On!")
btn.on_click(btn_eventhandler)
接下来让我们关掉灯泡。这次我们将“on”值设置为 False。
btn = widgets.Button(description='OFF')
display(btn)
def btn_eventhandler(obj):
data = {"on": False}
r = requests.put(URL+"/D78828C329/lights/1/state", json = data)
print("Lamp is OFF!")
btn.on_click(btn_eventhandler)
我们甚至可以添加一个颜色选择器小部件。颜色选择器小部件返回所选颜色的 RGB 值。然而,这带来了一个小问题。deCONZ rest api 需要 HSV 中的值。HSV 颜色模型中的色调参数在 0°–360° 之间,映射到 0–65535 以获得 16 位分辨率。
首先让我们添加颜色选择器
colorpicker = widgets.ColorPicker(
concise=False,
description='Pick a color',
value="#121254",
disabled=False )
colorpicker ## Click the little blue square
接下来是获取颜色选择器中的信息并将值转换为 deCONZ 软件可以理解的可用格式。经过无数小时的调试和挠头。复制以下代码:
import math
#print(colorpicker.value)
def RGBtoHSV(colorpicker):
R = int(colorpicker.value[1:3],16)
G = int(colorpicker.value[3:5],16)
B = int(colorpicker.value[5:7],16)
R1 = R/255
G1 = G/255
B1 = B/255
#print(R1)
#print(G1)
#print(B1)
#print("\n")
Cmax = max(R1,G1,B1)
#print(Cmax)
Cmin = min(R1,G1,B1)
#print(Cmin)
delta = Cmax - Cmin
if delta != 0:
if Cmax == R1:
Hue = round(60*(((G1-B1)/delta)%6))
elif Cmax == G1:
Hue = round(60*(((B1-R1)/delta)+2))
else:
Hue = round(60*(((R1-G1)/delta)+4))
else:
if Cmax == R1:
Hue = R1
if Cmax == G1:
Hue = G1
if Cmax == B1:
Hue = B1
if Cmax != 0:
Sat = 255*(delta/Cmax)
#print("\nSaturation: {0}% of 255 is {1}".format(round((delta/Cmax)*100), round(Sat)))
else:
Sat = 0
#print("Saturation: 0%")
Vis = 255 * Cmax
Hue = round(Hue * ((2**16)/360)) ## Mapped to 360 degrees
#print("Visablity: {0}% of 255 is {1}".format(round((Cmax*100)), Vis))
#print("\nRed {0} Green {1} Blue {2}".format(R,G,B))
#print("Hue {0} Sat {1} Vis {2}".format(Hue,round(Sat),round(Vis)))
#print (json.dumps(pretty_json, indent=2))
return Hue, Sat, Vis
这会正确地从颜色选择器返回色相、饱和度和可见度。调用此函数:
Hue,Sat,Vis = RGBtoHSV(colorpicker)
接下来是简单地发送 PUT 请求,Lamp 将根据需要更改颜色。
data = {"on": True,
"bri" : Vis,
"hue" : Hue,
"sat" : Sat
}
r = requests.put(URL+"/D78828C329/lights/1/state", json = data)
#print(r)
pretty_json = json.loads(r.text)
#print (json.dumps(pretty_json, indent=2))
对于我们的最后一个示例,我们将使用滑块控制色相、饱和度和亮度!
有了这个,我们可以改变看到的光。
现在我们已经拥有了我们想要的所有 GUI 元素。我们需要将它们添加在一起以创建一个 GUI。我们可以通过使用 Juypter/Labs 创建我们自己的自定义界面来做到这一点,无需额外修改!
保存并关闭 Python3 笔记本。我们要导航到 Jupyter Labs,在搜索栏中简单输入
从这里您可以单击并拖动带有 UI 的单元格并开始创建独特的 UI
这是我们非常基本的用户界面。这可以在新选项卡中打开,如下所示。
本文转载自:电路城
以上内容翻译自网络,原作者:Adam Taylor,如涉及侵权,可联系删除。