Device shadow
Updated at:
If a product does not support the Thing Specification Language (TSL) model, you can use a device shadow to cache the latest status of the device in the cloud. The cloud caches the latest data in JSON format, which you must parse as required. The TSL model provides advanced device shadow features. It lets you display properties, events, and services independently and maintains a history of all operations.
Data upstream
Note For more information about the device shadow interface, see IDeviceShadow.
- Retrieve the device shadow from the cloud
- Update the device shadow in the cloud
- Delete the device shadow from the cloud
private int version = 1;
// To update the device shadow, read the returned version value from the obtained device shadow. When updating, replace {ver} with version+1.
private String shadowUpdate = "{" + "\"method\": \"update\"," + "\"state\": {" + "\"reported\": {" +
"\"color\": \"red\"" + ",\"mode\": \"1\"" + "}" + "}," + "\"version\": {ver}" + "}";
// Get the device shadow.
private String shadowGet = "{" + "\"method\": \"get\"" + "}";
// Delete the color property of the device shadow. {ver} must be replaced.
private String shadowDelete = "{" + "\"method\": \"delete\"," + "\"state\": {" + "\"reported\": {" +
"\"color\": \"null\"" + "}" + "}," + "\"version\": {ver}" + "}";
/**
* Updates the device shadow.
*/
public void shadowUpdate() {
ALog.d(TAG, "shadowUpdate");
version++;
shadowUpstream(shadowUpdate.replace("{ver}", String.valueOf(version)));
}
/**
* Gets the device shadow.
*/
public void shadowGet() {
ALog.d(TAG, "shadowGet");
shadowUpstream(shadowGet);
}
/**
* Deletes the device shadow.
*/
public void shadowDelete() {
ALog.d(TAG, "shadowDelete");
version++;
shadowUpstream(shadowDelete.replace("{ver}", String.valueOf(version)));
}
private void shadowUpstream(String requestData) {
if (requestData == null) {
ALog.e(TAG, "shadowUpstream error requestData=null.");
return;
}
LinkKit.getInstance().getDeviceShadow().shadowUpload(requestData, new IConnectSendListener() {
@Override
public void onResponse(ARequest aRequest, AResponse aResponse) {
ALog.d(TAG, "onResponse() called with: aRequest = [" + aRequest + "], aResponse = [" + (aResponse == null ? null : aResponse.data) + "]");
try {
if (aRequest instanceof MqttPublishRequest && aResponse != null) {
String dataStr = null;
if (aResponse.data instanceof byte[]) {
dataStr = new String((byte[]) aResponse.data, "UTF-8");
} else if (aResponse.data instanceof String) {
dataStr = (String) aResponse.data;
} else {
dataStr = String.valueOf(aResponse.data);
}
ALog.d(TAG, "dataStr = " + dataStr);
// {"method":"reply","payload":{"status":"success","state":{"reported":{}},"metadata":{"reported":{}}},"timestamp":1547641855,"version":7,"clientToken":"null"}
ShadowResponse<String> response = JSONObject.parseObject(dataStr, new TypeReference<ShadowResponse<String>>() {
}.getType());
if (response != null && response.version != null) {
version = Integer.valueOf(response.version);
}
}
} catch (NumberFormatException e) {
e.printStackTrace();
ALog.e(TAG, "update version failed.");
} catch (Exception e) {
ALog.e(TAG, "update response parse exception.");
}
}
@Override
public void onFailure(ARequest aRequest, AError aError) {
ALog.d(TAG, "onFailure() called with: aRequest = [" + aRequest + "], aError = [" + aError + "]");
}
});
} Data downstream
Listen for device shadow data updates from the cloud API. When the device receives the data, it performs an update based on the value of desired.
/**
* Subscribes to the device shadow update topic.
* The listener is triggered after the cloud sends device shadow data.
*/
public void listenDownStream() {
ThreadPool.execute(new Runnable() {
@Override
public void run() {
LinkKit.getInstance().getDeviceShadow().setShadowChangeListener(new IShadowRRPC() {
@Override
public void onSubscribeSuccess(ARequest aRequest) {
ALog.d(TAG, "Successfully subscribed to downstream device shadow data.");
ALog.d(TAG, "onSubscribeSuccess() called with: aRequest = [" + aRequest + "]");
}
@Override
public void onSubscribeFailed(ARequest aRequest, AError aError) {
ALog.d(TAG, "Failed to subscribe to downstream device shadow data.");
ALog.d(TAG, "onSubscribeFailed() called with: aRequest = [" + aRequest + "], aError = [" + aError + "]");
}
@Override
public void onReceived(ARequest aRequest, AResponse aResponse, IConnectRrpcHandle iConnectRrpcHandle) {
ALog.d(TAG, "onReceived() called with: aRequest = [" + aRequest + "], iConnectRrpcHandle = [" + iConnectRrpcHandle + "]");
// TODO: Implement device control logic.
ALog.d(TAG, "Received downstream instruction for device shadow.");
try {
if (aRequest != null) {
String dataStr = null;
if (aResponse.data instanceof byte[]) {
dataStr = new String((byte[]) aResponse.data, "UTF-8");
} else if (aResponse.data instanceof String) {
dataStr = (String) aResponse.data;
} else {
dataStr = String.valueOf(aResponse.data);
}
ALog.d(TAG, "dataStr = " + dataStr);
// Sample returned data
//{"method":"control","payload":{"state":{"desired":{"mode":2,"color":"white"},"reported":{"mode":"1","color":"red"}},"metadata":{"desired":{"mode":{"timestamp":1547642408},"color":{"timestamp":1547642408}},"reported":{"mode":{"timestamp":1547642408},"color":{"timestamp":1547642408}}}},"timestamp":1547642408,"version":12}
// For reference only
ShadowResponse<String> shadowResponse = JSONObject.parseObject(dataStr, new TypeReference<ShadowResponse<String>>() {
}.getType());
if (shadowResponse != null && shadowResponse.version != null) {
version = Integer.valueOf(shadowResponse.version);
}
AResponse response = new AResponse();
// TODO: Implement device control.
// After controlling the device, report the shadow value to the cloud.
// Report the value to the cloud after the setting is applied.
// Report based on the current actual value.
response.data = shadowUpdate.replace("{ver}", String.valueOf(++version));
// The first value, replyTopic, has a default value. You do not need to set it.
iConnectRrpcHandle.onRrpcResponse(null, response);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onResponseSuccess(ARequest aRequest) {
ALog.d(TAG, "onResponseSuccess() called with: aRequest = [" + aRequest + "]");
}
@Override
public void onResponseFailed(ARequest aRequest, AError aError) {
ALog.w(TAG, "onResponseFailed() called with: aRequest = [" + aRequest + "], aError = [" + aError + "]");
}
});
}
});
} Is this page helpful?