阿里云物联网 .NET Core 客户端 | CZGL.AliIoTClient:4. 设备上报属性
设备自身 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<TestModel>(model,false); }
启动控制台应用,在阿里云物联网控制台,打开设备,点击 运行状态 ,即可看到上传的属性数据。
文章后面会详细说明 CZGL.AliIoTClient 关于属性上传的具体情况。
当然,这样的数据只是固定赋值的,这里只是演示,具体数据需要开发者采集。下面给出一些模拟数据的方法。
4)模拟数据
笔者编写了三个数据模拟方法:
不需要理会里面是怎么写的,仅是个模拟数据的工具而已,你也可以自己编写相应的模拟数据方法。
里面有四个参数,对应:原始值、最小值、最大值、波动范围。
/// <summary> /// 模拟数据 /// </summary> public static class DeviceSimulate { /// <summary> /// /// </summary> /// <param name="original">原始数据</param> /// <param name="range">波动范围</param> /// <param name="min">最小值</param> /// <param name="max">最大值</param> /// <returns></returns> 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 < min || original - num < min) addorrm = true; else addorrm = ((new Random()).Next(1, 3) > 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 < min || original - num < min) addorrm = true; else addorrm = ((new Random()).Next(1, 3) > 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 < min || original - num < min) addorrm = true; else addorrm = ((new Random()).Next(1, 3) > 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<TestModel>(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<TestModel>(model, false); } /// <summary> /// 模拟数据 /// </summary> public static class DeviceSimulate { /// <summary> /// /// </summary> /// <param name="original">原始数据</param> /// <param name="range">波动范围</param> /// <param name="min">最小值</param> /// <param name="max">最大值</param> /// <returns></returns> 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 < min || original - num < min) addorrm = true; else addorrm = ((new Random()).Next(1, 3) > 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 < min || original - num < min) addorrm = true; else addorrm = ((new Random()).Next(1, 3) > 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 < min || original - num < min) addorrm = true; else addorrm = ((new Random()).Next(1, 3) > 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>(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);
上传属性数据,可以分开上传,不需要每次都要上传全部的属性。需要更新哪个属性,就上传这个属性。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
阿里云物联网 .NET Core 客户端 | CZGL.AliIoTClient:3. 订阅Topic与响应Topic
CZGL.AliIoTClient 将 Topic 分为五种 分别是:普通Topic、属性上报、属性下发、事件上报、服务调用,除了普通 Topic,每种 Topic 都有消息的发送、响应。 普通 Topic ,消息发送或,根据 MQTT 协议,SDK 严格保证消息能够到达另一端。 设备推送属性、事件等数据到服务器,则服务器要响应, 服务器推送(下发)数据到设备,则设备要响应。 当然,这些响应可有可无,无实质的影响。 每种、每个 Topic 都有特定的 MQTT 通讯地址,这些地址已经在 CZGL.AliIoTClient 中自动生成,你仅需填写普通 Topic 的通讯地址即可。 1) 订阅 Topic 订阅 Topic 前,需要在阿里云物联网定义相应的 Topic 以及设置 订阅 权限, 普通 Topic ,使用 string[] 包含列表,然后在调用连接方法时作为参数传入,亦可在连接服务器后,添加需要的订阅。 普通 Topic 可以动态添加,属于 热订阅 。 使用方法: // 设置要订阅的Topic、运行接收内容的Topic string[] topics = new string[...
- 下一篇
阿里云物联网 .NET Core 客户端 | CZGL.AliIoTClient:4.1 上报位置信息
阿里云物联网的位置服务,并不是完全独立的功能。位置信息包含 二维、三维,位置数据来源于属性的上传。 1)添加二维位置数据 打开 数据分析 -> 空间数据可视化 -> 二维数据 -> 添加,为上面演示的设备添加位置,刷新时间为1秒。在产品功能中,打开功能定义 ,在 标准功能 里,添加功能。 选择 其它类型 ,里面搜索 位置 ,在出现的列表中选一个(前面那几个都可以)。 笔者选择的是: 标识符:GeoLocation 适用类别:CuttingMachine 位置上传要设置的信息: 注意注意,如果选择的标准属性跟上图的类型定义不一样,需要手动修改。要把上面的位置属性按上图来改,有一个地方不同,都会失败。 当然,也可以一开始就按图手动创建。 2)基础代码 上传位置数据,不需要做什么大操作,按照属性的上传方法上传即可。模型代码参考: public class TestModel { public string id { get { return DateTime.Now.Ticks.ToString(); } set { } } public string version { ...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS7安装Docker,走上虚拟化容器引擎之路
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- Mario游戏-低调大师作品
- 2048小游戏-低调大师作品
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- Red5直播服务器,属于Java语言的直播服务器