📜 ⬆️ ⬇️

Apartment Automation with HomePod, Raspberry Pi and Node.js



We translated for you an article by Chris Hawkins in which he talks about turning his apartment into a smart home. The HomePod from Apple is used as a base, but, of course, other systems can also be used.

I have an Apple HomePod at home that helps control certain systems in the house (for example, smart lamps) with the usual request to Siri. The system works both from home and outside of it (there is a smart assistant on the phone).

Skillbox recommends: a two-year hands-on course “I am a web developer PRO” .

We remind: for all readers of "Habr" - a discount of 10,000 rubles when recording for any Skillbox course on the promotional code "Habr".

Initially, I was skeptical about the management of the house with the help of voice commands, because not everything is recognized by the assistants (not only Siri) correctly. But then it became a habit. Since Hue lamps do not have a physical switch, and in the application you need to take a few actions to control the lighting, I got Siri involved.

Then I wanted to start using a voice assistant to control other systems in the house, for example, a TV or a console. In the case of TV, for example, I discovered Simple IP Control, a method for controlling my Sony Bravia by sending commands via TCP.

Customize Siri


In the second half of 2018, Apple opened the Shortcuts application for all iOS users. It allows you to automate the work with the phone (or smart home) without the need to write code.

The application has many built-in commands. What it lacks is the ability to use TCP commands, although there is a mechanism for working with URLs.

Plus, you can write your own modules on Objective-C or Swift. I decided not to do this, because in the future I can change my HomePod to another assistant. Instead, I wanted to write a web application that can respond to Siri commands.

Sony Bravia TV Management


Armed with a manual with commands for my TV, I wrote an application on Node.js Express (Github) , which taught me how to respond to some of the common commands. I started with the power and volume.

The setPowerStatus command does everything we need.



The header consists of the characters * and s, which are static and used for all commands. Then the third byte (s) is used for Command. There are four values ​​that can take this position. C for Command (sending a command on TV), E for Inquiry (checking the current value of a certain parameter, for example, volume), A - Answer (sent in response to Commands and Enquiries) and N for Notify (notification of events, such as turning off the volume ).

To achieve my goal, I had to study the Sony's JSON-RPC documentation. As it turned out, the nature of JSON-RPC over HTTP simplified the task and reduced the amount of code.

Working with the JSON-RPC API was simple. Take, for example, a service (system), a command (getPowerStatus) plus parameters (true or false) and form an HTTP request, which we then send to the TV.

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); }); }); 

By default, authentication is performed using a pre-key sent in the HTTP request header. But there is a safer and more convenient way to do this with accessControl. In this case, we can send a command to the TV and carry out a secure code exchange with basic HTTP authentication. After authentication is performed once, further authorization is performed using a cookie.

But my TV is protected by a firewall configured on the router, so I used the preshared key.

Turn on Xbox One


The Xbox, of course, required a different setting. Microsoft seems to have decided not to use the REST API, so the work was done using UDP packets.

Fortunately, Node.js has a dgram module that works out of the box with all the features of USP. That's what I got in the end.

 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(); }); }); } 

For nastrioki I used the list of ID-devices, which can be found here . If you just want to take the code from my repository, then you need to replace the ID in the config.json file.

Configuring Shortcuts for Siri


In order for Siri to carry out the commands I just created, she needs an assistant. I created it from Raspberry Pi, because the “raspberry” is suitable for all parameters. For this, I bought a Pi 3 Model B + that supports Wi-Fi.

Raspbian has a GUI for customization. I connected to Wi-Fi, then turned off the display and continued to work on SSH. In order to make sure that the web application is constantly active, I configured the service activation socket in systemd, so if the Node.js process had crashed, the system could automatically restart it.

Actually, Shortcuts for Siri were the easiest stage of the work. This is an intuitive application with native support for voice commands. It is by default already able to work with HomePod, in addition, nothing needed to be configured.



Putting it all together


Since my TV runs on Android, it supports applications like Netflix and YouTube. With this in mind, I created commands to run these services. In addition, I added commands to control the volume, TV mode, pause and play content.

Here are examples of everything that I have created. I also tried to make the project modular, so adding other SmartTV models is not a problem.

Here is an example of a module that turns on the Xbox TV and activates the first HDMI port.

 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); }); }); 

And this is how it all works in practice.


Unfortunately, the functionality of Siri is not too good. Amazon’s Alexa also has a much wider range of capabilities and a very powerful API. I think on the basis of Alexa you can create much more serious projects.

Skillbox recommends:

Source: https://habr.com/ru/post/438292/