热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

阿里云物联网.NETCore客户端|CZGL.AliIoTClient:4.设备上报属性

阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient,

设备自身 CPU 温度、电源输入电压、内存使用率等,以及接入到设备的传感器如温度传感器、光敏传感器等,这些硬件的数据输出即是 属性
设备将这些硬件的数据上传到阿里云物联网平台,实时显示这些设备的状态和实测数据,这个过程是 上传设备属性


1)定义物模型

在阿里云物联网控制台,点击 产品 -> 功能定义 -> 添加自定义功能
填入一下内容:

功能类型:属性 功能名称: CPU温度 标识符: cpu_temperature 数据类型: float (单精度浮点型) 取值范围:0-120 步长: 0.1 单位: 摄氏度 / °C 读写类型:只读 

再定义一个属性:

功能类型:属性 功能名称: 格力空调温度 标识符: gree_temperature 数据类型: float (单精度浮点型) 取值范围:0-35 步长: 0.1 单位: 摄氏度 / °C 读写类型:读写

注意的是,表示符是区分大小写的,相当于 C# 中的变量,笔者这里建议统一使用小写,具体原因后面说明。
注意:读写类型,一个只读、一个读写。


2)编写模型

前面说过, Alink json 是阿里云定义具有一定格式的 Json ,
因此这些属性数据是以 Json 形式上传。在 C# 中,可以通过 类 快速生成 Json 。

| 参数 | 类型 | 说明 |
|---|---|---|
|id |string |消息ID号,在这个设备的生涯中,ID应当是唯一的。可以使用时间戳或guid|
|version| string| 协议版本号,目前协议版本号为1.0。固定 "1.0" 即可|
|params| Object| 属性数据,里面包含多个属性对象,每个属性对象包含上报时间(time)和上报的值(value)。|
|time |long| 属性上报时间。|
|value |object| 上报的属性值。|
|method |string| 固定取值 thing.event.property.post|

那么,我们要编写一个类,存储信息,然后转为 Alink json 上传到阿里云物联网服务器。在编写这个模型前,预览要生成的 Alink json :

{ "id": "123456789", "version": "1.0", "params": { "cpu_temperature": { "value": 58.6, "time": 1524448722000 }, "gree_temperature": { "value": 26.6, "time": 1524448722000 } }, "method": "thing.event.property.post" }

我们只需关注 params 部分的编写即可。

在控制台程序中,新建一个类 TestModel

 public class TestModel { public string id { get { return DateTime.Now.Ticks.ToString(); } set { } } public string version { get { return "1.0"; } set { } } public Params @params { get; set; } public class Params { /* * */ } public string @method { get { return "thing.event.property.post"; } set { } } }

这样定义后,我们使用时,只需定义 params 部分即可, id、version等,不需要自己动态取值,做重复劳动。
上面有个 @params ,这是因为 params 是 C# 的关键字,命名字段时为了取消冲突所以加个 @

根据我们在阿里云物联网控制台定义的 属性 ,继续补充内容:

 public class TestModel { public string id { get { return DateTime.Now.Ticks.ToString(); } set { } } public string version { get { return "1.0"; } set { } } public Params @params { get; set; } public class Params { public Cpu_temperature cpu_temperature { get; set; } public Gree_temperature gree_temperature { get; set; } public class Cpu_temperature { public float value{ get; set; } public long time { get; set; } } public class Gree_temperature { public float value { get; set; } public long time { get; set; } } } public string @method { get { return "thing.event.property.post"; } set { } } }

问题是,这样写还不行,因为还没有给 TestModel 里的类进行实例化。
我们可以利用 构造函数 对里面的引用类型进行实例化,当然亦可编写依赖注入容器。。

 public class TestModel { public string id { get { return DateTime.Now.Ticks.ToString(); } set { } } public string version { get { return "1.0"; } set { } } public Params @params { get; set; } public TestModel() { @params = new Params(); } public class Params { public Cpu_temperature cpu_temperature { get; set; } public Gree_temperature gree_temperature { get; set; } public Params() { cpu_temperature = new Cpu_temperature(); gree_temperature = new Gree_temperature(); } public class Cpu_temperature { public float value{ get; set; } public long time { get; set; } } public class Gree_temperature { public float value { get; set; } public long time { get; set; } } } public string method { get { return "thing.event.property.post"; } set { } } }

3)上传设备属性数据

编写控制台程序,引入 CZGL.AliIoTClient ,编写基础代码(请替换 DeviceOptions 的信息):

 static AliIoTClientJson client; static void Main(string[] args) { // 创建客户端 client = new AliIoTClientJson(new DeviceOptions { ProductKey = "a1A6VVt72pD", DeviceName = "json", DeviceSecret = "7QrjTptQYCdepjbQvSoqkuygic2051zM", RegiOnId= "cn-shanghai" }); // 设置要订阅的Topic、运行接收内容的Topic string[] topics = new string[] { client.CombineHeadTopic("get") }; // 使用默认事件 client.UseDefaultEventHandler(); // 连接服务器 client.ConnectIoT(topics,null,60); ToServer(); // 自定义方法,后面说明 Console.ReadKey(); }

再 Program 类中,编写一个方法用来收集属性数据、上传属性数据:

 public static void ToServer() { // 实例化模型 TestModel model = new TestModel(); // 设置属性值 model.@params.cpu_temperature.value = 56.5F; model.@params.cpu_temperature.time =AliIoTClientJson.GetUnixTime(); // 低碳环境、节约资源,从你我做起,夏天空调不低于 26° model.@params.gree_temperature.value=26.0F; model.@params.gree_temperature.time=AliIoTClientJson.GetUnixTime(); // 上传属性数据 client.Thing_Property_Post(model,false); }

启动控制台应用,在阿里云物联网控制台,打开设备,点击 运行状态 ,即可看到上传的属性数据。
文章后面会详细说明 CZGL.AliIoTClient 关于属性上传的具体情况。

当然,这样的数据只是固定赋值的,这里只是演示,具体数据需要开发者采集。下面给出一些模拟数据的方法。


4)模拟数据

笔者编写了三个数据模拟方法:
不需要理会里面是怎么写的,仅是个模拟数据的工具而已,你也可以自己编写相应的模拟数据方法。
里面有四个参数,对应:原始值、最小值、最大值、波动范围。

 ///  /// 模拟数据 ///  public static class DeviceSimulate { ///  /// ///  /// 原始数据 /// 波动范围 /// 最小值 /// 最大值 ///  public static int Property(ref int original, int min, int max, int range) { int num = (new Random()).Next(0, range + 1); bool addorrm; if (original + num > max || original > max) addorrm = false; else if (original  1) ? true : false; if (addorrm == true) original += num; else original -= num; return original; } public static float Property(ref float original, float min, float max, int range = 8) { original = float.Parse(original.ToString("#0.00")); float num = float.Parse(((new Random()).NextDouble() / range).ToString("#0.00")); bool addorrm; if (original + num > max || original > max) addorrm = false; else if (original  1) ? true : false; if (addorrm == true) original += num; else original -= num; original = float.Parse(original.ToString("#0.00")); return original; } public static double Property(ref double original, double min, double max, int range = 8) { original = double.Parse(original.ToString("#0.0000")); double num = double.Parse(((new Random()).NextDouble() / range).ToString("#0.0000")); bool addorrm; if (original + num > max || original > max) addorrm = false; else if (original  1) ? true : false; if (addorrm == true) original += num; else original -= num; original = double.Parse(original.ToString("#0.0000")); return original; } }

int 模拟数据
range 是指每次生成 [0,range] 范围的增/减量,
例如 初始值 56 , range = 2 ,那么可能 56±0 或 56±1 或 56±2 ,
是增还是减,是随机的。但是设置 min 、 max 后,最后生成的值会在此范围内波动。

float、double 模拟数据
对应 float、double,range 的值越大,波动范围越小。默认 range = 8,大概就是每次 0.1 的波动范围。
其中,float 小数保留两位, double 小数保留 4 位,
需要更高或减少小数位数,修改一下 ...ToString("#0.0000")

模拟属性数据
接下来我们模拟一下两个属性的数据。

在 Program 中定义两个变量存储 cpu 和 空调 数据。

 static float cpu_temperature = 50.0F; static float gree_temperature = 26.0F;

修改 ToServer() 方法

 public static void ToServer() { // 实例化模型 TestModel model = new TestModel(); // 设置属性值 model.@params.cpu_temperature.value = DeviceSimulate.Property(ref cpu_temperature, 40, 60, 8); model.@params.cpu_temperature.time = AliIoTClientJson.GetUnixTime(); // 低碳环境、节约资源,从你我做起,夏天空调不低于 26° model.@params.gree_temperature.value = DeviceSimulate.Property(ref gree_temperature, 40, 60, 8); ; model.@params.gree_temperature.time = AliIoTClientJson.GetUnixTime(); // 上传属性数据 client.Thing_Property_Post(model, false); }

在 Main() 方法里增加代码:

 // 定时上传数据 while (true) { ToServer(); Thread.Sleep(1000); }

至此,已经基本完成。

完整代码如下:

 class Program { static AliIoTClientJson client; static void Main(string[] args) { // 创建客户端 client = new AliIoTClientJson(new DeviceOptions { ProductKey = "a1A6VVt72pD", DeviceName = "json", DeviceSecret = "7QrjTptQYCdepjbQvSoqkuygic2051zM", RegiOnId= "cn-shanghai" }); // 设置要订阅的Topic、运行接收内容的Topic string[] topics = new string[] { client.CombineHeadTopic("get") }; // 使用默认事件 client.UseDefaultEventHandler(); // 连接服务器 client.ConnectIoT(topics, null, 60); // 定时上传数据 while (true) { ToServer(); Thread.Sleep(1000); } Console.ReadKey(); } static float cpu_temperature = 50.0F; static float gree_temperature = 26.0F; public static void ToServer() { // 实例化模型 TestModel model = new TestModel(); // 设置属性值 model.@params.cpu_temperature.value = DeviceSimulate.Property(ref cpu_temperature, 40, 60, 8); model.@params.cpu_temperature.time = AliIoTClientJson.GetUnixTime(); // 低碳环境、节约资源,从你我做起,夏天空调不低于 26° model.@params.gree_temperature.value = DeviceSimulate.Property(ref gree_temperature, 40, 60, 8); ; model.@params.gree_temperature.time = AliIoTClientJson.GetUnixTime(); // 上传属性数据 client.Thing_Property_Post(model, false); } ///  /// 模拟数据 ///  public static class DeviceSimulate { ///  /// ///  /// 原始数据 /// 波动范围 /// 最小值 /// 最大值 ///  public static int Property(ref int original, int min, int max, int range) { int num = (new Random()).Next(0, range + 1); bool addorrm; if (original + num > max || original > max) addorrm = false; else if (original  1) ? true : false; if (addorrm == true) original += num; else original -= num; return original; } public static float Property(ref float original, float min, float max, int range = 8) { original = float.Parse(original.ToString("#0.00")); float num = float.Parse(((new Random()).NextDouble() / range).ToString("#0.00")); bool addorrm; if (original + num > max || original > max) addorrm = false; else if (original  1) ? true : false; if (addorrm == true) original += num; else original -= num; original = float.Parse(original.ToString("#0.00")); return original; } public static double Property(ref double original, double min, double max, int range = 8) { original = double.Parse(original.ToString("#0.0000")); double num = double.Parse(((new Random()).NextDouble() / range).ToString("#0.0000")); bool addorrm; if (original + num > max || original > max) addorrm = false; else if (original  1) ? true : false; if (addorrm == true) original += num; else original -= num; original = double.Parse(original.ToString("#0.0000")); return original; } } }

运行控制台程序,然后打开阿里云物联网控制台,查看设备的运行状态,打开 自动刷新 ,查看数据变化。

如果你觉得每次波动得范围太大,可以把 range 改大一些,如果你觉得数据不稳定,
可以把 min - max 的范围改小一些,模拟的数据值将在此范围波动。


5)设备属性 - CZGL.AliIoTClient

首先要说明,产品创建前,需要设置为 Alinkjson/透传 产品,
因此 CZGL.AliIoTClient 设置了两个客户端类。

类名 说明
AliIoTClientJson 以Alink json形式上传数据
AliIoTClientBinary 以透传形式上传数据

这两个类,仅在 属性、事件、服务 三个功能中数据上传形式有差别,连接服务器、普通Topic等其它数据的使用是完全一致的。
一个产品只能定义一种上传数据的形式。

CZGL.AliIoTClient 中上传属性的方法(Alink json):

// 不需要SDK处理任何中间过程,直接把数据上传。 // 那你需要先将数据存储到json中,在转成byte[],由SDK发送。 public int Thing_Property_Post(byte[] json) // 由SDK帮你发送原始的json,是否需要将json转为小写再发送,默认 true public int Thing_Property_Post(string json, [bool isToLwer = True]) // 设置要发送的json;是否转为小写;设置编码格式,为空则为UTF8 public int Thing_Property_Post(string json, [bool isToLwer = True], [System.Text.Encoding encoding = null]) // 直接传入模型,什么都不需要管,SDK转换后上传 public int Thing_Property_Post(TModel model, [bool isToLower = True])

获取 UNIX 时间:
由于阿里云要求上传的属性数据等,要带上 Unix 时间,所以笔者一并写在 CZGL.AliIoTClient 了。

public static long GetUnixTime()

使用示例参考上面的过程。

透传
如果你想使用透传,则使用 AliIoTClientBinary 类,

// 设备上传属性--透传 public int Thing_Property_UpRaw(byte[] bytes) // 设备上传属性--透传,转为 Base 64位加密后上传 public int Thing_Property_UpRawToBase64(byte[] bytes, [System.Text.Encoding encoding = null])

6)关于透传

透传以二进制报文形式上传,例如 0x020000007b00 ,这里是 16 进制,每两位一个字节。
如果是 2进制 ,则是 8位 一个字节。

透传需要在阿里云物联网控制台创建 透传 产品后,设置脚本,将透传数据 转为 Alink json。
透传数据是自定义的,以字节为单位,其中有5个字节为特定字节,以字节位进行拆分的。

记住,是以字节为单位。

透传数据格式标准:

字段 字节数
帧类型 1字节
请求ID 4字节
属性数据 N个字节

帧类型:

值(16进制) 说明
0x00 属性上报
0x01 属性设置
0x02 上报数据返回结果
0x03 属性设置设备返回结果
0xff 未知的命令

举例说明

很多人是直接把 10进制 或 16进制 直接转换成 2进制 。
例如 0x020000007b00,转为 2进制 :100000000000000000000000000111101100000000。
但是这样是错误的。

以上面 cpu 和 空调温度 举例,要上传属性数据,帧类型为 0x00。

| 属性 | 10进制 | 16进制 | 2进制 | 划一下2进制 |
| --------------- | ------ | -------- | ----------- | ----------- |
| cpu_temperature | 56 | 38 | 00111000 | 00 11 10 00 |
| gree_temperature | 26 | 1a | 00011010 | 00 01 10 10 |

应当这样拆分和设置值:

字节类转 字节数 16进制 2进制
进制表示 0x
帧类型 1字节 00 00000000
ID 4字节 00 00 00 7b 00000000 00000000 00000000 01111011
cpu_temperature 1 字节 38 00111000
gree_temperature 1 字节 1a 00011010

16进制数据:
0x000000007b381a

2进制数据:
00000000000000000000000000000000011110110011100000011010

将 16进制 或 2进制 的数据存储到 byte[] 变量中,切记要强制转换。
存储时,一个 byte 为一个字节,M个字节,则 byte[M]。

存储:
使用 16进制 存储透传数据,2进制弄不来的。 :joy: :joy: :joy:
有些同学非要用 2进制 存储,反正我是弄不来,用 二进制 数值 存储,这个触发我的知识盲区了。

示例(仅对 AliIoTClientBinary 客户端有效):

 // 存储透传数据 byte[] b = new byte[7]; b[0] = 0x00; b[1] = 0x00; b[2] = 0x00; b[3] = 0x00; b[4] = 0x7b; b[5] = 0x38; b[6] = 0x1a; // 上传透传数据 client.Thing_Property_UpRaw(b);

如果上报属性,要求 请输入二进制数据Base64编码后的字符串,可以使用

 byte[] b = new byte[7]; b[0] = 0x00; b[1] = 0x00; b[2] = 0x00; b[3] = 0x00; b[4] = 0x7b; b[5] = 0x38; b[6] = 0x1a; // client.Thing_Property_UpRaw(b); client.Thing_Property_UpRawToBase64(b);

透传数据的坑很多,这里 CZGL.AliIoTClient 只提供如何处理数据和上传数据,云端的脚本解析请参考
https://help.aliyun.com/document_detail/114621.html?spm=a2c4g.11186623.2.13.209b65b9Q9z0Nx#concept-185365


7)后续说明

其实,每次上传服务器都会作出响应,CZGL.AliIoTClient 默认不接收这些响应信息。
你可以使用 OpenPropertyPostReply() 接收设备属性上传后服务器的响应,应当在连接服务器前使用此方法
使用 Close.PropertyPostReply() 取消接收设备属性上传后服务器的响应。

示例:

 // 。。。 client.ClosePropertyPostReply(); // 连接服务器 client.ConnectIoT(topics, null, 60);

上传属性数据,可以分开上传,不需要每次都要上传全部的属性。需要更新哪个属性,就上传这个属性。


推荐阅读
  • Docker安全策略与管理
    本文探讨了Docker的安全挑战、核心安全特性及其管理策略,旨在帮助读者深入理解Docker安全机制,并提供实用的安全管理建议。 ... [详细]
  • C# 中创建和执行存储过程的方法
    本文详细介绍了如何使用 C# 创建和调用 SQL Server 存储过程,包括连接数据库、定义命令类型、设置参数等步骤。 ... [详细]
  • 本文详细介绍了在 CentOS 系统中如何创建和管理 SWAP 分区,包括临时创建交换文件、永久性增加交换空间的方法,以及如何手动释放内存缓存。 ... [详细]
  • 本文介绍了SIP(Session Initiation Protocol,会话发起协议)的基本概念、功能、消息格式及其实现机制。SIP是一种在IP网络上用于建立、管理和终止多媒体通信会话的应用层协议。 ... [详细]
  • CentOS下ProFTPD的安装与配置指南
    本文详细介绍在CentOS操作系统上安装和配置ProFTPD服务的方法,包括基本配置、安全设置及高级功能的启用。 ... [详细]
  • 本文详细介绍了如何利用 Bootstrap Table 实现数据展示与操作,包括数据加载、表格配置及前后端交互等关键步骤。 ... [详细]
  • 在尝试通过自定义端口部署Spring Cloud Eureka时遇到了连接失败的问题。本文详细描述了问题的现象,并提供了有效的解决方案,以帮助遇到类似情况的开发者。 ... [详细]
  • 本文详细介绍了Elasticsearch中的分页查询机制,包括基本的分页查询流程、'from-size'浅分页与'scroll'深分页的区别及应用场景,以及两者在性能上的对比。 ... [详细]
  • 本文详细介绍了`android.os.Binder.getCallingPid()`方法的功能和应用场景,并提供了多个实际的代码示例。通过这些示例,开发者可以更好地理解如何在不同的开发场景中使用该方法。 ... [详细]
  • 使用C#构建动态图形界面时钟
    本篇文章将详细介绍如何利用C#语言开发一个具有动态显示功能的图形界面时钟。文章中不仅提供了详细的代码示例,还对可能出现的问题进行了深入分析,并给出了解决方案。 ... [详细]
  • 本文介绍了实时流协议(RTSP)的基本概念、组成部分及其与RTCP的交互过程,详细解析了客户端请求格式、服务器响应格式、常用方法分类及协议流程,并提供了SDP格式的深入解析。 ... [详细]
  • 如何在U8系统中连接服务器并获取数据
    本文介绍了如何在U8系统中通过不同的方法连接服务器并获取数据,包括使用MySQL客户端连接实例的方法,如非SSL连接和SSL连接,并提供了详细的步骤和注意事项。 ... [详细]
  • 在 Ubuntu 22.04 LTS 上部署 Jira 敏捷项目管理工具
    Jira 敏捷项目管理工具专为软件开发团队设计,旨在以高效、有序的方式管理项目、问题和任务。该工具提供了灵活且可定制的工作流程,能够根据项目需求进行调整。本文将详细介绍如何在 Ubuntu 22.04 LTS 上安装和配置 Jira。 ... [详细]
  • 本文探讨了如何将个人经历,特别是非传统的职业路径,转化为职业生涯中的优势。通过作者的亲身经历,展示了舞蹈生涯对商业思维的影响。 ... [详细]
  • GLiHT数据介绍
    GLiHT数据介绍 ... [详细]
author-avatar
狄言洁_171
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有