目錄:老小皆宜、超長乾貨文警告html
字數: 59710個
系統: linux、esp32
聲明: 非軟文linux
連接: https://iot.console.aliyun.com/quick_startgit
直接看下面的視頻:(注意瀏覽器使能下unsafe load,由於個人視頻服務器是本身搭的)github
這裏建立了一個名字爲aliyun_test
的產品,在該產品下建立一個名爲linux_aliyun_teset
的設備,並生成了一個基於linux平臺的嵌入式C開發工具包aliyun_iot_device_quickstart.zip
。咱們按照指引將工具包解壓、編譯、運行可看到經過MQTT雲端和本地進行通訊的效果:json
unzip aliyun_iot_device_quickstart.zip cd aliyun_iot_device_quickstart sh ./start.sh
運行啓動腳本後,能夠在雲端的設備日誌和本地termial中發現設備通訊的LOG:api
若是本文僅僅講體驗一下就太沒勁了!說不定博客園小編還會把個人文章從主頁上「拉下馬」。瀏覽器
下面是沒有執行腳本以前的壓縮包內容:安全
➜ Downloads mv aliyun_iot_device_quickstart aliyun_iot_device_quickstart2 ➜ Downloads unzip aliyun_iot_device_quickstart.zip ➜ Downloads cd aliyun_iot_device_quickstart ➜ aliyun_iot_device_quickstart tree . ├── device_id_password.json ├── makefile ├── sample.c └── start.sh 0 directories, 4 files
該壓縮包內包含:開始腳本start.sh,makefile,應用層代碼sample.c,設備訪問Aliyun的核心信息*.json。bash
1)其中start.sh前50行都在檢測你的環境是否安裝必要工具,例如gcc、tar、cmake...;而後讀取json
文件,抽出其中的pk\dn\ds
,分別是productKey\deviceName\deviceSecret;接下來是構建開發環境,主要是從雲端下載一個sdk:linkkit2.2.1.tar.gz
;接下來將託來的SDK調用make
進行編譯,生成aliyun-iot-c-sdk
的lib
庫文件,而後分別把對應的lib
和include
分別複製到根目錄下的lib
和include
中;最後再次使用make進行clean\all,而後啓動。(下面抽幾個核心代碼貼下)服務器
從json
讀取pk\dn\ds
:(我會用jq來處理)
pk=`grep -Po '(?<=productKey": ")[0-9a-zA-Z]*' ${json}` dn=`grep -Po '(?<=deviceName": ")[\-_@\.:0-9a-zA-Z]*' ${json}` ds=`grep -Po '(?<=deviceSecret": ")[0-9a-zA-Z]*' ${json}`
下載sdk並解壓:
echo "download sdk tar" wget ${url} tar -zxf ${sdktar} ${sdkdir}/ rm -f ${sdktar}
編譯成庫:
cd ./iotx-sdk-c make distclean make cd .. cp -r ./iotx-sdk-c/output/release/lib ./lib cp -r ./iotx-sdk-c/output/release/include ./include
編譯並運行:
make clean -s make all PK=${pk} DN=${dn} DS=${ds} ./quickstart
2)其中makefile過於簡單,主要是用SDK生成的lib
來編譯應用層代碼sample.c
,核心代碼以下:
sample.o:sample.c $(CC) $(CFLAGS) $(INCLUDE) ${DID} -c $^ OBJS= sample.o .PHONY:all all:$(OBJS) $(LIB) $(CC) $(CFLAGS) $(INCLUDE) -o $(TARGET) $(OBJS) $(LIBVAR) $(LIBPATH) .PHONY:clean clean: rm -f *.o rm -f $(TARGET)
應用層代碼總共約400行,下面是main函數:
int main(int argc, char **argv) { app_print_banner(); IOT_OpenLog("sample"); APP_TRACE("sample start!\n"); /* * C-SDK quick start sample * please check document: https://help.aliyun.com/document_detail/73708.html?spm=a2c4g.11174283.6.560.zfcQ3y * API introduce: https://help.aliyun.com/document_detail/68687.html?spm=a2c4g.11186623.6.627.RJcT3F */ app_setup_info(); app_linkkit_sample(); IOT_CloseLog(); APP_TRACE("sample end!\n"); return 0; }
其中最重要的就是app_linkkit_sampl(void)
, 該函數的前30行主要負責初始化linkkit結構體並啓動linkkit:
下圖很是詳細的展現了應用層上述函數指針的實現,以及程序運行起來後每部分的做用(建議單獨tab打開圖片):
爲了方便看,我把其縱向切割成3份:
linkkit_ops_t結構體初始化:
各類函數指針給linkkit_ops_t賦值:
LOG:
咱們建立的aliyun_test只有兩個自定義功能:
每次雲端有PROPERTY數據變化會出發下面的回調函數,在該函數中咱們經過判斷PROPERTY_ID,來區分不一樣功能點:
static int thing_prop_changed(const void *thing_id, const char *property, void *ctx) { int status[1]; char *data; if (memcmp(property, PROPERTY_ID_STATUS, strlen(PROPERTY_ID_STATUS)) == 0) { linkkit_get_value(linkkit_method_get_property_value, thing_id, property, status, NULL); APP_TRACE("Received a message: {\"%s\":%d}\n", property, status[0]); /* do user's data arrived process logical here. */ } else if (memcmp(property, PROPERTY_ID_DATA, strlen(PROPERTY_ID_DATA)) == 0) { linkkit_get_value(linkkit_method_get_property_value, thing_id, property, NULL, &data); APP_TRACE("Received a message: {\"%s\":\"%s\"}\n", property, data); HAL_Free(data); /* free memery as it was malloc by linkkit api linkkit_get_value() */ } return 0; }
下面是雲端主動推送信息下來後本地打印的LOG:
本DEMO啓動以後會每隔5S將上報全部(2個)property,具體邏輯是:先讀取STATUS和DATA,若是DATA沒有數據,則發送hello world:
static int app_post_all_property(void) { int res; int status[1] = {0}; char *data = NULL; linkkit_get_value(linkkit_method_get_property_value, app_context.thing, PROPERTY_ID_STATUS, status, NULL); linkkit_get_value(linkkit_method_get_property_value, app_context.thing, PROPERTY_ID_DATA, NULL, &data); /* init data property to "Hello world" if it is value is NULL */ if (data == NULL) { linkkit_set_value(linkkit_method_set_property_value, app_context.thing, PROPERTY_ID_DATA, NULL, PROPERTY_ID_DATA_VALUE); linkkit_get_value(linkkit_method_get_property_value, app_context.thing, PROPERTY_ID_DATA, NULL, &data); } APP_TRACE("{\"%s\":%d, \"%s\":\"%s\"}", PROPERTY_ID_STATUS, status[0], PROPERTY_ID_DATA, data); HAL_Free(data); /* free memery as it was malloc by linkkit api linkkit_get_value() */ /* demo for post all property */ res = linkkit_post_property(app_context.thing, NULL, post_property_cb); if (res == SUCCESS_RETURN) { APP_TRACE("app post all properties every 5 seconds successfully"); } else { APP_TRACE("app post all properties every 5 seconds fail"); } return res; }
下面是本地主動週期性上報的LOG:
若是本文到此爲止,老炮們確定會吐槽這是個騙流量的文章!老炮心裏OS中:阿里的linux上的調試工具挺方便的,若是上面不寫代碼分析,貼這麼多圖、變着花樣的貼圖,並且本身服務器上搭的圖牀帶寬還辣麼窄,看你寫啥(捂臉笑)。
經過下面兩個資料,你們能夠自行搭建環境:
SDK介紹:對於ESP32樂鑫官方提供了一個IDF :
環境搭建:若是你想本身搭建開發環境,參見樂鑫官方資料:
不過!做爲系統潔癖和拒絕重複造輪子的博主,已經寫了一個全自動構建環境的腳本、並把該工具在github上開源了:esp32_linux_tool [5]
注:nbtool是博主專門放本身造的或收集到的牛逼輪子的github組
博主造的這個輪子比較好用,基於all-in-one思想(全部相關文件在一個文件夾下;全部相關環境變量不須要額外配置):
用的時候須要git clone到本地,進入tool文件夾,運行bash run.sh tool會自動構建ESP-IDF開發環境:
git clone git@github.com:nbtool/esp32_linux_tool.git cd esp32_linux_tool cd tool bash run.sh help bash run.sh tool
當須要建立hello world時,只須要調用下面命令,便可從SDK中的DEMO複製到app文件夾下,並自動在app/hello_world下建立run.sh腳本:
bash run.sh create ../sdk/esp-idf/examples/get-started/hello_world hello_world cd ../app/hello_world ./run.sh help
當須要編譯並燒寫固件到ESP32中的時,只須要調用./run.sh flash便可:
./run.sh flash
當須要觀察LOG的時候,只須要:
./run.sh monitor
是否是很好用?(哈哈),想要了解其機制,只須要參考下tool下的run.sh便可~
設備廠商在設備上集成 Link Kit C-SDK 後, 能夠將設備安全的接入到阿里雲IoT物聯網平臺, 從而讓設備能夠被阿里雲IoT物聯網平臺進行管理。
設備須要支持TCP/IP協議棧才能集成SDK, zigbee/433/KNX這樣的非IP設備須要經過網關設備接入到阿里雲IoT物聯網平臺, 網關設備須要集成Link Kit SDK [6]。
基於咱們的esp_32_linux_tool環境來編譯iotkit-embedded:
cd esp32_linux_tool cd app git clone https://github.com/aliyun/iotkit-embedded.git cd iotkit-embedded
在iot-embedded文件夾下建立一個run.sh文件:
➜ iotkit-embedded git:(master) ✗ cat run.sh #!/bin/bash #I don't like to set environment variables in the system, #so I put the environment variables in run.sh. #Every time I use run.sh, the enviroment variables will be set, after use that will be unsetted. PROJECT_ROOT=../.. TOOLS_PATH=$PROJECT_ROOT/tool SDK_PATH=$PROJECT_ROOT/sdk APP_PATH=$PROJECT_ROOT/app XTENSA_ESP32_ELF_PATH=$TOOLS_PATH/xtensa-esp32-elf ESP_IDF_PATH=$SDK_PATH/esp-idf the_sdk_path=`cd $ESP_IDF_PATH; pwd` the_tool_chain_path=`cd $XTENSA_ESP32_ELF_PATH/bin; pwd` export PATH="$PATH:$the_tool_chain_path" export IDF_PATH="$the_sdk_path" if [ "$1" == "reconfig" ]; then make reconfig elif [ "$1" == "make" ]; then make elif [ "$1" == "clean" ]; then make clean else echo "error, try bash run.sh help" fi
將config.esp8266.aos
, 複製一份保存爲config.esp32.aos
,作一些細微調整,最終以下:
➜ iotkit-embedded git:(master) ✗ cat src/board/config.esp32.aos CONFIG_ENV_CFLAGS += \ -DBOARD_ESP32 -u call_user_start \ -fno-inline-functions \ -ffunction-sections \ -fdata-sections \ -mlongcalls \ -DESPOS_FOR_ESP32 -Wl,-static \ -DXT_USE_THREAD_SAFE_CLIB=0 \ CONFIG_ENV_CFLAGS += \ -Os \ -DCONFIG_HTTP_AUTH_TIMEOUT=500 \ -DCONFIG_MID_HTTP_TIMEOUT=500 \ -DCONFIG_GUIDER_AUTH_TIMEOUT=500 \ -DCONFIG_MQTT_TX_MAXLEN=640 \ -DCONFIG_MQTT_RX_MAXLEN=1200 \ CONFIG_src/ref-impl/tls := CONFIG_src/ref-impl/hal := CONFIG_examples := CONFIG_tests := CONFIG_src/tools/linkkit_tsl_convert := CROSS_PREFIX := xtensa-esp32-elf-
最後,運行下面語句進行選擇平臺並編譯生成lib庫:
./run.sh reconfig ./run.sh make
最終生成libiot_sdk.a以下:
esp-aliyun [7] 是樂鑫官網提供的一個經過MQTT訪問aliyun iot服務器的開源項目。該項目不只依賴於3.2節介紹的iotkit-embedded [6] 生成的lib,並且尷尬的是辛辛苦苦編譯成功後,還不能和咱們第一章建立的產品通訊(成功操做會鏈接到雲端保持online,可是update\get數據都有誤)。
樓主依次作了以下操做,均失敗(阿里雲IOT更新太快(資料不全)呀!):
可是樓主在前面已經立下flag,要基於我作的esp32_linux_tool實現一個可以與第一章建立的aliyun_test交互的DEMO,那是絕對不能拿AliOS Thing來糊弄你們的(AliOS Thing以後講,哈哈)!
利用下班的一點點時間,將3.3的問題趟了兩天、阿里資料看了多遍,最終又找到了一個奇巧淫技!我將linux版的DEMO開一段時間,在aliyun後臺看全部交互的log的數據包,而後我參考這個數據包用mqtt_example.c裏的原始MQTT函數進行合成高級命令,而後實現和阿里雲通訊。
採用上述方法,我發現原來mqtt_example.c中TOPIC和上報json數據格式是有問題的:
其中TOPIC要按照建立產品的topic列表中來(其中發佈用來上報數據、訂閱用來收取數據):
/* These are pre-defined topics */ #define TOPIC_UPDATE "/"PRODUCT_KEY"/"DEVICE_NAME"/user/update" #define TOPIC_ERROR "/"PRODUCT_KEY"/"DEVICE_NAME"/user/update/error" #define TOPIC_GET "/"PRODUCT_KEY"/"DEVICE_NAME"/user/get" #define DEVICE_PROPERTY_POST "/sys/"PRODUCT_KEY"/"DEVICE_NAME"/thing/event/property/post"//設備屬性上報 #define DEVICE_PROPERTY_POST_REPLY "/sys/"PRODUCT_KEY"/"DEVICE_NAME"/thing/event/property/post_reply"//設備屬性上報變化訂閱(這個topic列表中沒有,我本身抓出來的) #define DEVICE_PROPERTY_SET "/sys/"PRODUCT_KEY"/"DEVICE_NAME"/thing/service/property/set"//設備屬性設置訂閱 #define DEVICE_INFO_UPDATE "/sys/"PRODUCT_KEY"/"DEVICE_NAME"/thing/deviceinfo/update"//設備標籤上報
其中json數據格式有必定的規範,不能直接組一個{"Status":1}就上報,要帶一部分參數:
{ "method":"thing.event.property.post", "id":"7", "version":"1.0", "params":{ "Status":1, "Data":"Hello, World!" } }
注: 其實最後經過仔細閱讀Link Kit SDK用戶手冊 [8] ,也印證了我上面的嘗試~
採用上述json格式,成功將數據上報到DEVICE_PROPERTY_POST的TOPIC下,經過進一步查後臺LOG發現一個隱藏的TOPIC:DEVICE_PROPERTY_POST_REPLY,經過訂閱該TOPIC每次上報致使數據變化就能被監聽到了!(和linux SDK版本同樣了,舒服)
一不作二不休,直接實現全部訂閱:
/* Subscribe the specific topic */ rc = IOT_MQTT_Subscribe(pclient, DEVICE_PROPERTY_SET, IOTX_MQTT_QOS1, _demo_message_arrive, NULL); if (rc < 0) { IOT_MQTT_Destroy(&pclient); EXAMPLE_TRACE("IOT_MQTT_Subscribe() failed, rc = %d", rc); return -1; } rc = IOT_MQTT_Subscribe(pclient, DEVICE_INFO_UPDATE, IOTX_MQTT_QOS1, _demo_message_arrive, NULL); if (rc < 0) { IOT_MQTT_Destroy(&pclient); EXAMPLE_TRACE("IOT_MQTT_Subscribe() failed, rc = %d", rc); return -1; } rc = IOT_MQTT_Subscribe(pclient, TOPIC_GET, IOTX_MQTT_QOS1, _demo_message_arrive, NULL); if (rc < 0) { IOT_MQTT_Destroy(&pclient); EXAMPLE_TRACE("IOT_MQTT_Subscribe() failed, rc = %d", rc); return -1; } rc = IOT_MQTT_Subscribe(pclient, DEVICE_PROPERTY_POST_REPLY, IOTX_MQTT_QOS1, _demo_message_arrive, NULL); if (rc < 0) { IOT_MQTT_Destroy(&pclient); EXAMPLE_TRACE("IOT_MQTT_Subscribe() failed, rc = %d", rc); return -1; }
實現數據週期性上報:
do { /* Generate topic message */ cnt++; msg_len = snprintf(msg_pub, sizeof(msg_pub), "{\"method\":\"thing.event.property.post\",\"id\":\"7\",\"version\":\"1.0\",\"params\":{\"Status\":%d,\"Data\":\"Hello, World!-%d\"}}",cnt%2 == 0,cnt); if (msg_len < 0) { EXAMPLE_TRACE("Error occur! Exit program"); return -1; } topic_msg.payload = (void *)msg_pub; topic_msg.payload_len = msg_len; rc = IOT_MQTT_Publish(pclient, DEVICE_PROPERTY_POST, &topic_msg); ... }
最終週期性上報數據並收到訂閱的回調LOG截圖以下:
最後,爲了感謝2018年來新老訪客的點贊(瘋狂暗示中),我編寫了一個超級輕量級全自動構建、編譯、燒寫、DEBUG的腳本,助你一鍵體驗,爽翻。
GIT 地址: https://github.com/nbtool/esp32_linux_tool
體驗方法:
#克隆項目到本地 > git clone git@github.com:nbtool/esp32_linux_tool.git #構建esp32開發環境 > cd ./esp32_linux_tool/tool > ./run.sh help > ./run.sh tool #進入aliyun_demo應用文件夾,查看幫助 > cd ../app/aliyun_demo > ./run.sh help |---------------------------------------------------- | ./run.sh op param | op: | create : downloads iotkit and aliyun-esp32 from github and make some change | sdk : param = reconfig/config/make/clean | app : param = deconfig/config/make/erase/flash/monitor/clean | examples: | first create sdk lib : create -> sdk reconfig -> sdk config -> sdk make | second create app : config -> make -> flash -> monitor |---------------------------------------------------- #編譯iotkit-embedded成lib > ./run.sh create > ./run.sh sdk reconfig > ./run.sh sdk make #編譯應用層代碼,並燒寫查看LOG > ./run.sh app config > ./run.sh app make > ./run.sh app flash > ./run.sh app monitor
注:能夠從aliyun_demo/run.sh中瞭解如何實現自動化的~
: 完~
: 你們以爲不錯,能夠點推薦給更多人~
: 明天年會,再幹一週,放假,用這篇超長文作個年終總結吧(笑)~
[1]. MarkDown語法進階(三)(文字居中、圖片處理、插入視頻音樂、標準字體)
[2]. Aliyun IOT Console
[3]. ESP32-IDF GITHUB地址
[4]. ESP-IDF Program Guide
[5]. esp32_linux_tool GITHUB地址
[6]. iotkit-embedded GITHUB地址
[7]. esp-aliyun GITHUB地址
[8]. Link Kit SDK 用戶手冊
@beautifulzzzz 以藍牙技術爲基礎的的末梢無線網絡系統架構及創新型應用探索! 領域:智能硬件、物聯網、自動化、前沿軟硬件 博客:https://www.cnblogs.com/zjutlitao/ 園友交流羣|微信交流羣:414948975|園友交流羣