磁吸门锁设备数据上报阿里云

简介: 本文以磁吸门锁作为采集制对象,使用海创微联采集控制系统对磁吸门锁设备数据进行采集控制,然后将采集到的数据上传到阿里云物联网平台,阿里云物联网平台实现数据实时可视化。文章分为3部分:● 设备接线配置磁吸门锁的联网参数配置及实施接线。● 数据采集使用海创微联采集控制系统进行控件的部署、数据采集。● 数据上传阿里云平台物联网平台产品和设备的创建、数据可视化。

本文以磁吸门锁作为采集制对象,使用海创微联采集控制系统对磁吸门锁设备数据进行采集控制,然后将采集到的数据上传到阿里云物联网平台,阿里云物联网平台实现数据实时可视化。
文章分为3部分:

  • 设备接线配置
    磁吸门锁的联网参数配置及实施接线。
  • 数据采集
    使用海创微联采集控制系统进行控件的部署、数据采集。
  • 数据上传
    阿里云平台物联网平台产品和设备的创建、数据可视化。

一 设备接线配置

1.1 准备工具

实现磁吸门锁数据采集控制,主要需要准备以下产品工具:

1.海创Box智能采集网关

2.密码锁

3.磁吸门锁控制板

1.2 设备接线

将网关盒子与磁吸门锁主板都接入交换机,设备上电后,与PC端实现网络通信。

1.3 联网参数配置

打开磁吸门锁软件--管理中心V6.9进行ip配置,实现通信。输入如图所示用户和密码。

打开控制器,搜索局域网络初始ip,配置参数。

1.4 远程开门

通信成功后打开总控制台,选择初始配置的门号,点击远程开门,查看运行信息。

1.5 密码权限修改删除

打开密码管理,输入要设置的密码选择添加,添加完成后前往上传设置,将数据上传。

二 数据采集

使用海创微联采集控制系统对磁吸门锁设备数据进行采集、处理、转发等操作。

打开海创微联采集控制系统,从左边的采集引擎中选择定时器、udp、function、json、调试器和阿里云节点,按下图连接。

2.1.1 定时器配置

定时器周期性触发输入时间戳或者相应的字符,主要当触发流程使用,具体配置如下图

具体代码如下所示:

{

"type": "status",

"address": 62393,

"value": 0

}


具体代码如下所示:

{

"type": "open",

"address": 62393,

"value": 1

}

2.1.2 udp配置

Udp发送msg.payload到指定的UDP主机和端口,支持组播!输入以及输出控件设置如下配置,配置地址以及端口。

2.1.3 function配置

JavaScript函数块,使用js语言,用于定义、赋值、指定规则等等,是最多变的控件。

具体代码如下所示:
解析:

let payload = msg.payload;

let type, value, address, code, data = {};


if (!Buffer.isBuffer(payload)) {

   Node.error(msg, "msg.payload不是Buffer类型");

   return;

}

let dataBuf = payload;

if (dataBuf.length != 34) {

   Node.error(msg, "msg.payload报文解析错误,报文长度不为34:" + dataBuf.toString('hex'));

   return;

}

if (dataBuf[0] != 0x7E || dataBuf[dataBuf.length - 1] != 0x0D) {

   Node.error(msg, "msg.payload报文解析错误,报文头或者报文尾不正确:" + dataBuf.toString('hex'));

   return;

}


let count = 0;

for (let i = 1, len = dataBuf.length - 3; i < len; i++) {

   count += dataBuf[i];

}

if (count != dataBuf.readUInt16LE(dataBuf.length - 3)) {

   Node.error(msg, `msg.payload报文校验失败,累计计算和为${Buffer.allocUnsafe(2).writeUInt16LE(count).toString('hex')},实际收到为:${dataBuf.subarray(dataBuf.length - 3, dataBuf.length - 1)}`);

   return;

}


let success = function (data, message) {

   if (typeof (data) == "undefined") {

       data = {};

       message = "操作成功";

   }

   if (typeof (message) == "undefined") {

       message = "操作成功";

   }

   if (typeof (message) != "string") {

       message = String(message);

   }

   return { "code": 0, "msg": message, "data": data };

}


let error = function (code, message) {

   if (typeof (code) == "undefined" && typeof (message) == "undefined") {

       code = 500;

       message = "程序发生错误";

   }

   else if (typeof (code) != "undefined" && typeof (message) == "undefined") {

       message = code;

       code = 500;

   }

   if (typeof (message) != "string") {

       message = String(message);

   }

   return { "code": code, "msg": message }

}


let isEror = function (result) {

   if (typeof (result) == "boolean") {

       if (result == true) {

           return false;

       }

       else {

           return true;

       }

   }

   else if (typeof (result) == "object") {

       if (result.code == 0) {

           return false;

       }

       else {

           return true;

       }

   }

   else {

       if (result) {

           return false;

       }

       else {

           return true;

       }

   }

}


let getDateTime = function (dateTimeBuf) {

   if (!Buffer.isBuffer(dateTimeBuf)) {

       dateTimeBuf = Buffer.from(dateTimeBuf, 'hex');

   }

   

   let dateTime, year, month, day, time, min, second;

   if (dateTimeBuf.length == 7) {

       year = "20" + dateTimeBuf.subarray(0, 1).toString('hex');

       month = dateTimeBuf.subarray(1, 2).toString('hex');

       day = dateTimeBuf.subarray(2, 3).toString('hex');

       time = dateTimeBuf.subarray(4, 5).toString('hex');

       min = dateTimeBuf.subarray(5, 6).toString('hex');

       second = dateTimeBuf.subarray(6, 7).toString('hex');

   }

   else if (dateTimeBuf.length == 4) {

       year = (dateTimeBuf.readUInt16LE(0) >> 9) + 2000;

       month = dateTimeBuf.readUInt16LE(0) >> 5 & 0x000F;

       day = dateTimeBuf.readUInt16LE(0) & 0x001F;

       time = dateTimeBuf.readUInt16LE(2) >> 11;

       min = dateTimeBuf.readUInt16LE(2) >> 5 & 0x003F;

       second = dateTimeBuf.readUInt16LE(2) & 0x001F * 2;

   }

   else {

       return error(1, "获取日期报文长度不正确:正确长度为7或者4,得到" + dateTimeBuf.length);

   }

   dateTime = `${year}-${month}-${day} ${time}:${min}:${second}`;

   return success(dateTime);

}


let getBisStatus = function (num) {

   if (typeof (num) != "number") {

       num = Number(num);

   }

   let numArr = (Array(8).join('0') + num.toString(2)).slice(-8).split("");

   // node.log(numArr);

   let data = [];

   numArr.forEach(element => {

       let value = false;

       if (element == "1") {

           value = true;

       }

       data.push(value);

   });

   return data;

}



const recordingStatus = {

   0x00: { "type": "open", "msg": "1号读卡器刷卡开门" },

   0x01: { "type": "open", "msg": "2号读卡器刷卡开门" },

   0x02: { "type": "open", "msg": "3号读卡器刷卡开门" },

   0x03: { "type": "open", "msg": "4号读卡器刷卡开门" },

   0x80: { "type": "prohibit", "msg": "(1)号读卡器刷卡禁止通过: 原因不明" },

   0x81: { "type": "prohibit", "msg": "(2)号读卡器刷卡禁止通过: 原因不明" },

   0x82: { "type": "prohibit", "msg": "(3)号读卡器刷卡禁止通过: 原因不明" },

   0x83: { "type": "prohibit", "msg": "(4)号读卡器刷卡禁止通过: 原因不明" },

   0x90: { "type": "prohibit", "msg": "(1)号读卡器刷卡禁止通过: 没有权限" },

   0x91: { "type": "prohibit", "msg": "(2)号读卡器刷卡禁止通过: 没有权限" },

   0x92: { "type": "prohibit", "msg": "(3)号读卡器刷卡禁止通过: 没有权限" },

   0x93: { "type": "prohibit", "msg": "(4)号读卡器刷卡禁止通过: 没有权限" },

   0xA0: { "type": "prohibit", "msg": "(1)号读卡器刷卡禁止通过: 密码不对" },

   0xA1: { "type": "prohibit", "msg": "(2)号读卡器刷卡禁止通过: 密码不对" },

   0xA2: { "type": "prohibit", "msg": "(3)号读卡器刷卡禁止通过: 密码不对" },

   0xA3: { "type": "prohibit", "msg": "(4)号读卡器刷卡禁止通过: 密码不对" },

   0xB0: { "type": "prohibit", "msg": "(1)号读卡器刷卡禁止通过: 系统有故障" },

   0xB1: { "type": "prohibit", "msg": "(2)号读卡器刷卡禁止通过: 系统有故障" },

   0xB2: { "type": "prohibit", "msg": "(3)号读卡器刷卡禁止通过: 系统有故障" },

   0xB3: { "type": "prohibit", "msg": "(4)号读卡器刷卡禁止通过: 系统有故障" },

   0xC0: { "type": "prohibit", "msg": "(1)号读卡器刷卡禁止通过: 反潜回, 多卡开门或多门互锁" },

   0xC1: { "type": "prohibit", "msg": "(2)号读卡器刷卡禁止通过: 反潜回, 多卡开门或多门互锁" },

   0xC2: { "type": "prohibit", "msg": "(3)号读卡器刷卡禁止通过: 反潜回, 多卡开门或多门互锁" },

   0xC3: { "type": "prohibit", "msg": "(4)号读卡器刷卡禁止通过: 反潜回, 多卡开门或多门互锁" },

   0xC4: { "type": "prohibit", "msg": "(1)号读卡器刷卡禁止通过: 反潜回" },

   0xC5: { "type": "prohibit", "msg": "(2)号读卡器刷卡禁止通过: 反潜回" },

   0xC6: { "type": "prohibit", "msg": "(3)号读卡器刷卡禁止通过: 反潜回" },

   0xC7: { "type": "prohibit", "msg": "(4)号读卡器刷卡禁止通过: 反潜回" },

   0xC8: { "type": "prohibit", "msg": "(1)号读卡器刷卡禁止通过: 多卡" },

   0xC9: { "type": "prohibit", "msg": "(2)号读卡器刷卡禁止通过: 多卡" },

   0xCA: { "type": "prohibit", "msg": "(3)号读卡器刷卡禁止通过: 多卡" },

   0xCB: { "type": "prohibit", "msg": "(4)号读卡器刷卡禁止通过: 多卡" },

   0xCC: { "type": "prohibit", "msg": "(1)号读卡器刷卡禁止通过: 首卡" },

   0xCD: { "type": "prohibit", "msg": "(2)号读卡器刷卡禁止通过: 首卡" },

   0xCE: { "type": "prohibit", "msg": "(3)号读卡器刷卡禁止通过: 首卡" },

   0xCF: { "type": "prohibit", "msg": "(4)号读卡器刷卡禁止通过: 首卡" },

   0xD0: { "type": "prohibit", "msg": "(1)号读卡器刷卡禁止通过: 门为常闭" },

   0xD1: { "type": "prohibit", "msg": "(2)号读卡器刷卡禁止通过: 门为常闭" },

   0xD2: { "type": "prohibit", "msg": "(3)号读卡器刷卡禁止通过: 门为常闭" },

   0xD3: { "type": "prohibit", "msg": "(4)号读卡器刷卡禁止通过: 门为常闭" },

   0xD4: { "type": "prohibit", "msg": "(1)号读卡器刷卡禁止通过: 互锁" },

   0xD5: { "type": "prohibit", "msg": "(2)号读卡器刷卡禁止通过: 互锁" },

   0xD6: { "type": "prohibit", "msg": "(3)号读卡器刷卡禁止通过: 互锁" },

   0xD7: { "type": "prohibit", "msg": "(4)号读卡器刷卡禁止通过: 互锁" },

   0xE0: { "type": "prohibit", "msg": "(1)号读卡器刷卡禁止通过: 卡过期或不在有效时段" },

   0xE1: { "type": "prohibit", "msg": "(2)号读卡器刷卡禁止通过: 卡过期或不在有效时段" },

   0xE2: { "type": "prohibit", "msg": "(3)号读卡器刷卡禁止通过: 卡过期或不在有效时段" },

   0xE3: { "type": "prohibit", "msg": "(4)号读卡器刷卡禁止通过: 卡过期或不在有效时段" }

};


const noCardRecordingStatus = {

   0: { 0x00: { "type": "button", "msg": "1号门按钮动作" }, 0x03: { "type": "remoteOpen", "msg": "1号门远程开门动作" }, 0x81: { "type": "coercion", "msg": "1号读卡器胁迫报警" }, 0x82: { "type": "noClose", "msg": "1号门长时间未关报警" }, 0x84: { "type": "illegal", "msg": "1号门非法闯入报警" } },

   1: { 0x00: { "type": "button", "msg": "2号门按钮动作" }, 0x03: { "type": "remoteOpen", "msg": "2号门远程开门动作" }, 0x81: { "type": "coercion", "msg": "2号读卡器胁迫报警" }, 0x82: { "type": "noClose", "msg": "2号门长时间未关报警" }, 0x84: { "type": "illegal", "msg": "2号门非法闯入报警" } },

   2: { 0x00: { "type": "button", "msg": "3号门按钮动作" }, 0x03: { "type": "remoteOpen", "msg": "3号门远程开门动作" }, 0x81: { "type": "coercion", "msg": "3号读卡器胁迫报警" }, 0x82: { "type": "noClose", "msg": "3号门长时间未关报警" }, 0x84: { "type": "illegal", "msg": "3号门非法闯入报警" } },

   3: { 0x00: { "type": "button", "msg": "4号门按钮动作" }, 0x03: { "type": "remoteOpen", "msg": "4号门远程开门动作" }, 0x81: { "type": "coercion", "msg": "4号读卡器胁迫报警" }, 0x82: { "type": "noClose", "msg": "4号门长时间未关报警" }, 0x84: { "type": "illegal", "msg": "4号门非法闯入报警" } },

   4: { 0xA0: { "type": "fireAlarm", "msg": "火警动作" } },

   5: { 0x00: { "type": "superOpen", "msg": "1号读卡器超级密码开门" }, 0x01: { "type": "superOpen", "msg": "2号读卡器超级密码开门" }, 0x02: { "type": "superOpen", "msg": "3号读卡器超级密码开门" }, 0x03: { "type": "superOpen", "msg": "4号读卡器超级密码开门" } },

   6: { 0xA0: { "type": "mandatory", "msg": "强制锁门" } },

   8: { 0x00: { "type": "sensorOpen", "msg": "1号门打开[门磁信号]" } },

   9: { 0x00: { "type": "sensorOpen", "msg": "2号门打开[门磁信号]" } },

   10: { 0x00: { "type": "sensorOpen", "msg": "3号门打开[门磁信号]" } },

   11: { 0x00: { "type": "sensorOpen", "msg": "4号门打开[门磁信号]" } },

   12: { 0x00: { "type": "sensorClose", "msg": "1号门关闭[门磁信号]" } },

   13: { 0x00: { "type": "sensorClose", "msg": "2号门关闭[门磁信号]" } },

   14: { 0x00: { "type": "sensorClose", "msg": "3号门关闭[门磁信号]" } },

   15: { 0x00: { "type": "sensorClose", "msg": "4号门关闭[门磁信号]" } }

};



let getErrorCode = function (num) {

   let errorBisArr = getBisStatus(num);

   let result = errorBisArr.slice(0, 5);

   let errorMsg = [

       "系统故障1",

       "系统故障2",

       "控制器时钟有故障",

       "系统故障4",

       "网络芯片有故障"

   ];

   let data = [];

   for (let item in result) {

       if (result[item]) {

           data.push(errorMsg[item]);

       }

   }

   return data;

}


let getRecord = function (recordBuf) {

   if (!Buffer.isBuffer(recordBuf)) {

       recordBuf = Buffer.from(recordBuf, 'hex');

   }

   if (recordBuf.length != 8) {

       return error(1, "获取记录报文长度不正确:正确长度为7,得到" + recordBuf.length);

   }

   if (recordBuf.toString('hex') == "ffffffffffffffff") {

       return success(null);

   }


   let cardId = String(recordBuf[2]) + String(recordBuf.readUInt16LE(0));

   let code, dateTime, message;

   if (Number(cardId) > 100) {

       code = recordingStatus[recordBuf[3]]['type'];

       message = recordingStatus[recordBuf[3]]['msg'];

   }

   else {

       code = noCardRecordingStatus[Number(cardId)][recordBuf[3]]['type'];

       message = noCardRecordingStatus[Number(cardId)][recordBuf[3]]['msg'];

   }

   dateTime = getDateTime(recordBuf.subarray(4));


   if (isEror(dateTime)) {

       return dateTime;

   }

   dateTime = dateTime.data;

   let data = {

       "cardId": cardId,

       "type": code,

       "dateTime": dateTime,

       "msg": message

   }

   return success(data);

}


address = dataBuf.readUInt16LE(1);

code = dataBuf.subarray(3, 5).toString('hex');

data = {

   "address": address,

   "code": code

};


if (dataBuf.readUInt16BE(3) == 0x8110) {

   let dateTimeResult = getDateTime(dataBuf.subarray(5, 12));

   if (isEror(dateTimeResult)) {

       node.error(msg, dateTimeResult.msg);

       return;

   }

   let dateTime = dateTimeResult.data;

   let recordResult = getRecord(dataBuf.subarray(17, 25));

   if (isEror(recordResult)) {

       node.error(msg, recordResult, msg);

       return;

   }

   let record = recordResult.data;

   let swipeCount = dataBuf.readUIntLE(12, 3);

   let authCount = dataBuf.readUInt16LE(15);

   let relayStatus = getBisStatus(dataBuf[25]);

   let doorBtnStatus = getBisStatus(dataBuf[26]);


   let relay = relayStatus.slice(0, 4);

   let doorSensor = doorBtnStatus.slice(0, 4).reverse();

   let button = doorBtnStatus.slice(4);

   let errorMsg = getErrorCode(dataBuf[28]);


   data.dateTime = dateTime;

   data.record = record;

   data.swipeCount = swipeCount;

   data.authCount = authCount;

   data.relay = relay;

   data.doorSensor = doorSensor;

   data.button = button;

   data.errorMsg = errorMsg;

   data.type = "status";


}

else if (dataBuf.readUInt16BE(3) == 0x9D10) {

   value = true;

   if (dataBuf[5] != 0) {

       node.error(msg, "开门失败");

       code = false;

   }

   data.value = value;

   data.type = "open";

}

else if (dataBuf.readUInt16BE(3) == 0x0711) {

   value = true;

   if (dataBuf[5] != 1) {

       node.error(msg, "添加用户权限失败");

       code = false;

   }

   data.value = value;

   data.type = "addUser";

}

else if (dataBuf.readUInt16BE(3) == 0x0811) {

   value = true;

   if (dataBuf[5] != 1) {

       node.error(msg, "删除用户权限失败");

       code = false;

   }

   data.value = value;

   data.type = "deleteUser";

}

else {

   node.error(msg, "功能码不存在:" + dataBuf.subarray(3, 5).toString('hex'));

   return;

}

msg.payload = data;


return msg;

控制

let payload = msg.payload;

if(payload.lock == true){

   return {payload:{"type":"open","address":62393,"value":1}};

}

权限设置

let payload = msg.payload;

let type = payload.type;

let value = payload.value;

let address = payload.address;


if (!type) {

   node.error(msg, "type不能为空!");

   return;

}

if (!address) {

   node.error(msg, "address不能为空!");

   return;

}


let dataBuf = Buffer.alloc(34);

dataBuf[0] = 0x7E;

dataBuf.writeUInt16LE(Number(address), 1);

dataBuf[33] = 0x0D;


if(type == "status"){

  dataBuf[3] = 0x81;

  dataBuf[4] = 0x10;

  if (value) {

     value = Number(value);

     dataBuf.writeUInt32LE(value, 5);

  }

}

else if(type == "open"){

  dataBuf[3] = 0x9d;

  dataBuf[4] = 0x10;

  switch(Number(value))

  {

      case 1:

          dataBuf[5] = 0x01;

          break;

      case 2:

          dataBuf[5] = 0x02;

          break;

      case 3:

          dataBuf[5] = 0x03;

          break;

      case 4:

          dataBuf[5] = 0x04;

          break;

      default:

         node.error(msg, "需要开门的门号值不正确:" + value);

       break;

  }

}

else if(type == "addUser"){

  //功能码

  dataBuf[3] = 0x07;

  dataBuf[4] = 0x11;

  //权限索引

  dataBuf[5] = 0x00;

  dataBuf[6] = 0x00;

  //卡ID

  let cardId = Number(value.cardId);

  if(cardId >= 10000)

  {

    node.error(msg, "添加权限卡号值不正确,值要小于10000:" + cardId);

       return;  

  }

  dataBuf[7] = cardId & 0x00ff;

  dataBuf[8] = cardId >> 8;

  dataBuf[9] = 0x00;

  //门号 1~4

  switch(Number(value.door))

  {

      case 1:

          dataBuf[10] = 0x01;

          break;

      case 2:

          dataBuf[10] = 0x02;

          break;

      case 3:

          dataBuf[10] = 0x03;

          break;

      case 4:

          dataBuf[10] = 0x04;

          break;

      default:

         node.error(msg, "需要开门的门号值不正确:" + value);

       return;

  }

  //起始时间

  dataBuf[11] = 0x21;

  dataBuf[12] = 0x00;

  //终止时间

  dataBuf[13] = 0x9f;

  dataBuf[14] = 0x29;

  //时段

  dataBuf[15] = 0x01;

  //密码

  dataBuf[16] = 0x00;

  dataBuf[17] = 0x00;

  dataBuf[18] = 0x00;

 

}

else if(type == "deleteUser"){

  //功能码

  dataBuf[3] = 0x08;

  dataBuf[4] = 0x11;

  //权限索引

  dataBuf[5] = 0x00;

  dataBuf[6] = 0x00;

  //卡ID

  let cardId = Number(value.cardId);

  if(cardId >= 10000)

  {

    node.error(msg, "删除权限卡号值不正确,值要小于10000:" + cardId);

       return;  

  }

  dataBuf[7] = cardId & 0x00ff;

  dataBuf[8] = cardId >> 8;

  dataBuf[9] = 0x00;

  //门号 1~4

  switch(Number(value.door))

  {

      case 1:

          dataBuf[10] = 0x01;

          break;

      case 2:

          dataBuf[10] = 0x02;

          break;

      case 3:

          dataBuf[10] = 0x03;

          break;

      case 4:

          dataBuf[10] = 0x04;

          break;

      default:

         node.error(msg, "门号值不正确:" + value);

       return;

  }

}

else {

   node.error(msg, "编码类型不存在:" + type);

   return;

}


//校验和计算 计算位 bit1~bit30

let check_sum = 0;

for(let index = 1;index < 31;index++)

{

   check_sum += dataBuf[index];

}

dataBuf.writeUInt16LE(check_sum, 31);

msg.payload = dataBuf;


return msg;

2.1.4 json配置

JOSN格式在任一方向上在JSON字符串及其JavaScript对象表示之间进行转换!

全部节点设置后,连线,点击部署,设置定时器将消息注入流中,点击触发可以观察到流程调试成功。

三 数据上传

阿里云物联网平台能够与海创微联采集控制系统进行联动,将采集到的数据可视化。

3.1 产品创建

登录阿里云物联网平台,在左侧导航栏,选择设备管理 > 产品,单击创建产品。

在新建产品页签,按照页面提示填写信息,然后单击确认。

3.2 设备创建

在左侧导航栏,选择设备管理 > 设备。在设备页面,单击添加设备。

在添加设备对话框中,输入设备信息,单击确认。

返回选择设备管理 > 设备,即可查看设备详情。

3.3 采集量的定义

返回查看刚刚创建的产品,在功能定义中,点击编辑草稿。

点击添加自定义功能。

标识符一定要和调试窗口中的字段一致。在功能定义中创建需要上传云端的数据标识符,创建完成后点击左下角的发布上线。

返回查看创建的设备,点击下图位置的查看按钮,复制好设备的3个标识符,即ProductKey(产品标识)、DeviceKey(设备标识)、DeviceSecret(设备密钥)。

3.4 数据可视化

前往海创微联采集控制系统,在阿里云IOT输入3个唯一标识。

点击部署,阿里云IOT连接成功。

返回阿里云物联网平台,设备显示在线。在设备的物模型数据中实时显示磁吸门锁设备数据。

相关实践学习
钉钉群中如何接收IoT温控器数据告警通知
本实验主要介绍如何将温控器设备以MQTT协议接入IoT物联网平台,通过云产品流转到函数计算FC,调用钉钉群机器人API,实时推送温湿度消息到钉钉群。
阿里云AIoT物联网开发实战
本课程将由物联网专家带你熟悉阿里云AIoT物联网领域全套云产品,7天轻松搭建基于Arduino的端到端物联网场景应用。 开始学习前,请先开通下方两个云产品,让学习更流畅: IoT物联网平台:https://iot.console.aliyun.com/ LinkWAN物联网络管理平台:https://linkwan.console.aliyun.com/service-open
目录
相关文章
|
7月前
|
传感器 监控 自动驾驶
智能犁具与播种设备
智能犁具与播种设备
49 2
|
7月前
|
数据安全/隐私保护 Android开发
连接智能家电设备
连接智能家电设备
190 1
|
7月前
|
数据安全/隐私保护 网络架构 智能硬件
智能家电设备连接
智能家电设备连接
108 1
|
7月前
|
JavaScript
亚丁号云控之云控设备
亚丁号云控之云控设备
52 0
|
物联网 定位技术 API
IoT 设备定位服务:GPS,移动基站、WiFi
IoT企业物联网平台提供基于GPS,移动基站、WiFi热点的定位服务
3490 15
IoT 设备定位服务:GPS,移动基站、WiFi
|
算法 编译器 C语言
达夫设备简单介绍
达夫设备简单介绍
163 1
|
传感器 物联网 智能硬件
IoT设备与手机App之间实时消息通信解决方案
PLC 工控机和管理人员 App 的联动
1540 15
IoT设备与手机App之间实时消息通信解决方案
|
传感器 算法 测试技术
ESP32-C3 应用 篇(实例一、通过MQTT协议连接ONENET上报传感器数据,云平台下发灯光调色)
ESP32-C3学到现在,我们已经掌握了从基本外设到网络服务端的相关知识, 这篇文章就是做一个简单的应用,使用开发板连接ONENET云平台, 使用MQTT协议,上报温湿度和光照数据,平台下发命令控制全彩灯颜色切换。
1040 0
ESP32-C3 应用 篇(实例一、通过MQTT协议连接ONENET上报传感器数据,云平台下发灯光调色)
|
网络性能优化 物联网 API