阿里雲物聯網 .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); 

上傳屬性數據,可以分開上傳,不需要每次都要上傳全部的屬性。需要更新哪個屬性,就上傳這個屬性。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM