物模型是阿里雲物聯網平台為產品定義的資料模型。您可以通過Android Link SDK,實現裝置端上報屬性和事件,並接收物聯網平台發送的設定屬性和調用服務的指令。
背景資訊
物聯網平台物模型功能的更多資訊,請參見什麼是物模型。
物模型資料格式的更多資訊,請參見裝置屬性、事件、服務。
使用說明
調用下文提及的物模型相關介面後,回調中onSuccess僅代表對應訊息從裝置發出成功,不代表訊息對應的任務執行成功。裝置執行商務邏輯請勿依賴onSuccess。
Android Link SDK中,通過
getDeviceThing(),擷取的物模型對象即為IThing。IThing的詳細說明,請參見 IThing ApiReference。Android Link SDK預設未開啟物模型功能,如需使用,請參見一機一密裝置認證方式的範例程式碼Step 5。
調用物模型介面後,如果您需根據物模型指令的執行結果編寫業務的處理邏輯,請參考Demo的
InitManager.java類中的函數IConnectNotifyListener介面onNotify,處理下行訊息。具體代碼實現請參見Demo中的
TSLActivity.java。
裝置上報屬性
上報屬性:
// 裝置上報 Map<String, ValueWrapper> reportData = new HashMap<>(); // identifier為物聯網平台定義的屬性標識符,valueWrapper為屬性的值 // ValueWrapper valueWrapper = new ValueWrapper.BooleanValueWrapper(1); //以布爾型變數值1為例 // reportData.put(identifier, valueWrapper); // 參考樣本,更多使用可參考Demo LinkKit.getInstance().getDeviceThing().thingPropertyPost(reportData, new IPublishResourceListener() { @Override public void onSuccess(String alinkId, Object o) { // 訊息從裝置發出成功 // alinkId表示該訊息的messageId } public void onError(String alinkId, AError aError) { // 屬性上報失敗 // alinkId表示該訊息的messageId } });說明從1.7.3.1版本開始,
thingPropertyPost的回調介面通過alinkId欄位透出當前所發送的上行訊息的ID。如果要觀察裝置上報的屬性訊息是否已到達雲端,可以在訂閱
/sys/${productKey}/${deviceName}/thing/event/property/post_reply訊息後,關注IConnectNotifyListener類(參考Demo的InitManager.java)的介面onNotify。該介面會透出reply訊息的alinkId,如果上下行訊息的alinkId一致,表示上行訊息已經被服務端處理。
擷取屬性:
擷取的是緩衝在裝置本地的屬性資料,不是雲端即時的屬性資料。
// 通過identifier擷取物模型對應屬性的值(預設模組, 非使用者自訂模組) String identifier = "******"; LinkKit.getInstance().getDeviceThing().getPropertyValue(identifier); // 擷取預設模組(非使用者自訂模組)的屬性列表 LinkKit.getInstance().getDeviceThing().getProperties()
裝置上報事件
HashMap<String, ValueWrapper> hashMap = new HashMap<>();
// TODO 您需根據業務實際情況修改該代碼
// hashMap.put("ErrorCode", new ValueWrapper.IntValueWrapper(0));
OutputParams params = new OutputParams(hashMap);
LinkKit.getInstance().getDeviceThing().thingEventPost(identifier, params, new IPublishResourceListener() {
@Override
public void onSuccess(String alinkId, Object o) {
// 訊息從裝置發出成功
// alinkId表示該訊息的messageId
}
public void onError(String alinkId, AError aError) {
// 事件上報失敗
// alinkId表示該訊息的messageId
}
});從1.2.3版本開始,
thingEventPost的回調介面通過alinkId欄位透出當前所發送的上行訊息的ID。如果要觀察裝置上報的事件訊息是否已到達雲端,可以在訂閱
/sys/${productKey}/${deviceName}/thing/event/${tsl.event.identifier}/post_reply訊息後,關注IConnectNotifyListener類(參考Demo的InitManager.java)的介面onNotify。該介面會透出reply訊息的alinkId,如果上下行訊息的alinkId一致,表示上行訊息已經被服務端處理。
擷取預設模組(非使用者自訂模組)的事件列表:
擷取的是裝置本地的事件,不是上報到物聯網平台的即時事件。
LinkKit.getInstance().getDeviceThing().getEvents()雲端下發屬性和服務
裝置調用服務擷取Service的定義,請參見 Service API Reference。
擷取預設模組(非使用者自訂模組)的服務列表
LinkKit.getInstance().getDeviceThing().getServices()裝置的服務調用支援同步和非同步兩種方式。裝置屬性的設定和擷取也是通過該服務調用的監聽方式,實現物聯網平台服務的下發。
非同步呼叫
設定方法
callType="async"裝置註冊服務的處理監聽器,當物聯網平台觸發非同步服務調用時,下行的請求會到註冊的監聽器中。
onProcess為裝置收到的雲端下行的服務調用。其中,第一個參數為需調用服務對應的identifier。您可根據identifier做不同的業務處理。identifier為服務的標識符,更多資訊,請參見標識符。
裝置收到物聯網平台的下行服務調用後,根據指令執行對應操作,操作結束後上報一條屬性狀態變化的通知。
相關代碼
List<Service> serviceList = thing.getServices(); //設定handler處理屬性下發,以及預設模組中的非同步服務. 如果是使用者自訂模組的非同步服務,請參見"模組化服務的註冊"一節 for (int i = 0; serviceList != null && i < srviceList.size(); i++) { Service service = serviceList.get(i); LinkKit.getInstance().getDeviceThing().setServiceHandler(service.getIdentifier(), mCommonHandler); } private ITResRequestHandler mCommonHandler = new ITResRequestHandler() { @Override public void onProcess(String identify, Object result, ITResResponseCallback itResResponseCallback) { AppLog.d(TAG, "onProcess() called with: s = [" + identify + "], o = [" + result + "], itResResponseCallback = [" + itResResponseCallback + "]"); try { if (SERVICE_SET.equals(identify)) { /* 雲端下發屬性到裝置 */ // TODO 1:使用者需要按照真實裝置的介面調用,設定裝置的屬性. 使用者根據實際情況判斷屬性是否設定成功. // TODO 2:設定完真實裝置屬性之後,上報設定完成的屬性值. 這裡是測試代碼,做了簡化,直接返回成功 boolean isSetPropertySuccess = true; if (isSetPropertySuccess){ if (result instanceof InputParams) { //TODO 3:解析服務端下行的屬性資料 Map<String, ValueWrapper> data = (Map<String, ValueWrapper>) ((InputParams) result).getData(); // data.get() // 響應雲端 接收資料成功 itResResponseCallback.onComplete(identify, null, null); } else { itResResponseCallback.onComplete(identify, null, null); } } else { AError error = new AError(); error.setCode(100); error.setMsg("setPropertyFailed."); itResResponseCallback.onComplete(identify, new ErrorInfo(error), null); } } else if (SERVICE_GET.equals(identify)){ // 不需要使用者處理 } else { // 雲端下發服務到裝置. // TODO: 根據不同的服務做不同的處理,跟具體的服務有關係 OutputParams outputParams = new OutputParams(); // 參考例子: outputParams.put("op", new ValueWrapper.IntValueWrapper(20)); itResResponseCallback.onComplete(identify,null, outputParams); } } catch (Exception e) { e.printStackTrace(); } } @Override public void onSuccess(Object o, OutputParams outputParams) { AppLog.d(TAG, "onSuccess() called with: o = [" + o + "], outputParams = [" + outputParams + "]"); } @Override public void onFail(Object o, ErrorInfo errorInfo) { AppLog.d(TAG, "onFail() called with: o = [" + o + "], errorInfo = [" + errorInfo + "]"); } };同步調用
設定方法
callType="sync"先註冊一個下行資料監聽,註冊方法請參見認證與串連中串連狀態與下行訊息監聽的
notifyListener。當雲端觸發服務調用時,使用者可以在
onNotify收到雲端的下行服務調用。使用者收到雲端的下行服務調用後,根據實際服務調用對裝置做服務處理,處理之後需要裝置回複雲端的請求,即發布一個帶有處理結果的請求到雲端。
說明新版本的Android Link SDK支援自訂RRPC,如果您的SDK是由低版本升級而來,請注意同步服務屬性下行的通道為RRPC。
相關代碼
private static IConnectNotifyListener notifyListener = new IConnectNotifyListener() { @Override public void onNotify(String connectId, String topic, AMessage aMessage) { String data = new String((byte[]) aMessage.data); // 服務端返回資料樣本 data = {"method":"thing.service.test_service","id":"123374967","params":{"vv":60},"version":"1.0.0"} AppLog.d(TAG, "onNotify() called with: connectId = [" + connectId + "], topic = [" + topic + "], aMessage = [" + data + "]"); if (ConnectSDK.getInstance().getPersistentConnectId().equals(connectId) && !TextUtils.isEmpty(topic) && topic.startsWith("/ext/rrpc/")) { // 1.處理/ext/rrpc開頭的同步服務的topic //樣本 topic=/ext/rrpc/1138654706478941696//a1ExY4afKY1/testDevice/user/get //AppLog.d(TAG, "receice Message=" + new String((byte[]) aMessage.data)); //回複服務端資料樣本 {"method":"thing.service.test_service","id":"123374967","params":{"vv":60},"version":"1.0.0"} MqttPublishRequest request = new MqttPublishRequest(); request.isRPC = false; request.topic = topic; String[] array = topic.split("/"); String resId = array[3]; request.msgId = resId; String alinkdId = null; try{ JSONObject jsonObject = JSONObject.parseObject(data); alinkdId = jsonObject.getString("id"); }catch (Exception e){ AppLog.e(TAG,"parse alinkId failed, exit"); return; } // 雲端下發了同步服務,需要做回複,否則服務端會顯示調用逾時 // TODO 使用者根據實際情況填寫 僅做參考 request.payloadObj = "{\"id\":\"" + alinkdId + "\", \"code\":\"200\"" + ",\"data\":{\"aa\":1} }"; LinkKit.getInstance().publish(request, new IConnectSendListener() { @Override public void onResponse(ARequest aRequest, AResponse aResponse) { // 響應成功 } @Override public void onFailure(ARequest aRequest, AError aError) { // 響應失敗 } }); } else if (ConnectSDK.getInstance().getPersistentConnectId().equals(connectId) && !TextUtils.isEmpty(topic) && topic.startsWith("/sys/" + DemoApplication.productKey + "/" + DemoApplication.deviceName + "/rrpc/request/")) { // 2.處理/sys開頭的同步服務的topic // AppLog.d(TAG, "receice Message=" + new String((byte[]) aMessage.data)); // 回複服務端資料樣本 {"method":"thing.service.test_service","id":"123374967","params":{"vv":60},"version":"1.0.0"} MqttPublishRequest request = new MqttPublishRequest(); // 支援 0 和 1, 預設0 // request.qos = 0; request.isRPC = false; request.topic = topic.replace("request", "response"); String[] array = topic.split("/"); String resId = array[6]; request.msgId = resId; // TODO 使用者根據實際情況填寫 僅做參考 request.payloadObj = "{\"id\":\"" + resId + "\", \"code\":\"200\"" + ",\"data\":{} }"; LinkKit.getInstance().publish(request, new IConnectSendListener() { @Override public void onResponse(ARequest aRequest, AResponse aResponse) { } @Override public void onFailure(ARequest aRequest, AError aError) { } }); } else { // 3.處理其他訊息 /** * TODO * 根據訂閱的具體 topic 做業務處理 */ } //TODO: 實現其他回調 }
模組化物模型
使用說明
只有iot-device-manager的1.7.5.2及以上版本支援模組化物模型。
在物模型預設的模組中,屬性、事件、服務的identifier不用加首碼。例如名為
lightSwitch的屬性,identifier就是lightSwitch。在使用者自訂的模組中,屬性、事件、服務的identifier要加模組名為首碼。例如
myBlock模組中的lightSwitch屬性,identifier要寫成myBlock:lightSwitch。
模組化物模型屬性的上報
以上報myBlock模組中的lightSwitch屬性為例:
Map<String, ValueWrapper> reportData = new HashMap<>();
// identifier為物聯網平台定義的屬性的標識符,valueWrapper為屬性的值
String identifier = "myBlock:lightSwitch";
reportData.put(identifier, valueWrapper); // 參考樣本,更多內容可參考Demo
LinkKit.getInstance().getDeviceThing().thingPropertyPost(reportData, new IPublishResourceListener() {
@Override
public void onSuccess(String resID, Object o) {
// 屬性上報成功
}
@Override
public void onError(String resId, AError aError) {
// 屬性上報失敗
}
});模組化物模型事件的上報
以上報map模組中的OnDetect事件為例:
HashMap<String, ValueWrapper> hashMap = new HashMap<>();
hashMap.put("StoreID", new ValueWrapper.StringValueWrapper("1"));
OutputParams params = new OutputParams(hashMap);
LinkKit.getInstance().getDeviceThing().thingEventPost("map:OnDetect", params, new IPublishResourceListener() {
@Override
public void onSuccess(String resId, Object o) { // 事件上報動作成功
}
@Override
public void onError(String resId, AError aError) { // 事件上報失敗
}
});模組化服務的註冊
使用者自訂模組中的服務要先向SDK註冊,才能監聽到相應的回調,以map模組中的VehDtcService服務為例,需要通過如下方式訂閱:
thing.setServiceHandler("map:VehDtcService", resRequestHandler);其中resRequestHandler是物模型報文處理handler的執行個體,請參見demo中的TSLActivity.java。