本文講解設備開發者如何通過天貓精靈已認證的Inside+IoT模組上開發產品功能,并將設備連接到天貓精靈AI平臺設備和生活物聯網平臺。當您的設備需要同時支持Inside語音控制其他設備的能力和自身IoT的控制能力時(以下簡稱Inside + IoT),請參考該文檔進行開發,平臺當前僅支持TG6000A芯片。

創建產品

在生活物聯網平臺創建產品

  1. 創建產品。

    參見創建產品,并按如下要求設置參數。

    • 選擇節點類型設備
    • 選擇是否接入網關
    • 選擇連網方式WiFi
    • 選擇數據格式ICA標準數據格式(Alink JSON)
  2. 產品功能定義。
    參見功能概述來定義產品的功能。
  3. 調試設備。
    1. 選擇模組,支持的語音芯片暫未列入列表,請選擇其他即可。
      調試設備
    2. 新增測試設備,并獲取設備證書。
      詳細操作參見新增測試設備新增調試設備成功
  4. 在產品的人機交互頁面,可打開使用公版App控制產品的開關,使用生活物聯網平臺提供的云智能App對設備進行控制。App參數的配置請參見配置人機交互。配網方案選擇請配置“藍牙輔助配網”,配網入口選擇“掃碼/本地自動發現”。配網配置
  5. 批量投產頁面確認設備信息。
    說明 設備開發結束之后才會投產,開發階段請不要單擊完成開發

在天貓精靈AI平臺創建產品

請參考文檔天貓精靈AI平臺快速入門進行Inside語音產品創建和定義。

產品關聯

說明 請聯系商務或者技術支持通過內部流程關聯您生活物聯網平臺和天貓精靈AI平臺的產品,后續進行一次配網綁定。

設備端開發

獲取SDK代碼及編譯

請參考搭建芯片開發環境(TG6000A)進行芯片開發環境搭建和代碼下載編譯。

為節省ROM、RAM空間,請您在編譯時使能AIOT_LIVING_SDK模塊加入編譯。

具體配置方法:在代碼根目錄build.sh 文件中設置export CONFIG_AIOT_LIVING_SDK=0宏的值為1, 其中build.sh 腳本由aligenieSDK/scripts/build_TG6000A.sh 在repo sync時拷貝生成,可以直接更改該文件提交到您的代碼倉庫中, 因為repo sync不會自動拷貝覆蓋,請手動拷貝到根目錄中。

export CONFIG_AIOT_LIVING_SDK=1

使能后AIOT Living SDK將加入編譯,其中AIoTSDK目錄、thirdparty_app目錄相關代碼將加入編譯,從而支持設備具備自身IoT的被控能力,使您的設備可以具備使用云智能App或自有品牌App進行設備控制和查看設備狀態的能力。

其中AIoTSDK目錄為該芯片平臺適配層代碼與AIoT Living SDK相關靜態庫;thirdparty_app為您的設備應用層代碼,包含部分Inside + IoT配網業務流程邏輯,請合入代碼時謹慎處理。

燒寫固件到模組

請參考搭建芯片開發環境(TG6000A)文檔中的燒錄方式進行固件燒錄。

產品功能開發

  1. 配置設備IoT身份信息。

    設備激活憑證寫入,您可以將您的IoT設備身份信息寫入設備存儲介質中,并通過下述方案實現讀取的相關代碼并傳入AIoT Living SDK中。

    在應用示例代碼thirdparty_app/vendor.c的代碼中有參考讀取設備信息的方式,設備開發者可以參考。

    vendor_set_dev_meta_info( )函數中有調用vendor_get_product_idvendor_get_product_keyvendor_get_product_secretvendor_get_device_namevendor_get_device_secret等函數獲取IoT身份信息,實現上述函數可以完成設備身份的獲取。

    設備開發者將設備身份信息設置到程序之后,可以將代碼進行編譯并遵循模組商提供的燒寫工具將固件寫入模組,并將模組上電。

    如果模組可以正常連接生活物聯網平臺,在生活物聯網平臺的設備調試頁面可以看到該設備已激活在線,以及設備連接到生活物聯網平臺的時間信息。

    模組設備在線
  2. 配置設備語音能力身份信息。
    請參考設備產品入網指南寫入Inside身份信息。
  3. 上報產品屬性。
    產品的屬性發生變化時,需要將變化后的數值上報到生活物聯網平臺。屬性變化的檢測以及上報是由設備開發者定義和實現的。

    如下示例代碼對應的產品具有一個LightSwitch的屬性,類型為bool,還具有一個RGBColor的屬性,類型為復合型。用戶可以參照該代碼上報產品的屬性變化。

    void user_post_property(void)
    {
        static int example_index = 0;
        int res = 0;
        user_example_ctx_t *user_example_ctx = user_example_get_ctx();
        char *property_payload = "NULL";
    
        if (example_index == 0) {
            /* Normal Example */
            property_payload = "{\"LightSwitch\":1}";
            example_index++;
        } else if (example_index == 1) {
            /* Wrong Property ID */
            property_payload = "{\"LightSwitchxxxx\":1}";
            example_index++;
        } else if (example_index == 2) {
            /* Wrong Value Format */
            property_payload = "{\"LightSwitch\":\"test\"}";
            example_index++;
        } else if (example_index == 3) {
            /* Wrong Value Range */
            property_payload = "{\"LightSwitch\":10}";
            example_index++;
        } else if (example_index == 4) {
            /* Missing Property Item */
            property_payload = "{\"RGBColor\":{\"Red\":45,\"Green\":30}}";
            example_index++;
        } else if (example_index == 5) {
            /* Wrong Params Format */
            property_payload = "\"hello world\"";
            example_index++;
        } else if (example_index == 6) {
            /* Wrong Json Format */
            property_payload = "hello world";
            example_index = 0;
        }
    
        res = IOT_Linkkit_Report(user_example_ctx->master_devid, ITM_MSG_POST_PROPERTY,
                                 (unsigned char *)property_payload, strlen(property_payload));
    
        EXAMPLE_TRACE("Post Property Message ID: %d", res);
    }
  4. 上報產品事件。
    如果產品定義了事件,當事件發生時也需要向云端發送事件。事件的檢測以及上報由設備開發者實現。

    例如產品定義了一個標識符為Error的事件,該事件還有一個標識符為ErrorCode的輸出參數。如下示例代碼描述了如何向物聯網平臺發送一個事件。

    void user_post_event(void)
    {
        static int example_index = 0;
        int res = 0;
        user_example_ctx_t *user_example_ctx = user_example_get_ctx();
        char *event_id = "Error";
        char *event_payload = "NULL";
    
        if (example_index == 0) {
            /* Normal Example */
            event_payload = "{\"ErrorCode\":0}";
            example_index++;
        } else if (example_index == 1) {
            /* Wrong Property ID */
            event_payload = "{\"ErrorCodexxx\":0}";
            example_index++;
        } else if (example_index == 2) {
            /* Wrong Value Format */
            event_payload = "{\"ErrorCode\":\"test\"}";
            example_index++;
        } else if (example_index == 3) {
            /* Wrong Value Range */
            event_payload = "{\"ErrorCode\":10}";
            example_index++;
        } else if (example_index == 4) {
            /* Wrong Value Range */
            event_payload = "\"hello world\"";
            example_index++;
        } else if (example_index == 5) {
            /* Wrong Json Format */
            event_payload = "hello world";
            example_index = 0;
        }
    
        res = IOT_Linkkit_TriggerEvent(user_example_ctx->master_devid, event_id, strlen(event_id),
                                       event_payload, strlen(event_payload));
        EXAMPLE_TRACE("Post Event Message ID: %d", res);
    }

    示例代碼中的定義了系統的各種事件處理函數,處理產品回調函數。示例代碼如下所示。

        /* Register Callback */
        IOT_RegisterCallback(ITE_CONNECT_SUCC, user_connected_event_handler);
        IOT_RegisterCallback(ITE_DISCONNECTED, user_disconnected_event_handler);
        IOT_RegisterCallback(ITE_RAWDATA_ARRIVED, user_down_raw_data_arrived_event_handler);
        IOT_RegisterCallback(ITE_SERVICE_REQUST, user_service_request_event_handler);
        IOT_RegisterCallback(ITE_PROPERTY_SET, user_property_set_event_handler);
        IOT_RegisterCallback(ITE_PROPERTY_GET, user_property_get_event_handler);
        IOT_RegisterCallback(ITE_REPORT_REPLY, user_report_reply_event_handler);
        IOT_RegisterCallback(ITE_TRIGGER_EVENT_REPLY, user_trigger_event_reply_event_handler);
        IOT_RegisterCallback(ITE_TIMESTAMP_REPLY, user_timestamp_reply_event_handler);
        IOT_RegisterCallback(ITE_INITIALIZE_COMPLETED, user_initialized);
        IOT_RegisterCallback(ITE_FOTA, user_fota_event_handler);
        IOT_RegisterCallback(ITE_COTA, user_cota_event_handler);

    關于回調函數的說明如下。

    事件回調函數原型事件觸發條件說明
    ITE_CONNECT_SUCC
    int callback(void);
    與云端連接成功時
    ITE_DISCONNECTED
    int callback(void);
    與云端連接斷開時
    ITE_RAWDATA_ARRIVED
    int callback(const int devid, const unsigned char *payload, const int payload_len);
    Linkkit收到raw data數據時
    ITE_SERVICE_REQUEST
    int callback(const int devid, const char _serviceid, const int serviceid_len, const char request, const int request_len, char _response, int *response_len);
    Linkkit收到服務(同步/異步)調用請求時
    ITE_PROPERTY_SET
    int callback(const int devid, const char *request, const int request_len);
    Linkkit收到屬性設置請求時
    ITE_PROPERTY_GET
    int callback(const int devid, const char _request, const int request_len, char _response, int response_len);
    Linkkit收到屬性獲取的請求時
    ITE_REPORT_REPLY
    int callback(const int devid, const int msgid, const int code, const char *reply, const int reply_len);
    Linkkit收到上報消息的應答時
    ITE_TRIGGER_EVENT_REPLY
    int callback(const int devid, const int msgid, const int code, const char eventid, const int eventid_len, const char message, const int message_len);
    Linkkit收到事件上報消息的應答時
    ITE_TIMESTAMP_REPLY
    int callback(const char *timestamp);
    當Linkkit收到查詢時間戳請求的應答時
    ITE_TOPOLIST_REPLY
    int callback(const int devid, const int msgid, const int code, const char * payload, const int payload_len);
    Linkkit收到查詢拓撲關系請求的應答時
    ITE_PERMIT_JOIN
    int callback(const char * product_key, const int time);
    Linkkit收到允許子設備入網的請求時
    ITE_INITIALIZE_COMPLETED
    int callback(const int devid);
    設備初始化完成時
    ITE_FOTA
    int callback(int type, const char *version);
    Linkkit收到可用固件的通知時
    ITE_COTA
    int callback(int type, const char config_id, int config_size, const char get_type, const char sign, const char sign_method, const char *url);
    Linkkit收到可用遠程配置文件的通知時
  5. 主循環處理。
    IOT_Linkkit_Yield必須周期調用,用于linkkit業務處理。代碼示例代碼如下,示例代碼用于示例上報所有的屬性、事件等,在實際產品開發時需要將其修改為設備商自己的邏輯。
    time_begin_sec = user_update_sec();
        while (1) {
            IOT_Linkkit_Yield(USER_EXAMPLE_YIELD_TIMEOUT_MS);
    
            time_now_sec = user_update_sec();
            if (time_prev_sec == time_now_sec) {
                continue;
            }
            if (max_running_seconds && (time_now_sec - time_begin_sec > max_running_seconds)) {
                EXAMPLE_TRACE("Example Run for Over %d Seconds, Break Loop!\n", max_running_seconds);
                break;
            }
    
            /* Post Property Example */
            if (time_now_sec % 11 == 0 && user_master_dev_available()) {
                user_post_property();
            }
            /* Post Event Example */
            if (time_now_sec % 17 == 0 && user_master_dev_available()) {
                user_post_event();
            }
    
            /* Device Info Update Example */
            if (time_now_sec % 23 == 0 && user_master_dev_available()) {
                user_deviceinfo_update();
            }
    
            /* Device Info Delete Example */
            if (time_now_sec % 29 == 0 && user_master_dev_available()) {
                user_deviceinfo_delete();
            }
    
            /* Post Raw Example */
            if (time_now_sec % 37 == 0 && user_master_dev_available()) {
                user_post_raw_data();
            }
    
            time_prev_sec = time_now_sec;
        }

    設備商完成自己物模型功能的代碼編寫之后,可以將固件編譯出來并根據相關模組的燒寫方法把固件燒寫到模組上進行功能驗證和調試。

Wi-Fi配網

配網支持如下所示。

  • 藍牙配網(ble-config):借助BT/BLE為設備配網

當前Inside+IoT方案配網僅支持藍牙輔助配網方案,請勿使用其他配網方案,代碼中已默認配置為藍牙輔助配網方式。通過藍牙輔助配網您可以一次配網綁定天貓精靈AI平臺設備和生活物聯網平臺設備身份,從而使設備同時具備天貓精靈語音能力和IoT設備的身份。

配網支持
static void start_netmgr(void *p) 
{

    /*
     * register event callback to detect event of AWSS
     */
    iotx_event_regist_cb(linkkit_event_monitor);
    netmgr_start(true);
    aos_task_exit(0);
}

詳細的開發過程如下步驟所示。

  1. 配網對外披露的API列表。
    #ifndef __IOT_EXPORT_AWSS_H__
    #define __IOT_EXPORT_AWSS_H__
    
    #if defined(__cplusplus)  /* If this is a C++ compiler, use C linkage */
    extern "C" {
    #endif
    
    /**
     * @brief   start Wi-Fi setup service
     *
     * @retval  -1 : Wi-Fi setup fail
     * @retval  0 : sucess
     * @note: awss_config_press must been called to enable Wi-Fi setup service
     */
    int awss_start();
    
    /**
     * @brief   stop wifi setup service
     *
     * @retval  -1 : failure
     * @retval  0 : sucess
     * @note
     *      if awss_stop is called before exit of awss_start, awss and notify will stop.
     *      it may cause failutre of awss and device bind.
     */
    int awss_stop();
    
    /**
     * @brief   make sure user touches device belong to themselves
     *
     * @retval  -1 : failure
     * @retval  0 : sucess
     * @note: AWSS dosen't parse awss packet until user touch device using this api.
     */
    int awss_config_press();
    
    /**
     * @brief   start Wi-Fi setup service with device ap
     *
     * @retval  -1 : failure
     * @retval  0 : sucess
     * @note
     *      1. if awss_stop or awss_dev_ap_stop is called before exit of awss_dev_ap_start
     *         awss with device ap and notify will stop, it may cause failutre of device ap
     *         and device bind.
     *      2. awss_dev_ap_start doesn't need to call awss_config_press to been enabled.
     */
    int awss_dev_ap_start();
    
    /**
     * @brief   stop Wi-Fi setup service with device ap
     *
     * @retval  -1 : failure
     * @retval  0 : sucess
     * @note
     *      if awss_dev_ap_stop is called before exit of awss_dev_ap_start
     *      awss with device ap and notify will stop, it may cause failutre of device ap
     */
    int awss_dev_ap_stop();
    
    /**
     * @brief   report token to cloud after Wi-Fi setup success
     *
     * @retval  -1 : failure
     * @retval  0 : sucess
     */
    int awss_report_cloud();
    
    /**
     * @brief   report reset to cloud.
     *
     * @retval  -1 : failure
     * @retval  0 : sucess
     * @note
     *      device will save reset flag if device dosen't connect cloud, device will fails to send reset to cloud.
     *      when connection between device and cloud is ready, device will retry to report reset to cloud.
     */
    int awss_report_reset();
    
    enum awss_event_t {
        AWSS_START = 0x1000,       // AWSS start without enbale, just supports device discover
        AWSS_ENABLE,               // AWSS enable
        AWSS_LOCK_CHAN,            // AWSS lock channel(Got AWSS sync packet)
        AWSS_CS_ERR,               // AWSS AWSS checksum is error
        AWSS_PASSWD_ERR,           // AWSS decrypt passwd error
        AWSS_GOT_SSID_PASSWD,      // AWSS parse ssid and passwd successfully
        AWSS_CONNECT_ADHA,         // AWSS try to connnect adha (device discover, router solution)
        AWSS_CONNECT_ADHA_FAIL,    // AWSS fails to connect adha
        AWSS_CONNECT_AHA,          // AWSS try to connect aha (AP solution)
        AWSS_CONNECT_AHA_FAIL,     // AWSS fails to connect aha
        AWSS_SETUP_NOTIFY,         // AWSS sends out device setup information (AP and router solution)
        AWSS_CONNECT_ROUTER,       // AWSS try to connect destination router
        AWSS_CONNECT_ROUTER_FAIL,  // AWSS fails to connect destination router.
        AWSS_GOT_IP,               // AWSS connects destination successfully and got ip address
        AWSS_SUC_NOTIFY,           // AWSS sends out success notify (AWSS sucess)
        AWSS_BIND_NOTIFY,          // AWSS sends out bind notify information to support bind between user and device
        AWSS_ENABLE_TIMEOUT,       // AWSS enable timeout(user needs to call awss_config_press again to enable awss)
        AWSS_RESET = 0x3000,       // Linkkit reset success (just got reset response from cloud without any other operation)
    };
    
    #if defined(__cplusplus)  /* If this is a C++ compiler, use C linkage */
    }
    #endif
    
    #endif
  2. 在應用代碼中調用配網,目前藍牙輔助配網已配置好。
  3. 使用云智能App或集成云智能AppSDK的品牌App進行設備發現配網。

云端解綁與恢復出廠默認設置通知

設備被解綁后,云端會下發一個解綁事件通知:{"identifier":"awss.BindNotify","value":{"Operation":"Unbind"}} 設備收到此消息可以做重置配網、清空本地數據等處理。

如果通過App將設備恢復出廠默認設置,云端會下發一個Reset事件通知:{"identifier":"awss.BindNotify","value":{"Operation":"Reset"}} 設備收到此消息可以做重置配網、清空本地數據等處理。設備開發者可以結合具體產品類型,決定收到解綁和恢復出廠默認設置通知后做哪些清空操作。

可以參考示例代碼example/smart_outlet/smart_outlet_main.cnotify_msg_handle函數,做如下改動。

static int notify_msg_handle(const char *request, const int request_len)
{
    ....

    if (!strcmp(item->valuestring, "awss.BindNotify")) {
        cJSON *value = cJSON_GetObjectItem(request_root, "value");
        if (item == NULL || !cJSON_IsObject(value)) {
            cJSON_Delete(request_root);
            return -1;
        }
        cJSON *op = cJSON_GetObjectItem(value, "Operation");
        if (op != NULL && cJSON_IsString(op)) {
            if (!strcmp(op->valuestring, "Bind")) {
                EXAMPLE_TRACE("Device Bind");
                vendor_device_bind();
            }
            if (!strcmp(op->valuestring, "Unbind")) {
                EXAMPLE_TRACE("Device unBind");
                vendor_device_unbind();
            }
            if (!strcmp(op->valuestring, "Reset")) {
                EXAMPLE_TRACE("Device Reset");
                vendor_device_reset();
            }
        }
    }

    ....
}

設備重置

建議產品設計一個reset按鍵用于清除設備上的配置,將設備恢復到出廠狀態。應用示例代碼中也有reset CLI命令用于進行恢復出廠設置重新進入配網模式,可參考do_awss_cmd_reset()相關實現。

在復位時需要同時重置天貓精靈AI平臺設備和生活物聯網平臺的身份,在linkkit_reset() 函數中包含了兩部分的解綁和復位代碼。

開發OTA

若使能了OTA功能,請參考文檔OTA開發教程進行開發。