小学生
最后登录1970-1-1
在线时间 小时
注册时间2023-6-18
|
本帖最后由 bigbig 于 2023-7-30 20:45 编辑
1、方案概述
近年来,清洁的室内空气成为诸多重视健康生活人士的新需求。评价室内空气质量的重要指标有2个:TVOC(挥发性有机化合物):TVOC 是在室温或更高温度下蒸发的含碳物质。短期接触会导致刺激、头晕或哮喘恶化;长期接触则可能会导致肺癌或损害肝脏、肾脏或神经系统。温湿度:40-60%的相对湿度是人类理想的舒适度范围。极度干燥的空气会刺激呼吸道,而过分潮湿的空气会导致冷凝,进而引发霉菌滋生,其他影响可能包括头痛甚至偏头痛。改善室内空气质量有两种方式:通风和净化。对于家庭或小型封闭空间而言,如果周围的室外空气干净,理想选择是打开窗户或使用智能通风系统进行通风。室内空气质量的监测数据可用于配置空气净化系统或智能管理通风系统,本文基于野火启明6M5开发板利用腾讯云物联网平台IoT Explorer 和腾讯连连小程序开发了能够实时监测室内空气质量的应用。
2、系统结构
系统采用野火启明6M5开发板作为控制核心,esp8266无线wifi模块用于和腾讯物联网平台通信,svm40模块用于采集室内VOC指数、温湿度,led和按键用于人机交互,用户可通过微信小程序实时查看监测数据。系统结构如图所示:
3、硬件介绍
3.1 sgp30
SGP30是一款单一芯片上具有多个传感元件的金属氧化物室内气体传感器,内部集成4个气体传感元件,具有完全校准的空气质量输出信号,主要是对空气质量进行检测。可以输出:TVOC(Total Volatile Organic Compounds,总挥发性有机物),量程为0~60000ppb;CO2浓度,量程400~60000ppm。
3.2 esp8266
ESP8266 Wi-Fi模块作为可以进行WiFi传输的模块集成了业内领先的Tensilica L106超低功耗32位微型MCU,带有16位精简模式,主频可达160MHz。同时支持RTOS(Real Time Operating System)集成Wi-Fi MAC/BB/RF/PA/LNA和 IEEE802.11 b/g/n 协议,支持完整的TCP/IP协议栈,也支持STA(Station),AP(Access Point),ATA+AP三种模式。
3.3 野火启明6M5开发板
启明6M5是野火电子基于瑞萨 RA 系列微控制器设计的一款开发板,具体实物如下图。
启明6M5开发板板载的是瑞萨的 RA6M5 芯片(型号为:R7FA6M5BH3CFC), RA6M5 基于Cortex-M33 内核,主频高达 200MHz,具有 512KB SRAM、2MB Code Flash 和 8KB Data Flash。
野火启明6M5开发板硬件资源 | [size=0.9]R7FA6M5BH3CFC (RA6M5),Cortex-M33 内核 | | | | | | [size=0.9]2MB Code Flash 和 8KB Data Flash | | [size=0.9]LQFP 176,工业级(-40℃ ~ +105℃) | | [size=0.9]5V USB Type-C 供电 | | [size=0.9]1路 Type-C USB转串口 | | | | | | | | | | [size=0.9]1个电源指示灯、3个用户LED灯 | | [size=0.9]1个复位按键、2个普通用户按键 | | | | | | [size=0.9]1路 EEPROM:AT24C02 | | [size=0.9]1路外部Flash:W25Q32 (32M-bit) | | | | | | | | | | | | [size=0.9]1路百兆以太网 PHY:LAN8720A | | | | | | | | |
4、系统亮点
支持腾讯连连小程序查看数据(TVOC指数、二氧化碳)
支持腾讯云IoT Explorer平台实时查看上报数据信息(TVOC指数、二氧化碳)
支持腾讯连连微信公众号信息推送(TVOC超标告警)
采用腾讯云可视化编辑器自定义腾讯连连小程序界面
5、系统实现
系统实现分为2个部分,一是云端产品建立、小程序界面配置,二是MCU端编程。
在腾讯物联网开发平台IoT Explorer创建产品并按照平台规则设置数据点,设计小程序界面:
设备端开发主要完成单片机的外设初始化、传感器数据读取、mqtt协议数据发送功能。基于RT-Thread开发,只需要添加传感器驱动、wifi驱动、IoT平台驱动即可,十分简单,在底层适配一下板卡即可:
添加了tencent-iot软件包和传感器驱动软件包:
传感器数据采集线程将数据采集后通过消息队列发送给mqtt上传线程:
- /*
- * Copyright (c) 2020, RudyLo <luhuadong@163.com>
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2020-02-22 luhuadong the first version
- */
- #include <rtthread.h>
- #include <rtdevice.h>
- #include <board.h>
- #include "sgp30.h"
- #ifdef PKG_USING_SGP30_SAMPLE_I2C_BUS_NAME
- #define SGP30_I2C_BUS_NAME PKG_USING_SGP30_SAMPLE_I2C_BUS_NAME
- #else
- #define SGP30_I2C_BUS_NAME "i2c1"
- #endif
- struct rt_messagequeue sgp30_mq;
- rt_uint8_t sgp30_msg_pool[2048];
- typedef struct
- {
- int tvoc;
- int co2;
- }sgp30_msg_t;
- int sgp30_thread(void)
- {
- int result;
- sgp30_msg_t msg;
- rt_uint64_t i = 0;
- sgp30_device_t sgp30 = sgp30_create(SGP30_I2C_BUS_NAME);
- if(!sgp30)
- {
- rt_kprintf("(SGP30) Init failed\n");
- return -1;
- }
- while(1)
- {
- /* Read TVOC and eCO2 */
- if(!sgp30_measure(sgp30))
- {
- rt_kprintf("(SGP30) Measurement failed\n");
- sgp30_delete(sgp30);
- break;
- }
- /* Read rawH2 and rawEthanol */
- if(!sgp30_measure_raw(sgp30))
- {
- rt_kprintf("(SGP30) Raw Measurement failed\n");
- sgp30_delete(sgp30);
- break;
- }
- i++;
- rt_thread_mdelay(5000);
- if(sgp30->TVOC == 0 && sgp30->eCO2 == 400)
- {
- continue;
- }
- msg.co2= sgp30->eCO2;
- msg.tvoc=sgp30->TVOC;
- /* 发送消息到消息队列中 */
- result = rt_mq_send(&sgp30_mq, &msg, sizeof(sgp30_msg_t));
- if (result != RT_EOK)
- {
- rt_kprintf("rt_mq_send ERR\n");
- }
-
- rt_kprintf("[%2u] TVOC: %d ppb, eCO2: %d ppm; Raw H2: %d, Raw Ethanol: %d\n",
- i, sgp30->TVOC, sgp30->eCO2, sgp30->rawH2, sgp30->rawEthanol);
- }
- rt_mq_detach(&sgp30_mq);
- sgp30_delete(sgp30);
- return 0;
- }
- static void cat_sgp30(void)
- {
- rt_err_t result;
- /* 初始化消息队列 */
- result = rt_mq_init(&sgp30_mq,
- "mqt",
- &sgp30_msg_pool[0], /* 内存池指向 msg_pool */
- sizeof(sgp30_msg_t), /* 每个消息的大小是 1 字节 */
- sizeof(sgp30_msg_pool), /* 内存池的大小是 msg_pool 的大小 */
- RT_IPC_FLAG_PRIO); /* 如果有多个线程等待,优先级大小的方法分配消息 */
- if (result != RT_EOK)
- {
- rt_kprintf("init message queue failed.\n");
- return;
- }
-
- rt_thread_t tid = rt_thread_create("spg30_get_data", (void (*)(void *))sgp30_thread,
- NULL, 2048, RT_THREAD_PRIORITY_MAX / 2 - 1, 10);
- if (tid != RT_NULL)
- {
- rt_thread_startup(tid);
- }
-
- }
- INIT_APP_EXPORT(cat_sgp30);
复制代码 上传线程:
- /*
- * Tencent is pleased to support the open source community by making IoT Hub available.
- * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
- * Licensed under the MIT License (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://opensource.org/licenses/MIT
- * Unless required by applicable law or agreed to in writing, software distributed under the License is
- * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
- #include "qcloud_iot_export.h"
- #include "qcloud_iot_import.h"
- #include "lite-utils.h"
- #include "data_config.c"
- #include "rtthread.h"
- #include "hal_data.h"
- #include <rtdevice.h>
- #define BLUE_LED_PIN BSP_IO_PORT_04_PIN_03 /* blue LED pins */
- #define GREEN_LED_PIN BSP_IO_PORT_04_PIN_04 /* green LED pins */
- #define DATA_TEMPLATE_THREAD_STACK_SIZE 6144
- #define YEILD_THREAD_STACK_SIZE 4096
- static uint8_t running_state = 0;
- #ifdef AUTH_MODE_CERT
- static char sg_cert_file[PATH_MAX + 1]; // full path of device cert file
- static char sg_key_file[PATH_MAX + 1]; // full path of device key file
- #endif
- static DeviceInfo sg_devInfo;
- static MQTTEventType sg_subscribe_event_result = MQTT_EVENT_UNDEF;
- static bool sg_control_msg_arrived = false;
- static char sg_data_report_buffer[2048];
- static size_t sg_data_report_buffersize = sizeof(sg_data_report_buffer) / sizeof(sg_data_report_buffer[0]);
- #ifdef EVENT_POST_ENABLED
- #include "events_config.c"
- static void update_events_timestamp(sEvent *pEvents, int count)
- {
- int i;
- for (i = 0; i < count; i++) {
- if (NULL == (&pEvents[i])) {
- Log_e("null event pointer");
- return;
- }
- #ifdef EVENT_TIMESTAMP_USED
- pEvents[i].timestamp = time(NULL); //should be UTC and accurate
- #else
- pEvents[i].timestamp = 0;
- #endif
- }
- }
- static void event_post_cb(void *pClient, MQTTMessage *msg)
- {
- Log_d("Reply:%.*s", msg->payload_len, msg->payload);
- // IOT_Event_clearFlag(pClient, FLAG_EVENT0 | FLAG_EVENT1 | FLAG_EVENT2);
- }
- //event check and post
- static void eventPostCheck(void *client)
- {
- int i;
- int rc;
- uint32_t eflag;
- uint8_t event_count;
- sEvent *pEventList[EVENT_COUNTS];
- eflag = IOT_Event_getFlag(client);
- if ((EVENT_COUNTS > 0 ) && (eflag > 0)) {
- event_count = 0;
- for (i = 0; i < EVENT_COUNTS; i++) {
- if ((eflag & (1 << i))&ALL_EVENTS_MASK) {
- pEventList[event_count++] = &(g_events[i]);
- update_events_timestamp(&g_events[i], 1);
- IOT_Event_clearFlag(client, (1 << i)&ALL_EVENTS_MASK);
- }
- }
- rc = IOT_Post_Event(client, sg_data_report_buffer, sg_data_report_buffersize, \
- event_count, pEventList, event_post_cb);
- if (rc < 0) {
- Log_e("events post failed: %d", rc);
- }
- }
- }
- #endif
- #ifdef ACTION_ENABLED
- #include "action_config.c"
- // action : regist action and set the action handle callback, add your aciton logic here
- static void OnActionCallback(void *pClient, const char *pClientToken, DeviceAction *pAction)
- {
- int i;
- sReplyPara replyPara;
- //do something base on input, just print as an sample
- DeviceProperty *pActionInput = pAction->pInput;
- for (i = 0; i < pAction->input_num; i++) {
- if (JSTRING == pActionInput[i].type) {
- Log_d("Input:[%s], data:[%s]", pActionInput[i].key, pActionInput[i].data);
- HAL_Free(pActionInput[i].data);
- } else {
- if (JINT32 == pActionInput[i].type) {
- Log_d("Input:[%s], data:[%d]", pActionInput[i].key, *((int*)pActionInput[i].data));
- } else if ( JFLOAT == pActionInput[i].type) {
- Log_d("Input:[%s], data:[%f]", pActionInput[i].key, *((float*)pActionInput[i].data));
- } else if ( JUINT32 == pActionInput[i].type) {
- Log_d("Input:[%s], data:[%u]", pActionInput[i].key, *((uint32_t*)pActionInput[i].data));
- }
- }
- }
- // construct output
- memset((char *)&replyPara, 0, sizeof(sReplyPara));
- replyPara.code = eDEAL_SUCCESS;
- replyPara.timeout_ms = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
- strcpy(replyPara.status_msg, "action execute success!"); //add the message about the action resault
- DeviceProperty *pActionOutnput = pAction->pOutput;
- (void)pActionOutnput; //elimate warning
- //TO DO: add your aciont logic here and set output properties which will be reported by action_reply
- IOT_ACTION_REPLY(pClient, pClientToken, sg_data_report_buffer, sg_data_report_buffersize, pAction, &replyPara);
- }
- static int _register_data_template_action(void *pTemplate_client)
- {
- int i, rc;
- for (i = 0; i < TOTAL_ACTION_COUNTS; i++) {
- rc = IOT_Template_Register_Action(pTemplate_client, &g_actions[i], OnActionCallback);
- if (rc != QCLOUD_RET_SUCCESS) {
- rc = IOT_Template_Destroy(pTemplate_client);
- Log_e("register device data template action failed, err: %d", rc);
- return rc;
- } else {
- Log_i("data template action=%s registered.", g_actions[i].pActionId);
- }
- }
- return QCLOUD_RET_SUCCESS;
- }
- #endif
- static void event_handler(void *pclient, void *handle_context, MQTTEventMsg *msg)
- {
- uintptr_t packet_id = (uintptr_t)msg->msg;
- switch (msg->event_type) {
- case MQTT_EVENT_UNDEF:
- Log_i("undefined event occur.");
- break;
- case MQTT_EVENT_DISCONNECT:
- Log_i("MQTT disconnect.");
- rt_pin_write(BLUE_LED_PIN, PIN_LOW);
- break;
- case MQTT_EVENT_RECONNECT:
- Log_i("MQTT reconnect.");
- rt_pin_write(BLUE_LED_PIN, PIN_HIGH);
- break;
- case MQTT_EVENT_SUBCRIBE_SUCCESS:
- sg_subscribe_event_result = msg->event_type;
- Log_i("subscribe success, packet-id=%u", packet_id);
- rt_pin_write(GREEN_LED_PIN, PIN_HIGH);
- break;
- case MQTT_EVENT_SUBCRIBE_TIMEOUT:
- sg_subscribe_event_result = msg->event_type;
- Log_i("subscribe wait ack timeout, packet-id=%u", packet_id);
- break;
- case MQTT_EVENT_SUBCRIBE_NACK:
- sg_subscribe_event_result = msg->event_type;
- Log_i("subscribe nack, packet-id=%u", packet_id);
- break;
- case MQTT_EVENT_PUBLISH_SUCCESS:
- Log_i("publish success, packet-id=%u", (unsigned int)packet_id);
- rt_pin_write(GREEN_LED_PIN, PIN_LOW);
- break;
- case MQTT_EVENT_PUBLISH_TIMEOUT:
- Log_i("publish timeout, packet-id=%u", (unsigned int)packet_id);
- break;
- case MQTT_EVENT_PUBLISH_NACK:
- Log_i("publish nack, packet-id=%u", (unsigned int)packet_id);
- break;
- default:
- Log_i("Should NOT arrive here.");
- break;
- }
- }
- /*add user init code, like sensor init*/
- static void _usr_init(void)
- {
- Log_d("add your init code here");
- }
- // Setup MQTT construct parameters
- static int _setup_connect_init_params(TemplateInitParams* initParams)
- {
- int ret;
- ret = HAL_GetDevInfo((void *)&sg_devInfo);
- if (QCLOUD_RET_SUCCESS != ret) {
- return ret;
- }
- initParams->device_name = sg_devInfo.device_name;
- initParams->product_id = sg_devInfo.product_id;
- #ifdef AUTH_MODE_CERT
- /* TLS with certs*/
- char certs_dir[PATH_MAX + 1] = "certs";
- char current_path[PATH_MAX + 1];
- char *cwd = getcwd(current_path, sizeof(current_path));
- if (cwd == NULL) {
- Log_e("getcwd return NULL");
- return QCLOUD_ERR_FAILURE;
- }
- sprintf(sg_cert_file, "%s/%s/%s", current_path, certs_dir, sg_devInfo.dev_cert_file_name);
- sprintf(sg_key_file, "%s/%s/%s", current_path, certs_dir, sg_devInfo.dev_key_file_name);
- initParams->cert_file = sg_cert_file;
- initParams->key_file = sg_key_file;
- #else
- initParams->device_secret = sg_devInfo.device_secret;
- #endif
- initParams->command_timeout = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
- initParams->keep_alive_interval_ms = QCLOUD_IOT_MQTT_KEEP_ALIVE_INTERNAL;
- initParams->auto_connect_enable = 1;
- initParams->event_handle.h_fp = event_handler;
- return QCLOUD_RET_SUCCESS;
- }
- static void OnControlMsgCallback(void *pClient, const char *pJsonValueBuffer, uint32_t valueLength, DeviceProperty *pProperty)
- {
- int i = 0;
- for (i = 0; i < TOTAL_PROPERTY_COUNT; i++) {
- /* handle self defined string/json here. Other properties are dealed in _handle_delta()*/
- if (strcmp(sg_DataTemplate[i].data_property.key, pProperty->key) == 0) {
- sg_DataTemplate[i].state = eCHANGED;
- Log_i("Property=%s changed", pProperty->key);
- sg_control_msg_arrived = true;
- return;
- }
- }
- Log_e("Property=%s changed no match", pProperty->key);
- }
- static void OnReportReplyCallback(void *pClient, Method method, ReplyAck replyAck, const char *pJsonDocument, void *pUserdata)
- {
- Log_i("recv report reply response, reply ack: %d", replyAck);
- }
- // register data template properties
- static int _register_data_template_property(void *pTemplate_client)
- {
- int i, rc;
- for (i = 0; i < TOTAL_PROPERTY_COUNT; i++) {
- rc = IOT_Template_Register_Property(pTemplate_client, &sg_DataTemplate[i].data_property, OnControlMsgCallback);
- if (rc != QCLOUD_RET_SUCCESS) {
- rc = IOT_Template_Destroy(pTemplate_client);
- Log_e("register device data template property failed, err: %d", rc);
- return rc;
- } else {
- Log_i("data template property=%s registered.", sg_DataTemplate[i].data_property.key);
- }
- }
- return QCLOUD_RET_SUCCESS;
- }
- // when control msg received, data_template's properties has been parsed in pData
- // you should add your logic how to use pData
- void deal_down_stream_user_logic(void *client, ProductDataDefine * pData)
- {
- Log_d("someting about your own product logic wait to be done");
-
- if(pData->m_fan)
- {
- Log_d( "=====fan on====");
- }
- else
- {
- Log_d( "=====fan off====");
- }
- #ifdef EVENT_POST_ENABLED
- //IOT_Event_setFlag(client, FLAG_EVENT0); //set the events flag when the evnts your defined occured, see events_config.c
- #endif
- }
- /*get local property data, like sensor data*/
- static void _refresh_local_property(void)
- {
- //add your local property refresh logic
- /*用户根据业务修改属性值,然后设置属性状态为eCHANGED*/
- //sg_ProductData.m_temperature++;
- //sg_DataTemplate[0].state = eCHANGED;
- }
- /*find propery need report*/
- static int find_wait_report_property(DeviceProperty *pReportDataList[])
- {
- int i, j;
- for (i = 0, j = 0; i < TOTAL_PROPERTY_COUNT; i++) {
- if (eCHANGED == sg_DataTemplate[i].state) {
- pReportDataList[j++] = &(sg_DataTemplate[i].data_property);
- sg_DataTemplate[i].state = eNOCHANGE;
- }
- }
- return j;
- }
- // demo for up-stream
- // add changed properties to pReportDataList, then the changed properties would be reported
- // you should add your own logic for how to get the changed properties
- int deal_up_stream_user_logic(DeviceProperty *pReportDataList[], int *pCount)
- {
- //refresh local property
- _refresh_local_property();
- /*find propery need report*/
- *pCount = find_wait_report_property(pReportDataList);
- return (*pCount > 0) ? QCLOUD_RET_SUCCESS : QCLOUD_ERR_FAILURE;
- }
- /*You should get the real info for your device, here just for example*/
- static int _get_sys_info(void *handle, char *pJsonDoc, size_t sizeOfBuffer)
- {
- /*platform info has at least one of module_hardinfo/module_softinfo/fw_ver property*/
- DeviceProperty plat_info[] = {
- {.key = "module_hardinfo", .type = TYPE_TEMPLATE_STRING, .data = "ESP8266"},
- {.key = "module_softinfo", .type = TYPE_TEMPLATE_STRING, .data = "V1.0"},
- {.key = "fw_ver", .type = TYPE_TEMPLATE_STRING, .data = QCLOUD_IOT_DEVICE_SDK_VERSION},
- {.key = "imei", .type = TYPE_TEMPLATE_STRING, .data = "11-22-33-44"},
- {.key = "lat", .type = TYPE_TEMPLATE_STRING, .data = "22.546015"},
- {.key = "lon", .type = TYPE_TEMPLATE_STRING, .data = "113.941125"},
- {NULL, NULL, 0} //end
- };
- /*self define info*/
- DeviceProperty self_info[] = {
- {.key = "append_info", .type = TYPE_TEMPLATE_STRING, .data = "your self define info"},
- {NULL, NULL, 0} //end
- };
- return IOT_Template_JSON_ConstructSysInfo(handle, pJsonDoc, sizeOfBuffer, plat_info, self_info);
- }
- static int data_template_thread(void)
- {
- int rc;
- sReplyPara replyPara;
- DeviceProperty *pReportDataList[TOTAL_PROPERTY_COUNT];
- int ReportCont;
- //init log level
- IOT_Log_Set_Level(eLOG_DEBUG);
- //init connection
- TemplateInitParams init_params = DEFAULT_TEMPLATE_INIT_PARAMS;
- rc = _setup_connect_init_params(&init_params);
- if (rc != QCLOUD_RET_SUCCESS) {
- Log_e("init params err,rc=%d", rc);
- return rc;
- }
- void *client = IOT_Template_Construct(&init_params, NULL);
- if (client != NULL) {
- Log_i("Cloud Device Construct Success");
- } else {
- Log_e("Cloud Device Construct Failed");
- return QCLOUD_ERR_FAILURE;
- }
- #ifdef MULTITHREAD_ENABLED
- if (QCLOUD_RET_SUCCESS != IOT_Template_Start_Yield_Thread(client)) {
- Log_e("start template yield thread fail");
- goto exit;
- }
- #endif
- //user init
- _usr_init();
- //init data template
- _init_data_template();
- //register data template propertys here
- rc = _register_data_template_property(client);
- if (rc == QCLOUD_RET_SUCCESS) {
- Log_i("Register data template propertys Success");
- } else {
- Log_e("Register data template propertys Failed: %d", rc);
- goto exit;
- }
- //register data template actions here
- #ifdef ACTION_ENABLED
- rc = _register_data_template_action(client);
- if (rc == QCLOUD_RET_SUCCESS) {
- Log_i("Register data template actions Success");
- } else {
- Log_e("Register data template actions Failed: %d", rc);
- goto exit;
- }
- #endif
- //report device info, then you can manager your product by these info, like position
- rc = _get_sys_info(client, sg_data_report_buffer, sg_data_report_buffersize);
- if (QCLOUD_RET_SUCCESS == rc) {
- rc = IOT_Template_Report_SysInfo_Sync(client, sg_data_report_buffer, sg_data_report_buffersize, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
- if (rc != QCLOUD_RET_SUCCESS) {
- Log_e("Report system info fail, err: %d", rc);
- }
- } else {
- Log_e("Get system info fail, err: %d", rc);
- }
- //get the property changed during offline
- rc = IOT_Template_GetStatus_sync(client, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
- if (rc != QCLOUD_RET_SUCCESS) {
- Log_e("Get data status fail, err: %d", rc);
- } else {
- Log_d("Get data status success");
- }
- running_state = 1;
- while (IOT_Template_IsConnected(client) || rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT
- || rc == QCLOUD_RET_MQTT_RECONNECTED || QCLOUD_RET_SUCCESS == rc) {
- if(0 == running_state) {
- break;
- }
- #ifndef MULTITHREAD_ENABLED
- rc = IOT_Template_Yield(client, 200);
- if (rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT) {
- HAL_SleepMs(1000);
- continue;
- } else if (rc != QCLOUD_RET_SUCCESS) {
- Log_e("Exit loop caused of errCode: %d", rc);
- }
- #endif
- /* handle control msg from server */
- if (sg_control_msg_arrived) {
- deal_down_stream_user_logic(client, &sg_ProductData);
- /* control msg should reply, otherwise server treat device didn't receive and retain the msg which would be get by get status*/
- memset((char *)&replyPara, 0, sizeof(sReplyPara));
- replyPara.code = eDEAL_SUCCESS;
- replyPara.timeout_ms = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
- replyPara.status_msg[0] = '\0'; //add extra info to replyPara.status_msg when error occured
- rc = IOT_Template_ControlReply(client, sg_data_report_buffer, sg_data_report_buffersize, &replyPara);
- if (rc == QCLOUD_RET_SUCCESS) {
- Log_d("Contol msg reply success");
- sg_control_msg_arrived = false;
- } else {
- Log_e("Contol msg reply failed, err: %d", rc);
- }
- } else {
- Log_d("No control msg received...");
- }
- /*report msg to server*/
- /*report the lastest properties's status*/
- if (QCLOUD_RET_SUCCESS == deal_up_stream_user_logic(pReportDataList, &ReportCont)) {
- rc = IOT_Template_JSON_ConstructReportArray(client, sg_data_report_buffer, sg_data_report_buffersize, ReportCont, pReportDataList);
- if (rc == QCLOUD_RET_SUCCESS) {
- rc = IOT_Template_Report(client, sg_data_report_buffer, sg_data_report_buffersize,
- OnReportReplyCallback, NULL, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
- if (rc == QCLOUD_RET_SUCCESS) {
- Log_i("data template reporte success");
- } else {
- Log_e("data template reporte failed, err: %d", rc);
- }
- } else {
- Log_e("construct reporte data failed, err: %d", rc);
- }
- } else {
- //Log_d("no data need to be reported or someting goes wrong");
- }
- #ifdef EVENT_POST_ENABLED
- eventPostCheck(client);
- #endif
- HAL_SleepMs(3000);
- }
- exit:
- #ifdef MULTITHREAD_ENABLED
- IOT_Template_Stop_Yield_Thread(client);
- #endif
- rc = IOT_Template_Destroy(client);
- running_state = 0;
- return rc;
- }
- extern struct rt_messagequeue sgp30_mq;
- static int recv_spg30_data_thread(void)
- {
- typedef struct
- {
- int tvoc;
- int co2;
- }sgp30_msg_t;
- sgp30_msg_t msg;
- while (1)
- {
- /* 从消息队列中接收消息 */
- if (rt_mq_recv(&sgp30_mq, &msg, sizeof(sgp30_msg_t), RT_WAITING_FOREVER) == RT_EOK)
- {
- rt_kprintf("thread1: recv msg from msg queue, the content:tvoc=%d co2=%d\n", msg.tvoc,msg.co2);
- sg_ProductData.m_tvoc = msg.tvoc;
- sg_ProductData.m_co2 = msg.co2;
- sg_DataTemplate[2].state = eCHANGED;
- sg_DataTemplate[5].state = eCHANGED;
- }
- rt_thread_mdelay(10);
- }
- }
- static int tc_data_template_example(void)
- {
- rt_thread_mdelay(5000);
- rt_thread_t tid;
- int stack_size = DATA_TEMPLATE_THREAD_STACK_SIZE;
- int argc=2;
- char *argv[3]={"none","start","stop"};
- //init log level
- IOT_Log_Set_Level(eLOG_DEBUG);
- if (2 == argc) {
- if (!strcmp("start", argv[1])) {
- if (1 == running_state) {
- Log_d("tc_data_template_example is already running\n");
- return 0;
- }
- } else if (!strcmp("stop", argv[1])) {
- if (0 == running_state) {
- Log_d("tc_data_template_example is already stopped\n");
- return 0;
- }
- running_state = 0;
- return 0;
- } else {
- Log_d("Usage: tc_data_template_example start/stop");
- return 0;
- }
- } else {
- Log_e("Para err, usage: tc_data_template_example start/stop");
- return 0;
- }
- tid = rt_thread_create("data_template", (void (*)(void *))data_template_thread,
- NULL, stack_size, RT_THREAD_PRIORITY_MAX / 2 - 2, 10);
- if (tid != RT_NULL) {
- rt_thread_startup(tid);
- }
-
- tid = rt_thread_create("get_data", (void (*)(void *))recv_spg30_data_thread,
- NULL, stack_size, RT_THREAD_PRIORITY_MAX / 2 - 3, 10);
- if (tid != RT_NULL) {
- rt_thread_startup(tid);
- }
- return 0;
- }
- INIT_APP_EXPORT(tc_data_template_example);
复制代码
程序运行正常的情况下,在云平台调试界面就可以看到设备发送的数据,进入腾讯连连小程序连接设备后也能看到之前设计的小程序界面。
最后附上代码:
R6M5.part1.rar
(10 MB, 下载次数: 11)
R6M5.part2.rar
(5.3 MB, 下载次数: 11)
6、活动总结
很幸运能够参加这次比赛,再次感谢火哥和瑞萨的活动支持,通过活动学习到了瑞萨单片机图形化非常简单傻瓜化的开发方式,火哥6M5开发板资料十分丰富。
由于本人能力水平不足,文章写的有误或者不清楚的地方敬请见谅,可在评论区留言以改正。
|
|