IoT Device ArkTS (OpenHarmony) SDK
The IoT Device ArkTS (OpenHarmony) SDK provides abundant demo code for devices to communicate with the platform.
Preparations
- DevEco Studio 5.0.0 or later has been installed.
- The matching Node.js has been installed.
Requirements
- Download and installation: In DevEco Studio, run the following command to import and install the SDK.
ohpm install @huaweicloud/iot-device-sdk
- Permission configuration: To use the SDK, add the ohos.permission.INTERNET permission to requestPermissions in the module.json5 file.
{ "module": { "requestPermissions": [ { "name": "ohos.permission.INTERNET" } ] } }
Creating a Product
A smoke detector product model is provided to help you understand the product model. This smoke detector can report the smoke density, temperature, humidity, and smoke alarms, and execute the ring alarm command. The following uses the smoke detector as an example to introduce the procedures of message reporting and property reporting.
- Access the IoTDA service page and click Access Console. Click the target instance card. Check and save the MQTTS device access domain name.
- Choose Products in the navigation pane and click .
- Set the parameters as prompted and click OK.
Set Basic Info
Resource Space
The platform automatically allocates the created product to the default resource space. If you want to allocate the product to another resource space, select the resource space from the drop-down list box. If a resource space does not exist, create it first.
Product Name
Customize the product name. The name can contain letters, numbers, underscores (_), and hyphens (-).
Protocol
Select MQTT.
Data Type
Select JSON.
Device Type Selection
Select Custom.
Device Type
Select smokeDetector.
Advanced Settings
Product ID
Leave this parameter blank.
Description
Set this parameter based on service requirements.
Uploading a Product Model
- Download the smokeDetector product model file.
- Click the name of the product created in 3 to access its details.
- On the Basic Information tab page, click Import from Local to upload the product model file obtained in 1.
Figure 1 Product - Uploading a product model
Registering a Device
- In the navigation pane, choose Devices > All Devices, and click Register Device.
- Set the parameters as prompted and click OK.
Parameter
Description
Resource Space
Ensure that the device and the product created in 3 belong to the same resource space.
Product
Select the product created in 3.
Node ID
This parameter specifies the unique physical identifier of the device. The value can be customized and consists of letters and numbers.
Device Name
Customize the device name.
Authentication Type
Select Secret.
Secret
Customize the device secret. If this parameter is not set, the platform automatically generates a secret.
After the device is registered, save the node ID, device ID, and secret.
Initializing a Device

Demo: entry/src/main/ets/pages/Index.ets
- Enter the device ID and secret obtained in Registering a Device and the device connection information obtained in 1. The format is ssl://Domain name:Port or ssl://IP address:Port.
1 2 3 4
private device: IoTDevice | null = null; // Replace the access address, device ID, device secret, and certificate path with your own ones. (Use the corresponding certificate when connecting to Huawei Cloud. The certificate file is stored in resource/resfile. Download the certificate file.) this.device = new IoTDevice ("ssl://Domain name:8883","deviceId","mySecret","filePath");
- Call the init method to establish a connection in either asynchronous or synchronous initialization mode.
1 2 3 4 5 6 7 8 9
// Perform initialization in asynchronous mode. this.device.init().then((data: boolean) => { // Connection succeeded. }).catch((err: string) => { // Connection failed. }) // Perform initialization in synchronous mode. // await this.device.init();
- Check device logs. The device is successfully connected.
1
IoTDA_SDK# connect result is {"code":0,"message":"Connect Success"}
- After the device is created and connected, it can be used for communication. Call the client method of the IoT Device SDK to obtain the device client. The client provides communication APIs for processing messages, properties, and commands.
Reporting a Message

Demo: entry/src/main/ets/pages/MessageSample.ets
Message reporting is the process in which a device reports messages to the platform.
- After the device is initialized and connected to the platform, call the reportDeviceMessage method of the client to report device messages and call the publishRawMessage method to report messages through custom topics.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
// Report messages through system topics. const reportMessage: DeviceMessage = { content: this.message } this.device.client.reportDeviceMessage(reportMessage) .then((data: IoTMqttResponse) => { LogUtil.info(TAG, `report deviceMessage success ${JSON.stringify(data)}. DeviceMessage is ${JSON.stringify(reportMessage)}`); }) .catch((error: IoTMqttResponse | string) => { LogUtil.error(TAG, `report deviceMessage failed ${JSON.stringify(error)}`); }) // Report messages through custom topics starting with $oc, which must be configured on the platform first. const topic = `$oc/devices/${this.device?.deviceId}/user/test`; const rawMessage: RawMessage = { topic: topic, qos: 0, payload: this.message } this.device?.client.publishRawMessage((rawMessage)).then((res: IoTMqttResponse) => { LogUtil.info(TAG, `publish rawMessage(${rawMessage.topic}) success, message is ${JSON.stringify(rawMessage)}}`); }).catch((error: IoTMqttResponse | string) => { LogUtil.error(TAG, `publish rawMessage(${rawMessage.topic}) failed, error is ${JSON.stringify(error)}}`); }); // Report messages through custom topics not starting with $oc (controlled by device topic policies). const topic = "hello/world"; const rawMessage: RawMessage = { topic: topic, qos: 0, payload: this.message } this.device?.client.publishRawMessage((rawMessage)).then((res: IoTMqttResponse) => { LogUtil.info(TAG, `publish rawMessage(${rawMessage.topic}) success, message is ${JSON.stringify(rawMessage)}}`); }).catch((error: IoTMqttResponse | string) => { LogUtil.error(TAG, `publish rawMessage(${rawMessage.topic}) failed, error is ${JSON.stringify(error)}}`); });
- The logs show that the message is successfully sent.
Figure 2 Logs for reporting messages through system topicsFigure 3 Logs for reporting messages through custom topics (starting with $oc)Figure 4 Logs for reporting messages through custom topics (not starting with $oc)
- On the IoTDA console, choose Devices > All Devices and check whether the device is online.
Figure 5 Device list - Device online status
- Select the device, click the button to access its details page, and enable message tracing.
Figure 6 Message tracing - Starting message tracing
- The message tracing results show that the platform successfully receives the message from the device.
Figure 7 Message tracing - Viewing device_sdk_java tracing result
Message tracing may be delayed. If no data is displayed, wait for a while and refresh the page.
Reporting Properties

Demo: entry/src/main/ets/pages/PropertySample.ets
1. After the device is initialized and connected to the platform, call the reportProperties method of the client to report device properties.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
const properties: ServiceProperty[] = [ { "service_id": "smokeDetector", "properties": { "alarm": 1, "temperature": Math.random() * 100, "humidity": Math.random() * 100, "smokeConcentration": Math.random() * 100, } } ] ; this.device.client.reportProperties(properties) .then((data: IoTMqttResponse) => { LogUtil.info(TAG, `report properties success ${JSON.stringify(data)}, properties is ${JSON.stringify(properties)}}`); }) .catch((error: IoTMqttResponse | string) => { LogUtil.error(TAG, `report properties failed ${JSON.stringify(error)}`); }) |
2. The logs show that the properties are successfully sent.

3. On the IoTDA console, choose Devices > All Devices, and click the target device to access its details page. The latest reported property values are displayed.

Reading and Writing Properties

Demo: entry/src/main/ets/pages/PropertySample.ets
- After the device is successfully initialized, call the propertyListener method of the client to set the property callback interface.
- Property reading: Only the alarm property can be written.
- Property reading: Assemble the local property value based on the API format.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
let propertyListener: PropertyListener = { onPropertiesSet: (requestId: string, services: ServiceProperty[]): void => { this.logArr.unshift(`${new Date()}: onPropertiesSet requestId is ${requestId}, services is ${JSON.stringify(services)}`) // Traverse services. services.forEach(serviceProperty => { LogUtil.info("onPropertiesSet, serviceId is ", serviceProperty.service_id); // Traverse properties. Object.keys(serviceProperty.properties).forEach(name => { LogUtil.log(TAG, `property name is ${name}`); LogUtil.log(TAG, `set property value is ${serviceProperty.properties[name]}`); }) }) // Change the local properties. this.device?.client.respondPropsSet(requestId, IotResult.SUCCESS); }, onPropertiesGet: (requestId: string, serviceId?: string): void => { this.logArr.unshift(`${new Date()}: onPropertiesGet requestId is ${requestId}, serviceId is ${serviceId} and respondPropsGet`) LogUtil.info(TAG, `onPropertiesGet, the serviceId is ${serviceId}`); const serviceProperties: ServiceProperty[] = [ { "service_id": "smokeDetector", "properties": { "alarm": 1, "temperature": Math.random() * 100, "humidity": Math.random() * 100, "smokeConcentration": Math.random() * 100, } } ]; this.device?.client.respondPropsGet(requestId, serviceProperties); } } // Set the property listener. this.device.client.propertyListener = propertyListener;
- The property reading/writing API must call the respondPropsGet and respondPropsSet methods to report the operation result.
- If the device does not allow the platform to proactively read data from the device, the onPropertiesGet method can be left not implemented.
- Run the preceding code to set the property listener. On the device shadow page of the platform, check the value of alarm, which is 1. Change the value to 0, and check the device logs. The results show that the device receives a request for setting the value of alarm to 0.
Figure 10 Device shadow - Viewing property (Alarm)Figure 11 Device shadow - Configuring property (alarm)Figure 12 Checking property setting results
Delivering a Command

Demo: entry/src/main/ets/pages/CommandSample.ets
You can set a command listener to receive commands delivered by the platform. The callback API needs to process the commands and report responses.
- Command processing in the CommandSample example: Print the received command, and then call respondCommand method to report the response.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
let commandListener: CommandListener = { onCommand: (requestId: string, serviceId: string, commandName: string, paras: object): void => { const command = `requestId is ${requestId}, serviceId is ${serviceId}, commandName is ${commandName}, paras is ${JSON.stringify(paras)}`; LogUtil.info(TAG, `received command is ${command}`); // Process commands. const commandRsp: CommandRsp = { result_code: 0 } this.device?.client.respondCommand(requestId, commandRsp).then((data: IoTMqttResponse) => { LogUtil.info(TAG, `respond command success ${JSON.stringify(data)}, commandRsp is ${commandRsp}}`); }).catch((err: IoTMqttResponse | string) => { LogUtil.error(TAG, `respond command failed ${JSON.stringify(err)}`); }) } } this.device.client.commandListener = commandListener;
- After the preceding code is executed to set the command listening, deliver a command on the platform, in which serviceId is smokeDetector, command name is ringAlarm, and duration is 20.
- Check the log, which indicates that the device receives the command and reports a response successfully.
Object-oriented Programming

Demo: entry/src/main/ets/pages/ProfileSample.ets
Calling device client APIs to communicate with the platform is flexible but requires you to properly configure each API.
The SDK provides a simpler method, object-oriented programming. You can use the product model capabilities provided by the SDK to define device services and call the property reading/writing API to access the device services. In this way, the SDK can automatically communicate with the platform to synchronize properties and call commands.
Object-oriented programming simplifies the complexity of device code and enables you to focus only on services rather than the communications with the platform. This method is much easier than calling client APIs and suitable for most scenarios.
ProfileSample demonstrates the process of object-oriented programming.
- Define a smoke detector service class, which is inherited from AbstractService. (If there are multiple services, define multiple service classes.)
1 2 3
class SmokeDetector extends AbstractService { }
- Define service properties. Private variables start with underscores (_). Use @Reflect.metadata ("Property", { name: "string", writeable: boolean}) to indicate a property. The name must be the same as the property name in the product model. writeable indicates whether the property is writable.
1 2 3 4 5 6 7 8 9 10 11
@Reflect.metadata("Property", { name: "alarm", writeable: true }) private _smokeAlarm: number = 1; @Reflect.metadata("Property", { name: "smokeConcentration", writeable: false }) private _concentration: number = 0; @Reflect.metadata("Property", { name: "humidity", writeable: false }) private _humidity: number = 0; @Reflect.metadata("Property", { name: "temperature", writeable: false }) private _temperature: number = 10;
- Define service commands. The SDK automatically calls the commands below when the device receives commands from the platform. The name corresponds to command_name of the product model, and method corresponds to the method for receiving the command. The input parameter and return value type of the command cannot be changed.
The following code defines a ring alarm command named ringAlarm. The delivered parameter is duration, which indicates the duration of the ringing alarm.
1 2 3 4 5 6 7 8 9
@Reflect.metadata("DeviceCommand", { name: "ringAlarm", method: (paras: object): CommandRsp => { let duration: number = paras['duration']; LogUtil.log(TAG, `duration is ${duration}`); return IotResult.SUCCESS; } }) private _alarm: Function = () => {};
- Define the getter and setter methods.
- The device automatically calls the getter method after receiving the commands for querying and reporting properties from the platform. The getter method reads device properties from the sensor in real time or from the local cache.
- The device automatically calls the setter method after receiving the commands for setting properties from the platform. The setter method updates the local values of the device. If a property is not writable, leave the setter method not implemented.
- Click Generate on the DevEco Studio and choose Getter and Setter, and then modify the method. The setter and getter interfaces are automatically generated.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
public set smokeAlarm(value: number) { this._smokeAlarm = value; if (value == 0) { LogUtil.info(TAG, "alarm is cleared by app"); } } public get smokeAlarm(): number { return this._smokeAlarm; } public set concentration(value: number) { // Read-only fields do not need to implement the set method. } public get concentration(): number { return Math.floor(Math.random() * 100); } public set humidity(value: number) { // Read-only fields do not need to implement the set method. } public get humidity(): number { return Math.floor(Math.random() * 100); } public set temperature(value: number) { // Read-only fields do not need to implement the set method. } public get temperature(): number { return Math.floor(Math.random() * 100); }
- Implement the constructor to initialize properties and commands.
constructor() { super(); const fields = Object.getOwnPropertyNames(this); this.init(fields); }
- Create a device and register the smoke sensor service.
1 2 3
// Create a device service. const smokeDetector = new SmokeDetector(); this.device.addService("smokeDetector", smokeDetector);
- Enable periodic property reporting.
1 2
// Enable periodic property reporting. this.device.getService("smokeDetector")?.enableAutoReport(10000);
- Execute the preceding code to check the logs of reported properties.
- Check the value of the alarm property in the device shadow on the platform. The value is 1. Change the value to 0 and check the device logs.
Figure 13 Device shadow - Viewing property (Alarm)Figure 14 Logs for successful device property setting
- Deliver the ringAlarm command on the platform. Check the device logs, which indicate that the ringAlarm command is called and a response is successfully reported.
Change History
Version |
Change |
Description |
---|---|---|
0.0.1 |
New function |
Added the capability of connecting to the Huawei Cloud IoT platform to facilitate service scenarios such as access, device management, and command delivery. |
Feedback
Was this page helpful?
Provide feedbackThank you very much for your feedback. We will continue working to improve the documentation.See the reply and handling status in My Cloud VOC.
For any further questions, feel free to contact us through the chatbot.
Chatbot