1.2.4.5 场景联动

优质
小牛编辑
123浏览
2023-12-01

更新时间:2018-09-14 16:44:18

本程序设计旨在给开发者展示如何通过 miio 接入小米的智能设备,如何编写场景联动程序,基本组网图如下所示:

miio设备组网图.jpg | center | 747x420

基本原理

TinyEngine 为接入小米设备,在TinyEngine的 Native 层,实现了小米设备 miio 通信协议,并向上提供了 JS 调用接口。Native miio 库实现数据传输通道(包括会话建立、加密发送数据、解密接收数据等)和事件转发,具体的设备模型(属性、接口、事件)在JS应用层可见。

miio-module-arch.png | center | 392x401

MIIO JS 对象接口说明

  • 创建设备

    • miio.createDevice(host, token)
      • host - 设备的ip地址
      • token - 设备对应的token
      • return - 设备标识
  • 注册设备事件监听器

    • miio.deviceOnEvent(device, cb)
      • device - miio.createDevice创建的设备
      • cb - function (event) {} 类型的回调函数
      • return - 无
  • 控制设备

    • miio.deviceControl(device, method, args, sid)
      • device - miio.createDevice创建的设备
      • method - 设备控制接口,如:set_power
      • args - 设备控制接口参数,如:["on"],["off"]等
      • sid - 子设备标识,控制device下的子设备时才会用到,其他情况不用填写
      • return - 设备返回子符串 注:该接口为同步接口,最长等待时间为2秒
  • IP自发现

    • miio.discover(timeout, cb)
      • timeout - 单位为秒
      • cb - function(host, deviceId) {} 类型的回调函数

对接流程

miio设备接入分为两类,一类 WIFI接入直连设备,可以连接WIFI AP,能直接被控制;另一类是通过Zigbee/Bluetooth</span>接入的子设备,它需要通过小米网关(此类设备需要先连接网关)才能被控制。

不管哪一类都需要知道设备的控制接口以及对应的参数
获取设备的控制接口以及对应的参数的方法如下:

  • 一种方法是参考home-assistant和miio源码;

  • 一种方法是安装一个android虚拟机,在android虚拟机上安装一个米家app,然后在米家app上对设备进行操作,同时抓取操作包,再通过miio工具解包,详细请参看

针对wifi设备,获取设备的ip和token的方法如下:

控制网关子设备

  • 获取网关ip和token

  • 调用miio.createDevice创建设备

  • 通过miio.deviceControl接口获取子设备列表,具体为var res = miio.deviceControl(gateway, 'get_device_prop', '["lumi.0","device_list"]');

  • 调用miio.deviceOnEvent注册事件监听器

  • 调用miio.deviceControl对子设备进行控制

控制WIF直连设备

  • 获取设备ip和token

  • 调用miio.createDevice创建设备

  • 调用miio.deviceControl对设备进行控制

示例说明

所需硬件配置

  • ESP32-DevkitC

  • STM32-developkit

  • TinyEngine 虚拟设备

实现代码实例

var lightDevice;

// 控制开灯
function lightOn() {
  console.log("lightOn");
  if (lightDevice) {
    miio.deviceControl(lightDevice, "set_power", '["on"]');
  }
}

// 控制开关
function lightOff() {
  console.log("lightOff");
  if (lightDevice) {
    miio.deviceControl(lightDevice, "set_power", '["off"]');
  }
}

function setupLight(host) {
  // 创建小米灯设备,如何获取小米设备的token,

  lightDevice = miio.createDevice(
    host,
    "ae65d127852df5c2b86f38b6878e8706"
  );

  // 初次启动时,第一次关闭小米灯
  lightOff();
}

function setupGateway(host) {
  // 创建小米 Zigbee 网关设备:如何获取小米设备的token,

  var gatewayDevice = miio.createDevice(
    host,
    "Please input your tiock"
  );

  var motionSensorId = null;
  var timeout = null;
  // 注册监听事件,回调函数
  miio.deviceOnEvent(gatewayDevice, function(event) {
    console.log("gateway receive event");

    var obj = JSON.parse(event);
    var open = false;

    if (obj.data) {
      open = JSON.parse(obj.data).status === "motion";
    }
    //如果人体感应器检测到人,则开灯,如果一分钟没有感应到人存在,则关灯
    if (obj.cmd === "report" && obj.sid === motionSensorId && open) {
      lightOn();
      if (timeout) {
        clearTimeout(timeout);
        timeout = null;
      }
      //每分钟接收一次
      timeout = setTimeout(function() {
        lightOff();
      }, 60 * 1000);
    }
  });

  // 获取小米网关的设备列表
  var device_list = miio.deviceControl(
    gatewayDevice,
    "get_device_prop",
    '["lumi.0","device_list"]'
  );
  console.log("device list: " + device_list);

  // 从小米网关下挂的设备列表中,找到人体感应设备,网关下的其他设备可以按照类似的方法
  var deviceList = JSON.parse(device_list);
  for (var i = 0; i < deviceList.result.length; i++) {
    if (deviceList.result[i + 1] === 2) {
      motionSensorId = deviceList.result[i].substring(5);
      console.log("motion sensor id: " + motionSensorId);
      break;
    }
  }
}

miio.discover(20, function(host, deviceId) {
  console.log('discovered device, host: ' + host + ', deviceId: ' + deviceId);
  if (deviceId === 61632282) {
    setupLight(host);
  } else if (deviceId === 78463041) {
    setupGateway(host);
  }
});

示例所需设备清单