使用HomePod,Raspberry Pi和Node.js的公寓自动化



克里斯·霍金斯(Chris Hawkins)为您翻译了一篇文章 ,其中谈到了将自己的公寓变成智能家居。 苹果的HomePod用作基础,但是当然也可以使用其他系统。

我有一个Apple HomePod在家中运行,通过向Siri发出简单的请求,它有助于控制房屋中的某些系统(例如,智能灯)。 该系统可在家中和室外(电话上都有智能助手)运行。

Skillbox建议:为期两年的实践课程“我是PRO Web开发人员”

我们提醒您: 对于所有“哈勃”读者来说,使用“哈勃”促销代码注册任何Skillbox课程时均可享受10,000卢布的折扣。

最初,我对使用语音命令管理房屋持怀疑态度,因为并非所有东西都能被助手(不仅是Siri)正确识别。 但是后来这成为一种习惯。 由于Hue灯没有物理开关,并且在应用程序中您需要执行一些操作来控制照明,所以我提请Siri工作。

然后,我想开始使用语音助手来控制房屋中的其他系统,例如电视或控制台。 以电视为例,我发现了简单IP控制-一种通过TCP发送命令来控制Sony Bravia的方法。

自定义Siri


在2018年下半年,Apple为所有iOS用户启动了Shortcuts应用程序。 它使您无需编写代码即可自动使用电话(或智能家居)进行工作。

该应用程序具有许多内置命令。 他缺乏使用TCP命令的能力,尽管存在使用URL的机制。

另外,您可以使用Objective-C或Swift编写自己的模块。 我决定不这样做,因为将来我可以将HomePod更改为其他助手。 相反,我想编写一个可以响应Siri命令的Web应用程序。

索尼Bravia电视控制


带着电视命令手册,我在Node.js Express(Github)编写了一个应用程序,该程序教会了我如何响应一些常见命令。 我从打开音量开始。

setPowerStatus命令可完成我们所需的一切。



标头由字符*和s组成,它们是静态的,用于所有命令。 然后,第三个字节用于命令。 有四个含义可以保留这个位置。 C表示命令(在电视上发送命令),E表示查询(检查某个参数的当前值,例如,音量),A表示答案(响应命令和查询发送),N表示通知(事件通知,如关闭音量) )

为了实现我的目标,我必须研究Sony的JSON-RPC文档。 事实证明,基于HTTP的JSON-RPC的性质使得简化任务和减少代码量成为可能。

使用JSON-RPC API很简单。 以服务(系统),命令(getPowerStatus)加上参数(真或假)为例,形成一个HTTP请求,然后将其发送到电视。

let body = JSON.stringify({ method: command, id: ++this.id, params: params, version: "1.0", }); return new Promise((resolve, reject) => { fetch('http://' + this.ip + ':' + this.port + '/sony/' + service, { method: 'post', headers: { 'X-Auth-PSK': this.psk }, body: body, }).then(response => { return response.json(); }).then(response => { if (response.error && (!response.result || response.result.length === 0)) { reject({ code: response.error[0] }); } else { resolve(response.result[0]); } }).catch(error => { reject(error); }); }); 

默认情况下,使用HTTP请求标头中发送的预密钥执行身份验证。 但是,通过accessControl有一种更安全,更方便的方法。 在这种情况下,我们可以向电视发送命令,并通过基本的HTTP身份验证安全地交换代码。 一次执行身份验证后,将使用cookie执行进一步的身份验证。

但是我的电视受到路由器上配置的防火墙的保护,因此我使用了预共享密钥。

打开Xbox One


Xbox当然需要不同的设置。 Microsoft似乎已决定不使用REST API,因此该工作是使用UDP数据包完成的。

幸运的是,Node.js有一个dgram模块,可以直接使用USP的所有功能。 那就是我最后得到的。

 turnOn() { let socket = dgram.createSocket('udp4'); let powerPayload = new Buffer('\x00' + String.fromCharCode(this.liveId.length) + this.liveId.toUpperCase() + '\x00'); let powerHeader = Buffer.concat([new Buffer('dd0200', 'hex'), new Buffer(String.fromCharCode(powerPayload.length)), new Buffer('\x00\x00')]); let powerPacket = Buffer.concat([powerHeader, powerPayload]); return this._sendPacket(socket, powerPacket); } _sendPacket(socket, buffer) { return new Promise((resolve, reject) => { socket.send(buffer, 0, buffer.length, Constants.xboxPort, this.ip, function(err) { socket.close(); if (err) { return reject(err); } resolve(); }); }); } 

对于配置,我使用了ID设备列表, 可以在此处找到 。 如果您只想从我的存储库中获取代码,则需要替换config.json文件中的ID。

配置Siri的快捷方式


为了使Siri能够执行我刚创建的命令,她需要一个助手。 我从Raspberry Pi创建了它,因为“ raspberry”在各个方面都适用。 为此,我购买了支持Wi-Fi的Pi 3 Model B +。

Raspbian具有要配置的GUI。 我已连接到Wi-Fi,然后关闭了显示器并继续使用SSH。 为了确保Web应用程序始终处于活动状态,我在systemd中配置了服务激活套接字,以便如果Node.js进程崩溃,系统可以自动重新启动它。

实际上,Siri的快捷方式是最简单的工作阶段。 这是具有本地语音命令支持的直观应用程序。 默认情况下,它已经知道如何使用HomePod,因此无需额外配置任何内容。



全部放在一起


由于我的电视运行在Android上,因此它支持Netflix和YouTube等应用。 考虑到这一点,我创建了启动这些服务的命令。 另外,我添加了命令来控制音量,电视模式,暂停和播放内容。

这是我创建所有内容的示例 。 我还尝试使该项目模块化,因此添加其他SmartTV型号不是问题。

这是一个示例模块,其中包括Xbox,电视并激活第一个HDMI端口。

 router.post('/turnOnXboxAndTV', function(req, res, next) { Promise.all([ xbox.turnOn(), tv.turnOn() .then(() => new Promise(resolve => setTimeout(resolve, 2000))) .then(() => tv.setInput(config.scripts.xboxInput)), ]).then(() => { res.sendStatus(200); }).catch((error) => { res.status(500).send(error); }); }); 

这就是实践中所有工作的方式。


不幸的是,Siri的功能不是很好。 来自亚马逊的同一Alexa具有更广泛的功能和非常强大的API。 我认为,基于Alexa,您可以创建更严肃的项目。

Skillbox建议:

Source: https://habr.com/ru/post/zh-CN438292/


All Articles