OpenHarmony南向设备开发中的JSON&MQTT基础

吃吃的等
发布于 2022-8-2 23:35
浏览
4收藏

一、JSON基础

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。
JSON优点:数据格式比较简单,易于读写。
 
JSON主要有3种结构:

  • JSON对象
  • JSON数组
  • JSON对象和数组嵌套

JSON对象简单而言便是键值对或名值对,而“值”可以是数值、字符串和布尔类型等。
JSON对象具体格式如下图1所示。 以 { } 包围。
OpenHarmony南向设备开发中的JSON&MQTT基础-鸿蒙开发者社区OpenHarmony南向设备开发中的JSON&MQTT基础-鸿蒙开发者社区
 
JSON数组的表达方法和C语言数组的表达方法完全相同。以 [ ] 包围。
OpenHarmony南向设备开发中的JSON&MQTT基础-鸿蒙开发者社区OpenHarmony南向设备开发中的JSON&MQTT基础-鸿蒙开发者社区
 
JSON嵌套就是JSON对象中可包括JSON数组,JSON数组中可包括JSON对象,值中可包括JSON对象。
OpenHarmony南向设备开发中的JSON&MQTT基础-鸿蒙开发者社区OpenHarmony南向设备开发中的JSON&MQTT基础-鸿蒙开发者社区
 
华为云IoTDA平台下方的命令即是一个JSON对象,在根对象内包含三个string:value键值对,其中“paras"键对应的值是一个对象:
OpenHarmony南向设备开发中的JSON&MQTT基础-鸿蒙开发者社区OpenHarmony南向设备开发中的JSON&MQTT基础-鸿蒙开发者社区
理解了JSON基础语法后,再看下面代码对上述JSON对象的抽丝剥茧,逻辑就很清晰了。

cJSON *root = cJSON_ParseWithLength(data->message->payload, data->message->payloadlen);
if(root != NULL){
    cJSON *serv_id_obj = cJSON_GetObjectItem(root, "service_id");  //根对象的object item
    if(serv_id_obj!= NULL){
        char *serv_id_str = cJSON_GetStringValue(serv_id_obj);
        if(strcmp(serv_id_str,"fan_service") == 0){
            cJSON *cmd_name = cJSON_GetObjectItem(root, "command_name");  //根对象的object item
            if(cmd_name != NULL){
                char *cmd_name_str = cJSON_GetStringValue(cmd_name);
                if(strcmp(cmd_name_str,"motor_cmd") == 0){
                    cJSON *para_obj = cJSON_GetObjectItem(root, "paras");  //根对象的object item
                    if(para_obj != NULL){
                        cJSON *level_obj = cJSON_GetObjectItem(para_obj,"motor_level");  //嵌套子对象的object item
                        if(level_obj != NULL){
                            int motor_level = (int)cJSON_GetNumberValue(level_obj);
                            //contrl motor run
                            motor_speed(motor_level);
                        }
                    }
                }
            }
        }
    }
}

二、MQTT基础

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输), 是IBM开发的一个即时通讯协议。

MQTT协议是为计算能力有限,且工作在低带宽、不可靠的网络的传感器和控制设备通讯而设计的协议,它有以下主要特性:

  • 特别轻量级,使用一个8位的系统、30KB的空间,就可以运行MQTT的客户端
  • 使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序耦合
  • 对负载内容屏蔽的消息传输
  • 使用 TCP/IP 提供网络连接
  • 有消息发布服务质量(QoS)机制,用户可根据应用场景需要选择:
    • “至多一次”,消息发布完全依赖底层TCP/IP网络。会发生消息丢失或重复
    • “至少一次”,确保消息到达,但消息重复可能会发生
    • “只有一次”,确保消息到达一次
  • 小型传输,开销很小(固定长度的头部是 2 字节),以降低网络流量
  • 使用 “Last Will and Testament(最后的遗嘱)” 特性保证在客户端异常断开时实施各种策略

MQTT包括客户端、代理(broker)两部分.以智能家居系统为例,智能家电和手机为客户端,云端为代理。客户端首先向代理发起请求,代理收到后对客户端进行认证,认证通过后在客户端与代理之间建立一个TCP长连接通道,客户端通过该通道订阅若干关注的主题(Topic),同时在自身状态变化时,向相应的主题发布消息,代理将该消息发给正在订阅该主题的所有客户端。
OpenHarmony南向设备开发中的JSON&MQTT基础-鸿蒙开发者社区OpenHarmony南向设备开发中的JSON&MQTT基础-鸿蒙开发者社区

三、OpenHarmony南向设备实践

1.在学习OpenHarmony南向设备开发学习时,可以借助华为云物联网平台IoTDA进行云端与智能设备的MQTT通讯功能实践。
OpenHarmony南向设备开发中的JSON&MQTT基础-鸿蒙开发者社区OpenHarmony南向设备开发中的JSON&MQTT基础-鸿蒙开发者社区
 
2.使用开源c库cJSON
https://gitee.com/DaveGamble/cJSON

/* The cJSON structure: */
typedef struct cJSON
{
    struct cJSON *next;
    struct cJSON *prev;
    struct cJSON *child;

    /* The type of the item, as above. */
    int type;
    char *valuestring;
    int valueint;
    double valuedouble;
    char *string;
} cJSON;

使用该库的重要注意事项
cJSON的所有操作都是基于链表,在使用过程中大量使用malloc从堆中分配动态内存。在使用完之后,应当及时清空cJSON指针所指向的内存。

  • 调用cJSON_Delete(cJSON *item)删除一个JSON对象数据时,如果有嵌套,会递归删除子对象数据
  • 调用cJSON_Print(const cJSON *item) 或 cJSON_PrintUnformatted(const cJSON *item)函数将JSON对象转化为字符串时,同样会申请动态内存,也需要在使用完后,显式调用cJSON_free(void *object)函数释放内存。

3.使用开源c库paho.mqtt
https://github.com/eclipse/paho.mqtt.embedded-c
该库包含三个子目录(子工程):
OpenHarmony南向设备开发中的JSON&MQTT基础-鸿蒙开发者社区

  • MQTTPacket - simple de/serialization of MQTT packets, plus helper functions
  • MQTTClient - higher level C++ client
  • MQTTClient-C - higher level C client
static void MQTTDemoTask(void)
{
    int rc, count = 0;
    WifiConnect(WIFI_SSID, WIFI_PWD);
    NetworkInit(&network);

begin:
    NetworkConnect(&network, HOST_ADDR, 1883);
    MQTTClientInit(&client, &network, 2000, sendBuf, sizeof(sendBuf), readBuf, sizeof(readBuf));

    MQTTString userName = MQTTString_initializer;
    userName.cstring = "test_fan_01"; //deviceID

    //clientId & password are generated by IoTDA website using DeviceId & DeviceSecret
    MQTTString clientId = MQTTString_initializer;
    clientId.cstring = "test_fan_01_0_0_2022073006"; //MQTT ClientId 

    MQTTString password = MQTTString_initializer;
    password.cstring = "1d8581020a508d7854d1be17e8dab075fcb70e6364b99f6a916374cb212041ab";

    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
    data.clientID = clientId;
    data.username = userName;
	data.password = password;
    data.willFlag = 0;
    data.MQTTVersion = 4;
    data.keepAliveInterval = 60;
    data.cleansession = 1;

    printf("MQTTConnect  ...\n");
    rc = MQTTConnect(&client, &data);
    if (rc != 0) {
        //连接错误处理
        NetworkDisconnect(&network);
        MQTTDisconnect(&client);
        goto begin;
    }

    printf("MQTTSubscribe cloud cmd topic ...\n");
    rc = MQTTSubscribe(&client, SUBCRIB_TOPIC, 0, messageArrived);
    if (rc != 0) {
        //订购错误处理
        goto begin;
    }

    while (true) {
        MQTTMessage message;
        char *publishtopic="$oc/devices/test_fan_01/sys/properties/report";

        char payload[300]={0};
        //将上传数据打包为JSON对象
        cJSON *root = cJSON_CreateObject();
        if (root !=NULL) {
            cJSON *serv_arr = cJSON_AddArrayToObject(root, "services");
            cJSON *arr_item = cJSON_CreateObject();
            cJSON_AddStringToObject(arr_item,"service_id","fan_service");
            cJSON *data_obj = cJSON_CreateObject();
            cJSON_AddItemToObject(arr_item, "properties", data_obj);
            cJSON_AddNumberToObject(data_obj,"temperature",temp_val);
            cJSON_AddNumberToObject(data_obj,"humidity",humi_val);
            cJSON_AddItemToArray(serv_arr, arr_item);
            char *payload_str =cJSON_PrintUnformatted(root);            
            strcpy(payload,payload_str);
            //释放cJSON相关内存及对象
            cJSON_free(payload_str);
            cJSON_Delete(root);
        }

        //publish temperature & humidity data to cloud
        message.qos = 0;
        message.retained = 0;
        message.payload = payload;
        message.payloadlen = strlen(payload);

        if ((rc = MQTTPublish(&client, publishtopic, &message)) != 0) {
            //publish 错误处理
            NetworkDisconnect(&network);
            MQTTDisconnect(&client);
            goto begin;
        }
        MQTTYield(&client, 5000);
    }
}    

已于2022-8-3 16:03:26修改
4
收藏 4
回复
举报
1条回复
按时间正序
/
按时间倒序
物联风景
物联风景

太好了,思路很清晰,先理论,再实战,手动点赞

回复
2022-8-3 09:37:31
回复
    相关推荐