树莓派3B+ 智能家居(HomeKit)

树莓派3B+ 智能家居(HomeKit)

当今科技发展日新月异,越来越多的新兴技术步入人们生活,智能家居同样也不例外,然后人们面对新科技却望而却步,因为整套设备的价格是非常昂贵的,而且现在还没有一个厂商能提供一套完整且稳定的系统,导致现在还不能快速普及。如果你想尝尝鲜,那么,一个树莓派就能为你创建一个这样的基础环境。

1.安装脚本

安装过程比较累赘,这里就不做过多的解释了。
安装所需的库 :Node 和 HAP-NodeJS(Node版本为8.2.1,HAP-NodeJS更新为Nov 6, 2017)
打包链接:http://download.csdn.net/download/kxwinxp/10124545

完整实现脚本如下:

#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

echo "
+----------------------------------------------------------------------
|                 HAP-NodeJS FOR Debian raspberry
+----------------------------------------------------------------------
|            Copyright © 2017 kioye All rights reserved.
+----------------------------------------------------------------------
"
#make sure your confirm. 
read -p "Do you want to install HAP-NodeJS to the $setup_path directory now?(y/n): " go;

if [ "$go" == 'n' ]||[ "$go" == 'N' ];then
    exit;
fi
# get into directory of application
cd ~
mkdir application
cd application

sudo apt-get install -y git avahi-daemon avahi-discover libnss-mdns libavahi-compat-libdnssd-dev build-essential
# apt-get update --fix-missing -y
sudo service avahi-daemon start
wget -O node.tar.gz https://nodejs.org/dist/v8.2.1/node-v8.2.1-linux-armv7l.tar.xz
tar -zxvf node.tar.gz
mv node-*l usr
sudo cp -rf usr /
# install node base cross-platform
sudo npm install -g -y node-gyp
# install C++ lib
sudo apt-get install -y libavahi-compat-libdnssd-dev
# download HAP-NodeJS
git clone https://github.com/KhaosT/HAP-NodeJS.git
sudo chmod -R 777 /root ./HAP-NodeJS
# get into HAP-NodeJS directory
cd HAP-NodeJS
# install some access for HAP-NodeJS
sudo npm install -y node-persist debug mdns fast-srp-hap ed25519 buffer-shims curve25519-n2 ip python-shell
cd ..
echo "
+----------------------------------------------------------------------
|                    HAP-NodeJS Installed finish!!
+----------------------------------------------------------------------
|   start in Bridged mode:
|         sudo node HAP-NodeJS/BridgedCore.js
+----------------------------------------------------------------------
|   run as an independent HomeKit device:
|         sudo node HAP-NodeJS/Core.js
+----------------------------------------------------------------------
"
exit 0

2.添加到自启动

sudo vim /etc/rc.local
// 在 exit 0 前添加如下:
# HAP-NodeJS 开机自启脚本(nohup为后台执行,run.log为运行记录。)
sudo nohup node /home/pi/application/HAP-NodeJS/Core.js >/home/pi/application/HAP-NodeJS/run.log 2>&1 &
# python GPIO口初始化!
python /home/pi/application/HAP-NodeJS/python/init.py

GPIO初始化口,我接下来要用的是 11、13和15口。
脚本如下:

vim ~/application/HAP-NodeJS/python/init.py
// -------------请完整复制粘贴如下内容!!------------------
#!/usr/bin/env python
import RPi.GPIO as GPIO
import sys

def setup(p):
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(p, GPIO.OUT)


GPIO.setwarnings(False)
# 初始化 11、13和15口。
arr={11,13,15}
for gp in arr:
    setup(gp);


sys.exit(0)

3.HAP-NodeJS介绍

GitHub:https://github.com/KhaosT/HAP-NodeJS


HAP Nodejs是一个通过Nodejs搭建的HomeKit服务器。因此,它能直接和苹果 家庭(home)应用相连。苹果设备又支持Siri,故可以直接通过Siri控制HomeKit设备。

它有两种启动模式:

  • 桥接模式启动HAP服务器:
    sudo node HAP-NodeJS/BridgedCore.js
  • 独立模式(各配件作为一个的HomeKit设备启动):
    sudo node HAP-NodeJS/Core.js

可自己定义配件:

  • 格式为:accessories/**_accessory.js文件
    **为简短的描述,所有此类定义的附件都会在服务器上加载。(非此类将不会加载!)

4.模拟配件


4.1 模拟一个两级亮度的灯

该配件是通过python-shell来控制GPIO,故需安装python的gpio包。

sudo apt-get install -y python-rpi.gpio

一个控制灯的附件代码:

功能:控制 GPIO 13 和 15 口,分别控制灯开关和亮度(两级),默认高电平为开启。
可以直接在var powergp='13';var brightnessgp='15';修改GPIO口。

树莓派3B+ 智能家居(HomeKit)_第1张图片

// 创建MyTableLight_accessory.js
sudo vim ~/application/HAP-NodeJS/accessories/MyTableLight_accessory.js
// -------------请完整复制粘贴如下内容!!------------------
var Accessory = require('../').Accessory;
var Service = require('../').Service;
var Characteristic = require('../').Characteristic;
var uuid = require('../').uuid;
var PythonShell = require('python-shell');
var powergp='13';
var brightnessgp='15';

var LightController = {
  name: "My Table Light", //name of accessory
  pincode: "031-45-154",
  username: "FA:3C:ED:5A:1A:1F", // MAC like address used by HomeKit to differentiate accessories. 
  manufacturer: "HAP-NodeJS", //manufacturer (optional)
  model: "v1.0", //model (optional)
  serialNumber: "A12S345KGB", //serial number (optional)

  power: false, //curent power status
  brightness: 100, //current brightness
  hue: 0, //current hue
  saturation: 0, //current saturation

  outputLogs: true, //output logs

  setPower: function(status) { //set power of accessory
    if(this.outputLogs) {
        console.log("Turning the '%s' %s", this.name, status ? "on" : "off");
    }
    PythonShell.run('../../home/pi/application/HAP-NodeJS/python/gpio.py', {args:[powergp+':'+(status?1:0)]}, function (err,results) {
      if (err) console.log(err);
    });
    this.power = status;
  },

  getPower: function() { //get power of accessory
    PythonShell.run('../../home/pi/application/HAP-NodeJS/python/gpio.py', {args:[powergp+':g']}, function(err,results){
        console.log('results: %j', results);
        var resultMap=eval('('+results.pop()+')');
        this.power=(resultMap[powergp]==1)?true:false;
    });
    if(this.outputLogs) console.log("'%s' is %s.", this.name, this.power ? "on" : "off");
    return this.power;
  },

  setBrightness: function(brightness) { //set brightness
    if(this.outputLogs) console.log("Setting '%s' brightness to %s", this.name, brightness);
    PythonShell.run('../../home/pi/application/HAP-NodeJS/python/gpio.py', {args:[brightnessgp+':'+((brightness <= 50)?1:0)]}, function (err,results) {
      if (err) console.log(err);
    });
    this.brightness = brightness;
  },

  getBrightness: function() { //get brightness
    PythonShell.run('../../home/pi/application/HAP-NodeJS/python/gpio.py', {args:[brightnessgp+':g']}, function(err,results){
        console.log('results: %j', results);
        var resultMap=eval('('+results.pop()+')');
        this.brightness=(resultMap[brightnessgp]==1)?50:100;
    });
    if(this.outputLogs) console.log("'%s' brightness is %s", this.name, this.brightness);
    return this.brightness;
  },

  setSaturation: function(saturation) { //set brightness
    if(this.outputLogs) console.log("Setting '%s' saturation to %s", this.name, saturation);
    this.saturation = saturation;
  },

  getSaturation: function() { //get brightness
    if(this.outputLogs) console.log("'%s' saturation is %s", this.name, this.saturation);
    return this.saturation;
  },

  setHue: function(hue) { //set brightness
    if(this.outputLogs) console.log("Setting '%s' hue to %s", this.name, hue);
    this.hue = hue;
  },

  getHue: function() { //get hue
    if(this.outputLogs) console.log("'%s' hue is %s", this.name, this.hue);
    return this.hue;
  },

  identify: function() { //identify the accessory
    if(this.outputLogs) console.log("Identify the '%s'", this.name);
  }
}

// Generate a consistent UUID for our light Accessory that will remain the same even when
// restarting our server. We use the `uuid.generate` helper function to create a deterministic
// UUID based on an arbitrary "namespace" and the word "light".
var lightUUID = uuid.generate('hap-nodejs:accessories:light' + LightController.name);

// This is the Accessory that we'll return to HAP-NodeJS that represents our light.
var lightAccessory = exports.accessory = new Accessory(LightController.name, lightUUID);

// Add properties for publishing (in case we're using Core.js and not BridgedCore.js)
lightAccessory.username = LightController.username;
lightAccessory.pincode = LightController.pincode;

// set some basic properties (these values are arbitrary and setting them is optional)
lightAccessory
  .getService(Service.AccessoryInformation)
    .setCharacteristic(Characteristic.Manufacturer, LightController.manufacturer)
    .setCharacteristic(Characteristic.Model, LightController.model)
    .setCharacteristic(Characteristic.SerialNumber, LightController.serialNumber);

// listen for the "identify" event for this Accessory
lightAccessory.on('identify', function(paired, callback) {
  LightController.identify();
  callback();
});

// Add the actual Lightbulb Service and listen for change events from iOS.
// We can see the complete list of Services and Characteristics in `lib/gen/HomeKitTypes.js`
lightAccessory
  .addService(Service.Lightbulb, LightController.name) // services exposed to the user should have "names" like "Light" for this case
  .getCharacteristic(Characteristic.On)
  .on('set', function(value, callback) {
    LightController.setPower(value);

    // Our light is synchronous - this value has been successfully set
    // Invoke the callback when you finished processing the request
    // If it's going to take more than 1s to finish the request, try to invoke the callback
    // after getting the request instead of after finishing it. This avoids blocking other
    // requests from HomeKit.
    callback();
  })
  // We want to intercept requests for our current power state so we can query the hardware itself instead of
  // allowing HAP-NodeJS to return the cached Characteristic.value.
  .on('get', function(callback) {
    callback(null, LightController.getPower());
  });

// To inform HomeKit about changes occurred outside of HomeKit (like user physically turn on the light)
// Please use Characteristic.updateValue
// 
// lightAccessory
//   .getService(Service.Lightbulb)
//   .getCharacteristic(Characteristic.On)
//   .updateValue(true);

// also add an "optional" Characteristic for Brightness
lightAccessory
  .getService(Service.Lightbulb)
  .addCharacteristic(Characteristic.Brightness)
  .on('set', function(value, callback) {
    LightController.setBrightness(value);
    callback();
  })
  .on('get', function(callback) {
    callback(null, LightController.getBrightness());
  });

// also add an "optional" Characteristic for Saturation
lightAccessory
  .getService(Service.Lightbulb)
  .addCharacteristic(Characteristic.Saturation)
  .on('set', function(value, callback) {
    LightController.setSaturation(value);
    callback();
  })
  .on('get', function(callback) {
    callback(null, LightController.getSaturation());
  });

// also add an "optional" Characteristic for Hue
lightAccessory
  .getService(Service.Lightbulb)
  .addCharacteristic(Characteristic.Hue)
  .on('set', function(value, callback) {
    LightController.setHue(value);
    callback();
  })
  .on('get', function(callback) {
    callback(null, LightController.getHue());
  });

准备一个python脚本控制GPIO口:

sudo vim ~/application/HAP-NodeJS/python/gpio.py
// -------------请完整复制粘贴如下内容!!------------------
#!/usr/bin/env python
import RPi.GPIO as GPIO
import sys

def init(gp):
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(gp, GPIO.OUT)

GPIO.setwarnings(False)
# simple argument echo script
ret={}
for arg in sys.argv[1:]:
    #print arg
    args=arg.split(':')
    init(int(args[0]))
    if args[1]=='g':
        ret[args[0]]=GPIO.input(int(args[0]))
    elif args[1]=='0':
        GPIO.output(int(args[0]), GPIO.LOW)
    elif args[1]=='1':
        GPIO.output(int(args[0]), GPIO.HIGH)
    #setup(int(v))

print ret
sys.exit(0)

4.2 模拟一个开关插座

我这个插座是接的音响,所以叫“My sound”,不要见怪。
这里使用的是 GPIO 11 口,默认是高电平是开启。
代码如下:

// 创建MySound_accessory.js
sudo vim ~/application/HAP-NodeJS/accessories/MySound_accessory.js
// -------------请完整复制粘贴如下内容!!------------------
var Accessory = require('../').Accessory;
var Service = require('../').Service;
var Characteristic = require('../').Characteristic;
var uuid = require('../').uuid;
var err = null; // in case there were any problems
var PythonShell = require('python-shell');
var soundgp='11';

// here's a fake hardware device that we'll expose to HomeKit
var FAKE_OUTLET = {
    setPowerOn: function(on) {
    console.log("Turning the MySound %s!...", on ? "on" : "off");
    PythonShell.run('../../home/pi/application/HAP-NodeJS/python/gpio.py', {args:[soundgp+':'+(on?1:0)]}, function (err,results) {
      if (err) console.log(err);
    });
    FAKE_OUTLET.powerOn=on;
  },
    identify: function() {
    console.log("Identify the MySound.");
    }
}

// Generate a consistent UUID for our MySound Accessory that will remain the same even when
// restarting our server. We use the `uuid.generate` helper function to create a deterministic
// UUID based on an arbitrary "namespace" and the accessory name.
var outletUUID = uuid.generate('hap-nodejs:accessories:MySound');

// This is the Accessory that we'll return to HAP-NodeJS that represents our fake light.
var outlet = exports.accessory = new Accessory('MySound', outletUUID);

// Add properties for publishing (in case we're using Core.js and not BridgedCore.js)
outlet.username = "1A:2B:3C:4D:5D:FG";
outlet.pincode = "031-45-154";

// set some basic properties (these values are arbitrary and setting them is optional)
outlet
  .getService(Service.AccessoryInformation)
  .setCharacteristic(Characteristic.Manufacturer, "Oltica")
  .setCharacteristic(Characteristic.Model, "Rev-1")
  .setCharacteristic(Characteristic.SerialNumber, "A1S2NASF88EW");

// listen for the "identify" event for this Accessory
outlet.on('identify', function(paired, callback) {
  FAKE_OUTLET.identify();
  callback(); // success
});

// Add the actual MySound Service and listen for change events from iOS.
// We can see the complete list of Services and Characteristics in `lib/gen/HomeKitTypes.js`
outlet
  .addService(Service.Outlet, "My Sound") // services exposed to the user should have "names" like "Fake Light" for us
  .getCharacteristic(Characteristic.On)
  .on('set', function(value, callback) {
    FAKE_OUTLET.setPowerOn(value);
    callback(); // Our fake Outlet is synchronous - this value has been successfully set
  });

// We want to intercept requests for our current power state so we can query the hardware itself instead of
// allowing HAP-NodeJS to return the cached Characteristic.value.
outlet
  .getService(Service.Outlet)
  .getCharacteristic(Characteristic.On)
  .on('get', function(callback) {

    // this event is emitted when you ask Siri directly whether your light is on or not. you might query
    // the light hardware itself to find this out, then call the callback. But if you take longer than a
    // few seconds to respond, Siri will give up.

    var err = null; // in case there were any problems

    if (FAKE_OUTLET.powerOn) {
      console.log("Are we on? Yes.");
      callback(err, true);
    }
    else {
      console.log("Are we on? No.");
      callback(err, false);
    }
  }); 

控制也是通过调用 gpio.py 的 python 脚本,和 4.1 里面的 python 脚本一样的。

好了,现在可以重启一下树莓派。

5.将HomeKit设备添加到家庭中

树莓派3B+ 智能家居(HomeKit)_第2张图片

如图,选择将这些设备添加进去,输入认证代码 03145154(这个可以在accessary.js修改)。

然后就可以愉快使用 Siri 进行语音控制了!

你可能感兴趣的:(树莓派3B+(⊙o⊙)开源硬件)