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

文档目录:


 

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


1)定义物模型

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

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

再定义一个属性:git

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

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


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 :less

{
  "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 部分的编写便可。dom

在控制台程序中,新建一个类 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# 的关键字,命名字段时为了取消冲突因此加个 @工具

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

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

上传属性数据,能够分开上传,不须要每次都要上传所有的属性。须要更新哪一个属性,就上传这个属性。

相关文章
相关标签/搜索