前言
很幸运有这一次的Tencent Tiny OS的内测机会,体验了一把腾讯自主研发的物联网操作系统。在7月尾我参加了腾讯举办的物联网分享大会,在那一次的技术交流会上,腾讯的IOT云端技术大佬就讲解了腾讯开发的物联网操作系统Tiny OS。简单来说,该操作系统简洁、实用,系统拥有线程管理与信号量处理等满足物联网需求的基础功能,专门为物联网的打造,所以具备有CoAP、MQTT等应用层的协议架构。该操作系统为腾讯云自主研发,所以在连接腾讯云的物联网平台已经提供最佳参考。
一、Tiny OS 连上腾讯云小案例
参加这次内测,能够体验一把使用腾讯云的Tiny OS系统连接上腾讯云的物联网平台。由于个人时间并不是很宽裕,这里我就简单的做一个环境监测的Demo。通过Tiny OS系统通过调用GPS定位模块、温湿度传感器模块、PM2.5粉尘传感器模块收集到经纬度、时间、温湿度、PM2.5值等信息,然后通过MQTT上报到腾讯云。
如何实现呢?我们都知道需要三步就能将大象装进冰箱里去(1.打开冰箱;2.把大象装进去;3.把冰箱关上)。同样,要实现用Tiny OS连接腾讯云也是三步:1.打开Tiny OS开源代码 2.将自己需要的功能代码加进去 3.编译成功连上腾讯云。
本人才疏学浅,而且时间上并不是很充裕,所以也仅仅是粗略看了下Tiny OS的代码,下文如有分析不正确之处望见谅。
Tiny OS基础功能点:
- 线程创建、销毁
- 定时器Timer简单调度
- MQTT应用层协议订阅、推送
- MQTT消息回调
- 设备影子Client云端同步
- 非对称加解密
- 设备Token
- 事件触发与上报
- 详细的日志信息
那我具体要做哪些呢?
1.将Tiny OS中的设备名称、产品ID、设备密钥换成自己在云端生成的。
代码语言:txt复制/* 产品ID */
static char sg_product_id[MAX_SIZE_OF_PRODUCT_ID 1] = "";
/* 设备密钥 */
static char sg_product_secret[MAX_SIZE_OF_PRODUCT_KEY 1] = "";
#endif
/* 设备名称, 与云端同步设备状态时需要 */
static char sg_device_name[MAX_SIZE_OF_DEVICE_NAME 1] = "dev05";
2.初始化硬件。
代码语言:txt复制void board_init(void)
{
char *str = "Xiao Fang He";
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
//MX_ADC1_Init();
//MX_DAC1_Init();
//MX_I2C1_Init();
//MX_LPUART1_UART_Init();
MX_USART2_UART_Init();
MX_USART3_UART_Init();
//MX_SPI1_Init();
//MX_SPI3_Init();
DHT11_Init();
//PM2.5粉尘
Adc_Init();
GP2Y1014AU_init();
GPS_Init();
OLED_Init();
OLED_Clear();
OLED_ShowCHinese(0,0,0);
OLED_ShowCHinese(18,0,1);
OLED_ShowCHinese(36,0,2);
OLED_ShowCHinese(54,0,3);
OLED_ShowCHinese(72,0,4);
OLED_ShowCHinese(90,0,5);
OLED_ShowString(0,2,(uint8_t*)str,16);
}
3.在application_entry函数内修改自己的Wi-Fi信息(由于使用的是ESP8266,只能接2.4GWi-Fi,调了很久一段时间)然后将自己的线程任务添加到这里。
代码语言:txt复制void application_entry(void *arg)
{
#ifdef USE_ESP8266
extern int esp8266_sal_init(hal_uart_port_t uart_port);
extern int esp8266_join_ap(const char *ssid, const char *pwd);
esp8266_sal_init(HAL_UART_PORT_0);
esp8266_join_ap("xiaofanghe", "xiaofanghe123456");
#endif
#ifdef USE_NB_BC35
extern int bc35_28_95_sal_init(hal_uart_port_t uart_port);
bc35_28_95_sal_init(HAL_UART_PORT_0);
#endif
extern int data_template_thread(void);
data_template_thread();
while (1) {
printf("This is a tencent cloud sdk data template demo!rn");
tos_task_delay(1000);
}
}
4.直接在定时上报设备属性那获取到定位信息、时间信息、温度、湿度、PM2.5值,然后封装成JSON直接上报给云端即可。
代码语言:txt复制int data_template_thread(void) {
int rc, i;
int ReportCont;
Timer reportTimer;
DeviceProperty *pReportDataList[TOTAL_PROPERTY_COUNT];
int tem;
int hum;
unsigned long *time;
double *longitude;
double *latitude;
int pm2_5;
IOT_Log_Set_Level(LOG_DEBUG);
// init connection
ShadowInitParams init_params = DEFAULT_SHAWDOW_INIT_PARAMS;
rc = _setup_connect_init_params(&init_params);
if (rc != QCLOUD_ERR_SUCCESS) {
Log_e("init params err,rc=%d", rc);
return rc;
}
void *client = IOT_Shadow_Construct(&init_params);
if (client != NULL) {
Log_i("Cloud Device Construct Success");
} else {
Log_e("Cloud Device Construct Failed");
return QCLOUD_ERR_FAILURE;
}
// init data template
_init_data_template();
#ifdef EVENT_POST_ENABLED
rc = event_init(client);
if (rc < 0) {
Log_e("event init failed: %d", rc);
return rc;
}
#endif
rc = IOT_Shadow_Yield(client, 200);
if (rc != QCLOUD_ERR_SUCCESS) {
return rc;
}
// register data template propertys here
rc = _register_data_template_property(client);
if (rc == QCLOUD_ERR_SUCCESS) {
Log_i("Register data template propertys Success");
} else {
Log_e("Register data template propertys Failed: %d", rc);
return rc;
}
rc = IOT_Shadow_Get_Sync(client, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
if (rc != QCLOUD_ERR_SUCCESS) {
Log_e("get device shadow failed, err: %d", rc);
return rc;
}
InitTimer(&reportTimer);
running_state = 1;
while ((IOT_Shadow_IsConnected(client) ||
rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT ||
rc == QCLOUD_ERR_MQTT_RECONNECTED ||
rc == QCLOUD_ERR_SUCCESS) &&
running_state) {
rc = IOT_Shadow_Yield(client, 200);
if (rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT) {
HAL_SleepMs(1000);
continue;
} else if (rc != QCLOUD_ERR_SUCCESS) {
Log_e("Exit loop caused of errCode: %d", rc);
}
//设备属性收集
tem = DHT11_tem();
hum = DHT11_hum();
pm2_5 = Get_Adc_Average();
GPS(time,longitude,latitude);
Construct_My_JSON(tem,hum,pm2_5,time,longitude,latitude,sg_shadow_update_buffer);
if(sg_dev_report_new_data){
if(QCLOUD_ERR_SUCCESS == deal_up_stream_user_logic(pReportDataList, &ReportCont)){
Log_d("report:%s",sg_shadow_update_buffer);
rc = IOT_Shadow_JSON_ConstructReportArray(client, sg_shadow_update_buffer, sg_shadow_update_buffersize, ReportCont, pReportDataList);
if (rc == QCLOUD_ERR_SUCCESS) {
rc = IOT_Shadow_Update(client, sg_shadow_update_buffer, sg_shadow_update_buffersize,
OnShadowUpdateCallback, NULL, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
if (rc == QCLOUD_ERR_SUCCESS) {
sg_dev_report_new_data = false;
Log_i("shadow update(reported) success");
} else {
Log_e("shadow update(reported) failed, err: %d", rc);
}
} else {
Log_e("construct reported failed, err: %d", rc);
}
} else {
Log_d("no data need to be reported or someting goes wrong");
}
}
if (QCLOUD_ERR_SUCCESS == cycle_report(pReportDataList, &reportTimer)){
rc = IOT_Shadow_JSON_ConstructReportArray(client, sg_shadow_update_buffer, sg_shadow_update_buffersize, TOTAL_PROPERTY_COUNT, pReportDataList);
if (rc == QCLOUD_ERR_SUCCESS) {
Log_d("cycle report:%s",sg_shadow_update_buffer);
rc = IOT_Shadow_Update(client, sg_shadow_update_buffer, sg_shadow_update_buffersize,
OnShadowUpdateCallback, NULL, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
if (rc == QCLOUD_ERR_SUCCESS) {
sg_dev_report_new_data = false;
Log_i("shadow update(reported) success");
} else {
Log_e("shadow update(reported) failed, err: %d", rc);
}
} else {
Log_e("construct reported failed, err: %d", rc);
}
}
#ifdef EVENT_POST_ENABLED
uint32_t eflag;
sEvent *pEventList[EVENT_COUNTS];
uint8_t EventCont;
eflag = getEventFlag();
if ((EVENT_COUNTS > 0) && (eflag > 0)) {
EventCont = 0;
for (i = 0; i < EVENT_COUNTS; i ) {
if ((eflag & (1 << i)) & ALL_EVENTS_MASK){
pEventList[EventCont ] = &(g_events[i]);
update_events_timestamp(&g_events[i], 1);
}
}
rc = qcloud_iot_post_event(client, sg_shadow_update_buffer, sg_shadow_update_buffersize,
EventCont, pEventList, event_post_cb);
if (rc < 0) {
Log_e("event post failed: %d", rc);
}
}
#endif
HAL_SleepMs(3000);
}
rc = IOT_Shadow_Destroy(client);
return rc;
}
二、效果
原本我是想完成一个微信小程序调用腾讯地图API来查看设备所在位置的环境粉尘PM2.5情况与温湿度情况。同时可以通过微信小程序查看收集历史记录。奈何时间上不充裕,加上我弄着弄着就忘了小程序的事情。以后有空继续捣鼓这东西。
三、总结
腾讯出品的Tiny OS对连接上腾讯云有着极大的便利,简单几步就可以将一个设备连接到腾讯云平台上。确实Tiny OS相当简洁,同时已经添加好MQTT、CoAP等物联网应用层协议逻辑,极大方便了设备厂商的开发。虽然我在体验的过程中,发现有少许情况是很难连接上腾讯的MQTT broker的,掉线的情况也有,但是我相信肯定以后会更好的。