RTOS SDK Integration
This document describes how the smart home plugin integrates with the RTOS platform SDK. The RTOS version is linked directly into the firmware at compile time in the form of a static library libjdsmart_demo.a.
After integration is complete, the following features are supported: device login, device discovery, device control, and device status feedback.
| Version | Change Log |
|---|---|
| V1.0.0 | Initial version |
| V1.1.0 | Added device category and sub-category descriptions; completed protocol, event, packet-building API and command set descriptions; added platform utility interfaces (HTTP / MD5 / MQTT / UART) |
The smart home SDK integration method is suitable for companies with embedded C development capabilities, supporting device login, device discovery, device control, and device status feedback.
Demo plugin source code Download
1. Project Structure
libdemo/
├── Makefile # RTOS static library build script (riscv64-unknown-elf toolchain)
├── libjdsmart_demo.a # Build artifact: static library
├── include/ # Integration header files
│ ├── device_sdk_plugin.h # Plugin API / device types / properties / actions / event definitions
│ ├── device_sdk_music.h # Music playback and device status feedback command definitions, currently unused
│ ├── smarthome_packet.h # Device discovery protocol packet-building API
│ ├── smarthome_common.h # Platform data directory macros (including OS_RTOS)
│ ├── smarthome_priv.h # Private structures: device_info_t / device mapping table
│ ├── cJSON.h # JSON parsing/generation
│ └── tkc/ # Base utility library (dynamic arrays, strings, memory, etc.)
├── src/
│ ├── smarthome_demo.c # Integration implementation (core business code to be implemented)
│ ├── smarthome_packet.c # Packet-building API implementation
│ └── smarthome_utils.h # Platform utility function declarations (unused in demo, no need to focus on)
└── smarthome_utils/ # Reserved directory (empty in libdemo, no need to focus on)
The integrator needs to focus on the header files under include/ and src/smarthome_demo.c. All smarthome_xxx() functions are the integration interfaces defined by the SDK.
2. Build Environment
The RTOS version uses Makefile for building, producing the static library libjdsmart_demo.a. The toolchain is configured in the first line of Makefile:
Allwinner R128 Source Code Compilation Toolchain Path Download
COMPILE_PREX := /home/virtual_tmp/mm/riscv64-elf-x86_64-20201104/bin/riscv64-unknown-elf-
CC := $(COMPILE_PREX)gcc
AR := $(COMPILE_PREX)ar
# Automatically collect all .c/.cpp/.cc source files under src/
LOCAL_SRC_FILES := $(shell find $(LOCAL_PATH)/src -name "*.c" -o -name "*.cpp" -o -name "*.cc")
# Target: static library, packaged using $(AR) (not dynamic library linking)
all: libjdsmart_demo.a rm_objs
libjdsmart_demo.a: $(OBJS)
$(AR) rcs $@ $^
%.o:%.c
$(CC) -Wall -c $(CFLAGS) $< -o $@
Integration steps:
- Modify
COMPILE_PREXto the actual RISC-V cross-compiler path prefix you are using; - Run
make(ormake PLATFORM=tinato enable Tina platform-related macros) to generatelibjdsmart_demo.a; - Link this static library in your firmware project, and add the
include/directory to the header file search path.
3. Integration Flow
smarthome_preinit() Pre-initialization: save callback listener, parse parameters
│
smarthome_init() Initialization: parse deviceID, create device list, start loading thread
│
smarthome_get_state() Central controller queries plugin state (IDLE / LOGGED ...)
smarthome_get_pluginfo() Central controller gets plugin info (appid, login method, flag, etc.)
│
├──► listener(PLUGIN_EVENT_ON_DEVICES_SYNC) Report device list (discovery protocol)
│
smarthome_device_control() Central controller sends control commands → operate hardware → feedback status
│
├──► listener(PLUGIN_EVENT_ON_DEVICE_PROP_CHANGE) Report property changes
│
smarthome_reset() Reset / unbind
Core concept: The central controller drives the plugin by calling smarthome_xxx() interfaces; the plugin reports device lists, status, and property changes to the central controller via listener callbacks.
From the user's perspective, the overall demo flow is:
Login → Discover devices and scenes → Display devices and scenes → Interface click or voice control of scenes and devices
After device discovery is complete, you can see devices on the left screen of the desktop and scenes on the right screen, then click or use voice to control devices or scenes.
4. API Description
The following functions need to be implemented by the integration plugin. Function prototypes are defined in include/device_sdk_plugin.h, and reference implementations can be found in src/smarthome_demo.c.
Callback function type:
typedef void (*callback_func)(void* context, int code, void* result);
4.1 smarthome_preinit — Pre-initialization
Called earliest, used to save the application-layer callback listener (must be saved locally for the long term, all subsequent reports go through it), and parse input parameters.
/**
* @brief Pre-initialization
* @param params: {"feature":0, "switchs_count":2}
* @param listener: Application-layer callback function, needs to be saved locally
*/
int smarthome_preinit(char* params, callback_func listener);
Reference implementation (smarthome_demo.c):
int smarthome_preinit(char* params, callback_func listener) {
g_context = (smarthome_context_t*)malloc(sizeof(smarthome_context_t));
memset(g_context, 0, sizeof(smarthome_context_t));
g_context->listener = listener; // Key: save callback
if (params && strlen(params) > 0) {
cJSON* root = cJSON_Parse(params);
if (root != NULL) {
cJSON *obj = cJSON_GetObjectItem(root, "switchs_count");
if (obj) g_context->switchs_count = obj->valueint;
cJSON_Delete(root);
}
}
return 0;
}
4.2 smarthome_init — Initialization
Parse local deviceID, create device container, and start device loading process.
/**
* @param params: {
* "uuid": "Plugin device id bound to AIS backend",
* "key": "Plugin device key bound to AIS backend",
* "deviceID": "Unique device ID of this device"
* }
*/
int smarthome_init(char* params, callback_func listener);
Reference implementation:
int smarthome_init(char* params, callback_func listener) {
g_context->devices = darray_create(50, (tk_destroy_t)plug_device_destroy, plug_device_compare);
cJSON* root = cJSON_Parse(params);
if (root != NULL) {
cJSON* jobj_deviceID = cJSON_GetObjectItem(root, "deviceID");
strncpy(g_context->device_id, jobj_deviceID->valuestring, sizeof(g_context->device_id) - 1);
cJSON_Delete(root);
} else {
return -1;
}
pthread_t t1;
pthread_create(&t1, NULL, &smart_demo_start, NULL); // Async device loading
return 0;
}
Note: The platform supports pthread. Devices are loaded by calling
parse_config_file()in a task/thread. After loading is complete, the state is set toPLUGIN_STATE_LOGGEDandnotify_devices_change()is called to report the device list. In the demo,uuid/keyare reserved for AIS backend binding (not needed whenauthTypeis none); currently onlydeviceIDis used.
4.3 smarthome_get_state — Get State
Returns the current plugin state for the central controller to determine login/loading progress.
int smarthome_get_state();
Return values are from enum SS_PLUGIN_STATE:
| State | Value | Description |
|---|---|---|
| PLUGIN_STATE_FAIL | -1 | Failed |
| PLUGIN_STATE_IDLE | 0 | Idle |
| PLUGIN_STATE_INITED | 1 | Initialized |
| PLUGIN_STATE_GET_CODE | 2 | Getting QR code |
| PLUGIN_STATE_GET_TOKEN | 3 | Getting token |
| PLUGIN_STATE_LOGGED | 4 | Logged in |
| PLUGIN_STATE_BINDED | 5 | Binded |
4.4 smarthome_get_pluginfo — Get Plugin Info
Returns a JSON string describing the plugin version, appid, login method, login prompt text, and feature flags.
char* smarthome_get_pluginfo();
Reference implementation:
char* smarthome_get_pluginfo() {
cJSON* root = cJSON_CreateObject();
cJSON_AddNumberToObject(root, "version", PLUGIN_PROTOCOL_VERSION);
cJSON_AddStringToObject(root, "appid", "xxx.com"); // Vendor appid, recommended to be a domain name
cJSON_AddNumberToObject(root, "state", g_context->state);
cJSON_AddStringToObject(root, "authType", AUTH_TYPE_NONE); // Auth type, keep as is, do not modify
cJSON_AddStringToObject(root, "loginType", LOGIN_TYPE_QRCODE); // Login method
cJSON_AddStringToObject(root, "loginTitle", "Device Binding");
cJSON_AddStringToObject(root, "loginHint", "Scan with mobile APP");
if (g_context->qr_url && strlen(g_context->qr_url) > 0)
cJSON_AddStringToObject(root, "loginUrl", g_context->qr_url);
int flag = 0;
flag |= PLUG_FLAG_LOAD_OFFLINE; // Supports offline loading
cJSON_AddNumberToObject(root, "flag", flag);
char* info = cJSON_PrintUnformatted(root);
cJSON_Delete(root);
return info; // Caller is responsible for free
}
Flag definitions (can be combined as needed):
| Flag | Description |
|---|---|
| PLUG_FLAG_LOAD_OFFLINE | Supports offline loading |
| PLUG_FLAG_STATE_FEEDBACK | Switch button waits for device status feedback before changing |
| PLUG_FLAG_SMART_BUS | Plugin occupies RS485 device, used for 485 plugin integration development |
| PLUG_FLAG_NO_SMART_BUS | Disable RS485 related UI display |
| PLUG_FLAG_PAIRD_DEVICES | Plugin has device discovery and auto-pairing functionality |
Additionally, two optional fields are supported (demo has commented examples):
| Field | Description |
|---|---|
| custom_model | Custom device name, max 32 bytes, displayed at "Settings > About This Device > Device Name" |
4.5 smarthome_device_control — Device Control
Called when the central controller sends control commands. Parameters are in JSON format; parse them and drive the actual hardware, then callback to report execution results and property changes.
/**
* @param params: {
* "id":"vdevo161103533857949", // Device ID
* "type":"aircondition", // Device type
* "sub_type":"unknown", // Device sub-type
* "action":"SetTemperature", // Action
* "value":"19" // Value
* }
* @param callback: (void* context, int code, void* result)
* code: 0 = success, -1 = error; on error, result passes text for display
*/
int smarthome_device_control(const char* params, callback_func callback);
Reference implementation (using light as an example, showing the complete chain of parse → drive → feedback):
int smarthome_device_control(const char* params, callback_func callback) {
cJSON* root = cJSON_Parse(params);
if (root != NULL) {
char* id = cJSON_GetObjectItem(root, "id")->valuestring;
device_info_t *device = find_device_by_id(id);
if (device) {
char* action = cJSON_GetObjectItem(root, "action")->valuestring;
char* type = cJSON_GetObjectItem(root, "type")->valuestring;
char* value = NULL;
cJSON *jobj = cJSON_GetObjectItem(root, "value");
if (jobj) value = jobj->valuestring;
if (my_streq(type, DEVICE_TYPE_LIGHT)) {
if (my_streq(action, DEVICE_ACTION_TURN_ON)) {
// leshi_ble_set_onoff(...); // Call actual hardware driver
device->status = 1;
notify_prop_change(device->device_id.str, DEVICE_PROPERTIE_POWERSTATE,
DEVICE_PROPERTIES_VALUE_ON);
} else if (my_streq(action, DEVICE_ACTION_SET_BRIGHTNESS)) {
device->data.light.brightness = atoi(value);
notify_prop_change(device->device_id.str, DEVICE_PROPERTIE_BRIGHTNESS, value);
} else if (my_streq(action, DEVICE_ACTION_SET_COLOR_TEMPERATURE)) {
device->data.light.color_temp = atoi(value);
int max = 6400, min = 2700;
int dst = (max - min) * device->data.light.color_temp / 100 + min; // Percentage to Kelvin
notify_prop_change(device->device_id.str, DEVICE_PROPERTIE_COLOR_TEMPERATURE, value);
}
}
// ... See source code for aircondition / curtain / switch / bath_heater / fan_light types
}
cJSON_Delete(root);
}
return 0;
}
Complete control branches for light, switch, aircondition, curtain, bath_heater, music_player, hanger, fan and other device types are already provided in
src/smarthome_demo.c. During integration, simply replace the commented-outleshi_ble_xxx()calls with your own hardware drivers.
4.6 smarthome_device_discover — Device Discovery
int smarthome_device_discover(int method, callback_func callback);
Called when the central controller needs to refresh the device list (also called once during the initial loading process). method and callback are reserved parameters; the demo has empty implementations.
Note: RTOS device loading is completed in the thread started by
smarthome_init. When the device list changes (devices added/removed, renamed, etc.), the plugin should proactively re-report the complete device list viaPLUGIN_EVENT_ON_DEVICES_SYNC, without waiting for the central controller to call this interface.
4.7 smarthome_reset — Reset / Unbind
int smarthome_reset();
Reference implementation:
int smarthome_reset() {
g_context->state = PLUGIN_STATE_IDLE;
notify_gw_status(PLUGIN_STATE_IDLE, "Gateway has been reset");
return 0;
}
When unbinding/logging out, the application usually needs to restart. You can call
g_listener(NULL, PLUGIN_EVENT_REQ_REBOOT, NULL);.
4.8 smarthome_ioctl — Extended Commands
Used for extended scenarios such as device discovery, debug info, and production testing.
int smarthome_ioctl(char* cmd, char* key, char* value);
Supported cmds (see source code):
| cmd | Description |
|---|---|
| discovery_device | Enter device discovery mode (requires setting PLUG_FLAG_PAIRD_DEVICES) |
| discovery_device_exit | Exit discovery interface |
| get_debug_info | Return debug info (plain text or input dialog, reported via PLUGIN_EVENT_ON_DEBUG_INFO) |
| test_mode_start | Start production test, return results via PLUGIN_EVENT_ON_TEST_RESULT |
4.9 smarthome_slave_report — Slave Device Status Report
When the plugin acts as a slave device, report hardware events such as button presses and relay states to the central controller/server.
int smarthome_slave_report(const char* params, callback_func callback);
In params, i0 is the command code, with values defined in device_sdk_music.h (e.g., DEVICE_REPORT_KEY_EVENT=254 for key events, DEVICE_REPORT_DEVICE_PROP=250 for property reports).
Reference implementation (key event):
int smarthome_slave_report(const char* params, callback_func callback) {
cJSON* root = cJSON_Parse(params);
if (root != NULL) {
int cmd = cJSON_GetObjectItem(root, "i0")->valueint;
switch (cmd) {
case DEVICE_REPORT_KEY_EVENT: {
unsigned char did = cJSON_GetObjectItem(root, "i1")->valueint;
device_info_t *device = find_device_by_type_id(LETS_OEM_ZHINENG_SW, did);
if (device && device->data.smart_switch.mode == LETS_SWITCH_MODE_NORMAL) {
device->status = !device->status;
slave_on_dp_cb(device->id - 1 + DEVICE_SWICTH_1, device->status); // Operate relay
notify_prop_change(device->device_id.str, DEVICE_PROPERTIE_POWERSTATE,
device->status ? DEVICE_PROPERTIES_VALUE_ON : DEVICE_PROPERTIES_VALUE_OFF);
}
} break;
default: break;
}
cJSON_Delete(root);
}
return 0;
}
5. Callback Events (listener)
The plugin reports events to the central controller via listener(context, event, result). Events are defined in enum SS_PLUGIN_EVENT:
| Event | Value | Description | result Content |
|---|---|---|---|
| PLUGIN_EVENT_ON_GW_RESET | 1 | Gateway reset | - |
| PLUGIN_EVENT_ON_GW_STATUS | 2 | Gateway/login status change | plugin_ret_t{code,msg} |
| PLUGIN_EVENT_ON_GW_URL | 3 | Gateway URL | URL string |
| PLUGIN_EVENT_ON_DEVICES_SYNC | 4 | Report device list | Discovery protocol JSON string (see 7.2) |
| PLUGIN_EVENT_ON_DEVICE_PROP_CHANGE | 5 | Device property change | Property JSON string (see 7.3) |
| PLUGIN_EVENT_ON_DEVICE_DISCOVERY | 6 | Device discovery progress hint | {"version":1,"msg":"Searching..."} |
| PLUGIN_EVENT_ON_DEBUG_INFO | 7 | Debug info / input dialog | JSON |
| PLUGIN_EVENT_REQ_REBOOT | 1000 | Request app restart | NULL |
| PLUGIN_EVENT_SLAVE_CONTROL | 1001 | Slave device relay control | {"i0":..,"i1":..} |
| PLUGIN_EVENT_ON_VOICE_RESP | 1002 | Voice response | Reserved |
| PLUGIN_EVENT_ON_CLOCK_UPDATE | 1003 | Clock update | Reserved |
| PLUGIN_EVENT_ON_UI_TOAST | 1004 | UI toast | {"version":1,"msg":"..."} |
| PLUGIN_EVENT_ON_HOTEL_RESET | 1005 | Hotel mode reset | Reserved |
| PLUGIN_EVENT_ON_TEST_RESULT | 1006 | Production test result | >0 success / <0 failure |
| PLUGIN_EVENT_ON_UI_DIALOG | 1007 | UI dialog | JSON |
| PLUGIN_EVENT_ON_UI_STRING | 1008 | UI string | JSON |
Events actually used in the demo: ON_GW_STATUS, ON_DEVICES_SYNC, ON_DEVICE_PROP_CHANGE, ON_DEVICE_DISCOVERY, ON_DEBUG_INFO, ON_UI_TOAST, ON_TEST_RESULT, SLAVE_CONTROL, REQ_REBOOT; the rest are reserved.
Report gateway status:
static void notify_gw_status(int code, char* msg) {
plugin_ret_t ret;
ret.code = code;
ret.msg = msg;
g_context->listener(NULL, PLUGIN_EVENT_ON_GW_STATUS, &ret);
}
Report property changes:
static void notify_prop_change(char *id, char *prop, const char *value) {
char* tmpl = "{\"version\":1,\"deviceId\":\"%s\",\"name\":\"%s\",\"value\":\"%s\"}";
char result[160];
snprintf(result, 160, tmpl, id, prop, value);
g_context->listener(NULL, PLUGIN_EVENT_ON_DEVICE_PROP_CHANGE, result);
}
You can also use smarthome_packet_smart_prop(id, name, value) from the packet library to generate the same JSON (see Chapter 6).
Report device list (packet building + sync):
static void notify_devices_change() {
if (g_context->listener == NULL) return;
smarthome_packet_devicelist_t* packet_devicelist = smarthome_packet_devicelist_new();
convert_devices_pack(g_context, packet_devicelist); // Iterate local devices and build packets
char* result = smarthome_packet_devicelist_pack(packet_devicelist);
free(packet_devicelist);
g_context->listener(NULL, PLUGIN_EVENT_ON_DEVICES_SYNC, result);
if (result != NULL) free(result);
}
6. Device Packet-Building API
smarthome_packet.h / smarthome_packet.c provide a set of cJSON-based packet-building interfaces for generating "device discovery protocol" JSON, avoiding manual string concatenation.
| API | Description |
|---|---|
| smarthome_packet_devicelist_new() | Create device list container |
| smarthome_packet_devicelist_add_device(devlist, dev) | Add device to list (dev ownership transfers, internally freed, do not double free) |
| smarthome_packet_devicelist_pack(devlist) | Pack into JSON string (contains version/name/devices, caller responsible for free) |
| smarthome_packet_device_new_object(id, name, online) | Create single device object (automatically includes actions/properties arrays) |
| smarthome_packet_device_set_type(dev, type) | Set device type (deviceType) |
| smarthome_packet_device_set_sub_type(dev, sub_type) | Set device sub-type (deviceSubType), optional |
| smarthome_packet_device_set_zone(dev, zone) | Set room name (zone), optional |
| smarthome_packet_device_add_action(dev, action) | Add action |
| smarthome_packet_device_create_action_instructions(dev, action) | Add action with enums, returns instructions array |
| smarthome_packet_device_append_action_instruction(instr, value, desc) | Append an enum item to instructions (code and value are the same) |
| smarthome_packet_device_add_property(dev, name, value) | Add property |
| smarthome_packet_device_delete_object(dev) | Free device object (called internally after add_device) |
| smarthome_packet_smart_prop(id, name, value) | Assemble single property change JSON (for property reports) |
Packet-building example (air conditioner device, with mode/wind speed enums), from convert_devices_pack():
case DEVICE_AIR_CONDITION:
device_type = DEVICE_TYPE_AIRCONDITION;
smarthome_packet_device_add_action(dev_pack, DEVICE_ACTION_TURN_ON);
smarthome_packet_device_add_action(dev_pack, DEVICE_ACTION_TURN_OFF);
// SetMode action + enum items
instructions = smarthome_packet_device_create_action_instructions(dev_pack, DEVICE_ACTION_SET_MODE);
for (int i = 0; i < sizeof(MAP_AIS_DEMO_MODE)/sizeof(map_smart_ais_demo_t); i++) {
map_smart_ais_demo_t *m = &MAP_AIS_DEMO_MODE[i];
if (m->key == NULL) break;
smarthome_packet_device_append_action_instruction(instructions, m->key, m->desc);
}
smarthome_packet_device_add_property(dev_pack, DEVICE_PROPERTIE_POWERSTATE, DEVICE_PROPERTIES_VALUE_OFF);
smarthome_packet_device_add_property(dev_pack, DEVICE_PROPERTIE_TEMPERATURE, "16");
smarthome_packet_device_add_property(dev_pack, DEVICE_PROPERTIE_WINDSPEED, DEVICE_WINDSPEED_AUTO);
break;
7. Protocol Description
7.1 Integration Requirements
- Must be able to provide all device list data, with device info including device ID, device name, and device type;
- Must be able to provide all scene list data, with scene info including scene ID and scene name;
- Must be able to provide all room list data, with room info including room ID and room name.
7.2 Device Discovery Protocol
Reported by notify_devices_change() via PLUGIN_EVENT_ON_DEVICES_SYNC. Root fields:
| Field | Type | Description |
|---|---|---|
| version | int | Protocol version, fixed at 1 |
| name | string | Fixed as "DiscoveryDevicesResponse" |
| devices | array | Array of device objects |
Device object fields:
| Field | Required | Description |
|---|---|---|
| deviceId | Yes | Device unique ID. Demo uses hex format type:seq:check (e.g., 08:01:03), central controller parses by : delimiter |
| deviceName | Yes | Device name, also used for voice matching. Recommended format: "room+device" or common name, e.g., "Living Room Light" |
| online | Yes | 1 = online / 0 = offline |
| deviceType | Yes | Device type, see Chapter 8 |
| deviceSubType | No | Device sub-type, see category descriptions in 8.x (required for multi-way switches) |
| zone | No | Room name, e.g., "Living Room" |
| icon / iconPath | No | Icon |
| actions | Yes | Supported action array, determines central controller panel shape and voice support scope |
| actions[].action | Yes | Action name, see 9.1 |
| actions[].instructions | No | Action enum items (needed for discrete value actions like mode, wind speed) |
| instructions[].value / code | Yes | Enum value, sent as-is as value during control |
| instructions[].desc | Yes | Enum description (e.g., "Cooling"), used for voice and UI display |
| properties | No | Property array {name, value}, reports current state initial values |
Report example:
{
"version": 1,
"name": "DiscoveryDevicesResponse",
"devices": [
{
"deviceId": "vdevo162130282208556",
"deviceName": "Color Light",
"online": 1,
"actions": [
{ "action": "TurnOn" },
{ "action": "TurnOff" },
{
"action": "SetMode",
"instructions": [
{ "value": "lightWhite", "code": "lightWhite", "desc": "White Light" },
{ "value": "lightColour", "code": "lightColour", "desc": "Color Light" },
{ "value": "lightScene", "code": "lightScene", "desc": "Scene" }
]
},
{ "action": "SetBrightness" },
{ "action": "SetColorTemperature" },
{ "action": "SetColor" },
{
"action": "SetScene",
"instructions": [
{ "value": "light_scene_1", "code": "light_scene_1", "desc": "Good Night" },
{ "value": "light_scene_2", "code": "light_scene_2", "desc": "Reading" }
]
}
],
"properties": [
{ "name": "powerstate", "value": "on" },
{ "name": "mode", "value": "lightWhite" },
{ "name": "brightness", "value": "18" },
{ "name": "color_temperature","value": "10" },
{ "name": "color_hsv", "value": "{\"h\":0,\"s\":0,\"v\":1}" }
],
"zone": "Balcony",
"deviceType": "light",
"deviceSubType": "unknown"
},
{
"deviceId": "SN8hzCSAbWrCtjIE",
"deviceName": "Morning Rise",
"deviceType": "smartscene",
"actions": [ { "action": "TurnOn" } ]
}
]
}
7.3 Device Response Protocol
When device properties change, report via PLUGIN_EVENT_ON_DEVICE_PROP_CHANGE, format:
| Field | Description |
|---|---|
| version | Fixed at 1 |
| deviceId | Device ID |
| name | Property name, see 9.2 |
| value | Property value |
{ "version": 1, "deviceId": "vdevo162088709984066#1", "name": "online", "value": "1" }
Common control/feedback examples:
// Power state
{ "version":1, "deviceId":"vdevo162088709984066#1", "name":"powerstate", "value":"on" }
// Brightness (0~100)
{ "id":"vdevo162192408876410", "type":"light", "sub_type":"", "action":"SetBrightness", "value":"53" }
// Color (h:0~360, s:0~1, v:0~1)
{ "id":"vdevo162130282208556", "type":"light", "sub_type":"", "action":"SetColor",
"value":"{\"h\":359.37,\"s\":0.75,\"v\":1}" }
// Color temperature (0~100)
{ "id":"vdevo161847485227864", "type":"light", "sub_type":"", "action":"SetColorTemperature", "value":"50" }
// Air conditioner temperature
{ "id":"vdevo161103533857949", "type":"aircondition", "sub_type":"", "action":"SetTemperature", "value":"20" }
// Air conditioner wind speed
{ "id":"vdevo161103533857949", "type":"aircondition", "sub_type":"", "action":"SetWindSpeed", "value":"low" }
// Mode
{ "version":1, "deviceId":"vdevo161103533857949", "name":"mode", "value":"heat" }
// Oscillation (switch_horizontal = left-right, switch_vertical = up-down)
{ "version":1, "deviceId":"vdevo161103533857949", "name":"switch_horizontal", "value":"on" }
8. Supported Device Categories
The central controller identifies devices, renders corresponding control panels, and supports voice control based on a three-level hierarchy: device type (deviceType) → device sub-type (deviceSubType) → reported actions (actions). Integrators should report the corresponding types, sub-types, and actions based on their actual hardware capabilities.
8.1 Smart Device Types
Device type macros are defined in include/device_sdk_plugin.h. Packet-building logic for each category in the demo can be found in convert_devices_pack(), and control branches in smarthome_device_control().
| Name | Function | Macro | Type | Sub-type |
|---|---|---|---|---|
| Light | On/off, brightness, color temperature, color, scene mode | DEVICE_TYPE_LIGHT | light | Sub-types distinguished by actions (see 8.1.1) |
| Switch | On/off; multi-way switch supports per-channel control | DEVICE_TYPE_SWITCH | switch | Single-way / switchs_2 ~ switchs_6 |
| Outlet | On/off | DEVICE_TYPE_OUTLET | outlet | Same as switch, multi-hole uses switchs_N |
| Power Strip | On/off | DEVICE_TYPE_SOCKETS | sockets | Same as switch, multi-hole uses switchs_N |
| Curtain | Open, close, pause, percentage, angle | DEVICE_TYPE_CURTAIN | curtain | Sub-types distinguished by actions (see 8.1.4) |
| Air Conditioner | On/off, temperature, mode, wind speed, oscillation | DEVICE_TYPE_AIRCONDITION | aircondition | AC / temperature_ctrl thermostat / floor_heat floor heating |
| Bath Heater | On/off, lighting, exhaust/ventilation/sleep, wind speed | DEVICE_TYPE_BATH_HEATER | bath_heater | |
| Music Player | Play, pause, skip, volume | DEVICE_TYPE_MUSIC_PLAYER | music_player | |
| Clothes Hanger | Raise, lower, pause, lighting | DEVICE_TYPE_HANGER | hanger | |
| Fan (Fan Light) | Fan on/off, lighting, oscillation, wind speed | DEVICE_TYPE_FAN | fan | |
| Scene | Scene execution | DEVICE_TYPE_SMARTSCENE | smartscene |
8.1.1 Light (light)
Lights do not use deviceSubType for distinction. The central controller identifies light sub-types based on the reported action combinations and displays the corresponding control panel:
| Sub-type | Required Actions | Control Panel |
|---|---|---|
| Basic light (on/off only) | TurnOn / TurnOff | Single switch |
| Dimmable light | Also report SetBrightness | Brightness slider |
| Color temperature light | Also report SetColorTemperature | Brightness + color temperature |
| Color light | Also report SetColor | Color (HSV) panel |
| Scene light | Also report SetScene (with mode property) | Scene mode |
| Action | Value | Description |
|---|---|---|
| TurnOn / TurnOff | None | Light on / Light off |
| SetBrightness | 0~100 | Set brightness, read back brightness |
| AdjustUpBrightness / AdjustDownBrightness | None | Brightness +/-10 |
| SetColorTemperature | 0~100 | Color temperature percentage, linearly mapped to Kelvin based on colortemp_range_min~max (demo: 2700K~6400K) |
| AdjustUpColorTemperature / AdjustDownColorTemperature | None | Color temperature +/-10 |
| SetColor | {"h":0~360,"s":0~1,"v":0~1} |
HSV color |
| SetScene | light_scene_N (e.g., light_scene_1 Good Night) | Scene mode, see 7.2 example, demo control branch not implemented, can be extended as needed |
Feedback properties: powerstate(on/off), brightness(0~100), color_temperature(0~100), color_hsv, mode(lightWhite / lightColour / lightScene).
When building packets, inform the central controller of the color temperature range via
colortemp_range_min/colortemp_range_max/colortemp_range_stepproperties (see 7.2 example).
8.1.2 Switch (switch)
Sub-types are distinguished by deviceSubType:
| Sub-type | Description | Control Method |
|---|---|---|
| Not reported / switchs_1 | Single-way switch | TurnOn / TurnOff, feedback powerstate |
| switchs_2 ~ switchs_6 | N-way switch, central controller displays N-channel panel | SetSwitchN (N is channel number, value = on/off), feedback switchsN and powerstate |
| Local switch (LETS_OEM_ZHINENG_SW type) | Uses local relay | Same as single-way; identify corresponding relay channel via ais_relay property |
For multi-way switch packet building, report each button name via properties subdev_name_switch_1 ~ subdev_name_switch_N; when setting switchs_ sub-type, the panel does not display a master power button — the central controller automatically generates per-channel switches based on N, no need to report TurnOn/TurnOff actions.
Multi-way switch packet building example (2-way switch):
smarthome_packet_device_t* dev_pack = smarthome_packet_device_new_object("b2:02:11", "2-Way Switch", 1);
smarthome_packet_device_set_type(dev_pack, DEVICE_TYPE_SWITCH);
smarthome_packet_device_set_sub_type(dev_pack, "switchs_2"); // Key: N-way uses switchs_N
// Button names (optional, for UI display and voice matching)
smarthome_packet_device_add_property(dev_pack, "subdev_name_switch_1", "Switch Button 1");
smarthome_packet_device_add_property(dev_pack, "subdev_name_switch_2", "Switch Button 2");
smarthome_packet_device_add_property(dev_pack, DEVICE_PROPERTIE_POWERSTATE, DEVICE_PROPERTIES_VALUE_OFF);
smarthome_packet_devicelist_add_device(devlist, dev_pack);
Corresponding discovery protocol JSON report:
{
"deviceId": "b2:02:11",
"deviceName": "2-Way Switch",
"online": 1,
"deviceType": "switch",
"deviceSubType": "switchs_2",
"properties": [
{ "name": "subdev_name_switch_1", "value": "Switch Button 1" },
{ "name": "subdev_name_switch_2", "value": "Switch Button 2" },
{ "name": "powerstate", "value": "off" }
]
}
Central controller control commands (params of smarthome_device_control(), action is SetSwitch + channel number, value = on/off):
{ "id":"b2:02:11", "type":"switch", "sub_type":"switchs_2", "action":"SetSwitch1", "value":"on" }
{ "id":"b2:02:11", "type":"switch", "sub_type":"switchs_2", "action":"SetSwitch2", "value":"off" }
Control branch reference implementation (parse channel → operate hardware → feedback per-channel and master power status):
} else if (!strncmp(action, "SetSwitch", strlen("SetSwitch"))) { // Multi-way switch
int index = atoi(action + strlen("SetSwitch")); // Channel number, starting from 1
unsigned char is_on = my_streq(value, DEVICE_PROPERTIES_VALUE_ON);
// Record per-channel status by bits (bit0~bitN of device->status correspond to channel 1~N)
if (is_on) {
device->status |= 1 << (index - 1);
} else {
device->status &= ~(1 << (index - 1));
}
// TODO: Operate actual hardware, e.g., relay
// leshi_ble_set_data_short(LETS_OEM_86_SW, did + (index - 1), seq + (index - 1), 1, is_on);
// Feedback per-channel status: property name is switchs + channel number (switchs1, switchs2, ...)
char prop_id[12] = {0};
snprintf(prop_id, sizeof(prop_id), "switchs%d", index);
notify_prop_change(device->device_id.str, prop_id,
is_on ? DEVICE_PROPERTIES_VALUE_ON : DEVICE_PROPERTIES_VALUE_OFF);
// Feedback master power status: on if any channel is on
notify_prop_change(device->device_id.str, DEVICE_PROPERTIE_POWERSTATE,
device->status ? DEVICE_PROPERTIES_VALUE_ON : DEVICE_PROPERTIES_VALUE_OFF);
}
Corresponding property feedback:
{ "version":1, "deviceId":"b2:02:11", "name":"switchs1", "value":"on" }
{ "version":1, "deviceId":"b2:02:11", "name":"powerstate", "value":"on" }
8.1.3 Outlet (outlet) / Power Strip (sockets)
TurnOn / TurnOff, feedback powerstate. Multi-hole power strips can reference multi-way switches, using switchs_N sub-type for per-channel control (central controller also recognizes switchs_ sub-type for both switch and sockets). Macros are already defined in the header file; the demo does not provide example devices for these, implementation can reference the switch.
8.1.4 Curtain (curtain)
The central controller identifies curtain sub-types based on the reported action combinations:
| Sub-type | Required Actions | Control Panel |
|---|---|---|
| Basic curtain | TurnOn / TurnOff | Switch type |
| Curtain with pause | Also report Pause | Open / Close / Pause |
| Curtain with position | Also report SetProgress | Percentage slider |
| Angle blind (dream curtain) | Also report SetProgress + SetAngle | Position + angle panel |
| Action | Value | Description |
|---|---|---|
| TurnOn | None | Open curtain (local command 0x00) |
| TurnOff | None | Close curtain (local command 0x02) |
| Pause | None | Pause (local command 0x01) |
| SetProgress | 0~100 | Open/close percentage |
| SetAngle | 0~100 | Blade angle (for angle blinds; macro value "SetAngle" not included in device_sdk_plugin.h, define yourself) |
Feedback properties: progress(0~100), powerstate (on when progress>0).
8.1.5 Air Conditioner (aircondition)
Sub-types are distinguished by deviceSubType:
| Sub-type | deviceSubType | Control Panel |
|---|---|---|
| Air conditioner | Not reported / unknown | AC panel (temperature, mode, wind speed, oscillation) |
| Thermostat | temperature_ctrl | Shows AC panel if SetWindSpeed reported, otherwise shows thermostat panel |
| Floor heating | floor_heat | Thermostat panel |
| Action | Value | Description |
|---|---|---|
| TurnOn / TurnOff | None | AC on / AC off |
| SetTemperature | 16~32 | Temperature (°C), auto-clamped on overflow (MIN_TEMP/MAX_TEMP) |
| AdjustUpTemperature / AdjustDownTemperature | None | Temperature +/-1°C |
| SetMode | cold / heat / auto / airsupply / dehumidification | Mode, demo enum mapping see MAP_AIS_DEMO_MODE |
| SetWindSpeed | auto / low / medium / high / strong | Wind speed, demo enum mapping see MAP_AIS_DEMO_WINDSPEED |
Feedback properties: powerstate, temperature, mode, windspeed; oscillation properties switch_horizontal (left-right) / switch_vertical (up-down), values on/off, corresponding actions SwitchHorizontal / SwitchVertical.
8.1.6 Bath Heater (bath_heater)
| Action | Value | Description |
|---|---|---|
| TurnOn / TurnOff | None | Bath heater on / off |
| SwitchLight | on / off | Lighting |
| SetMode | exhaustWind / airsupply / sleep | Ventilation mode |
| SetWindSpeed | high / low | Wind speed level |
Feedback properties: powerstate, switch_light, mode, windspeed.
8.1.7 Music Player (music_player)
| Action | Description |
|---|---|
| TurnOn / TurnOff | Power |
| Play / Pause | Play / Pause |
| Next / Prev | Next track / Previous track |
| AdjustUpVolume / AdjustDownVolume | Volume +/- |
Feedback properties: powerstate, playback status (defined in device_sdk_music.h, currently unused).
8.1.8 Clothes Hanger (hanger)
| Action | Description |
|---|---|
| TurnOn | Raise (retract) |
| TurnOff | Lower |
| Pause | Pause |
| SwitchLight | on / off lighting |
| SetProgress | Raise/lower position percentage |
Feedback properties: powerstate, switch_light, progress. Demo control branch already implements lighting / pause / progress; raise/lower actions need to be supplemented by the integrator in the TurnOn / TurnOff branches with hardware drivers.
8.1.9 Fan (fan)
Demo local type is fan light (LETS_OEM_FAN_LIGHT), fan and lighting integrated.
| Action | Value | Description |
|---|---|---|
| TurnOn / TurnOff | None | Fan on / off |
| SwitchLight | on / off | Lighting |
| SwitchHorizontal | on / off | Left-right oscillation |
| SetWindSpeed | auto / low / medium / high / strong | Wind speed |
Feedback properties: powerstate, switch_light, switch_horizontal, windspeed, progress.
8.1.10 Scene (smartscene)
Scenes only need to report the TurnOn action. When the central controller clicks or uses voice to "execute scene", it sends TurnOn.
Note: All action/property macros above are defined in
include/device_sdk_plugin.h. Enum values for mode and wind speed are detailed in Chapter 9.
9. Command Set, Properties and Enum Definitions
The following macros are all defined in include/device_sdk_plugin.h.
9.1 Device Actions (action)
| Macro | Value | Description |
|---|---|---|
| DEVICE_ACTION_TURN_ON | TurnOn | Turn on |
| DEVICE_ACTION_TURN_OFF | TurnOff | Turn off |
| DEVICE_ACTION_PAUSE | Pause | Pause |
| DEVICE_ACTION_TURN_UP | TurnUp | Raise |
| DEVICE_ACTION_TURN_DOWN | TurnDown | Lower |
| DEVICE_ACTION_SET_MODE | SetMode | Set mode |
| DEVICE_ACTION_SET_SCENE | SetScene | Set scene |
| DEVICE_ACTION_SET_TEMPERATURE | SetTemperature | Set temperature |
| DEVICE_ACTION_ADJUST_UP_TEMPERATURE | AdjustUpTemperature | Temperature + |
| DEVICE_ACTION_ADJUST_DOWN_TEMPERATURE | AdjustDownTemperature | Temperature - |
| DEVICE_ACTION_SET_WINDSPEED | SetWindSpeed | Set wind speed |
| DEVICE_ACTION_SET_BRIGHTNESS | SetBrightness | Set brightness |
| DEVICE_ACTION_ADJUST_UP_BRIGHTNESS | AdjustUpBrightness | Brightness + |
| DEVICE_ACTION_ADJUST_DOWN_BRIGHTNESS | AdjustDownBrightness | Brightness - |
| DEVICE_ACTION_SET_COLOR_TEMPERATURE | SetColorTemperature | Set color temperature |
| DEVICE_ACTION_ADJUST_UP_COLOR_TEMPERATURE | AdjustUpColorTemperature | Color temperature + |
| DEVICE_ACTION_ADJUST_DOWN_COLOR_TEMPERATURE | AdjustDownColorTemperature | Color temperature - |
| DEVICE_ACTION_SET_COLOR | SetColor | Set color |
| DEVICE_ACTION_SET_PROGRESS | SetProgress | Set progress (percentage) |
| DEVICE_ACTION_SWITCH_HORIZONTAL | SwitchHorizontal | Left-right oscillation |
| DEVICE_ACTION_SWITCH_VERTICAL | SwitchVertical | Up-down oscillation |
| DEVICE_ACTION_SWITCH_LIGHT | SwitchLight | Lighting |
| DEVICE_ACTION_SWITCH_STERILIZE | SwitchSterilize | Sterilize |
| DEVICE_ACTION_SWITCH_AIRDRY | SwitchAirdry | Air dry |
| DEVICE_ACTION_SWITCH_DRYING | SwitchDrying | Dry |
| DEVICE_ACTION_PLAY | Play | Play |
| DEVICE_ACTION_NEXT | Next | Next track |
| DEVICE_ACTION_PREV | Prev | Previous track |
| DEVICE_ACTION_ADJUST_UP_VOLUME | AdjustUpVolume | Volume + |
| DEVICE_ACTION_ADJUST_DOWN_VOLUME | AdjustDownVolume | Volume - |
| DEVICE_ACTION_SET_BATTERY_PERCENTAGE | SetBatteryPercentage | Set battery percentage |
Per-channel control actions for multi-way switches are
SetSwitchN(N is channel number, e.g., SetSwitch1, SetSwitch2). These actions are auto-generated by the central controller based on sub-type and have no corresponding macro.
9.2 Device Properties (property)
| Macro | Value | Description |
|---|---|---|
| DEVICE_PROPERTIE_POWERSTATE | powerstate | Power state |
| DEVICE_PROPERTIE_MODE | mode | Mode |
| DEVICE_PROPERTIE_TEMPERATURE | temperature | Temperature |
| DEVICE_PROPERTIE_CURRENT_TEMPERATURE | current_temperature | Current temperature |
| DEVICE_PROPERTIE_WINDSPEED | windspeed | Wind speed |
| DEVICE_PROPERTIE_BRIGHTNESS | brightness | Brightness |
| DEVICE_PROPERTIE_COLOR_HSV | color_hsv | Color (HSV) |
| DEVICE_PROPERTIE_COLOR_TEMPERATURE | color_temperature | Color temperature |
| DEVICE_PROPERTIE_PROGRESS | progress | Progress |
| DEVICE_PROPERTIE_SWITCH_HORIZONTAL | switch_horizontal | Left-right oscillation |
| DEVICE_PROPERTIE_SWITCH_VERTICAL | switch_vertical | Up-down oscillation |
| DEVICE_PROPERTIE_SWITCH_LIGHT | switch_light | Lighting |
| DEVICE_PROPERTIE_SWITCH_STERILIZE | switch_sterilize | Sterilize |
| DEVICE_PROPERTIE_SWITCH_AIRDRY | switch_airdry | Air dry |
| DEVICE_PROPERTIE_SWITCH_DRYING | switch_drying | Dry |
| DEVICE_PROPERTIES_VALUE_ON / OFF | on/off | On/Off |
Extended properties used in demo (no macros, use string literals directly):
| Property | Description |
|---|---|
| colortemp_range_min / max / step | Light color temperature range and step (K), see 8.1.1 |
| subdev_name_switch_1 ~ N | Multi-way switch button names, see 8.1.2 |
| switchs1 ~ switchsN | Multi-way switch per-channel status feedback (on/off), see 8.1.2 |
| ais_relay | Central controller relay channel corresponding to local switch, see 8.1.2 |
9.3 Mode and Wind Speed Enums
Mode (in smarthome_priv.h, AIS values are mapped to local codes via MAP_AIS_DEMO_MODE):
| Macro | Value | Description |
|---|---|---|
| DEVICE_MODE_COLD | cold | Cooling |
| DEVICE_MODE_HEAT | heat | Heating |
| DEVICE_MODE_AUTO | auto | Auto |
| DEVICE_MODE_AIRSUPPLY | airsupply | Ventilation |
| DEVICE_MODE_DEHUMIDIFICATION | dehumidification | Dehumidify |
| DEVICE_MODE_MANUAL | manual | Manual |
| DEVICE_MODE_ENERGY | energy | Energy saving |
| DEVICE_MODE_COMFORTABLE | comfortable | Comfort |
| DEVICE_MODE_HOLIDY | holiday | Holiday |
| DEVICE_MODE_ECO | eco | Eco |
| DEVICE_MODE_SLEEP | sleep | Sleep |
| DEVICE_MODE_PROGRAM | program | Program |
| DEVICE_MODE_FLOOR_HEAT | floorHeat | Floor heating |
| DEVICE_MODE_AUXILIARY_HEAT | auxiliaryHeat | Auxiliary heating |
| DEVICE_MODE_SILENT | silent | Silent |
| DEVICE_MODE_EXHAUSTWIND | exhaustWind | Exhaust |
Wind speed (MAP_AIS_DEMO_WINDSPEED):
| Macro | Value | Description |
|---|---|---|
| DEVICE_WINDSPEED_AUTO | auto | Auto |
| DEVICE_WINDSPEED_HIGH | high | High |
| DEVICE_WINDSPEED_MIDDLE | medium | Medium |
| DEVICE_WINDSPEED_LOW | low | Low |
| DEVICE_WINDSPEED_HEALTH | health | Health |
| DEVICE_WINDSPEED_NATURAL | natural | Natural |
| DEVICE_WINDSPEED_STRONG | strong | Strong |
| DEVICE_WINDSPEED_QUIET | quietWind | Quiet |
| DEVICE_WINDSPEED_SLEEP | sleep | Sleep |
| DEVICE_WINDSPEED_COMFORTABLE | comfortableWind | Comfort |
Mapping table definition example:
static map_smart_ais_demo_t MAP_AIS_DEMO_MODE[] = {
{DEVICE_MODE_COLD, "1", "Cooling"},
{DEVICE_MODE_AIRSUPPLY, "2", "Ventilation"},
{DEVICE_MODE_DEHUMIDIFICATION, "3", "Dehumidify"},
{DEVICE_MODE_HEAT, "4", "Heating"},
{NULL, NULL, NULL} // End sentinel
};
10. Data Structures
smarthome_priv.h defines the device info structure, used by integrators to maintain device lists locally:
typedef struct {
str_t name; // Device name
str_t device_id; // Device ID
str_t room_name; // Room name
unsigned char type; // Device type (LETS_OEM_xxx)
unsigned char id;
unsigned char seq;
unsigned char flag; // bit0:online, bit2:local, bit4~7:switchs
unsigned char show;
device_status_t status;
unsigned char pic_id;
device_data_t data; // Union: stores brightness/temperature/... based on device type
} device_info_t;
device_data_t is a union that reuses memory based on device type (light / curtain / air_condition / fan_light / hanger / music_box / bath_heat / smart_switch).
Device default configuration is stored as text (demo path is /data/plugin_devices_info, adjustable per platform), format is type:id:seq^name^pic_id, for example:
const char* DEFAULT_PLUG_DEVICE_INFO =
"22:01:00^Going Home^0\n" // Scene
"08:04:06^Color Light^0\n" // Light
"b0:01:07^Curtain^0\n" // Curtain
"21:01:0B^Air Conditioner^0^0\n" // Air conditioner
"b2:01:10^1-Way Switch^0\n"; // Switch
parse_config_file() reads this configuration, parses it into device_info_t and adds to the device list, then sets state to PLUGIN_STATE_LOGGED and calls notify_devices_change() to report.
11. Platform Utility Interfaces
The RTOS platform provides the following utility interfaces for convenient plugin development.
11.1 Unbind and Reboot
When unbinding/logging out, the application usually needs to restart. Call:
g_context->listener(NULL, PLUGIN_EVENT_REQ_REBOOT, NULL);
11.2 UI Toast
void smarthome_plugin_toast(const char* msg) {
if (g_context->listener == NULL) return;
char toast[256];
snprintf(toast, sizeof(toast), "{\"version\":1,\"msg\":\"%s\"}", msg);
g_context->listener(NULL, PLUGIN_EVENT_ON_UI_TOAST, toast);
}
11.3 Get IP / MAC Address
The platform has implemented network information retrieval interfaces (declared in platform header files ssutils.h / ss_deviceinfo.h, can be called directly after extern declaration in the plugin):
// Get IP address, name is network interface name (ignored on RTOS side, always gets WiFi STA IP)
// Returns 0 on success, ip like "192.168.1.100"
extern int ssutils_get_ip_address(char* name, char* ip);
// Get MAC address, name is network interface name (ignored on RTOS side, always gets WiFi STA MAC)
// format=0: "aa:bb:cc:dd:ee:ff", buffer needs 18 bytes
// format=1: "aabbccddeeff", buffer needs 13 bytes
extern int ssutils_get_mac_addr(char* name, char* mac, int format);
// Convenience interface: get MAC without colons (equivalent to ssutils_get_mac_addr(name, sn, 1))
extern int ss_deviceinfo_get_mac(char* sn);
Example:
char ip[20] = {0};
char mac[18] = {0};
if (ssutils_get_ip_address("wlan0", ip) == 0) {
printf("ip: %s\n", ip);
}
if (ssutils_get_mac_addr("wlan0", mac, 0) == 0) {
printf("mac: %s\n", mac);
}
11.4 HTTP Requests
The platform has a built-in HTTP client (asynchronous). Plugins can call it directly; callbacks execute in the HTTP service thread:
typedef void (*cb_on_result)(void* context, int code, void* result);
// GET
void http_client_add_request_get(void* context, cb_on_result on_result, int req_type, const char* url);
void http_client_add_request_get_with_header(void* context, cb_on_result on_result, int req_type, const char* url);
// POST, data is JSON string
void http_client_add_request_post_json(void* context, cb_on_result on_result, int req_type,
const char* url, const char* data, int size);
void http_client_add_request_post_json_with_header(void* context, cb_on_result on_result, int req_type,
const char* url, const char* data, int size);
// POST / PUT raw data
void http_client_add_request_post_data(void* context, cb_on_result on_result, int req_type,
const char* url, const char* data, int size);
void http_client_add_request_put_data(void* context, cb_on_result on_result, int req_type,
const char* url, const char* data, int size);
void http_client_add_request_put_stream(void* context, cb_on_result on_result, int req_type,
const char* url, const char* data, int size);
Callback prototype: after response arrives, callback on_result(context, size, data) is invoked, data is the response body (string), size is the length, context is the user pointer passed during the call (passed through unchanged).
Example (POST JSON, with MD5 signature, see 11.5):
static void cb_config_data(void* context, int size, void* data) {
if (size <= 0 || data == NULL) {
LOGE("http response: size = 0\n");
return;
}
char* json_str = (char*)data; // Response body, parse with cJSON_Parse
cJSON* json = cJSON_Parse(json_str);
// ... process response
cJSON_Delete(json);
}
void http_request_config(void) {
const char* url = "http://xxxxx";
char post_data[128];
char md5[33] = {0};
// sign = md5(device_id + salt)
char sign_str[48] = {0};
snprintf(sign_str, sizeof(sign_str), "%s52S#8@8f5cLn", g_device_id);
get_buffer_md5sum_text(sign_str, strlen(sign_str), md5);
extern char* ss_device_info_get_pid();
snprintf(post_data, sizeof(post_data),
"{\"pid\":\"%s\",\"id\":\"%s\",\"sign\":\"%s\"}",
ss_device_info_get_pid(), g_device_id, md5);
http_client_add_request_post_json(NULL, cb_config_data, 0, url, post_data, strlen(post_data));
}
11.5 MD5
// Calculate MD5 of buffer, result output as 32-char text (needs 33-byte buffer, including '\0')
extern int get_buffer_md5sum_text(char* buffer, unsigned int size, unsigned char* result);
Usage reference: see signature calculation in 11.4 example.
11.6 MQTT
The RTOS platform provides a lightweight MQTT client (mqtt_client.h), running internally as a separate thread. Interfaces:
typedef void (*cb_on_mqtt_connect)(int is_connected);
typedef void (*cb_on_mqtt_message)(char* topic, char* payload, int len);
// Start MQTT service and connect; if sub_info is non-NULL, auto-subscribe
// Returns MQTT instance pointer, NULL on failure
struct cmd_mqtt_common* mqtt_client_start(char* init_config, char* sub_info,
cb_on_mqtt_connect on_mqtt_connect,
cb_on_mqtt_message on_mqtt_message);
void mqtt_client_subscribe(struct cmd_mqtt_common* inst, char* sub_info); // Subscribe
int mqtt_client_publish(struct cmd_mqtt_common* inst, char* topic, char* message); // Async publish
int mqtt_client_publish_sync(struct cmd_mqtt_common* inst, char* topic, char* message); // Sync publish
void mqtt_client_connect(struct cmd_mqtt_common* inst); // Connect
void mqtt_client_disconnect(struct cmd_mqtt_common* inst); // Disconnect
int mqtt_client_is_connecting(struct cmd_mqtt_common* inst);
void mqtt_client_stop(struct cmd_mqtt_common* inst); // Stop and release resources
Parameter format is space-separated key=value strings (consistent with serial debug commands):
| Parameter | Supported Keys |
|---|---|
| init_config | host, port, client_id, username, password, alive (heartbeat seconds), ssl (0/1), clean (0/1), will_topic, will_message |
| sub_info | qos, topic |
Example:
static void on_mqtt_connect(int is_connected) {
// is_connected == 1 means connection successful, can subscribe to topics here
}
static void on_mqtt_message(char* topic, char* payload, int len) {
printf("recv: %s %.*s\n", topic, len, payload);
}
void mqtt_demo(void) {
char config[80];
snprintf(config, sizeof(config), "host=%s port=%d alive=60 client_id=%s",
"192.168.0.117", 1883, "R1005538268211647727");
struct cmd_mqtt_common* mqtt =
mqtt_client_start(config, "", on_mqtt_connect, on_mqtt_message);
// Subscribe (can also be called in the connection success callback)
mqtt_client_subscribe(mqtt, "qos=0 topic=zhiju/zhiju_switch_wr10/R1009181328178345312/command/down");
// Publish
mqtt_client_publish(mqtt, "zhiju/zhiju_switch_wr10/R1009181328178345312/message/up", "{\"state\":1}");
}
11.7 UART Example Code
Serial communication example code: Download