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

上傳屬性數據,能夠分開上傳,不須要每次都要上傳所有的屬性。須要更新哪一個屬性,就上傳這個屬性。

相關文章
相關標籤/搜索