1.4.4.6 台灯接入实例

优质
小牛编辑
131浏览
2023-12-01

概述

本文档通过具体产品-台灯的开发,说明如何使用IoT模组基于HeyThings RTOS SDK进行开发,完成产品接入。 产品实现模式为:模组SDK + MCU

产品控制功能在MCU侧实现,IoT模组通过厂家私有串口协议与MCU通信。IoT模组为ESP32平台。

1. 开发准备

在开放平台注册产品id等信息,申请设备证书。

2. 目录结构

app_src/
    ├── protobuf-c                  //protobuf的C语言实现库
    │   ├── protobuf-c.c
    │   └── protobuf-c.h
    ├── app_main.c                  //应用层入口主程序文件
    ├── app_main.h
    ├── app_version.h               //应用层软件版本号定义
    ├── debug_cli.c                 //终端调试命令任务
    ├── debug_cli.h
    ├── dev_abstract.c              //设备抽模型接收回调,SDK命令处理入口
    ├── dev_abstract.h
    ├── devInfo.pb-c.c              //设备基础信息服务protobuf定义
    ├── devInfo.pb-c.h
    ├── devInfo.proto
    ├── light.pb-c.c                //智能灯控制服务protobuf定义
    ├── light.pb-c.h
    ├── light.proto
    ├── light_service.c             //灯控制服务的模型封装和解析,即user helper
    ├── light_service.h
    ├── light_service_devinfo.c     //灯基础信息服务的模型封装和解析
    ├── light_service_devinfo.h
    ├── light_service_upgrade.c     //设备OTA升级服务的模型封装和解析
    ├── light_service_upgrade.h
    ├── ota_task.c                  //应用层实现的ota升级处理,平台相关
    ├── softwareUpdate.pb-c.c       //设备OTA升级服务protobuf定义
    ├── softwareUpdate.pb-c.h
    └── softwareUpdate.proto

3. 信息存储

ESP32模组存储分区示例如下:

序号 标签              用途             类型 子类型 偏移     长度
0   nvs              SDK数据区         01   02   00009000 00008000       32k
1   dev_base         用户烧录信息       40   40   00011000 00002000       8k
2   user_base        用户PIN码区       40   41   00013000 00001000       4k
3   otadata          OTA data         01   00   00014000 00002000       8K
4   phy_init         RF data          01   01   00016000 00001000       4K
5   resv1            预留用户nvs分区    01   02   00018000 00048000       288K
6   ota_0            OTA app          00   10   00060000 001d0000       1.81M
7   ota_1            OTA app          00   11   00230000 001d0000       1.81M

SDK数据区:存储SDK内部运行时信息
出厂烧录信息:包含用户烧录信息 和 用户PIN码区, 主要存储设备证书、PIN码等 预留用户nvs分区: 预留给用户使用,用户可使用ESP32平台的API访问。

4. 用户实现的函数

  • HeyThings SDK回调函数设置
/**
 * @brief : callback function implement by user app.
 */
static oc_handler_t handler = {
    .cmd_set_handle          = cmd_set_user_cb,         //属性设置处理
    .cmd_array_add_handle    = cmd_array_add_user_cb,   //数组类型属性添加元素
    .cmd_array_del_handle    = cmd_array_del_user_cb,   //数组类型属性删除元素
    .cmd_array_update_handle = cmd_array_update_user_cb,//数组类型属性更新元素
    .cmd_action_call         = cmd_action_call_cb,      //设备动作处理
    .cmd_get_cmd_cb          = cmd_get_user_cb,         //属性获取处理

    .dev_provision_confirm   = wait_user_confirm_cb,    //业务层确认配网回调处理
    .event_handle            = demo_user_event_handle,  //SDK状态事件处理
    .init_complete_cb        = init_complete_cb_func    //SDK初始化完成回调
};
  • 属性操作的回调实例,用户可以直接使用,只需完成实际设备操作
/**
 * @brief entry function to handle service.light
 * @param siid          [service id]
 * @param iid           [property id]
 * @param properties    [property data]
 * @return int          [handle result, 0 on success; -1 on error]
 */
int service_light_cmd_set_handle(int siid, int iid, void* properties)
{
    Iot__Service__Light__Properties* p = (Iot__Service__Light__Properties*)properties;
    int ret = 0;

    int field_index = get_field_index_by_iid(ServiceLight, IID_CNT, iid);
    if(field_index < 0) {
        printf("ERROR: not find this iid in the service. siid=%d iid=%d\n", siid, iid);
        return -1;
    }

    printf("in service_light_cmd_set_handle siid=%d iid=%d\n", siid, iid);

    switch(iid) {
        case 1:
            /* set switch_ */
            // ret = user_handle_set_prop_switch_(siid, p->switch_);
            printf("set light switch : %d\n", p->switch_);
            serviec_light_property_switch__changed(siid, p->switch_);   //demo just response had done
            break;
        case 2:
            /* set brightness */
            // ret = user_handle_set_prop_brightness(siid, p->brightness);
            break;
        case 3:
            // ret = user_handle_set_prop_colortemperature(siid, p->colortemperature);
            break;
        case 4:
            // ret = user_handle_set_prop_workmode(siid, p->lightmode);
            break;
        case 5:
            // ret = user_handle_set_autoColorTemperature(siid, p->autocolortemperature);
            break;
        case 6:
            if(p->colorrgb) {
                // ret = user_handle_set_prop_rgb(siid, p->colorrgb);
            } else {
                printf("ignore this cmd, rgb is empty\n");
            }
            break;
        case 7:
            // ret = user_handle_set_colorSaturation(siid, p->colorsaturation);
            break;
        case 8:
            //reserved.
            break;
        case 9:
            // ret = user_handle_set_prop_autobrightness(siid, p->autobrightness);
            break;
        case 10:
            // ret = user_handle_set_prop_lightlanguagemode(siid, p->lightlanguagemode);
            break;
        default:
            break;
    }

    return ret;
}
  • 状态通知的接口示例,各属性变化,调用相应的接口函数通知到SDK
/**
 * @brief notify sdk the property.switch_ changed, sdk will notify all observer
 * @param siid      [service id]
 * @param switch_   [switch state]
 */
void serviec_light_property_switch__changed(int siid, int switch_)
{
    Iot__Service__Light__Properties tmp_light = IOT__SERVICE__LIGHT__PROPERTIES__INIT;
    tmp_light.switch_ = switch_;

    //save new value.
    struct light_service_instance* p_instance =  get_light_instance_by_siid(siid);
    if(p_instance) {
        p_instance->service.switch_ = switch_;
    }

    inner_service_light_property_change(siid, ServiceLight[0].iid, &tmp_light);

    printf("report : sii=%d (%s) = %d\n", siid, iid_string(ServiceLight[0].iid), switch_);
}
  • 用户应用层入口函数,提供回调函数,启动SDK主循环
/**
 * @brief The appliction entry function to calls IoT WiFi SDK
 * @return int [start result]
 */
int user_sdk_main(void)
{
    int ret;

    printf("user app start. build at %s %s.\n", __DATE__, __TIME__);

    start_uart_debug_cli();

    // start iot wifi sdk and will never exit.
    ret = iot_sdk_start(&iot_sdk_callback_handler, dev_odos, secert_mode, &g_dev_info);
    if(ret < 0) {
        // here means iot_sdk_start has fail.
        printf("FATAL ERROR, reboot after 10 seconds.\n");
    }

    return -1;
}

5. 代码编译

乐鑫esp-idf平台下使用idf.py编译。

学习使用esp-idf

ESP-IDF是ESP32芯片的官方开发框架,新版本的ESP8266也已经使用该框架。关于esp-idf的基础开发环境搭建及其SDK的使用说明请参考ESP官方文档资源。

https://github.com/espressif/esp-idf
https://docs.espressif.com/projects/esp-idf/zh_CN/latest/index.html

在可以编译烧录并运行乐鑫SDK的example(如get-started/hello_world)后再来编译使用本例程。

使用idf.py工具编译烧录

HeyThings SDK APP demo在ESP平台下使用的是其cmake编译系统,编译工具为idf.py

编译调试的路径:HeyThings_SDK_app_demo

cd到该路径下,执行命令
编译:idf.py build
运行:idf.py flash
查看:idf.py monitor
或者组合命令:idf.py build flash monitor