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.
文章评论