Alibaba Cloud IoT .NET Core Client | CZGL.AliIoTClient: 4. Device Attribute Reporting

2019年12月15日 34点热度 0人点赞 0条评论
内容目录

Document Directory:


 

The data output of the device itself, such as CPU temperature, power input voltage, memory usage rate, etc., along with the sensors connected to the device, such as temperature sensors and photoresistor sensors, constitutes the attributes. The device uploads this hardware data to the Alibaba Cloud IoT platform, which displays the status and measured data of these devices in real-time. This process is called uploading device attributes.


1) Define the Thing Model

In the Alibaba Cloud IoT console, click Product -> Function Definition -> Add Custom Function. Fill in the following content:

Function Type: Attribute  
Function Name: CPU Temperature  
Identifier: cpu_temperature  
Data Type: float (single precision floating point)  
Value Range: 0-120  
Step:    0.1  
Unit:  Celsius / °C  
Read/Write Type: Read-only  

Then define another attribute:

Function Type: Attribute  
Function Name: Gree Air Conditioner Temperature  
Identifier: gree_temperature  
Data Type: float (single precision floating point)  
Value Range: 0-35  
Step:    0.1  
Unit:  Celsius / °C  
Read/Write Type: Read/Write  

Note that the identifiers are case-sensitive, similar to variables in C#. It is recommended to use lowercase uniformly for specific reasons that will be explained later.

Note: One is Read-only, and the other is Read/Write.


2) Write the Model

As mentioned earlier, Alink JSON is a specific format of JSON defined by Alibaba Cloud, therefore, the attribute data is uploaded in JSON format. In C#, a class can quickly generate JSON.

Parameter Type Description
id string Message ID, which should be unique during the device’s lifecycle. Can use a timestamp or GUID.
version string Protocol version number; currently, the protocol version number is 1.0. Fixed value "1.0".
params Object Attribute data, which contains multiple attribute objects, each of which includes the report time (time) and reported value (value).
time long Attribute reporting time.
value object Reported attribute value.
method string Fixed value thing.event.property.post.

Thus, we need to write a class to store the information and then convert it to Alink JSON for upload to the Alibaba Cloud IoT server. Before writing this model, preview the Alink JSON to be generated:

{
  "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"
}

We only need to focus on the creation of the params part.

In the console application, create a new class called 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 { } }
    }

With this definition, when using it, we only need to define the params part; we do not need to dynamically obtain values for id, version, etc., avoiding redundant work.
Here, @params is used because params is a keyword in C#, so the @ symbol is added to avoid conflicts.

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

   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) Simulated Data

The author has written three methods for data simulation:

You do not need to concern yourself with how it is written; it's merely a tool for simulating data. You can also create your own corresponding simulation methods. There are four parameters inside, corresponding to: original value, minimum value, maximum value, and fluctuation range.

    /// <summary>
    /// Simulated Data
    /// </summary>
    public static class DeviceSimulate
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="original">Original Data</param>
        /// <param name="range">Fluctuation Range</param>
        /// <param name="min">Minimum Value</param>
        /// <param name="max">Maximum Value</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 simulated data range refers to the increase/decrease amount generated each time within the range of [0, range], for example, starting value 56, range = 2, the possible values are 56±0 or 56±1 or 56±2, and whether it is an increase or decrease is random. However, after setting min and max, the final generated value will fluctuate within this range. float and double simulated data Corresponding to float and double, the larger the value of range, the smaller the fluctuation range. The default range = 8 roughly corresponds to a fluctuation range of 0.1 each time. Among them, float retains two decimal places, and double retains four decimal places. To retain more or fewer decimal places, modify ...ToString("#0.0000") Simulating property data Next, let's simulate the data for two properties. Define two variables to store CPU and air conditioning data in Program.

```cpp static float cpu_temperature = 50.0F; static float gree_temperature = 26.0F; ```
修改 `ToServer()` 方法: ```cs 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()` 方法里增加代码: ```less // 定时上传数据 while (true) { ToServer(); Thread.Sleep(1000); } ```
至此,已经基本完成
完整代码如下: ``` class Program { static AliIoTClientJson client; static void Main(string[] args) { // Create client client = new AliIoTClientJson(new DeviceOptions { ProductKey = "a1A6VVt72pD", DeviceName = "json", DeviceSecret = "7QrjTptQYCdepjbQvSoqkuygic2051zM", RegionId = "cn-shanghai" }); // Set the Topic to subscribe to and the Topic to run receive content string[] topics = new string[] { client.CombineHeadTopic("get") }; // Use default event client.UseDefaultEventHandler(); // Connect to server client.ConnectIoT(topics, null, 60); // Periodically upload data while (true) { ToServer(); Thread.Sleep(1000); } Console.ReadKey(); } static float cpu_temperature = 50.0F; static float gree_temperature = 26.0F; public static void ToServer() { // Instantiate model TestModel model = new TestModel(); // Set property values model.@params.cpu_temperature.value = DeviceSimulate.Property(ref cpu_temperature, 40, 60, 8); model.@params.cpu_temperature.time = AliIoTClientJson.GetUnixTime(); // Low carbon environment, save resources, start from ourselves, summer air conditioning not lower than 26° model.@params.gree_temperature.value = DeviceSimulate.Property(ref gree_temperature, 40, 60, 8); model.@params.gree_temperature.time = AliIoTClientJson.GetUnixTime(); // Upload property data client.Thing_Property_Post(model, false); } /// /// Simulate data /// public static class DeviceSimulate { /// /// /// /// Original data /// Fluctuation range /// Minimum value /// Maximum value /// 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; } } ```
```markdown (original.ToString("#0.0000")); return original; } } }

Run the console program, then open the Alibaba Cloud IoT console to check the device's operating status, enable Auto Refresh to observe data changes.

If you find the fluctuation range too large each time, you can increase the range; if you find the data unstable, you can decrease the min - max range; the simulated data values will fluctuate within this range.


5) Device Properties - CZGL.AliIoTClient

First, it is necessary to state that before creating a product, it needs to be set as Alinkjson/Transparency Product, so CZGL.AliIoTClient has set up two client classes.

Class Name Description
AliIoTClientJson Uploads data in Alink JSON format
AliIoTClientBinary Uploads data in transparent format

These two classes only differ in data upload formats for attributes, events, and services; the use of connecting to the server, general topics, and other data is completely consistent. A product can only define one data upload format.

The method to upload attributes in CZGL.AliIoTClient (Alink JSON):

// No intermediate processes handled by SDK, upload data directly.
// You need to first store the data in JSON, then convert it to byte[], sent by SDK.
public int Thing_Property_Post(byte[] json)

// SDK sends original JSON for you; whether to convert JSON to lowercase before sending, default is true
public int Thing_Property_Post(string json, 
                               [bool isToLwer = True])

// Sets the JSON to be sent; whether to convert to lowercase; sets encoding format, empty defaults to UTF8
public int Thing_Property_Post(string json, 
                               [bool isToLwer = True], 
                               [System.Text.Encoding encoding = null])

// Directly pass in the model, nothing else to manage, SDK will convert and upload
public int Thing_Property_Post<TModel>(TModel model, 
                               [bool isToLower = True])

Get UNIX time: Since Alibaba Cloud requires that the uploaded attribute data must include Unix time, I have also included it in CZGL.AliIoTClient.

public static long GetUnixTime()

Refer to the above process for usage examples.

Transparency
If you want to use transparency, use the AliIoTClientBinary class,

// Device uploads attributes--transparency
public int Thing_Property_UpRaw(byte[] bytes)

// Device uploads attributes--transparency, converted to Base64 for upload
public int Thing_Property_UpRawToBase64(byte[] bytes, 
                        [System.Text.Encoding encoding = null])

6) About Transparency

Transparency uploads data in binary message form, such as 0x020000007b00, where this is in hexadecimal, with two digits forming one byte.
If in binary, it would be 8 bits for one byte.

Transparency requires that after creating a transparency product in the Alibaba Cloud IoT console, a script is set to convert the transparent data into Alink JSON.
Transparent data is custom and works in bytes, with 5 of those bytes being specific bytes, split by byte positions.

Remember, it's in bytes.

Transparency data format standard:

Field Byte Count
Frame Type 1 byte
Request ID 4 bytes
Attribute Data N bytes

Frame Type:

Value (Hexadecimal) Description
0x00 Attribute Reporting
0x01 Attribute Setting
0x02 Report Data Return Result
0x03 Attribute Setting Device Return Result
0xff Unknown Command

**Example Explanation**

Many people directly convert decimal or hexadecimal to binary.
For example, 0x020000007b00, converted to binary: 100000000000000000000000000111101100000000. However, this is incorrect.

Taking CPU and air conditioning temperature as examples to upload attribute data, the frame type is 0x00.

Attribute Decimal Hexadecimal Binary Breakdown of Binary
cpu_temperature 56 38 00111000 00 11 10 00
gree_temperature 26 1a 00011010 00 01 10 10

This should be split and set as follows:

Byte Class Conversion Byte Count Hexadecimal Binary
Base Representation None 0x None
Frame Type 1 byte 00 00000000
ID 4 bytes 00 00 00 7b 00000000 00000000 00000000 01111011
cpu_temperature 1 byte 38 00111000
gree_temperature 1 byte 1a 00011010

Hexadecimal data:
0x000000007b381a

Binary data:
00000000000000000000000000000000011110110011100000011010

Store the hexadecimal or binary data into a byte[] variable, and remember to cast it. When storing, one byte is one byte, and M bytes will be byte[M].

Storage:
Use hexadecimal to store transparent data, binary is not feasible. 🤣🤣🤣

PS: New versions of C# support binary literals.
Some students insist on using binary for storage, but I can't manage it; storing using binary values triggers my knowledge blind spot.


<br />



Example (valid only for AliIoTClientBinary client):  
<pre><code class="hljs armasm">            // Store transparent transmission data
            <span class="hljs-keyword">byte[] <span class="hljs-keyword">b = new <span class="hljs-keyword">byte[7];
            <span class="hljs-keyword">b[0] = <span class="hljs-number">0x00<span class="hljs-comment">;
            <span class="hljs-keyword">b[1] = <span class="hljs-number">0x00<span class="hljs-comment">;
            <span class="hljs-keyword">b[2] = <span class="hljs-number">0x00<span class="hljs-comment">;
            <span class="hljs-keyword">b[3] = <span class="hljs-number">0x00<span class="hljs-comment">;
            <span class="hljs-keyword">b[4] = <span class="hljs-number">0x7b<span class="hljs-comment">;
            <span class="hljs-keyword">b[5] = <span class="hljs-number">0x38<span class="hljs-comment">;
            <span class="hljs-keyword">b[6] = <span class="hljs-number">0x1a<span class="hljs-comment">;

            // Upload transparent transmission data
            client.Thing_Property_UpRaw(<span class="hljs-keyword">b);
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>  
If reporting properties, it requires <code>Enter the Base64 encoded string of binary data</code>. You can use  
<pre><code class="hljs armasm">            <span class="hljs-keyword">byte[] <span class="hljs-keyword">b = new <span class="hljs-keyword">byte[7];
            <span class="hljs-keyword">b[0] = <span class="hljs-number">0x00<span class="hljs-comment">;
            <span class="hljs-keyword">b[1] = <span class="hljs-number">0x00<span class="hljs-comment">;
            <span class="hljs-keyword">b[2] = <span class="hljs-number">0x00<span class="hljs-comment">;
            <span class="hljs-keyword">b[3] = <span class="hljs-number">0x00<span class="hljs-comment">;
            <span class="hljs-keyword">b[4] = <span class="hljs-number">0x7b<span class="hljs-comment">;
            <span class="hljs-keyword">b[5] = <span class="hljs-number">0x38<span class="hljs-comment">;
            <span class="hljs-keyword">b[6] = <span class="hljs-number">0x1a<span class="hljs-comment">;

            // client.Thing_Property_UpRaw(<span class="hljs-keyword">b);
            client.Thing_Property_UpRawToBase64(<span class="hljs-keyword">b);
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>  
There are many pitfalls with transparent transmission data. Here, CZGL.AliIoTClient only provides how to process and upload data. For cloud-side script parsing, please refer to  
<a href="https://help.aliyun.com/document_detail/114621.html?spm=a2c4g.11186623.2.13.209b65b9Q9z0Nx#concept-185365">https://help.aliyun.com/document_detail/114621.html?spm=a2c4g.11186623.2.13.209b65b9Q9z0Nx#concept-185365</a>  

<hr />  

<h2><a id="7后续说明" class="anchor" href="https://gitee.com/whuanle/CZGL.AliIoTClient/wikis/4.%20%E8%AE%BE%E5%A4%87%E4%B8%8A%E6%8A%A5%E5%B1%9E%E6%80%A7?sort_id=1479193#7%E5%90%8E%E7%BB%AD%E8%AF%B4%E6%98%8E"></a>7) Follow-up Instructions</h2>  
In fact, the server will respond every time you upload. CZGL.AliIoTClient does not receive these response messages by default.  
You can use <code>OpenPropertyPostReply()</code> to receive the server's response after the device property upload, which should be used before connecting to the server.  
Use <code>Close.PropertyPostReply()</code> to cancel receiving responses after device property uploads.  

Example:  
<pre><code class="hljs less">            <span class="hljs-comment">// 。。。
            <span class="hljs-selector-tag">client<span class="hljs-selector-class">.ClosePropertyPostReply();

            <span class="hljs-comment">// Connect to server
            <span class="hljs-selector-tag">client<span class="hljs-selector-class">.ConnectIoT(topics, null, <span class="hljs-number">60);
</span></span></span></span></span></span></span></code></pre>  
Property data can be uploaded separately; it is not necessary to upload all properties each time. Just upload the property that needs to be updated.

痴者工良

高级程序员劝退师

文章评论