物模型通信
設(shè)備與云端基于Alink協(xié)議進(jìn)行物模型數(shù)據(jù)通信,包括設(shè)備上報(bào)屬性或事件消息到云端,從云端下發(fā)設(shè)置屬性或調(diào)用服務(wù)消息到設(shè)備。本實(shí)踐案例提供Java Demo,介紹物模型數(shù)據(jù)通信代碼配置。
前提條件
- 已開(kāi)通物聯(lián)網(wǎng)平臺(tái)服務(wù)。
- 已安裝Java開(kāi)發(fā)環(huán)境。
創(chuàng)建產(chǎn)品和設(shè)備
首先,需創(chuàng)建產(chǎn)品和設(shè)備,為產(chǎn)品定義功能(即物模型)。
- 登錄物聯(lián)網(wǎng)平臺(tái)控制臺(tái)。
在實(shí)例概覽頁(yè)簽的全部環(huán)境下,找到對(duì)應(yīng)的實(shí)例,單擊實(shí)例卡片。
- 在左側(cè)導(dǎo)航欄,單擊 。
- 單擊創(chuàng)建產(chǎn)品,自定義產(chǎn)品名稱,選擇自定義品類,其他參數(shù)使用默認(rèn)值,然后單擊確認(rèn),完成創(chuàng)建產(chǎn)品。詳細(xì)操作指導(dǎo),請(qǐng)參見(jiàn)創(chuàng)建產(chǎn)品。
- 在產(chǎn)品詳情的功能定義頁(yè)簽下,定義物模型。
- 在左側(cè)導(dǎo)航欄,單擊設(shè)備,創(chuàng)建設(shè)備。本示例代碼中涉及批量設(shè)置設(shè)備屬性和批量調(diào)用設(shè)備服務(wù),所以需至少創(chuàng)建兩個(gè)設(shè)備。詳細(xì)操作指導(dǎo),請(qǐng)參見(jiàn)批量創(chuàng)建設(shè)備。
下載、安裝Demo SDK
本示例提供的SDK Demo中包含了服務(wù)端SDK Demo和設(shè)備端SDK Demo。
- 單擊下載iotx-api-demo,并解壓縮。
- 打開(kāi)Java開(kāi)發(fā)工具,導(dǎo)入解壓縮后的iotx-api-demo文件夾。
- 在pom.xml文件中,添加以下Maven依賴,導(dǎo)入阿里云云端SDK和設(shè)備端SDK。
<!-- https://mvnrepository.com/artifact/com.aliyun/aliyun-java-sdk-iot --> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-iot</artifactId> <version>7.33.0</version> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-core</artifactId> <version>3.5.1</version> </dependency> <dependency> <groupId>com.aliyun.alink.linksdk</groupId> <artifactId>iot-linkkit-java</artifactId> <version>1.2.0</version> <scope>compile</scope> </dependency>
- 在java/src/main/resources/目錄下的config文件中,填入初始化信息。
user.accessKeyID = <your accessKey ID> user.accessKeySecret = <your accessKey Secret> iot.regionId = <regionId> iot.productCode = Iot iot.domain = iot.<regionId>.aliyuncs.com iot.version = 2018-01-20
參數(shù) 說(shuō)明 accessKeyID 您的阿里云賬號(hào)的AccessKey ID。 將光標(biāo)定位到您的賬號(hào)頭像上,選擇AccessKey管理,進(jìn)入安全信息管理頁(yè),可創(chuàng)建或查看您的AccessKey。
accessKeySecret 您的阿里云賬號(hào)的AccessKey Secret。查看方法同上AccessKey ID。 regionId 您的物聯(lián)網(wǎng)設(shè)備所屬地域ID。地域ID的表達(dá)方法,請(qǐng)參見(jiàn)地域和可用區(qū)。
設(shè)備端SDK上報(bào)屬性和事件
配置設(shè)備端SDK連接物聯(lián)網(wǎng)平臺(tái),上報(bào)屬性和事件消息。
Demo中,java/src/main/com.aliyun.iot.api.common.deviceApi目錄下的ThingTemplate文件是設(shè)備端上報(bào)屬性和事件的Demo。
- 設(shè)置連接信息。
將代碼中productKey、deviceName、deviceSecret和url替換為您的設(shè)備證書信息和MQTT接入域名。接入域名獲取方法,請(qǐng)參見(jiàn)查看和配置實(shí)例終端節(jié)點(diǎn)信息(Endpoint),接入域名必須攜帶端口1883。
public static void main(String[] args) { /** * 設(shè)備證書信息。 */ String productKey = "your productKey"; String deviceName = "your deviceName"; String deviceSecret = "your deviceSecret"; /* TODO: 替換為您物聯(lián)網(wǎng)平臺(tái)實(shí)例的接入地址 */ String url = "iot-6d***ql.mqtt.iothub.aliyuncs.com:1883"; /** * mqtt連接信息。 */ ThingTemplate manager = new ThingTemplate(); DeviceInfo deviceInfo = new DeviceInfo(); deviceInfo.productKey = productKey; deviceInfo.deviceName = deviceName; deviceInfo.deviceSecret = deviceSecret; /** * 服務(wù)器端的Java HTTP客戶端使用TSLv1.2。 */ System.setProperty("https.protocols", "TLSv2"); manager.init(deviceInfo, url); }
- 初始化連接。
public void init(final DeviceInfo deviceInfo, String url) { LinkKitInitParams params = new LinkKitInitParams(); /** * 設(shè)置mqtt初始化參數(shù)。 */ IoTMqttClientConfig config = new IoTMqttClientConfig(); config.productKey = deviceInfo.productKey; config.deviceName = deviceInfo.deviceName; config.deviceSecret = deviceInfo.deviceSecret; config.channelHost = url; /** * 是否接受離線消息。 * 對(duì)應(yīng)mqtt的cleanSession字段。 */ config.receiveOfflineMsg = false; params.mqttClientConfig = config; ALog.setLevel(LEVEL_DEBUG); ALog.i(TAG, "mqtt connetcion info=" + params); /** * 設(shè)置初始化,傳入設(shè)備證書信息。 */ params.deviceInfo = deviceInfo; /**建立連接。**/ LinkKit.getInstance().init(params, new ILinkKitConnectListener() { public void onError(AError aError) { ALog.e(TAG, "Init Error error=" + aError); } public void onInitDone(InitResult initResult) { ALog.i(TAG, "onInitDone result=" + initResult); List<Property> properties = LinkKit.getInstance().getDeviceThing().getProperties(); ALog.i(TAG, "設(shè)備屬性列表" + JSON.toJSONString(properties)); List<Event> getEvents = LinkKit.getInstance().getDeviceThing().getEvents(); ALog.i(TAG, "設(shè)備事件列表" + JSON.toJSONString(getEvents)); /*屬性上報(bào)。TODO: 需確保所報(bào)的屬性, 比如MicSwitch, 是產(chǎn)品的物模型的一部分. 否則會(huì)返回錯(cuò)誤 */ handlePropertySet("MicSwitch", new ValueWrapper.IntValueWrapper(1)); /* 事件上報(bào). TODO: 需確保所報(bào)的事件, 比如Offline_alarm, 是產(chǎn)品的物模型的一部分. 否則會(huì)返回錯(cuò)誤 */ Map<String,ValueWrapper> values = new HashMap<>(); values.put("eventValue",new ValueWrapper.IntValueWrapper(0)); OutputParams outputParams = new OutputParams(values); handleEventSet("Offline_alarm",outputParams); } }); }
說(shuō)明 代碼中的屬性和事件標(biāo)識(shí)符需與物模型中定義的標(biāo)識(shí)符一致。 - 設(shè)置設(shè)備端上報(bào)屬性。
/** * Alink JSON方式設(shè)備端上報(bào)屬性。 * @param identifier:屬性標(biāo)識(shí)符。 * @param value:上報(bào)屬性值。 * @return */ private void handlePropertySet(String identifier, ValueWrapper value ) { ALog.i(TAG, "上報(bào)屬性identity=" + identifier); Map<String, ValueWrapper> reportData = new HashMap<>(); reportData.put(identifier, value); LinkKit.getInstance().getDeviceThing().thingPropertyPost(reportData, new IPublishResourceListener() { public void onSuccess(String s, Object o) { // 屬性上報(bào)成功。 ALog.i(TAG, "上報(bào)成功 onSuccess() called with: s = [" + s + "], o = [" + o + "]"); } public void onError(String s, AError aError) { // 屬性上報(bào)失敗。 ALog.i(TAG, "上報(bào)失敗onError() called with: s = [" + s + "], aError = [" + JSON.toJSONString(aError) + "]"); } }); }
- 設(shè)置設(shè)備端上報(bào)事件。
/** * Alink JSON方式設(shè)備端上報(bào)事件。 * @param identifyID:事件標(biāo)識(shí)符。 * @param params:事件上報(bào)參數(shù)。 * @return */ private void handleEventSet(String identifyID, OutputParams params ) { ALog.i(TAG, "上報(bào)事件 identifyID=" + identifyID + " params=" + JSON.toJSONString(params)); LinkKit.getInstance().getDeviceThing().thingEventPost( identifyID, params, new IPublishResourceListener() { public void onSuccess(String s, Object o) { // 事件上報(bào)成功。 ALog.i(TAG, "上報(bào)成功 onSuccess() called with: s = [" + s + "], o = [" + o + "]"); } public void onError(String s, AError aError) { // 事件上報(bào)失敗。 ALog.i(TAG, "上報(bào)失敗onError() called with: s = [" + s + "], aError = [" + JSON.toJSONString(aError) + "]"); } }); }
云端SDK下發(fā)設(shè)置屬性和調(diào)用服務(wù)指令
- 初始化SDK客戶端。
Demo中,java/src/main/com.aliyun.iot.client目錄下IotClient文件是SDK客戶端初始化Demo。
public class IotClient { private static String accessKeyID; private static String accessKeySecret; private static String regionId; private static String domain; private static String version; public static DefaultAcsClient getClient() { DefaultAcsClient client = null; Properties prop = new Properties(); try { prop.load(Object.class.getResourceAsStream("/config.properties")); accessKeyID = prop.getProperty("user.accessKeyID"); accessKeySecret = prop.getProperty("user.accessKeySecret"); regionId = prop.getProperty("iot.regionId"); domain = prop.getProperty("iot.domain"); version = prop.getProperty("iot.version"); IClientProfile profile = DefaultProfile.getProfile(regionId, accessKeyID, accessKeySecret); DefaultProfile.addEndpoint(regionId, regionId, prop.getProperty("iot.productCode"), prop.getProperty("iot.domain")); // 初始化client。 client = new DefaultAcsClient(profile); } catch (Exception e) { LogUtil.print("初始化client失敗!exception:" + e.getMessage()); } return client; } public static String getRegionId() { return regionId; } public static void setRegionId(String regionId) { IotClient.regionId = regionId; } public static String getDomain() { return domain; } public static void setDomain(String domain) { IotClient.domain = domain; } public static String getVersion() { return version; } public static void setVersion(String version) { IotClient.version = version; } }
- 初始化封裝CommonRequest公共類。
Demo中,java/src/main/com.aliyun.iot.api.common.openApi目錄下的AbstractManager文件是封裝云端API的CommonRequest公共類的Demo。
public class AbstractManager { private static DefaultAcsClient client; static { client = IotClient.getClient(); } /** * 接口請(qǐng)求地址。action:接口名稱。 * domain:線上地址。 * version:接口版本。 */ public static CommonRequest executeTests(String action) { CommonRequest request = new CommonRequest(); request.setDomain(IotClient.getDomain()); request.setMethod(MethodType.POST); request.setVersion(IotClient.getVersion()); request.setAction(action); return request; }
- 配置云端SDK調(diào)用物聯(lián)網(wǎng)平臺(tái)云端API,下發(fā)設(shè)置屬性和調(diào)用服務(wù)的指令。
java/src/main/com.aliyun.iot.api.common.openApi目錄下的ThingManagerForPopSDk是云端SDK調(diào)用API設(shè)置設(shè)備屬性和調(diào)用設(shè)備服務(wù)的Demo文件。
- 調(diào)用SetDeviceProperty設(shè)置設(shè)備屬性值。
public static void SetDeviceProperty(String InstanceId, String IotId, String ProductKey, String DeviceName , String Items) { SetDevicePropertyResponse response =null; SetDevicePropertyRequest request=new SetDevicePropertyRequest(); request.setDeviceName(DeviceName); request.setIotId(IotId); request.setItems(Items); request.setProductKey(ProductKey); request.setIotInstanceId(InstanceId); try { response = client.getAcsResponse(request); if (response.getSuccess() != null && response.getSuccess()) { LogUtil.print("設(shè)置設(shè)備屬性成功"); LogUtil.print(JSON.toJSONString(response)); } else { LogUtil.print("設(shè)置設(shè)備屬性失敗"); LogUtil.error(JSON.toJSONString(response)); } } catch (ClientException e) { e.printStackTrace(); LogUtil.error("設(shè)置設(shè)備屬性失敗!" + JSON.toJSONString(response)); } }
- 調(diào)用SetDevicesProperty批量設(shè)置設(shè)備屬性值。
/** * 批量設(shè)置設(shè)備屬性。 * * @param ProductKey:要設(shè)置屬性的設(shè)備所隸屬的產(chǎn)品Key。 * @param DeviceNames:要設(shè)置屬性的設(shè)備名稱列表。 * @param Items:要設(shè)置的屬性信息,組成為key:value,數(shù)據(jù)格式為JSON String,必須傳入。 * * @Des:描述。 */ public static void SetDevicesProperty(String InstanceId, String ProductKey, List<String> DeviceNames, String Items) { SetDevicesPropertyResponse response = new SetDevicesPropertyResponse(); SetDevicesPropertyRequest request = new SetDevicesPropertyRequest(); request.setDeviceNames(DeviceNames); request.setItems(Items); request.setProductKey(ProductKey); request.setIotInstanceId(InstanceId); try { response = client.getAcsResponse(request); if (response.getSuccess() != null && response.getSuccess()) { LogUtil.print("批量設(shè)置設(shè)備屬性成功"); LogUtil.print(JSON.toJSONString(response)); } else { LogUtil.print("批量設(shè)置設(shè)備屬性失敗"); LogUtil.error(JSON.toJSONString(response)); } } catch (ClientException e) { e.printStackTrace(); LogUtil.error("批量設(shè)置設(shè)備屬性失敗!" + JSON.toJSONString(response)); } }
- 調(diào)用InvokeThingService調(diào)用設(shè)備服務(wù)。
/** * @param Identifier:服務(wù)的Identifier,必須傳入。 * @param Args:要啟用服務(wù)的入?yún)⑿畔ⅲ仨殏魅搿? */ public static InvokeThingServiceResponse.Data InvokeThingService(String InstanceId, String IotId, String ProductKey, String DeviceName, String Identifier, String Args) { InvokeThingServiceResponse response =null; InvokeThingServiceRequest request = new InvokeThingServiceRequest(); request.setArgs(Args); request.setDeviceName(DeviceName); request.setIotId(IotId); request.setIdentifier(Identifier); request.setProductKey(ProductKey); request.setIotInstanceId(InstanceId); try { response = client.getAcsResponse(request); if (response.getSuccess() != null && response.getSuccess()) { LogUtil.print("服務(wù)執(zhí)行成功"); LogUtil.print(JSON.toJSONString(response)); } else { LogUtil.print("服務(wù)執(zhí)行失敗"); LogUtil.error(JSON.toJSONString(response)); } return response.getData(); } catch (ClientException e) { e.printStackTrace(); LogUtil.error("服務(wù)執(zhí)行失敗!" + JSON.toJSONString(response)); } return null; }
- 調(diào)用InvokeThingsService批量調(diào)用設(shè)備服務(wù)。
/** * @param Identifier:服務(wù)的Identifier,必須傳入。 * @param Args:要啟用服務(wù)的入?yún)⑿畔ⅲ仨殏魅搿? */ public static void InvokeThingsService(String InstanceId, String IotId, String ProductKey, List<String> DeviceNames, String Identifier, String Args) { InvokeThingsServiceResponse response =null; InvokeThingsServiceRequest request = new InvokeThingsServiceRequest(); request.setArgs(Args); request.setIdentifier(Identifier); request.setDeviceNames(DeviceNames); request.setProductKey(ProductKey); request.setIotInstanceId(InstanceId); try { response = client.getAcsResponse(request); if (response.getSuccess() != null && response.getSuccess()) { LogUtil.print("批量調(diào)用設(shè)備服務(wù)成功"); LogUtil.print(JSON.toJSONString(response)); } else { LogUtil.print("批量調(diào)用設(shè)備服務(wù)失敗"); LogUtil.error(JSON.toJSONString(response)); } } catch (ClientException e) { e.printStackTrace(); LogUtil.error("批量調(diào)用設(shè)備服務(wù)失敗!" + JSON.toJSONString(response)); } }
- 調(diào)用SetDeviceProperty設(shè)置設(shè)備屬性值。
設(shè)置屬性和調(diào)用服務(wù)的請(qǐng)求示例:
public static void main(String[] args) {
/**上線設(shè)備的設(shè)備名稱和所屬產(chǎn)品的ProductKey。*/
String deviceName = "2pxuAQB2I7wGPmqq***";
String deviceProductkey = "a1QbjI2***";
/**對(duì)于企業(yè)版實(shí)例和新版公共實(shí)例,設(shè)置InstanceId為具體實(shí)例ID值,您可在物聯(lián)網(wǎng)平臺(tái)控制臺(tái)的實(shí)例概覽頁(yè)面,查看當(dāng)前實(shí)例的ID。
*對(duì)于舊版公共實(shí)例,設(shè)置InstanceId為空值""。
*/
String InstanceId = "iot-***tl02";
//1 設(shè)置設(shè)備的屬性。
SetDeviceProperty(InstanceId, null, deviceProductkey, deviceName,"{\"hue\":0}");
//2 批量設(shè)置設(shè)備屬性。
List<String> deviceNames = new ArrayList<>();
deviceNames.add(deviceName);
SetDevicesProperty(InstanceId, deviceProductkey, deviceNames, "{\"hue\":0}");
//3 調(diào)用設(shè)備的服務(wù)。
InvokeThingService(InstanceId, null, deviceProductkey, deviceName, "ModifyVehicleInfo", "{}");
//4 批量調(diào)用設(shè)備的服務(wù)。
List<String> deviceNamesService = new ArrayList<>();
deviceNamesService.add(deviceName);
InvokeThingsService(InstanceId, null, deviceProductkey, deviceNamesService, "ModifyVehicleInfo", "{}");
}
運(yùn)行調(diào)試
設(shè)備端SDK和云端SDK配置完成后,運(yùn)行各SDK。
查看結(jié)果:
- 查看本地日志。
- 在物聯(lián)網(wǎng)平臺(tái)控制臺(tái),對(duì)應(yīng)實(shí)例下設(shè)備的設(shè)備詳情頁(yè)面,單擊默認(rèn)模塊:
- 運(yùn)行狀態(tài)頁(yè)簽下,查看設(shè)備最后一次上報(bào)的屬性值和屬性數(shù)據(jù)記錄。
- 事件管理頁(yè)簽下,查看設(shè)備上報(bào)的事件記錄。
- 服務(wù)調(diào)用頁(yè)簽下,查看云端下發(fā)的服務(wù)調(diào)用記錄。