【IoT迷你赛】环境监测小Demo

2019-08-28 14:59:18 浏览数 (1)

前言

很幸运有这一次的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;
}
二、效果

图2.1 控制台图2.1 控制台

图2.2 实物图2.2 实物

原本我是想完成一个微信小程序调用腾讯地图API来查看设备所在位置的环境粉尘PM2.5情况与温湿度情况。同时可以通过微信小程序查看收集历史记录。奈何时间上不充裕,加上我弄着弄着就忘了小程序的事情。以后有空继续捣鼓这东西。

三、总结

腾讯出品的Tiny OS对连接上腾讯云有着极大的便利,简单几步就可以将一个设备连接到腾讯云平台上。确实Tiny OS相当简洁,同时已经添加好MQTT、CoAP等物联网应用层协议逻辑,极大方便了设备厂商的开发。虽然我在体验的过程中,发现有少许情况是很难连接上腾讯的MQTT broker的,掉线的情况也有,但是我相信肯定以后会更好的。

0 人点赞