目录:老小皆宜、超长干货文警告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|园友交流群