DISCLAIMER
Please note that all content presented on this page is provided by Tuya (HK) Limited. Alibaba Cloud makes no representations and warranties, explicit or implied, as to the authenticity or accuracy of any such content, nor makes any guarantee to the condition, quality, durability, performance, reliability, merchantability or fitness for a particular purpose, or non-infringement of any products and/or services made available by Tuya (HK) Limited.
In the Internet of Things solution, if the device is not online when distributing attributes, the distribution will fail. If you want to be more elegant and efficient to complete the distribution of attributes? The IoT platform provides the function of setting expected attribute values. By caching the expected values of device attributes, the IoT platform can control device attribute values from the cloud. This article introduces the operation of setting the desired attribute value to control the status of the light bulb from the Internet of Things platform.
Scene Information
After the Switch device is connected to the Internet of Things platform, if the working state of the light bulb needs to be controlled from the Internet of Things platform (1: On; 0: off), the light bulb needs to be kept online all the time. In reality, the light bulb may not always be online. You can set expected device attribute values on IoT Platform so that they are stored in IoT Platform. After the device is online, it can read the expected attribute value stored by the IoT platform to update its own attribute value. Then, the device reports the updated attribute values to IoT Platform.
Overall Process
1. Create products and equipment 2. Use Postman to simulate devices 3. Set and get the desired properties. 4. Equipment development
Create Products And Devices
1 Enter Tuya IoT platform Alibaba Cloud Computing nest . 2 In service Instance tab fully Managed Services find the corresponding instance and click the instance card.
3 In the left navigation bar, choose product Development> Products , click create Product , create a product: bulb test.
4 After the product is successfully created, click continue to develop heading function Definition , add custom features to the product and publish it. As shown in the figure, this example adds the attribute working status (LightStatus) .
5 In the left navigation bar, choose device Management> Device List , click add Device , add equipment under the BULB product: LampTest. After the device is added, obtain the device certificate information (ProductKey, DeviceName, and DeviceSecret).
In the device list, you can click view enter equipment Details page, viewing running status and connection parameters
Using Postman To Simulate A Device
1. You can carry the MQTT connection parameters in Postman create a corresponding MQTT connection. For more information, see using Postman to simulate a device.
2. Complete the pair /sys/${productKey}/${deviceName}/thing/service/property/set subscribe to a topic.
Set and Get Expected Property Values
You can provide through the platform. Java signature sample codegenerate after the URL syntax, call the IoT platform cloud API to set the desired device attribute value. 1. Find the corresponding code block in the OpenAPISignatureDemo class of the sample code and complete the replacement of the SetDeviceDesiredProperty method parameter.
//Method 2: There is already a parameter map, use the parameters to sign it
Map<String, String> map = new HashMap<String, String>();
//Public parameters
map.put("AccessKeyId", accessKey);
map.put("SignatureMethod", "HMAC-SHA1");
map.put("Timestamp", formattedDateTime);
map.put("SignatureNonce", signatureOnce);
//Interface request parameters
map.put("Action", "SetDeviceDesiredProperty");
map.put("Versions", "{}");
map.put("Items", "{\"LightStatus\":13}");
map.put("ProductKey", "xZluAsUunlbuhDdG");
map.put("DeviceName", "LampTest");
try {
String signature = SignatureUtils.generate(httpMethod, map, secretKey);
System. out. println ("[Method 2: Start Generating]=====Generate signature based on parameters and generate curl command");
System.out.println("curl " + "'" + host+"/?"+buildQueryParam(map) + "&Signature=" + signature + "'");
} catch (Exception e) {
System. out. println ("signature generation failed"+e.g. etMessage ());
e.printStackTrace();
}
After execution, you will get the following URL syntax request.
curl 'https://si-d6e8d812acb848958054.tuyacloud.com:8686/?Action=SetDeviceDesiredProperty&Versions=%7B%7D&SignatureNonce=c653621a65e444b18786e0f096e92b72&AccessKeyId=xMr9wgwXQLhv5AUa65o03mcD&SignatureMethod=HMAC-SHA1&Items=%7B%22LightStatus%22%3A1%7D&Timestamp=2024-11-19T10%3A24%3A29Z&ProductKey=xZluAsUunlbuhDdG&DeviceName=LampTest&Signature=d3RCeZ%2FSk2orvOn8XHzVn3jh8NM%3D'
When the device is online, device monitoring/sys/ ${productKey}/${deviceName} /thing/service/property/set can receive the set properties directly
When the device is offline, the device cannot receive the message, after the device goes online, push the corresponding uplink message through/sys/${productKey}/${deviceName}/thing/property/desired/get, subscribe to/sys/${productKey}/${deviceName}/thing/property/desired/get_reply to obtain the latest desired properties. Specific message format can be referred device Expected Attribute Value
Device Development
The device obtains the expected attribute value. There are two scenarios: ●When the light bulb goes online again, it actively obtains the expected attribute value of the cloud cache of the Internet of Things platform. ●The light bulb is in the online state and receives the expected attribute values pushed by the IoT platform in real time. For more information on device-side development, see use the device SDK to access . This article uses Java code as an example to provide a device Demo example. For more information, see the following Appendix: Device Demo code. 1 enter the information of the device certificate, region, and MQTT access address.
/**
* Información del certificado del dispositivo
*/
cadena estática privada productKey = "******";
Nombre del dispositivo de cadena estática privada = "********";
cadena estática privada deviceSecret = "***************";
/**
* Información de conexión MQTT
*/
cadena estática privada regionId = "******";
Cadena estática privada iotInstanceId = "si-*************";
...
/**
* Establecer los parámetros de inicialización de Mqtt
*/
config.channelHost = iotInstanceId + ".aliyun.tuyacloud.com:1883";
2. Add the following method to change the attributes of the actual light bulb and report the information to the latest attribute value after the attribute is changed.
/**
*When real devices handle attribute changes, they will be called in the following two fields:
*Scenario 1 Proactively obtain the latest expected attribute values after device networking (initiated by the device, pull mode)
*Scenario 2 When the device is online, it receives the expected value of the attribute pushed by the cloud's property. set (initiated by the cloud, push mode)
*@ param identifier attribute identifier
*@ param value Expected attribute value
*Whether @ paramNeedReport sends status reports through property. post.
*The processing function in scenario 2 has integrated attribute reporting capability and will set the demandReport to false
* @return
*/
private boolean handlePropertySet(String identifier, ValueWrapper value, boolean needReport) {
ALog.d(TAG, "Real device processing attribute changes = [" + identifier + "], value = [" + value + "]");
// The user determines whether the setting is successful based on the actual situation, and the test returns success directly here
boolean success = true;
if (needReport) {
reportProperty(identifier, value);
}
return success;
}
private void reportProperty(String identifier, ValueWrapper value){
if (StringUtils.isEmptyString(identifier) || value == null) {
return;
}
ALog.d(TAG, "Report attributes 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) {
// Attribute reporting successful
ALog.d(TAG, "Report successful onSuccess() called with: s = [" + s + "], o = [" + o + "]");
}
public void onError(String s, AError aError) {
// Attribute reporting failed
ALog.d(TAG, "Reporting failed onError() called with: s = [" + s + "], aError = [" + JSON.toJSONString(aError) + "]");
}
});
}
3. When the bulb is online, if the IoT platform sets the expected attribute value of the bulb, the value will be pushed to the device. The light bulb processes the message and changes the property state. In the following code, connectNotifyListener to process messages, for details about the Alink protocol, see Device properties, events, and services. After receiving the asynchronous downlink data, mCommonHandler is called, which in turn calls handlePropertySet update the physical properties of the device.
/**
* Response function for registering service calls (and property settings)。
* When calling a service from a device in the cloud, the device needs to respond to the service and reply。
*/
public void connectNotifyListener() {
List<Service> serviceList = LinkKit.getInstance().getDeviceThing().getServices();
for (int i = 0; serviceList != null && i < serviceList.size(); i++) {
Service service = serviceList.get(i);
LinkKit.getInstance().getDeviceThing().setServiceHandler(service.getIdentifier(), mCommonHandler);
}
}
private ITResRequestHandler mCommonHandler = new ITResRequestHandler() {
public void onProcess(String serviceIdentifier, Object result, ITResResponseCallback itResResponseCallback) {
ALog.d(TAG, "onProcess() called with: s = [" + serviceIdentifier + "]," +
" o = [" + result + "], itResResponseCallback = [" + itResResponseCallback + "]");
ALog.d(TAG, "Received asynchronous service call from the cloud " + serviceIdentifier);
try {
if (SERVICE_SET.equals(serviceIdentifier)) {
Map<String, ValueWrapper> data = (Map<String, ValueWrapper>)((InputParams)result).getData();
ALog.d(TAG, "Received asynchronous downlink data " + data);
// Set the properties of the real device and report the completed property values
boolean isSetPropertySuccess =
handlePropertySet("LightStatus", data.get("LightStatus"), false);
if (isSetPropertySuccess) {
if (result instanceof InputParams) {
// Response to cloud, data received successfully
itResResponseCallback.onComplete(serviceIdentifier, null, null);
} else {
itResResponseCallback.onComplete(serviceIdentifier, null, null);
}
} else {
AError error = new AError();
error.setCode(100);
error.setMsg("setPropertyFailed.");
itResResponseCallback.onComplete(serviceIdentifier, new ErrorInfo(error), null);
}
} else if (SERVICE_GET.equals(serviceIdentifier)) {
} else {
// Handling different services differently is related to the specific service
ALog.d(TAG, "Return the value of the service based on the actual service, please refer to the set example");
OutputParams outputParams = new OutputParams();
// outputParams.put("op", new ValueWrapper.IntValueWrapper(20));
itResResponseCallback.onComplete(serviceIdentifier, null, outputParams);
}
} catch (Exception e) {
e.printStackTrace();
ALog.d(TAG, "Abnormal data format returned from the cloud");
}
}
public void onSuccess(Object o, OutputParams outputParams) {
ALog.d(TAG, "onSuccess() called with: o = [" + o + "], outputParams = [" + outputParams + "]");
ALog.d(TAG, "Registration service successful");
}
public void onFail(Object o, ErrorInfo errorInfo) {
ALog.d(TAG, "onFail() called with: o = [" + o + "], errorInfo = [" + errorInfo + "]");
ALog.d(TAG, "Registration service failed");
}
};
4. After the light bulb is offline, if the desired attribute value of the light is set on the cloud of the Internet of Things platform, the value will be stored in the cloud. After the light bulb goes online, it actively obtains the desired attribute value and then calls handlePropertySet update the properties of the actual device.
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);
connectNotifyListener();
// Get the latest expected attribute values from the cloud
getDesiredProperty(deviceInfo, Arrays.asList("LightStatus"), new IConnectSendListener() {
public void onResponse(ARequest aRequest, AResponse aResponse) {
if(aRequest instanceof MqttPublishRequest && aResponse.data != null) {
JSONObject jsonObject = JSONObject.parseObject(aResponse.data.toString());
ALog.i(TAG, "onResponse result=" + jsonObject);
JSONObject dataObj = jsonObject.getJSONObject("data");
if (dataObj != null) {
if (dataObj.getJSONObject("LightStatus") == null) {
// Expected value not set
} else {
Integer value = dataObj.getJSONObject("LightStatus").getInteger("value");
handlePropertySet("LightStatus", new ValueWrapper.IntValueWrapper(value), true);
}
}
}
}
public void onFailure(ARequest aRequest, AError aError) {
ALog.d(TAG, "onFailure() called with: aRequest = [" + aRequest + "], aError = [" + aError + "]");
}
});
}
});
private void getDesiredProperty(BaseInfo info, List<String> properties, IConnectSendListener listener) {
ALog.d(TAG, "getDesiredProperty() called with: info = [" + info + "], listener = [" + listener + "]");
if(info != null && !StringUtils.isEmptyString(info.productKey) && !StringUtils.isEmptyString(info.deviceName)) {
MqttPublishRequest request = new MqttPublishRequest();
request.topic = DESIRED_PROPERTY_GET.replace("{productKey}", info.productKey).replace("{deviceName}", info.deviceName);
request.replyTopic = DESIRED_PROPERTY_GET_REPLY.replace("{productKey}", info.productKey).replace("{deviceName}", info.deviceName);
request.isRPC = true;
RequestModel<List<String>> model = new RequestModel<>();
model.id = String.valueOf(IDGeneraterUtils.getId());
model.method = METHOD_GET_DESIRED_PROPERTY;
model.params = properties;
model.version = "1.0";
request.payloadObj = model.toString();
ALog.d(TAG, "getDesiredProperty: payloadObj=" + request.payloadObj);
ConnectSDK.getInstance().send(request, listener);
} else {
ALog.w(TAG, "getDesiredProperty failed, baseInfo Empty.");
if(listener != null) {
AError error = new AError();
error.setMsg("BaseInfoEmpty.");
listener.onFailure(null, error);
}
}
}