前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【IoT迷你赛】使用门磁传感器和JS控制小米智能灯

【IoT迷你赛】使用门磁传感器和JS控制小米智能灯

原创
作者头像
熊的一些事
修改2020-04-20 14:28:22
1.7K0
修改2020-04-20 14:28:22
举报
文章被收录于专栏:腾讯云IoT

我家里的小米智能电器有米家、yeelight、aqara等品牌,米家有小米电视、米家空调等,yeelight有各个房间的吸顶灯,aqara有智能开关。由于米家开发者文档显示目前当前仅面向企业开放,暂未面向个人开发者开放。而aqara智能开关可玩性一般(文档可访问这里),而yeelight智能灯可以调节灯光开关、光暗、与传感器联动,可玩性更高,于是我就把魔爪伸向了yeelight智能灯了。

我想做的效果是门开灯亮,门关灯灭。先来看一下效果:视频地址

要完成这个效果,需要完成两大工作:接入门磁传感器编码联动。接下来逐一细讲。

接入门磁传感器

这部分包含控制台操作 LoRa 门磁传感器控制台操作 LoRa 网关网关实物操作门磁传感器实物操作等步骤。具体操作步骤如下:

1. 控制台操作 LoRa 门磁传感器

1.1. 创建项目和产品
  1. 登录 物联网开发平台控制台,选择【新建项目】。
  2. 在新建项目页面,填写项目基本信息。
    • 项目名称:输入“LoRa楼宇传感器演示”或其他名称。
    • 项目描述:按照实际需求填写项目描述。
  3. 项目新建成功后,即可新建产品。1.2. 新建产品
  4. 进入该项目的产品列表页面,单击【新建产品】。
  5. 在新建产品页面,填写产品基本信息。
    • 产品名称输入“LoRa门磁传感器”或其他产品名称。
    • 产品类型选择“门磁传感器”。
    • 认证方式选择“密钥认证”。
    • 通信方式选择“LoRaWAN”。
新建产品
新建产品

产品新建成功后,您可在产品列表页查看到“LoRa门磁传感器”。

1.3. 创建数据模板

选择“门磁传感器”类型后,自定义产品功能。

示例中,我们仅使用最简单的默认工作模式。

  • 绑定 bound
  • 上报周期 period
  • 门窗打开状态 isOpen
创建数据模板
创建数据模板
1.4. 设备数据解析

在设备开发页面中,按需调整 设备数据解析。由于 LoRa 类资源有限设备不适合直接传输 JSON 格式数据,使用“设备数据解析”可以将设备原始数据转化为产品JSON数据。

在上行数据解析部分,javascript示例代码如下:

代码语言:txt
复制
function RawToProtocol(fPort, bytes) {
    const COMMAND_A1_UNBOUND = 0x02;
    const COMMAND_A1_BOUND = 0x03;
    const COMMAND_07_FLAG_MODE = 0x05;
    const COMMAND_07_LEN_MODE = 1;
    const COMMAND_07_FLAG_VER = 0x90;
    const COMMAND_07_LEN_VER = 3;
    const COMMAND_07_FLAG_DELAY = 0x9c;
    const COMMAND_07_LEN_DELAY = 2;
    const COMMAND_07_FLAG_ULPRD = 0x9d;
    const COMMAND_0f_ALERT_KIND = 0x20;
    const COMMAND_0f_ALERT_OPEN = 2;
    const COMMAND_0f_ALERT_CLOSE = 4;
    
    var data = {
        "method": "report",
        "clientToken" : new Date(),
        "params" : {}
    };
    switch (bytes[0]) {
        case 0xA1:
        if (bytes[1] == COMMAND_A1_UNBOUND) {
            data.params.bound = 0;
        } else if (bytes[1] == COMMAND_A1_BOUND) {
            data.params.bound = 1;
        }
        break;
        case 0x07:
        for (let i = 1; i < bytes.length; i++) {
            if (bytes[i] == COMMAND_07_FLAG_MODE) {
                i += COMMAND_07_LEN_MODE;
            } else if (bytes[i] == COMMAND_07_FLAG_VER) {
                i += COMMAND_07_LEN_VER;
            } else if (bytes[i] == COMMAND_07_FLAG_DELAY) {
                i += COMMAND_07_LEN_DELAY;
            } else if (bytes[i] == COMMAND_07_FLAG_ULPRD) {
                data.params.period = bytes[i+1] | (bytes[i+2] << 8);
            }
        }
        break;
        case 0x00:
        if (bytes[5] & 0x80) {
            data.params.isOpen = 0;
        } else {
            data.params.isOpen = 1;
        }
        break;
        case 0x0f:
        if (bytes[1] == COMMAND_0f_ALERT_KIND) {
            if (bytes[2] == COMMAND_0f_ALERT_OPEN) {
                data.params.isOpen = 1;
            } else if (bytes[2] == COMMAND_0f_ALERT_CLOSE) {
                data.params.isOpen = 0;
            }
        }
        break;
    }
    return data;
}

在下行数据解析部分,javascript示例代码如下:

代码语言:txt
复制
function ProtocolToRaw(obj) {
    var data = new Array();
    var i = 0;

    data[i++] = 8;// fport=8
    data[i++] = 1;// confirmed mode
    for (var property in obj.params) {
        if ((property == "bound") && (obj.params[property] == 1)) {
            data[i++] = 0xA1;
            data[i++] = 0x03;
        }
        if (property == "period") {
            data[i++] = 0x9D;
            data[i++] = obj.params[property] & 0x00FF;
            data[i++] = (obj.params[property] >> 8) & 0x00FF;
        }
    }
    return data;
}
数据解析脚本
数据解析脚本
1.5 脚本模拟测试

这里也可以使用数据解析页面下方的模拟调试工具,如果开发更多的功能,这个模拟脚本将会提供很大帮助。

  1. 上行消息 - 归属状态 0xA1

设备原始数据为 0xA1,0x02,我们将其转化为数组,即上行模拟数据为:161,2,填入设备上行数据的编辑框中。

点击运行,即可在模拟调试界面右侧看到结果。

脚本模拟测试
脚本模拟测试
  1. 上行消息 - 设备基础参数 0x07 设备原始数据:07 05 06 90 00 08 04 9c 00 00 9d 80 70 9f 13 13 31 53 30 32 30 1f 02 05 20 95 模拟测试数据:7,5,6,144,0,8,4,156,0,0,157,128,112,159,19,19,49,83,48,50,48,31,2,5,32,149
  2. 上行消息 - 周期上报数据帧 0x00 设备原始数据:00 06 00 00 00 10 d5 模拟测试数据:0,6,0,0,0,16,213
  3. 上行消息 - 报警 0x0F 设备原始数据:0f 20 02 20 02 00 00 10 模拟测试数据:15,32,2,32,2,0,0,16 这条消息为开门报警消息。
  4. 设备原始数据:0f 20 04 20 05 00 00 90 模拟测试数据:15,32,4,32,5,0,0,144 这条消息为关门报警消息。
  5. 下行消息 - 设置上报周期(心跳周期) 0x9D 模拟测试数据如下,将其填入设备下行数据的编辑框中:{ "params": { "period": 300 } }
    设置上报周期
    设置上报周期
1.6 创建测试设备

在设备调试页面中,单击【新建设备】,设备名为 dws001。

  • DevEUI,每一个设备有一个唯一的身份识别地址 DEVEUI, 设备据此进行 LoRaWAN 网络入网并身份识别。 信息以二维码的形式体现在产品外壳。 本示例中为: 8cf957e0000001e7
DevEUI
DevEUI
  • AppKey,设备的密钥。 这可查找传感器厂家相关资料获取。
设备密钥
设备密钥

2. 控制台操作 LoRa 网关

  1. 登录 物联网开发平台控制台,选择上面章节 “控制台操作 LoRa 节点” 中对应的项目。
  2. 在左侧工具列表中选择“服务中心”中的“LoRa网关管理”,并在“LoRa网关管理”页面中选择“新建网关”。
    新建网关
    新建网关

在新建网关页面,填写网关基本信息。

网关名称,本示例中填写 GW2。

GwEUI,为网关唯一ID。本例中根据 RAK 网关产品背部的 MAC 地址,将6字节mac地址的中间补足0xfffe。

是否公开。选择“是”,表示社区开发者可在社区网络中看到该网关,并可通过这个网关进行LoRa节点接入。我们鼓励开发者们公开自己的网关,尽可能帮助到其他开发者。选择“否”,则只有用户自己才能看到该网关。

网关基本信息
网关基本信息

3 LoRa网关实物操作

3.1. 连接配置

网关默认开启Wi-Fi AP 模式,可以直接通过web配置LoRa网关,缺省IP:192.168.230.1,SSID:RAK72xx_xxxx(网关MAC地址尾号,见网关背后)

添加网关上行服务器的接口地址:loragw.things.qcloud.com,端口:1700

添加网关上行服务器信息
添加网关上行服务器信息

网关的上行频段默认设置使用8087信道编号, 频点486.3487.7Mhz共8个频点,LoRaWAN定义的终端频点使用一共有96个信道,部分终端入网时需要搜索频段,由于频段范围比较广,会存在入网时间长的问题,需要耐心等待。

3.2 网关上线确认

网关配置后之后重启,过半分钟左右会成功接入到物联网开发平台,我们可以在控制台的用户网关页面中看到网关的在线情况。

网关上线确认
网关上线确认

4 LoRa 门磁传感器实物操作

4.1 传感器复位

根据 《门磁传感器RHF1S020DWS规格书》中的操作说明,按照章节 3.8 进入无线固件升级, 将磁铁贴近门磁传感器(CE标志面的对面),红色LED从慢闪逐渐常亮后挪开磁铁, 即可让设备会自动重置复位。

传感器复位
传感器复位
4.2 下发门磁归属

门磁传感器在刚复位上电的一两分钟会上报3条归属状态的消息,我们必须在这点时间内尽快下发归属命令。

下发门磁归属
下发门磁归属

由于门磁传感器是 LoRaWAN Class A 类设备,这类设备不会立即下发数据,需要在有数据上行后,服务器才会向该设备下行数据。

因此我们下发了归属命令,当传感器上报归属状态消息后,即可收到我们下发的归属命令。这样门磁传感器之后才可正常使用。

注意:设备一旦归属之后,会再上报周期参数上来。如果看到平台的设备属性中没有更新“上报周期”,那说明传感器还未归属成功。此时需要重新下发归属命令,然后再复位传感器。

4.3 开关门操作

根据 《门磁传感器RHF1S020DWS规格书》 中的章节 2.10 操作说明,

磁铁部分外壳底部有一个开槽标识, 安装时请务必保证开槽的一边朝向正对传感器一边。 主体传感部分和用磁铁部分相对方位如下图, 分别安装在门(或窗)固定边和活动边,距离小于 20mm(不需紧贴) , 主体传感器部分和磁铁部分安装的表面高度基本在一个平面上。

开关门操作
开关门操作

如图所示,磁铁开槽方向贴近传感器位置,即触发了一次关门。将磁铁挪开 35 mm 以上,即可触发开门上报。

在控制台的设备调试页面下方则可以看到相应的属性做了更新。

属性更新
属性更新

至此,门磁传感器的接入便完成了。

编码联动

编码联动分两个步骤,分别是用JS控制智能灯,以及将其放到门磁传感器的状态变化事件中。

JS控制智能灯

这儿先脱离门磁传感器,用JS实现两个灯轮流变光变暗的效果:视频地址

由于百度谷歌都没有JS实现相关的教程,于是我只能从头开始摸索了。yeelight的开发文档比较简陋,而且是全英文的,社区更是提问题的多,解答问题的少,真是不太友好。

晦涩难懂的开发文档
晦涩难懂的开发文档

对可行性存在怀疑的我决定先尝试运行一下网站提供的mac版demo代码,看看是不是能跑通的。为此我还安装了xcode。结果直接运行会报如下错误:

error: No account for team "S4JD8QVPVY". Add a new account in the Accounts ...

解决办法是,这儿需要换上自己的开发者账号所在的team。

换上自己的开发者账号所在的team
换上自己的开发者账号所在的team

运行成功后发现找不到灯设备,fine,那我暂时也没办法了。

本着快速实现的想法,我逆转了一下思路,到github上看看有没有相关的轮子。筛选一下语言、高赞、文档详细的项目后,最后选择了几个项目尝试跑一下,但都没有找到灯设备。百思不得其解地吃了一个下午茶,以及抢了一轮小米有品的口罩结果被耍猴之后,不得不感叹整个下午都被小米耍了。

此刻作为一个逆转裁判粉丝,我也逆转一下思路,既然这么多demo都找不到设备,但他们既然存在,存在就是合理,那是不是其实demo是能跑通的,只是我缺了哪些步骤呢?把yeelight的论坛以及官网翻了个片后,我注意到官网的“局域网控制”入口,那是否我要给这些灯打开局域网控制才能够被发现呢?于是我被逼按照提示下载了他们的app来打开控制。再运行一遍mac版的demo,果然找到灯泡设备了!github上的项目也能顺利运行了。

允许局域网控制灯
允许局域网控制灯
找到设备了
找到设备了

没想到要运行成功一个demo,还需要经历探索、推理、逆转思路的过程,yeelight灯的开发入门真是趣味满满!建议官方出一个文档,让人按着步骤去做吧。这方面aqara的文档就做得好多了。

对比试用几个github库后,我最终选择了jamesblanksby的库来开发,虽然现在已经不再维护了。

实现如下:

先安装库:

npm i --save node-yeelight

再编写代码:

代码语言:txt
复制
var Yeelight = require('node-yeelight');
var y = new Yeelight;

y.on('ready', function() {
	console.log('ready');
	y.discover();
});

y.on('deviceadded', function(device) {
	console.log('device added');
	y.connect(device);
});

var deviceList = [];
y.on('deviceconnected', function(device) {
	console.log('device connected');
    deviceList.push(device);
    var state = true;
    setTimeout(function(){
        setInterval(function() {

            // 设置灯泡开关及过度时间
            // y.setPower(device, state, 2500);
    
            state = state ? false : true;
            
            // 设置灯泡亮度
            y.setBrightness(
                device, // device object
                state?100:1, // brightness percentage (1-100)
                800 // transition speed in ms
            );
        }, 1000);
    },(deviceList.length-1)*1000);
	
});

y.listen();

以上代码实现的是两个灯轮流变光变暗,即开始的视频效果。

将控制代码放到门磁传感器的状态变化事件中

参考腾讯云api调试工具实现代码如下:

代码语言:txt
复制
//腾讯云传感器初始化
const tencentcloud = require("tencentcloud-sdk-nodejs");

const IotexplorerClient = tencentcloud.iotexplorer.XXXX.Client;
const models = tencentcloud.iotexplorer.XXXX.Models;

const Credential = tencentcloud.common.Credential;
const ClientProfile = tencentcloud.common.ClientProfile;
const HttpProfile = tencentcloud.common.HttpProfile;

let cred = new Credential("XXXXX", "XXXXXX");
let httpProfile = new HttpProfile();
httpProfile.endpoint = "iotexplorer.tencentcloudapi.com";
let clientProfile = new ClientProfile();
clientProfile.httpProfile = httpProfile;
let client = new IotexplorerClient(cred, "ap-guangzhou", clientProfile);

let req = new models.DescribeDeviceDataRequest();

let params = '{"ProductId":"XXXX","DeviceName":"dev001"}'
req.from_json_string(params);

//yeelight 初始化

var Yeelight = require('node-yeelight');
var y = new Yeelight;

y.on('ready', function() {
	console.log('ready');
	y.discover();
});

y.on('deviceadded', function(device) {
	console.log('device added');

	y.connect(device);
});

var deviceList = [];
y.on('deviceconnected', function(device) {
	console.log('device connected');
    deviceList.push(device);
});

y.listen();

// 监听门窗传感器
var isOpen;
var interval = setInterval(function(){
    client.DescribeDeviceData(req, function(errMsg, response) {

        if (errMsg) {
            console.log(errMsg);
            clearInterval(interval);
            return;
        }

        // console.log(response.to_json_string());
        var data = JSON.parse(response.Data);
        if(data.isOpen.Value != isOpen){
            isOpen = data.isOpen.Value;
            let isOpenStr = isOpen == 1 ? "open":"close";
            console.log(`the door is ${isOpenStr}`)
            deviceList.forEach((device)=>{
                y.setPower(device, isOpen == 1, 100);
            });
        }
    });
},500);

至此总算实现了门开灯开,门关灯关的效果了。可惜的是这个智能灯得是局域网控制,就是要时刻开着本地服务器来控制,有点不太方便了,如果能提供云控制的办法就好了。

在遇到新的技术难题时,我们要尝试从多个角度去分析应对,一条路走不通就换个思路走,在解决的过程中逐渐理解问题所在。另外还要懂得用轮子,弯路会少走很多,效率也会提高很多。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 接入门磁传感器
    • 1. 控制台操作 LoRa 门磁传感器
      • 1.1. 创建项目和产品
      • 1.3. 创建数据模板
      • 1.4. 设备数据解析
      • 1.5 脚本模拟测试
      • 1.6 创建测试设备
    • 2. 控制台操作 LoRa 网关
      • 3 LoRa网关实物操作
        • 3.1. 连接配置
        • 3.2 网关上线确认
      • 4 LoRa 门磁传感器实物操作
        • 4.1 传感器复位
        • 4.2 下发门磁归属
        • 4.3 开关门操作
    • 编码联动
      • JS控制智能灯
        • 实现如下:
      • 将控制代码放到门磁传感器的状态变化事件中
      相关产品与服务
      云服务器
      云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档