两年前就想自己写Homebridge插件,奈何没有nodejis功底,而且这个js代码的可读性真的太差了,当时根本看不懂这些插件写的是什么,好在最近重新看了homebridge-aqara插件,内部重新整理了,花了几天算是看懂了,最后我进行了修改,将每个控件直接解耦,每个控件一个.js文件,非常方便。

而且去年我还尝试在windows上面安装homebridge,发现各种问题,今年重新试了一下,竟然一次成功,比linux上面简单不少,终于可以抛弃linux了,调试各种麻烦。

Homebridge插件内支持的设备类型,见HomeKitTypes.js,可以自己搜索一下。

具体的见我的代码,我直接把整个上传了,内部按照C语言的格式整理好了,也写了注释。

 

下面是我摘取的一部分,可以看到灯的一些属性。

**

 * Characteristic "Color Temperature"

 */

Characteristic.ColorTemperature = function() {

    Characteristic.call(this'Color Temperature''000000CE-0000-1000-8000-0026BB765291');

    this.setProps({

      format: Characteristic.Formats.UINT32,

      maxValue: 500,

      minValue: 140,

      minStep: 1,

      perms: [Characteristic.Perms.READCharacteristic.Perms.WRITECharacteristic.Perms.NOTIFY]

    });

    this.value = this.getDefaultValue();

  };

  

  inherits(Characteristic.ColorTemperatureCharacteristic);

  

  Characteristic.ColorTemperature.UUID = '000000CE-0000-1000-8000-0026BB765291';

 

  

/**

 * Service "Motion Sensor"

 */

Service.MotionSensor = function(displayNamesubtype) {

    Service.call(thisdisplayName'00000085-0000-1000-8000-0026BB765291'subtype);

  

    // Required Characteristics

    this.addCharacteristic(Characteristic.MotionDetected);

  

    // Optional Characteristics

    this.addOptionalCharacteristic(Characteristic.StatusActive);

    this.addOptionalCharacteristic(Characteristic.StatusFault);

    this.addOptionalCharacteristic(Characteristic.StatusTampered);

    this.addOptionalCharacteristic(Characteristic.StatusLowBattery);

    this.addOptionalCharacteristic(Characteristic.Name);

  };

  

  inherits(Service.MotionSensorService);

  

  Service.MotionSensor.UUID = '00000085-0000-1000-8000-0026BB765291';

  

 

 

/**

 * Service "Outlet" 电源插座

 */

Service.Outlet = function(displayNamesubtype) {

    Service.call(thisdisplayName'00000047-0000-1000-8000-0026BB765291'subtype);

  

    // Required Characteristics

    this.addCharacteristic(Characteristic.On);

    this.addCharacteristic(Characteristic.OutletInUse);

  

    // Optional Characteristics

    this.addOptionalCharacteristic(Characteristic.Name);

  };

  

  inherits(Service.OutletService);

  

  Service.Outlet.UUID = '00000047-0000-1000-8000-0026BB765291';

 

/**

 * Service "Lightbulb"  灯泡

 */

Service.Lightbulb = function(displayNamesubtype) {

    Service.call(thisdisplayName'00000043-0000-1000-8000-0026BB765291'subtype);

  

    // Required Characteristics 所需特性

    this.addCharacteristic(Characteristic.On);                  //开关

  

    // Optional Characteristics 可选特征

    this.addOptionalCharacteristic(Characteristic.Brightness);  //亮度

    this.addOptionalCharacteristic(Characteristic.Hue);         //色调

    this.addOptionalCharacteristic(Characteristic.Saturation);  //饱和度

    this.addOptionalCharacteristic(Characteristic.Name);        //名称

    this.addOptionalCharacteristic(Characteristic.ColorTemperature);//色温 //Manual fix to add temperature

  };

  

  inherits(Service.LightbulbService);

  

  Service.Lightbulb.UUID = '00000043-0000-1000-8000-0026BB765291';

 

 

windows下的配置文件在 用户文件夹下 .homebridge 中

{

  "bridge": {

    "name""Homebridge2",

    "username""12:23:3D:E3:CE:32",

    "port"51826,

    "pin""124-42-153"

  },

  

  "platforms": [

    {

      "platform""AqaraPlatform",

      "sid":["6409802da3ca"],

      "password":["1234567812345678"]

    }

  ],

  "accessories": [

     

  ]

}

 

 

比如下面是我写的一个插件,Platform_Switch.js

//电源开关

const inherits = require('util').inherits;                              //引用继承方法

const BaseParser = require('./BaseParser').BaseParser;                  //引用基类

const mBaseCommander = require('./BaseCommander').BaseCommander;        //引用基类

const crypto = require('crypto');                                       //引用加密方法

const iv = require('./Config').iv;                                      //加密公钥

 

//申明Parser

SwitchParser = function(platform

{

    this.init(platform);

    this.commanders = {};

}

 

//从基类继承Parser

inherits(SwitchParserBaseParser);

//具体方法实现

SwitchParser.prototype.parse = function(reportrinfo

{

    var deviceSid = report['sid'];

    var gatewaySid = this.platform.gatewaySids[deviceSid];

    var data = JSON.parse(report['data']);

    

    // channel_0 can be three states: on, off, unknown.

    // we can't do anything when state is unknown, so just ignore it.

    if (data.channel_0 === undefined

    {

        this.platform.log.warn("warn %s(sid:%s):channel_0's state is unknown, ignore it."report['model'], deviceSid);

    } 

    else 

    {

        var on = (data.channel_0 === 'on');

        var commander;

        //this.platform.log.warn("channel_0:%s bright_0:%s",on,Brightness );

        //下发命令到设备

        if (deviceSid in this.commanders

        {

            commander = this.commanders[deviceSid];

        } 

        else 

        {

            commander = new SwitchCommander(this.platformdeviceSidreport['model']);

            this.commanders[deviceSid] = commander;

        }

        var ThisValue = {};

        ThisValue.channel_0 = on;                       //开关

        commander.SetValueCache(ThisValue);             //存储状态

        //控制开关

        this.setSwitch(gatewaySiddeviceSid'SWITCH' + deviceSidoncommander);    //初始化命令回调接口或设备命令到homekit,设备主动上传状态

    }

}

 

 

 

//与AccessoryFactory对接,与homebridge通信,初始化控件与监听接口(从AccessoryFactory中分离,以后增加一个设备类型只需修改各自独立的文件,而无需修改AccessoryFactory.js)

SwitchParser.prototype.setSwitch = function(gatewaySiddeviceSiduuidSeedoncommander

{

    this.platform.log.warn("setSwitch: %s->channel_0:%s",deviceSidon);

    //开关控制

    isNaN(on) || this.factory.findServiceAndSetValue(

        gatewaySid,

        deviceSid,

        this.factory.UUIDGen.generate(uuidSeed),

        this.factory.Accessory.Categories.Switch,

        this.factoryService.Switch,

        this.factory.Characteristic.On,

        on,

        commander); //开关  

}

 

//==================================下面是与设备通信相关==========================================

// Commander 

SwitchCommander = function(platformdeviceSiddeviceModel)

{

    this.init(platformdeviceSiddeviceModel);

}

inherits(SwitchCommanderBaseCommander);

 

//用来执行手机端命令发送到设备

SwitchCommander.prototype.send = function(CharacteristiccharacteristicTypeValue

{

    var platform = this.platform;

    var gatewaySid = platform.gatewaySids[this.deviceSid];

    var password = platform.passwords[gatewaySid];

    // No password for this device, please edit ~/.homebridge/config.json

    if (!password

    {

        platform.log.error("No password for gateway %s, please edit ~/.homebridge/config.json 出现这个问题请重新发送一次设备列表"gatewaySid);

        return;

    }

    var cipher = crypto.createCipheriv('aes-128-cbc'passwordiv);        //使用aes-128加密

    var gatewayToken = platform.gatewayTokens[gatewaySid];

    // platform.log.debug("cipher gateway %s, device %s, password %s", gatewaySid, this.deviceSid, password);

    var key = "hello";

    if (cipher && gatewayToken

    {

        key = cipher.update(gatewayToken"ascii""hex");

        cipher.final('hex'); // Useless data, don't know why yet.

    }

 

    if(characteristicType == Characteristic.On//开关设置

    {

        this.SetValue.channel_0 = Value;                      //记录当前要设置的灯状态

        //开始发送数据了

         //核心data数据,每个命令对应的不一样

         var data = 

         {

             channel_0      :   this.SetValue.channel_0?'on':'off',         //开关

             key :  key                                                     //密匙

         }

 

         //通讯基本的json对象格式

         var JsonObj = 

         {

             cmd : 'write',                  //命令码

             model : this.deviceModel,       //设备类型

             sid : this.deviceSid,           //设备id

             data :JSON.stringify(data)      //data转换为字符串

         }

 

        var command  = JSON.stringify(JsonObj) + '\r\n';//转换为json  

        this.sendCommand(command);

    }

    else

    {

        platform.log.error("无效的characteristicType%s",characteristicType);

    }

}

 

//申明外部接口

module.exports = {

    SwitchParser

  }

  

  

进行了解耦,每个设备就一个文件,互补干扰

SwitchParser.prototype.parse = function(reportrinfo

这个方法中对来自设备的数据进行解析,解析后通过

this.setSwitch(gatewaySiddeviceSid'SWITCH' + deviceSidoncommander);    //初始化命令回调接口或设备命令到homekit,设备主动上传状态

进行控制。

SwitchCommander.prototype.send = function(CharacteristiccharacteristicTypeValue

这个是与设备通讯的接口

 

新增一个接口后只需要在 AqaraPlatform.js中添加一个引用,然后将接口放入到数组中。

var SwitchParser = require('./Platform_Switch').SwitchParser;   //引用Platform    

 

//接口注册                            

function AqaraPlatform(logconfigapi) {

  // Initialize

  this.log = log;

  this.factory = new AqaraAccessoryFactory(logconfigapi);

  this.parsers = {

    'sensor_ht' : new TemperatureAndHumidityParser(this),

    'motion' : new MotionParser(this),

    'magnet' : new ContactParser(this),

    'ctrl_neutral1' : new LightSwitchParser(this),

    'ctrl_neutral2' : new DuplexLightSwitchParser(this),

    'ctrl_ln1' : new LightSwitchParser(this),

    'ctrl_ln2' : new DuplexLightSwitchParser(this),

    '86sw1' : new EightySixSwitchParser(this),

    '86sw2' : new DuplexEightySixSwitchParser(this),

    'plug' : new PlugSwitchParser(this),

 

     

    'Bright_Light' : new BrightnessLightParser (this),      //可调亮度的灯

    'Lightbulb' : new LightbulbParser(this),                //灯泡  

    'Colored_Light' : new ColoredLightParser(this),         //彩灯

    'Outlet' : new OutletParser(this),                      //电源插座

    'Switch' : new SwitchParser(this),                      //电源开关

    'DoubleSwitch' : new DoubleSwitchParser(this),          //双通道电源开关

  };

 

 

通讯可以看我之前写的博文,通讯json还是一样的

先发送

{

    "cmd""get_id_list_ack",

    "sid""6409802da3ca",

    "token""1234567812345678",

    "data""[\"4000\"]"

}

 

再发送

{

    "cmd""return_read",

    "model""Switch",

    "sid""4000",

    "data""{\"channel_0\"\"on\"}"

}

 

Homebridge插件编写-基于homebridge-aqara

 

Homebridge插件编写-基于homebridge-aqara

 

 

Homebridge插件编写-基于homebridge-aqara

 

[第一步]homekit智能家居,homebridge与homebridge-aqara通信协议:https://blog.csdn.net/cp1300/article/details/52970883

相关文章:

  • 2022-12-23
  • 2021-10-31
  • 2021-06-29
  • 2022-12-23
  • 2021-08-09
  • 2022-02-10
  • 2021-08-04
  • 2021-09-14
猜你喜欢
  • 2021-06-18
  • 2021-12-24
  • 2021-12-12
  • 2021-09-12
  • 2021-12-01
  • 2022-12-23
  • 2021-05-17
相关资源
相似解决方案