使用騰訊樓宇套件 LoRa 門磁傳感器和Yeelight JS API 控制智能燈

我家里的小米智能電器有米家、yeelight、aqara等品牌,米家有小米電視、米家空調(diào)等,yeelight有各個房間的吸頂燈,aqara有智能開關(guān)。由于米家開發(fā)者文檔顯示目前當(dāng)前僅面向企業(yè)開放,暫未面向個人開發(fā)者開放。而aqara智能開關(guān)可玩性一般(文檔可訪問這里),而yeelight智能燈可以調(diào)節(jié)燈光開關(guān)、光暗、與傳感器聯(lián)動,可玩性更高,于是我就把魔爪伸向了yeelight智能燈了。

我想做的效果是門開燈亮,門關(guān)燈滅。先來看一下效果:視頻地址。

要完成這個效果,我們需要完成兩大工作:接入門磁傳感器編碼聯(lián)動。接下來逐一細(xì)講。

接入門磁傳感器

這部分包含控制臺操作 LoRa 門磁傳感器,控制臺操作 LoRa 網(wǎng)關(guān)、網(wǎng)關(guān)實物操作門磁傳感器實物操作等步驟。具體操作步驟如下:

1. 控制臺操作 LoRa 門磁傳感器

1.1. 創(chuàng)建項目和產(chǎn)品
  1. 登錄 物聯(lián)網(wǎng)開發(fā)平臺控制臺,選擇【新建項目】。
  2. 在新建項目頁面,填寫項目基本信息。
    • 項目名稱:輸入“LoRa樓宇傳感器演示”或其他名稱。
    • 項目描述:按照實際需求填寫項目描述。
  3. 項目新建成功后,即可新建產(chǎn)品。
1.2. 新建產(chǎn)品
  1. 進(jìn)入該項目的產(chǎn)品列表頁面,單擊【新建產(chǎn)品】。
  2. 在新建產(chǎn)品頁面,填寫產(chǎn)品基本信息。
    • 產(chǎn)品名稱輸入“LoRa門磁傳感器”或其他產(chǎn)品名稱。
    • 產(chǎn)品類型選擇“門磁傳感器”。
    • 認(rèn)證方式選擇“密鑰認(rèn)證”。
    • 通信方式選擇“LoRaWAN”。
新建產(chǎn)品

產(chǎn)品新建成功后,您可在產(chǎn)品列表頁查看到“LoRa門磁傳感器”。

1.3. 創(chuàng)建數(shù)據(jù)模板

選擇“門磁傳感器”類型后,自定義產(chǎn)品功能。

示例中,我們僅使用最簡單的默認(rèn)工作模式。

  • 綁定 bound
  • 上報周期 period
  • 門窗打開狀態(tài) isOpen
創(chuàng)建數(shù)據(jù)模板
1.4. 設(shè)備數(shù)據(jù)解析

在設(shè)備開發(fā)頁面中,按需調(diào)整 設(shè)備數(shù)據(jù)解析。由于 LoRa 類資源有限設(shè)備不適合直接傳輸 JSON 格式數(shù)據(jù),使用“設(shè)備數(shù)據(jù)解析”可以將設(shè)備原始數(shù)據(jù)轉(zhuǎn)化為產(chǎn)品JSON數(shù)據(jù)。

在上行數(shù)據(jù)解析部分,javascript示例代碼如下:

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

在下行數(shù)據(jù)解析部分,javascript示例代碼如下:

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;
}
數(shù)據(jù)解析腳本
1.5 腳本模擬測試

這里也可以使用數(shù)據(jù)解析頁面下方的模擬調(diào)試工具,如果開發(fā)更多的功能,這個模擬腳本將會提供很大幫助。

  1. 上行消息 - 歸屬狀態(tài) 0xA1

設(shè)備原始數(shù)據(jù)為 0xA1,0x02,我們將其轉(zhuǎn)化為數(shù)組,即上行模擬數(shù)據(jù)為:[161,2],填入設(shè)備上行數(shù)據(jù)的編輯框中。
點擊運行,即可在模擬調(diào)試界面右側(cè)看到結(jié)果。


腳本模擬測試
  1. 上行消息 - 設(shè)備基礎(chǔ)參數(shù) 0x07
    設(shè)備原始數(shù)據(jù):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
    模擬測試數(shù)據(jù):[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. 上行消息 - 周期上報數(shù)據(jù)幀 0x00
    設(shè)備原始數(shù)據(jù):00 06 00 00 00 10 d5
    模擬測試數(shù)據(jù):[0,6,0,0,0,16,213]

  3. 上行消息 - 報警 0x0F
    設(shè)備原始數(shù)據(jù):0f 20 02 20 02 00 00 10
    模擬測試數(shù)據(jù):[15,32,2,32,2,0,0,16]
    這條消息為開門報警消息。

  4. 設(shè)備原始數(shù)據(jù):0f 20 04 20 05 00 00 90
    模擬測試數(shù)據(jù):[15,32,4,32,5,0,0,144]
    這條消息為關(guān)門報警消息。

  5. 下行消息 - 設(shè)置上報周期(心跳周期) 0x9D
    模擬測試數(shù)據(jù)如下,將其填入設(shè)備下行數(shù)據(jù)的編輯框中:

{
  "params": {
    "period": 300
  }
}
設(shè)置上報周期
1.6 創(chuàng)建測試設(shè)備

在設(shè)備調(diào)試頁面中,單擊【新建設(shè)備】,設(shè)備名為 dws001。

  • DevEUI,每一個設(shè)備有一個唯一的身份識別地址 DEVEUI, 設(shè)備據(jù)此進(jìn)行 LoRaWAN 網(wǎng)絡(luò)入網(wǎng)并身份識別。 信息以二維碼的形式體現(xiàn)在產(chǎn)品外殼。
    本示例中為: 8cf957e0000001e7
DevEUI
  • AppKey,設(shè)備的密鑰。
    這可查找傳感器廠家相關(guān)資料獲取。
設(shè)備密鑰

2. 控制臺操作 LoRa 網(wǎng)關(guān)

  1. 登錄 物聯(lián)網(wǎng)開發(fā)平臺控制臺,選擇上面章節(jié) “控制臺操作 LoRa 節(jié)點” 中對應(yīng)的項目。
  2. 在左側(cè)工具列表中選擇“服務(wù)中心”中的“LoRa網(wǎng)關(guān)管理”,并在“LoRa網(wǎng)關(guān)管理”頁面中選擇“新建網(wǎng)關(guān)”。


    新建網(wǎng)關(guān)

在新建網(wǎng)關(guān)頁面,填寫網(wǎng)關(guān)基本信息。
網(wǎng)關(guān)名稱,本示例中填寫 GW2。
GwEUI,為網(wǎng)關(guān)唯一ID。本例中根據(jù) RAK 網(wǎng)關(guān)產(chǎn)品背部的 MAC 地址,將6字節(jié)mac地址的中間補足0xfffe。
是否公開。選擇“是”,表示社區(qū)開發(fā)者可在社區(qū)網(wǎng)絡(luò)中看到該網(wǎng)關(guān),并可通過這個網(wǎng)關(guān)進(jìn)行LoRa節(jié)點接入。我們鼓勵開發(fā)者們公開自己的網(wǎng)關(guān),盡可能幫助到其他開發(fā)者。選擇“否”,則只有用戶自己才能看到該網(wǎng)關(guān)。

網(wǎng)關(guān)基本信息

3 LoRa網(wǎng)關(guān)實物操作

3.1. 連接配置

網(wǎng)關(guān)默認(rèn)開啟Wi-Fi AP 模式,可以直接通過web配置LoRa網(wǎng)關(guān),缺省IP:192.168.230.1,SSID:RAK72xx_xxxx(網(wǎng)關(guān)MAC地址尾號,見網(wǎng)關(guān)背后)

添加網(wǎng)關(guān)上行服務(wù)器的接口地址:loragw.things.qcloud.com,端口:1700


添加網(wǎng)關(guān)上行服務(wù)器信息

網(wǎng)關(guān)的上行頻段默認(rèn)設(shè)置使用8087信道編號, 頻點486.3487.7Mhz共8個頻點,LoRaWAN定義的終端頻點使用一共有96個信道,部分終端入網(wǎng)時需要搜索頻段,由于頻段范圍比較廣,會存在入網(wǎng)時間長的問題,需要耐心等待。

3.2 網(wǎng)關(guān)上線確認(rèn)

網(wǎng)關(guān)配置后之后重啟,過半分鐘左右會成功接入到物聯(lián)網(wǎng)開發(fā)平臺,我們可以在控制臺的用戶網(wǎng)關(guān)頁面中看到網(wǎng)關(guān)的在線情況。

網(wǎng)關(guān)上線確認(rèn)

4 LoRa 門磁傳感器實物操作

4.1 傳感器復(fù)位

根據(jù) 《門磁傳感器RHF1S020DWS規(guī)格書》中的操作說明,按照章節(jié) 3.8 進(jìn)入無線固件升級, 將磁鐵貼近門磁傳感器(CE標(biāo)志面的對面),紅色LED從慢閃逐漸常亮后挪開磁鐵, 即可讓設(shè)備會自動重置復(fù)位。

傳感器復(fù)位
4.2 下發(fā)門磁歸屬

門磁傳感器在剛復(fù)位上電的一兩分鐘會上報3條歸屬狀態(tài)的消息,我們必須在這點時間內(nèi)盡快下發(fā)歸屬命令。

下發(fā)門磁歸屬

由于門磁傳感器是 LoRaWAN Class A 類設(shè)備,這類設(shè)備不會立即下發(fā)數(shù)據(jù),需要在有數(shù)據(jù)上行后,服務(wù)器才會向該設(shè)備下行數(shù)據(jù)。

因此我們下發(fā)了歸屬命令,當(dāng)傳感器上報歸屬狀態(tài)消息后,即可收到我們下發(fā)的歸屬命令。這樣門磁傳感器之后才可正常使用。

注意:設(shè)備一旦歸屬之后,會再上報周期參數(shù)上來。如果看到平臺的設(shè)備屬性中沒有更新“上報周期”,那說明傳感器還未歸屬成功。此時需要重新下發(fā)歸屬命令,然后再復(fù)位傳感器。

4.3 開關(guān)門操作

根據(jù) 《門磁傳感器RHF1S020DWS規(guī)格書》 中的章節(jié) 2.10 操作說明,

磁鐵部分外殼底部有一個開槽標(biāo)識, 安裝時請務(wù)必保證開槽的一邊朝向正對傳感器一邊。 主體傳感部分和用磁鐵部分相對方位如下圖, 分別安裝在門(或窗)固定邊和活動邊,距離小于 20mm(不需緊貼) , 主體傳感器部分和磁鐵部分安裝的表面高度基本在一個平面上。


開關(guān)門操作

如圖所示,磁鐵開槽方向貼近傳感器位置,即觸發(fā)了一次關(guān)門。將磁鐵挪開 35 mm 以上,即可觸發(fā)開門上報。

在控制臺的設(shè)備調(diào)試頁面下方則可以看到相應(yīng)的屬性做了更新。

屬性更新

至此,門磁傳感器的接入便完成了。

編碼聯(lián)動

編碼聯(lián)動分兩個步驟,分別是用JS控制智能燈,以及將其放到門磁傳感器的狀態(tài)變化事件中。

JS控制智能燈

這兒先脫離門磁傳感器,用JS實現(xiàn)兩個燈輪流變光變暗的效果:視頻地址。
?由于百度谷歌都沒有JS實現(xiàn)相關(guān)的教程,于是我只能從頭開始摸索了。yeelight的開發(fā)文檔比較簡陋,而且是全英文的,社區(qū)更是提問題的多,解答問題的少,真是不太友好。

晦澀難懂的開發(fā)文檔

對可行性存在懷疑的我決定先?嘗試運行一下網(wǎng)站提供的mac版demo代碼,看看是不是能跑通的。為此我還安裝了xcode。結(jié)果直接運行會報如下錯誤:
error: No account for team "S4JD8QVPVY". Add a new account in the Accounts ...
解決辦法是,這兒需要換上自己的開發(fā)者賬號所在的team。

換上自己的開發(fā)者賬號所在的team

運行成功后發(fā)現(xiàn)找不到燈設(shè)備,fine,那我暫時也沒辦法了。

本著快速實現(xiàn)的想法,我逆轉(zhuǎn)了一下思路,到github上看看有沒有相關(guān)的輪子。篩選一下語言、高贊、文檔詳細(xì)的項目后,最后選擇了幾個項目嘗試跑一下,但都沒有找到燈設(shè)備。百思不得其解地吃了一個下午茶,以及搶了一輪小米有品的口罩結(jié)果被耍猴之后,不得不感嘆整個下午都被小米耍了。

此刻作為一個逆轉(zhuǎn)裁判粉絲,我也逆轉(zhuǎn)一下思路,既然這么多demo都找不到設(shè)備,但他們既然存在,存在就是合理,那是不是其實demo是能跑通的,只是我缺了哪些步驟呢?把yeelight的論壇以及官網(wǎng)翻了個片后,我注意到官網(wǎng)的“局域網(wǎng)控制”入口,那是否我要給這些燈打開局域網(wǎng)控制才能夠被發(fā)現(xiàn)呢?于是我被逼按照提示下載了他們的app來打開控制。再運行一遍mac版的demo,果然找到燈泡設(shè)備了!github上的項目也能順利運行了。

允許局域網(wǎng)控制燈

找到設(shè)備了

沒想到要運行成功一個demo,還需要經(jīng)歷探索、推理、逆轉(zhuǎn)思路的過程,yeelight燈的開發(fā)入門真是趣味滿滿!建議官方出一個文檔,讓人按著步驟去做吧。這方面aqara的文檔就做得好多了。

對比試用幾個github庫后,我最終選擇了jamesblanksby的庫來開發(fā),雖然現(xiàn)在已經(jīng)不再維護(hù)了。

實現(xiàn)如下:

先安裝庫:
npm i --save node-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);
    var state = true;
    setTimeout(function(){
        setInterval(function() {

            // 設(shè)置燈泡開關(guān)及過度時間
            // y.setPower(device, state, 2500);
    
            state = state ? false : true;
            
            // 設(shè)置燈泡亮度
            y.setBrightness(
                device, // device object
                state?100:1, // brightness percentage (1-100)
                800 // transition speed in ms
            );
        }, 1000);
    },(deviceList.length-1)*1000);
    
});

y.listen();

以上代碼實現(xiàn)的是兩個燈輪流變光變暗,即開始的視頻效果。

將控制代碼放到門磁傳感器的狀態(tài)變化事件中

參考騰訊云api調(diào)試工具實現(xiàn)代碼如下:


//騰訊云傳感器初始化
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();

// 監(jiān)聽門窗傳感器
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);

至此總算實現(xiàn)了門開燈開,門關(guān)燈關(guān)的效果了。可惜的是這個智能燈得是局域網(wǎng)控制,就是要時刻開著本地服務(wù)器來控制,有點不太方便了,如果能提供云控制的辦法就好了。

在遇到新的技術(shù)難題時,我們要嘗試從多個角度去分析應(yīng)對,一條路走不通就換個思路走,在解決的過程中逐漸理解問題所在。另外還要懂得用輪子,彎路會少走很多,效率也會提高很多。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. LoRa射頻芯片提供商2. 開源的LoRa Server3. 免費的LoRa Server4. sx1276...
    聽力巴士閱讀 1,892評論 0 4
  • CDN能夠使用戶可就近取得所需內(nèi)容,解決 Internet網(wǎng)絡(luò)擁擠的狀況,提高用戶訪問網(wǎng)站的響應(yīng)速度CDN通過將網(wǎng)...
    Www劉閱讀 1,206評論 0 6
  • 其實只有具備遠(yuǎn)見卓識的領(lǐng)導(dǎo)者才能識別出來領(lǐng)導(dǎo)者。 任何工作都沒有前途,前途在于做工作的人。那么具備什么樣的素質(zhì)才是...
    張向武閱讀 439評論 0 0
  • 獨立于秋風(fēng)中,我問秋:雁去何時歸?秋答:且盼春來歸。 廊下細(xì)雨纏綿,我問雨:芳菲何時來?雨答:春來盡芳華。 陋室依...
    莫然失之閱讀 446評論 0 0
  • 歐陸戰(zhàn)爭5 是一款戰(zhàn)棋類游戲發(fā)布在手機和平板端。 歐陸戰(zhàn)爭5用一張全世界地圖標(biāo)注所有的城市。城市之間互相連接,海域...
    Hammer王閱讀 5,326評論 0 0

友情鏈接更多精彩內(nèi)容