ESP8266學(xué)習(xí)筆記(14)——接入樂鑫云Iot·Espressif

一屿储、創(chuàng)建樂鑫云設(shè)備

1.1 注冊樂鑫云賬號

打開鏈接并按提示進(jìn)行注冊
https://iot.espressif.cn/#/

1.2 創(chuàng)建產(chǎn)品

點擊 Device ,選擇 Create


選擇 Create New Product 輸入設(shè)備名惋耙,產(chǎn)品名澄峰,產(chǎn)品類型

1.3 創(chuàng)建數(shù)據(jù)流

點擊 Product盲泛,點擊藍(lán)色名字進(jìn)入產(chǎn)品



創(chuàng)建一個開關(guān)狀態(tài)的數(shù)據(jù)流 plug-status

1.4 創(chuàng)建設(shè)備

點擊 Device ,選擇 Create


選擇剛剛創(chuàng)建的產(chǎn)品進(jìn)行設(shè)備創(chuàng)建
下載 Master Device Key 用于等等燒錄使用考廉。

二捅位、移植文件

https://pan.baidu.com/s/1Ed1QW462zDjV0uX2_N-8OA[dldk]

2.1 ESP平臺初始化

在user_main.c中

void ICACHE_FLASH_ATTR
user_init(void)
{
    LoadAllParamFromFlash();                                            // 從Flash中加載所有參數(shù)
    EspPlatformInit();                                                  // ESP平臺初始化
}

2.2 檢查是否被分配IP

在user_esp_platform.c中

/**
 @brief ESP平臺TCP客戶端初始化
 @param 無
 @return 無
*/
void ICACHE_FLASH_ATTR
EspPlatformInit(void)
{
    printIotVersionInfo();                                                                  // 打印版本信息
    printResetInfo();                                                                       // 打印重啟信息

    uint8 activeStatus = s_flahSavedParam.activeStatus;
    if(activeStatus != 1)
    {
        if(wifi_get_opmode() == STATION_MODE)
        {
            wifi_set_opmode(STATIONAP_MODE);                                                // WIFI模式重置為STA+AP
        }                                                               
    }

    if(wifi_get_opmode() != SOFTAP_MODE)
    {
        startEspPlatformCheckIpTimer();
    }
}

startEspPlatformCheckIpTimer() 開啟定時器怒见,周期檢查是否被分配IP

/**
 @brief ESP平臺檢查IP定時器的回調(diào)函數(shù)
 @param resetFlag -[in] 重啟標(biāo)志
 @return 無
*/
static void ICACHE_FLASH_ATTR
espPlatformCheckIpTimerCallback(uint8 resetFlag)
{
    stopEspPlatformCheckTimer();

    struct ip_info ipInfo;
    wifi_get_ip_info(STATION_IF, &ipInfo);
    uint8 wifiStationConnectStatus = wifi_station_get_connect_status();

    if(wifiStationConnectStatus == STATION_GOT_IP && ipInfo.ip.addr != 0)
    {
        s_deviceStatus = DEVICE_CONNECTING;

        if(resetFlag)                                                                   // 重啟過
        {
            s_reconnectCount = 0;
        }

        tcpClientInit();                                                                // TCP客戶端初始化
    }
    else
    {
        if((wifiStationConnectStatus == STATION_WRONG_PASSWORD ||
            wifiStationConnectStatus == STATION_NO_AP_FOUND ||
            wifiStationConnectStatus == STATION_CONNECT_FAIL))
        {
            wifi_station_disconnect();                                                  // 斷開連接路由
            if(wifi_get_opmode() == STATION_MODE)
            {
                wifi_set_opmode(STATIONAP_MODE);                                        // WIFI模式重置為STA+AP
            }                                                           
        }
        else
        {
            startEspPlatformCheckIpTimer();
        }
    }
}

2.3 TCP客戶端初始化

wifiStationConnectStatus == STATION_GOT_IP 檢查到獲取IP后

/**
 @brief TCP客戶端初始化
 @param 無
 @return 無
*/
static void ICACHE_FLASH_ATTR
tcpClientInit(void)
{
    s_espPlatformTcpEspconn.type = ESPCONN_TCP;
    s_espPlatformTcpEspconn.state = ESPCONN_NONE;
    s_espPlatformTcpEspconn.proto.tcp = (esp_tcp *) os_zalloc(sizeof(esp_tcp));

    s_pingStatus = 1;

    char ip[16] = "115.29.202.58";                                                      // 默認(rèn)服務(wù)器IP
    g_tcpCloudServerUrl.ip.addr = ipaddr_addr(ip);
    g_tcpCloudServerUrl.port = 8000;                                                    // 默認(rèn)服務(wù)器端口
    connectEspPlatformByIp();
}

可選擇通過IP和端口進(jìn)行連接 connectEspPlatformByIp()
或選擇通過DNS域名解析連接 onnectEspPlatformByDns()

2.4 注冊連接/重連/斷連函數(shù)

/**
 @brief 通過IP連接ESP平臺
 @param 無
 @return 無
*/
static void ICACHE_FLASH_ATTR
connectEspPlatformByIp(void)
{
    os_memcpy(s_espPlatformTcpEspconn.proto.tcp->remote_ip, (uint8 *)(&g_tcpCloudServerUrl.ip.addr), 4);
    s_espPlatformTcpEspconn.proto.tcp->remote_port = g_tcpCloudServerUrl.port;
    s_espPlatformTcpEspconn.proto.tcp->local_port = espconn_port();

    os_printf("espPlatform:ip %d.%d.%d.%d\n",
                s_espPlatformTcpEspconn.proto.tcp->remote_ip[0], s_espPlatformTcpEspconn.proto.tcp->remote_ip[1],
                s_espPlatformTcpEspconn.proto.tcp->remote_ip[2], s_espPlatformTcpEspconn.proto.tcp->remote_ip[3]);
    os_printf("espPlatform:port %d\n", s_espPlatformTcpEspconn.proto.tcp->remote_port);

    espconn_regist_connectcb(&s_espPlatformTcpEspconn, connectCallback);
    espconn_regist_disconcb(&s_espPlatformTcpEspconn, disconnectCallback);
    espconn_regist_reconcb(&s_espPlatformTcpEspconn, reconnectCallback);
    espconn_connect(&s_espPlatformTcpEspconn);
}

/**
 @brief 連接成功的回調(diào)函數(shù)
 @param arg -[in] 指向傳遞給這個回調(diào)函數(shù)來使用的參數(shù)
 @return 無
*/
static void ICACHE_FLASH_ATTR
connectCallback(void *arg)
{
    struct espconn *pEspconn = arg;
    s_reconnectCount = 0;
    espconn_regist_recvcb(pEspconn, receiveDataCallback);
    sendActiveRequest();
}

/**
 @brief 斷連的回調(diào)函數(shù)
 @param arg -[in] 指向傳遞給這個回調(diào)函數(shù)來使用的參數(shù)
 @return 無
*/
static void ICACHE_FLASH_ATTR
disconnectCallback(void *arg)
{
    struct espconn *pEspconn = arg;

    stopSendPingTimer();

    if(pEspconn == NULL)
    {
        return ;
    }

    pEspconn->proto.tcp->local_port = espconn_port();

    espPlatformCheckReconnectTimerCallback();
}

/**
 @brief 重連的回調(diào)函數(shù)
 @param arg -[in] 指向傳遞給這個回調(diào)函數(shù)來使用的參數(shù)
 @param error -[in] 錯誤碼
 @return 無
*/
static void ICACHE_FLASH_ATTR
reconnectCallback(void *arg, sint8 error)
{
    stopSendPingTimer();

    if(++s_reconnectCount == 5)
    {
        s_deviceStatus = DEVICE_CONNECT_SERVER_FAIL;
        if(wifi_get_opmode() == STATION_MODE)
        {
            wifi_set_opmode(STATIONAP_MODE);
        }

        if(s_firstConnectFlag == true)
        {
            return ;
        }
    }

    startEspPlatformCheckReconnectTimer();
}

2.5 連接成功后發(fā)送設(shè)備激活請求

connectCallback() 中調(diào)用 sendActiveRequest()

/**
 @brief 發(fā)送激活請求
 @param 無
 @return 無
*/
static void ICACHE_FLASH_ATTR
sendActiveRequest(void)
{
    uint8 deviceKey[TOKEN_SIZE] = {0};
    uint32 nonce;
    char *pSendData = (char *) os_zalloc(SEND_DATA_SIZE);

    os_memcpy(deviceKey, s_flahSavedParam.devkey, sizeof(s_flahSavedParam.devkey));
    uint8 activeStatus = s_flahSavedParam.activeStatus;

    if(activeStatus == 0xFF)
    {
        activeStatus = 0;
    }

    if(pSendData != NULL)
    {
        if(activeStatus == 0)                                                           // 未激活
        {
            uint8 token[TOKEN_SIZE] = {0};
            uint8 wifiMac[23] = {0};

            os_memcpy(token, s_flahSavedParam.token, sizeof(s_flahSavedParam.token));

            uint8 macAddr[23] = {0};
            wifi_get_macaddr(STATION_IF, macAddr);                                      // 獲取STA模式的MAC地址
            os_sprintf(wifiMac, MACSTR, MAC2STR(macAddr));                              // MAC地址
            
            s_activeNonce = os_random() & 0x7FFFFFFF;

            os_sprintf(pSendData, ACTIVE_FRAME, s_activeNonce, token, wifiMac, s_iotVersion, deviceKey);
        }
        else                                                                            // 已激活
        {
            nonce = os_random() & 0x7FFFFFFF;
            os_sprintf(pSendData, FIRST_FRAME, nonce , deviceKey);
        }

        os_printf("%s\n", pSendData);

        espconn_sent(&s_espPlatformTcpEspconn, pSendData, os_strlen(pSendData));

        os_free(pSendData);
        pSendData = NULL;
    }
}

2.6 注冊接收回調(diào)函數(shù)

/**
 @brief 接收數(shù)據(jù)的回調(diào)函數(shù)
 @param arg -[in] 指向傳遞給這個回調(diào)函數(shù)來使用的參數(shù)
 @param pData -[in] 接收的數(shù)據(jù)
 @param len -[in] 接收的數(shù)據(jù)長度
 @return 無
*/
static void ICACHE_FLASH_ATTR
receiveDataCallback(void *arg, char *pData, unsigned short len)
{
    os_printf("espPlatform recvData: %s\n", pData);

    if(len == 1460)
    {
        os_memcpy(s_receiveData, pData, len);
    }
    else
    {
        os_memcpy(s_receiveData + os_strlen(s_receiveData), pData, len);
        parseUrl(pData);
        os_memset(s_receiveData, 0, sizeof(s_receiveData));
    }

    startSendPingTimer();
}

2.7 接收ESP平臺激活響應(yīng)后開啟周期Ping

receiveDataCallback() 中調(diào)用 startSendPingTimer()

/**
 @brief 開始發(fā)送PING的定時器
 @param 無
 @return 無
*/
static void ICACHE_FLASH_ATTR
startSendPingTimer(void)
{
    os_timer_disarm(&s_pingTimer);
    os_timer_setfn(&s_pingTimer, (os_timer_func_t *) sendPingTimerCallback, NULL);
    os_timer_arm(&s_pingTimer, ESP_PLATFORM_PING_PERIOD, false);
}

/**
 @brief 發(fā)送PING定時器的回調(diào)函數(shù)
 @param 無
 @return 無
*/
static void ICACHE_FLASH_ATTR
sendPingTimerCallback(void)
{
    if(s_espPlatformTcpEspconn.state == ESPCONN_CONNECT)
    {
        uint8 activeStatus = s_flahSavedParam.activeStatus;
        if(activeStatus == 0)
        {
            os_printf("Err:please check device is activated.\n");
            sendActiveRequest();
        }
        else
        {
            uint8 devicekey[TOKEN_SIZE] = {0};
            os_memcpy(devicekey, s_flahSavedParam.devkey, sizeof(s_flahSavedParam.devkey));

            os_printf("sendPingTimerCallback %u\n", system_get_time());

            if(s_pingStatus == 0)
            {
                os_printf("Err:sendPingTimerCallback sent fail!\n");
                os_printf("espPlatform disconnect\n");
                espconn_disconnect(&s_espPlatformTcpEspconn);
            }
            else
            {
                char *pSendData = (char *) os_zalloc(SEND_DATA_SIZE);

                if(pSendData != NULL)
                {
                    os_sprintf(pSendData, PING_FRAME, devicekey);

                    espconn_sent(&s_espPlatformTcpEspconn, pSendData, os_strlen(pSendData));

                    s_pingStatus = 0;
                    startSendPingTimer();

                    os_free(pSendData);
                    pSendData = NULL;
                }
            }
        }
    }
    else
    {
        os_printf("Err:sendPingTimerCallback sent fail!\n");
        os_printf("espPlatform disconnect\n");
        espconn_disconnect(&s_espPlatformTcpEspconn);
    }
}

2.8 解析URL

/**
 @brief 解析URL
 @param pRecvData -[in] 接收的數(shù)據(jù)
 @return 無
*/
static void ICACHE_FLASH_ATTR
parseUrl(char *pRecvData)
{
    char *pStr = NULL;

    if((pStr = (char *) os_strstr(s_receiveData, "\"activate_status\": ")) != NULL &&
        parseNonceFromReceiveData(s_receiveData) == s_activeNonce)
    {
        configDeviceActive(pStr);                                                       // 配置設(shè)備激活
    }
    else if((pStr = (char *) os_strstr(s_receiveData, "/v1/device/timers/")) != NULL)
    {
        configDeviceTimer();                                                            // 配置設(shè)備時鐘
    }
    else if((pStr = (char *) os_strstr(s_receiveData, "\"method\": ")) != NULL)
    {
        if(os_strncmp(pStr + 11, "GET", 3) == 0)                                        // 處理GET請求
        {
            handleGetUrlPath(s_receiveData);
        }
        else if(os_strncmp(pStr + 11, "POST", 4) == 0)
        {
            handlePostUrlPath(s_receiveData);                                           // 處理POST請求
        }
    }
    else if((pStr = (char *) os_strstr(s_receiveData, "ping success")) != NULL)
    {
        os_printf("ping success\n");
        s_pingStatus = 1;
    }
    else if((pStr = (char *) os_strstr(s_receiveData, "send message success")) != NULL)
    {
    }
    else if((pStr = (char *) os_strstr(s_receiveData, "timers")) != NULL)
    {
        user_platform_timer_start(s_receiveData , &s_espPlatformTcpEspconn);
    }
    else if((pStr = (char *) os_strstr(s_receiveData, "device")) != NULL)
    {
        handleDeviceKeyRequest();                                                       // 處理設(shè)備密鑰請求

        if(wifi_get_opmode() == STATIONAP_MODE)
        {
            wifi_set_opmode(STATION_MODE);                                              // WIFI模式重置為STA
        }

        SetFirstConnectEspPlatformFlag(false);                                          // 清除首次連接標(biāo)志
    }
}

2.8.1 處理GET請求URL

/**
 @brief 處理GET請求URL路徑
 @param pRecvData -[in] 接收的數(shù)據(jù)
 @return 無
*/
static void ICACHE_FLASH_ATTR
handleGetUrlPath(uint8 *pRecvData)
{
    char *pStr = NULL;
    if((pStr = (char *) os_strstr(pRecvData, "\"action\": \"sys_upgrade\"")) != NULL)
    {
        if((pStr = (char *) os_strstr(pRecvData, "\"version\":")) != NULL)
        {
            configSystemUpgrade(pStr);                                                  // 配置系統(tǒng)升級
        }
    }
    else if((pStr = (char *) os_strstr(pRecvData, "\"action\": \"sys_reboot\"")) != NULL)
    {
        configSystemReboot();                                                           // 配置系統(tǒng)重啟
    }
    else if((pStr = (char *) os_strstr(pRecvData, "\"action\": \"switch\"")) != NULL)
    {
        sendRelayStatusResponse(pRecvData);
    }
}

2.8.2 處理POST請求URL

/**
 @brief 處理POST請求URL路徑
 @param pRecvData -[in] 接收的數(shù)據(jù)
 @return 無
*/
static void ICACHE_FLASH_ATTR
handlePostUrlPath(uint8 *pRecvData)
{
    char *pStr = NULL;
    if((pStr = (char *) os_strstr(pRecvData, "plug-status")) != NULL)
    {
        handleRelayStatusRequest(pRecvData);
    }
}

2.9 處理請求和響應(yīng)


/**
 @brief 發(fā)送繼電器狀態(tài)響應(yīng)
 @param pRecvData -[in] 接收的數(shù)據(jù)
 @return 無
*/
static void ICACHE_FLASH_ATTR
sendRelayStatusResponse(uint8 *pRecvData)
{
    int nonce = 0;
    char *pSendData = (char *) os_zalloc(SEND_DATA_SIZE);

    nonce = parseNonceFromReceiveData(pRecvData);

    if(pSendData != NULL)
    {
        os_sprintf(pSendData, TCP_SERVER_SWITCH_RESPONSE_FRAME, GetRelayStatus(), nonce); // 修改為自己獲取繼電器狀態(tài)函數(shù)

        os_printf("%s\n", pSendData);

        espconn_sent(&s_espPlatformTcpEspconn, pSendData, os_strlen(pSendData));

        os_free(pSendData);
        pSendData = NULL;
    }
}

/**
 @brief 處理繼電器狀態(tài)請求
 @param pRecvData -[in] 接收的數(shù)據(jù)
 @return 無
*/
static void ICACHE_FLASH_ATTR
handleRelayStatusRequest(uint8 *pRecvData)
{
    char *pStr = NULL;
    pStr = (char *) os_strstr(pRecvData, "body");

    if(pStr != NULL)
    {
        if(os_strncmp(pStr + 27, "1", 1) == 0)
        {
            SetRelayStatus(SWITCH_ON);      // 修改為自己設(shè)置繼電器狀態(tài)函數(shù)
        }
        else if (os_strncmp(pStr + 27, "0", 1) == 0)
        {
            SetRelayStatus(SWITCH_OFF);     // 修改為自己設(shè)置繼電器狀態(tài)函數(shù)
        }
    }

    sendRelayStatusResponse(pRecvData);
}

三挨决、燒錄




例如4M的Flash



? 由 Leung 寫于 2019 年 8 月 16 日

? 參考:ESP8266 Non-OS SDK API參考[7qq6]
    ESP8266 Non-OS SDK IoT Demo指南[kvle]

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末也殖,一起剝皮案震驚了整個濱河市臀蛛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌殉摔,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件记焊,死亡現(xiàn)場離奇詭異逸月,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)遍膜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進(jìn)店門碗硬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人瓢颅,你說我怎么就攤上這事恩尾。” “怎么了惜索?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵特笋,是天一觀的道長。 經(jīng)常有香客問我巾兆,道長猎物,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任角塑,我火速辦了婚禮蔫磨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘圃伶。我一直安慰自己堤如,他們只是感情好蒲列,可當(dāng)我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著搀罢,像睡著了一般蝗岖。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上榔至,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天抵赢,我揣著相機(jī)與錄音,去河邊找鬼唧取。 笑死铅鲤,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的枫弟。 我是一名探鬼主播邢享,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼淡诗!你這毒婦竟也來了骇塘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤袜漩,失蹤者是張志新(化名)和其女友劉穎绪爸,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宙攻,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡奠货,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了座掘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片递惋。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖溢陪,靈堂內(nèi)的尸體忽然破棺而出萍虽,到底是詐尸還是另有隱情,我是刑警寧澤形真,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布杉编,位于F島的核電站,受9級特大地震影響咆霜,放射性物質(zhì)發(fā)生泄漏邓馒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一蛾坯、第九天 我趴在偏房一處隱蔽的房頂上張望光酣。 院中可真熱鬧,春花似錦脉课、人聲如沸救军。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽唱遭。三九已至戳寸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間胆萧,已是汗流浹背庆揩。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工俐东, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留跌穗,地道東北人。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓虏辫,卻偏偏與公主長得像蚌吸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子砌庄,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容