野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 841|回复: 1

【野火】瑞萨RA MCU创意氛围赛+室内空气质量监测

[复制链接]
发表于 2023-7-30 20:43:53 | 显示全部楼层 |阅读模式
本帖最后由 bigbig 于 2023-7-30 20:45 编辑

1、方案概述
       近年来,清洁的室内空气成为诸多重视健康生活人士的新需求。评价室内空气质量的重要指标有2个:TVOC(挥发性有机化合物):TVOC 是在室温或更高温度下蒸发的含碳物质。短期接触会导致刺激、头晕或哮喘恶化;长期接触则可能会导致肺癌或损害肝脏、肾脏或神经系统。温湿度:40-60%的相对湿度是人类理想的舒适度范围。极度干燥的空气会刺激呼吸道,而过分潮湿的空气会导致冷凝,进而引发霉菌滋生,其他影响可能包括头痛甚至偏头痛。改善室内空气质量有两种方式:通风和净化。对于家庭或小型封闭空间而言,如果周围的室外空气干净,理想选择是打开窗户或使用智能通风系统进行通风。室内空气质量的监测数据可用于配置空气净化系统或智能管理通风系统,本文基于野火启明6M5开发板利用腾讯云物联网平台IoT Explorer 和腾讯连连小程序开发了能够实时监测室内空气质量的应用。
2、系统结构
   系统采用野火启明6M5开发板作为控制核心,esp8266无线wifi模块用于和腾讯物联网平台通信,svm40模块用于采集室内VOC指数、温湿度,led和按键用于人机交互,用户可通过微信小程序实时查看监测数据。系统结构如图所示:
11.png
3、硬件介绍
3.1  sgp30
SGP30是一款单一芯片上具有多个传感元件的金属氧化物室内气体传感器,内部集成4个气体传感元件,具有完全校准的空气质量输出信号,主要是对空气质量进行检测。可以输出:TVOC(Total Volatile Organic Compounds,总挥发性有机物),量程为0~60000ppb;CO2浓度,量程400~60000ppm。
pin.jpg
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 系列微控制器设计的一款开发板,具体实物如下图。
qm_6m5_board1.jpg

启明6M5开发板板载的是瑞萨的 RA6M5 芯片(型号为:R7FA6M5BH3CFC), RA6M5 基于Cortex-M33 内核,主频高达 200MHz,具有 512KB SRAM、2MB Code Flash 和 8KB Data Flash。

野火启明6M5开发板硬件资源

[size=0.9]MCU
[size=0.9]R7FA6M5BH3CFC (RA6M5),Cortex-M33 内核
[size=0.9]频率
[size=0.9]200MHz
[size=0.9]SRAM
[size=0.9]512KB
[size=0.9]FALSH
[size=0.9]2MB Code Flash 和 8KB Data Flash
[size=0.9]封装和引脚
[size=0.9]LQFP 176,工业级(-40℃ ~ +105℃)
[size=0.9]电源
[size=0.9]5V USB Type-C 供电
[size=0.9]USB转串口
[size=0.9]1路 Type-C USB转串口
[size=0.9]JTAG
[size=0.9]1路
[size=0.9]SWD
[size=0.9]1路
[size=0.9]USB Device
[size=0.9]1路
[size=0.9]USB Host
[size=0.9]1路
[size=0.9]LED
[size=0.9]1个电源指示灯、3个用户LED灯
[size=0.9]按键
[size=0.9]1个复位按键、2个普通用户按键
[size=0.9]电容按键
[size=0.9]1个电容按键(CTSU)
[size=0.9]蜂鸣器
[size=0.9]1个有源蜂鸣器
[size=0.9]I2C
[size=0.9]1路 EEPROM:AT24C02
[size=0.9]QSPI Flash
[size=0.9]1路外部Flash:W25Q32 (32M-bit)
[size=0.9]SDHI
[size=0.9]1路SD卡接口
[size=0.9]ADC电位器
[size=0.9]1路
[size=0.9]RS232
[size=0.9]1路
[size=0.9]RS485
[size=0.9]2路
[size=0.9]CAN
[size=0.9]2路 CAN FD
[size=0.9]网口
[size=0.9]1路百兆以太网 PHY:LAN8720A
[size=0.9]无线WiFi
[size=0.9]1路 ESP8266
[size=0.9]EBF Module
[size=0.9]1路
[size=0.9]PMOD接口
[size=0.9]2路
[size=0.9]IO
[size=0.9]未用 IO 引脚全引出

4、系统亮点
支持腾讯连连小程序查看数据(TVOC指数、二氧化碳)
支持腾讯云IoT Explorer平台实时查看上报数据信息(TVOC指数、二氧化碳)
支持腾讯连连微信公众号信息推送(TVOC超标告警)
采用腾讯云可视化编辑器自定义腾讯连连小程序界面
5、系统实现
系统实现分为2个部分,一是云端产品建立、小程序界面配置,二是MCU端编程。
在腾讯物联网开发平台IoT Explorer创建产品并按照平台规则设置数据点,设计小程序界面:
aa.png
cc.png
设备端开发主要完成单片机的外设初始化、传感器数据读取、mqtt协议数据发送功能。基于RT-Thread开发,只需要添加传感器驱动、wifi驱动、IoT平台驱动即可,十分简单,在底层适配一下板卡即可:
333.png
添加了tencent-iot软件包和传感器驱动软件包:
44.png
传感器数据采集线程将数据采集后通过消息队列发送给mqtt上传线程:
  1. /*
  2. * Copyright (c) 2020, RudyLo <luhuadong@163.com>
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date           Author       Notes
  8. * 2020-02-22     luhuadong    the first version
  9. */

  10. #include <rtthread.h>
  11. #include <rtdevice.h>
  12. #include <board.h>
  13. #include "sgp30.h"

  14. #ifdef PKG_USING_SGP30_SAMPLE_I2C_BUS_NAME
  15. #define SGP30_I2C_BUS_NAME       PKG_USING_SGP30_SAMPLE_I2C_BUS_NAME
  16. #else
  17. #define SGP30_I2C_BUS_NAME       "i2c1"
  18. #endif

  19. struct rt_messagequeue sgp30_mq;
  20. rt_uint8_t sgp30_msg_pool[2048];

  21. typedef struct
  22. {
  23. int tvoc;
  24. int co2;
  25. }sgp30_msg_t;

  26. int sgp30_thread(void)
  27. {
  28.          int result;
  29.         sgp30_msg_t msg;
  30.         rt_uint64_t i = 0;
  31.         sgp30_device_t sgp30 = sgp30_create(SGP30_I2C_BUS_NAME);

  32.         if(!sgp30)
  33.         {
  34.                         rt_kprintf("(SGP30) Init failed\n");
  35.                         return -1;
  36.         }
  37.         while(1)
  38.         {
  39.                 /* Read TVOC and eCO2 */
  40.                 if(!sgp30_measure(sgp30))
  41.                 {
  42.                                 rt_kprintf("(SGP30) Measurement failed\n");
  43.                                 sgp30_delete(sgp30);
  44.                                 break;
  45.                 }

  46.                 /* Read rawH2 and rawEthanol */
  47.                 if(!sgp30_measure_raw(sgp30))
  48.                 {
  49.                                 rt_kprintf("(SGP30) Raw Measurement failed\n");
  50.                                 sgp30_delete(sgp30);
  51.                                 break;
  52.                 }
  53.                 i++;
  54.                 rt_thread_mdelay(5000);
  55.                 if(sgp30->TVOC == 0 && sgp30->eCO2 == 400)
  56.                 {
  57.                         continue;                                
  58.                 }
  59.                 msg.co2= sgp30->eCO2;
  60.                 msg.tvoc=sgp30->TVOC;
  61.                 /* 发送消息到消息队列中 */
  62.                 result = rt_mq_send(&sgp30_mq, &msg, sizeof(sgp30_msg_t));
  63.                 if (result != RT_EOK)
  64.                 {
  65.                                 rt_kprintf("rt_mq_send ERR\n");
  66.                 }
  67.                                                 
  68.         rt_kprintf("[%2u] TVOC: %d ppb, eCO2: %d ppm; Raw H2: %d, Raw Ethanol: %d\n",
  69.                                                                 i, sgp30->TVOC, sgp30->eCO2, sgp30->rawH2, sgp30->rawEthanol);        
  70.         }
  71.          rt_mq_detach(&sgp30_mq);
  72.         sgp30_delete(sgp30);
  73.         return 0;
  74. }

  75. static void cat_sgp30(void)
  76. {
  77.         rt_err_t result;

  78.     /* 初始化消息队列 */
  79.     result = rt_mq_init(&sgp30_mq,
  80.                         "mqt",
  81.                         &sgp30_msg_pool[0],             /* 内存池指向 msg_pool */
  82.                         sizeof(sgp30_msg_t),                          /* 每个消息的大小是 1 字节 */
  83.                         sizeof(sgp30_msg_pool),        /* 内存池的大小是 msg_pool 的大小 */
  84.                         RT_IPC_FLAG_PRIO);       /* 如果有多个线程等待,优先级大小的方法分配消息 */

  85.     if (result != RT_EOK)
  86.     {
  87.         rt_kprintf("init message queue failed.\n");
  88.         return;
  89.     }
  90.                
  91.           rt_thread_t tid = rt_thread_create("spg30_get_data", (void (*)(void *))sgp30_thread,
  92.                            NULL, 2048, RT_THREAD_PRIORITY_MAX / 2 - 1, 10);

  93.     if (tid != RT_NULL)
  94.                 {
  95.         rt_thread_startup(tid);
  96.     }
  97.                  
  98. }
  99. INIT_APP_EXPORT(cat_sgp30);
复制代码
上传线程:
  1. /*
  2. * Tencent is pleased to support the open source community by making IoT Hub available.
  3. * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.

  4. * Licensed under the MIT License (the "License"); you may not use this file except in
  5. * compliance with the License. You may obtain a copy of the License at
  6. * http://opensource.org/licenses/MIT

  7. * Unless required by applicable law or agreed to in writing, software distributed under the License is
  8. * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  9. * either express or implied. See the License for the specific language governing permissions and
  10. * limitations under the License.
  11. *
  12. */

  13. #include "qcloud_iot_export.h"
  14. #include "qcloud_iot_import.h"
  15. #include "lite-utils.h"
  16. #include "data_config.c"

  17. #include "rtthread.h"

  18. #include "hal_data.h"
  19. #include <rtdevice.h>
  20. #define BLUE_LED_PIN    BSP_IO_PORT_04_PIN_03 /* blue LED pins */
  21. #define GREEN_LED_PIN    BSP_IO_PORT_04_PIN_04 /* green LED pins */


  22. #define DATA_TEMPLATE_THREAD_STACK_SIZE 6144
  23. #define YEILD_THREAD_STACK_SIZE     4096

  24. static uint8_t running_state = 0;
  25. #ifdef AUTH_MODE_CERT
  26. static char sg_cert_file[PATH_MAX + 1];      // full path of device cert file
  27. static char sg_key_file[PATH_MAX + 1];       // full path of device key file
  28. #endif

  29. static DeviceInfo sg_devInfo;
  30. static MQTTEventType sg_subscribe_event_result = MQTT_EVENT_UNDEF;
  31. static bool sg_control_msg_arrived = false;
  32. static char sg_data_report_buffer[2048];
  33. static size_t sg_data_report_buffersize = sizeof(sg_data_report_buffer) / sizeof(sg_data_report_buffer[0]);

  34. #ifdef EVENT_POST_ENABLED

  35. #include "events_config.c"
  36. static void update_events_timestamp(sEvent *pEvents, int count)
  37. {
  38.     int i;

  39.     for (i = 0; i < count; i++) {
  40.         if (NULL == (&pEvents[i])) {
  41.             Log_e("null event pointer");
  42.             return;
  43.         }
  44. #ifdef EVENT_TIMESTAMP_USED
  45.         pEvents[i].timestamp = time(NULL); //should be UTC and accurate
  46. #else
  47.         pEvents[i].timestamp = 0;
  48. #endif
  49.     }
  50. }

  51. static void event_post_cb(void *pClient, MQTTMessage *msg)
  52. {
  53.     Log_d("Reply:%.*s", msg->payload_len, msg->payload);
  54. //    IOT_Event_clearFlag(pClient, FLAG_EVENT0 | FLAG_EVENT1 | FLAG_EVENT2);
  55. }

  56. //event check and post
  57. static void eventPostCheck(void *client)
  58. {
  59.     int i;
  60.     int rc;
  61.     uint32_t eflag;
  62.     uint8_t event_count;
  63.     sEvent *pEventList[EVENT_COUNTS];

  64.     eflag = IOT_Event_getFlag(client);
  65.     if ((EVENT_COUNTS > 0 ) && (eflag > 0)) {
  66.         event_count = 0;
  67.         for (i = 0; i < EVENT_COUNTS; i++) {
  68.             if ((eflag & (1 << i))&ALL_EVENTS_MASK) {
  69.                 pEventList[event_count++] = &(g_events[i]);
  70.                 update_events_timestamp(&g_events[i], 1);
  71.                 IOT_Event_clearFlag(client, (1 << i)&ALL_EVENTS_MASK);
  72.             }
  73.         }

  74.         rc = IOT_Post_Event(client, sg_data_report_buffer, sg_data_report_buffersize, \
  75.                             event_count, pEventList, event_post_cb);
  76.         if (rc < 0) {
  77.             Log_e("events post failed: %d", rc);
  78.         }
  79.     }

  80. }

  81. #endif

  82. #ifdef ACTION_ENABLED
  83. #include "action_config.c"

  84. // action : regist action and set the action handle callback, add your aciton logic here
  85. static void OnActionCallback(void *pClient, const char *pClientToken, DeviceAction *pAction)
  86. {
  87.     int i;
  88.     sReplyPara replyPara;

  89.     //do something base on input, just print as an sample
  90.     DeviceProperty *pActionInput = pAction->pInput;
  91.     for (i = 0; i < pAction->input_num; i++) {
  92.         if (JSTRING == pActionInput[i].type) {
  93.             Log_d("Input:[%s], data:[%s]",  pActionInput[i].key, pActionInput[i].data);
  94.             HAL_Free(pActionInput[i].data);
  95.         } else {
  96.             if (JINT32 == pActionInput[i].type) {
  97.                 Log_d("Input:[%s], data:[%d]",  pActionInput[i].key, *((int*)pActionInput[i].data));
  98.             } else if ( JFLOAT == pActionInput[i].type) {
  99.                 Log_d("Input:[%s], data:[%f]",  pActionInput[i].key, *((float*)pActionInput[i].data));
  100.             } else if ( JUINT32 == pActionInput[i].type) {
  101.                 Log_d("Input:[%s], data:[%u]",  pActionInput[i].key, *((uint32_t*)pActionInput[i].data));
  102.             }
  103.         }
  104.     }

  105.     // construct output
  106.     memset((char *)&replyPara, 0, sizeof(sReplyPara));
  107.     replyPara.code = eDEAL_SUCCESS;
  108.     replyPara.timeout_ms = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
  109.     strcpy(replyPara.status_msg, "action execute success!"); //add the message about the action resault


  110.     DeviceProperty *pActionOutnput = pAction->pOutput;
  111.     (void)pActionOutnput; //elimate warning
  112.     //TO DO: add your aciont logic here and set output properties which will be reported by action_reply


  113.     IOT_ACTION_REPLY(pClient, pClientToken, sg_data_report_buffer, sg_data_report_buffersize, pAction, &replyPara);
  114. }

  115. static int _register_data_template_action(void *pTemplate_client)
  116. {
  117.     int i, rc;

  118.     for (i = 0; i < TOTAL_ACTION_COUNTS; i++) {
  119.         rc = IOT_Template_Register_Action(pTemplate_client, &g_actions[i], OnActionCallback);
  120.         if (rc != QCLOUD_RET_SUCCESS) {
  121.             rc = IOT_Template_Destroy(pTemplate_client);
  122.             Log_e("register device data template action failed, err: %d", rc);
  123.             return rc;
  124.         } else {
  125.             Log_i("data template action=%s registered.", g_actions[i].pActionId);
  126.         }
  127.     }

  128.     return QCLOUD_RET_SUCCESS;
  129. }
  130. #endif


  131. static void event_handler(void *pclient, void *handle_context, MQTTEventMsg *msg)
  132. {
  133.     uintptr_t packet_id = (uintptr_t)msg->msg;

  134.     switch (msg->event_type) {
  135.         case MQTT_EVENT_UNDEF:
  136.             Log_i("undefined event occur.");
  137.             break;

  138.         case MQTT_EVENT_DISCONNECT:
  139.             Log_i("MQTT disconnect.");
  140.                                                 rt_pin_write(BLUE_LED_PIN, PIN_LOW);
  141.             break;

  142.         case MQTT_EVENT_RECONNECT:
  143.             Log_i("MQTT reconnect.");
  144.                                                 rt_pin_write(BLUE_LED_PIN, PIN_HIGH);
  145.             break;

  146.         case MQTT_EVENT_SUBCRIBE_SUCCESS:
  147.             sg_subscribe_event_result = msg->event_type;
  148.             Log_i("subscribe success, packet-id=%u", packet_id);
  149.                                 rt_pin_write(GREEN_LED_PIN, PIN_HIGH);
  150.             break;

  151.         case MQTT_EVENT_SUBCRIBE_TIMEOUT:
  152.             sg_subscribe_event_result = msg->event_type;
  153.             Log_i("subscribe wait ack timeout, packet-id=%u", packet_id);
  154.             break;

  155.         case MQTT_EVENT_SUBCRIBE_NACK:
  156.             sg_subscribe_event_result = msg->event_type;
  157.             Log_i("subscribe nack, packet-id=%u", packet_id);
  158.             break;

  159.         case MQTT_EVENT_PUBLISH_SUCCESS:
  160.             Log_i("publish success, packet-id=%u", (unsigned int)packet_id);
  161.                                 rt_pin_write(GREEN_LED_PIN, PIN_LOW);
  162.             break;

  163.         case MQTT_EVENT_PUBLISH_TIMEOUT:
  164.             Log_i("publish timeout, packet-id=%u", (unsigned int)packet_id);
  165.             break;

  166.         case MQTT_EVENT_PUBLISH_NACK:
  167.             Log_i("publish nack, packet-id=%u", (unsigned int)packet_id);
  168.             break;
  169.         default:
  170.             Log_i("Should NOT arrive here.");
  171.             break;
  172.     }
  173. }

  174. /*add user init code, like sensor init*/
  175. static void _usr_init(void)
  176. {
  177.     Log_d("add your init code here");
  178. }

  179. // Setup MQTT construct parameters
  180. static int _setup_connect_init_params(TemplateInitParams* initParams)
  181. {
  182.     int ret;

  183.     ret = HAL_GetDevInfo((void *)&sg_devInfo);
  184.     if (QCLOUD_RET_SUCCESS != ret) {
  185.         return ret;
  186.     }

  187.     initParams->device_name = sg_devInfo.device_name;
  188.     initParams->product_id = sg_devInfo.product_id;

  189. #ifdef AUTH_MODE_CERT
  190.     /* TLS with certs*/
  191.     char certs_dir[PATH_MAX + 1] = "certs";
  192.     char current_path[PATH_MAX + 1];
  193.     char *cwd = getcwd(current_path, sizeof(current_path));
  194.     if (cwd == NULL) {
  195.         Log_e("getcwd return NULL");
  196.         return QCLOUD_ERR_FAILURE;
  197.     }
  198.     sprintf(sg_cert_file, "%s/%s/%s", current_path, certs_dir, sg_devInfo.dev_cert_file_name);
  199.     sprintf(sg_key_file, "%s/%s/%s", current_path, certs_dir, sg_devInfo.dev_key_file_name);

  200.     initParams->cert_file = sg_cert_file;
  201.     initParams->key_file = sg_key_file;
  202. #else
  203.     initParams->device_secret = sg_devInfo.device_secret;
  204. #endif

  205.     initParams->command_timeout = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
  206.     initParams->keep_alive_interval_ms = QCLOUD_IOT_MQTT_KEEP_ALIVE_INTERNAL;
  207.     initParams->auto_connect_enable = 1;
  208.     initParams->event_handle.h_fp = event_handler;

  209.     return QCLOUD_RET_SUCCESS;
  210. }

  211. static void OnControlMsgCallback(void *pClient, const char *pJsonValueBuffer, uint32_t valueLength, DeviceProperty *pProperty)
  212. {
  213.     int i = 0;

  214.     for (i = 0; i < TOTAL_PROPERTY_COUNT; i++) {
  215.         /* handle self defined string/json here. Other properties are dealed in _handle_delta()*/
  216.         if (strcmp(sg_DataTemplate[i].data_property.key, pProperty->key) == 0) {
  217.             sg_DataTemplate[i].state = eCHANGED;
  218.             Log_i("Property=%s changed", pProperty->key);
  219.             sg_control_msg_arrived = true;
  220.             return;
  221.         }
  222.     }

  223.     Log_e("Property=%s changed no match", pProperty->key);
  224. }

  225. static void OnReportReplyCallback(void *pClient, Method method, ReplyAck replyAck, const char *pJsonDocument, void *pUserdata)
  226. {
  227.     Log_i("recv report reply response, reply ack: %d", replyAck);
  228. }

  229. // register data template properties
  230. static int _register_data_template_property(void *pTemplate_client)
  231. {
  232.     int i, rc;

  233.     for (i = 0; i < TOTAL_PROPERTY_COUNT; i++) {
  234.         rc = IOT_Template_Register_Property(pTemplate_client, &sg_DataTemplate[i].data_property, OnControlMsgCallback);
  235.         if (rc != QCLOUD_RET_SUCCESS) {
  236.             rc = IOT_Template_Destroy(pTemplate_client);
  237.             Log_e("register device data template property failed, err: %d", rc);
  238.             return rc;
  239.         } else {
  240.             Log_i("data template property=%s registered.", sg_DataTemplate[i].data_property.key);
  241.         }
  242.     }

  243.     return QCLOUD_RET_SUCCESS;
  244. }

  245. // when control msg received, data_template's properties has been parsed in pData
  246. // you should add your logic how to use pData
  247. void deal_down_stream_user_logic(void *client, ProductDataDefine   * pData)
  248. {
  249.     Log_d("someting about your own product logic wait to be done");
  250.         
  251.            if(pData->m_fan)
  252.                 {
  253.         Log_d( "=====fan on====");
  254.     }
  255.                 else
  256.                 {
  257.                         Log_d( "=====fan off====");
  258.     }



  259. #ifdef EVENT_POST_ENABLED
  260.     //IOT_Event_setFlag(client, FLAG_EVENT0);  //set the events flag when the evnts your defined occured, see events_config.c
  261. #endif

  262. }

  263. /*get local property data, like sensor data*/
  264. static void _refresh_local_property(void)
  265. {
  266.     //add your local property refresh logic
  267.         /*用户根据业务修改属性值,然后设置属性状态为eCHANGED*/
  268.         //sg_ProductData.m_temperature++;
  269.         //sg_DataTemplate[0].state = eCHANGED;
  270. }

  271. /*find propery need report*/
  272. static int find_wait_report_property(DeviceProperty *pReportDataList[])
  273. {
  274.     int i, j;

  275.     for (i = 0, j = 0; i < TOTAL_PROPERTY_COUNT; i++) {
  276.         if (eCHANGED == sg_DataTemplate[i].state) {
  277.             pReportDataList[j++] = &(sg_DataTemplate[i].data_property);
  278.             sg_DataTemplate[i].state = eNOCHANGE;
  279.         }
  280.     }

  281.     return j;
  282. }

  283. // demo for up-stream
  284. // add changed properties to pReportDataList, then the changed properties would be reported
  285. // you should add your own logic for how to get the changed properties
  286. int deal_up_stream_user_logic(DeviceProperty *pReportDataList[], int *pCount)
  287. {
  288.     //refresh local property
  289.     _refresh_local_property();

  290.     /*find propery need report*/
  291.     *pCount = find_wait_report_property(pReportDataList);

  292.     return (*pCount > 0) ? QCLOUD_RET_SUCCESS : QCLOUD_ERR_FAILURE;
  293. }

  294. /*You should get the real info for your device, here just for example*/
  295. static int _get_sys_info(void *handle, char *pJsonDoc, size_t sizeOfBuffer)
  296. {
  297.     /*platform info has at least one of module_hardinfo/module_softinfo/fw_ver property*/
  298.     DeviceProperty plat_info[] = {
  299.         {.key = "module_hardinfo", .type = TYPE_TEMPLATE_STRING, .data = "ESP8266"},
  300.         {.key = "module_softinfo", .type = TYPE_TEMPLATE_STRING, .data = "V1.0"},
  301.         {.key = "fw_ver", .type = TYPE_TEMPLATE_STRING, .data = QCLOUD_IOT_DEVICE_SDK_VERSION},
  302.         {.key = "imei", .type = TYPE_TEMPLATE_STRING, .data = "11-22-33-44"},
  303.         {.key = "lat", .type = TYPE_TEMPLATE_STRING, .data = "22.546015"},
  304.         {.key = "lon", .type = TYPE_TEMPLATE_STRING, .data = "113.941125"},
  305.         {NULL, NULL, 0}  //end
  306.     };

  307.     /*self define info*/
  308.     DeviceProperty self_info[] = {
  309.         {.key = "append_info", .type = TYPE_TEMPLATE_STRING, .data = "your self define info"},
  310.         {NULL, NULL, 0}  //end
  311.     };

  312.     return IOT_Template_JSON_ConstructSysInfo(handle, pJsonDoc, sizeOfBuffer, plat_info, self_info);
  313. }

  314. static int data_template_thread(void)
  315. {
  316.     int rc;
  317.     sReplyPara replyPara;
  318.     DeviceProperty *pReportDataList[TOTAL_PROPERTY_COUNT];
  319.     int ReportCont;

  320.     //init log level
  321.     IOT_Log_Set_Level(eLOG_DEBUG);

  322.     //init connection
  323.     TemplateInitParams init_params = DEFAULT_TEMPLATE_INIT_PARAMS;
  324.     rc = _setup_connect_init_params(&init_params);
  325.     if (rc != QCLOUD_RET_SUCCESS) {
  326.         Log_e("init params err,rc=%d", rc);
  327.         return rc;
  328.     }

  329.     void *client = IOT_Template_Construct(&init_params, NULL);
  330.     if (client != NULL) {
  331.         Log_i("Cloud Device Construct Success");
  332.     } else {
  333.         Log_e("Cloud Device Construct Failed");
  334.         return QCLOUD_ERR_FAILURE;
  335.     }

  336. #ifdef MULTITHREAD_ENABLED
  337.     if (QCLOUD_RET_SUCCESS != IOT_Template_Start_Yield_Thread(client)) {
  338.         Log_e("start template yield thread fail");
  339.         goto exit;
  340.     }
  341. #endif

  342.     //user init
  343.     _usr_init();

  344.     //init data template
  345.     _init_data_template();

  346.     //register data template propertys here
  347.     rc = _register_data_template_property(client);
  348.     if (rc == QCLOUD_RET_SUCCESS) {
  349.         Log_i("Register data template propertys Success");
  350.     } else {
  351.         Log_e("Register data template propertys Failed: %d", rc);
  352.         goto exit;
  353.     }

  354.     //register data template actions here
  355. #ifdef ACTION_ENABLED
  356.     rc = _register_data_template_action(client);
  357.     if (rc == QCLOUD_RET_SUCCESS) {
  358.         Log_i("Register data template actions Success");
  359.     } else {
  360.         Log_e("Register data template actions Failed: %d", rc);
  361.         goto exit;
  362.     }
  363. #endif

  364.     //report device info, then you can manager your product by these info, like position
  365.     rc = _get_sys_info(client, sg_data_report_buffer, sg_data_report_buffersize);
  366.     if (QCLOUD_RET_SUCCESS == rc) {
  367.         rc = IOT_Template_Report_SysInfo_Sync(client, sg_data_report_buffer, sg_data_report_buffersize, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
  368.         if (rc != QCLOUD_RET_SUCCESS) {
  369.             Log_e("Report system info fail, err: %d", rc);
  370.         }
  371.     } else {
  372.         Log_e("Get system info fail, err: %d", rc);
  373.     }

  374.     //get the property changed during offline
  375.     rc = IOT_Template_GetStatus_sync(client, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
  376.     if (rc != QCLOUD_RET_SUCCESS) {
  377.         Log_e("Get data status fail, err: %d", rc);
  378.     } else {
  379.         Log_d("Get data status success");
  380.     }

  381.     running_state = 1;

  382.     while (IOT_Template_IsConnected(client) || rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT
  383.            || rc == QCLOUD_RET_MQTT_RECONNECTED || QCLOUD_RET_SUCCESS == rc) {

  384.         if(0 == running_state) {
  385.             break;
  386.         }

  387. #ifndef MULTITHREAD_ENABLED
  388.         rc = IOT_Template_Yield(client, 200);
  389.         if (rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT) {
  390.             HAL_SleepMs(1000);
  391.             continue;
  392.         } else if (rc != QCLOUD_RET_SUCCESS) {
  393.             Log_e("Exit loop caused of errCode: %d", rc);
  394.         }
  395. #endif

  396.         /* handle control msg from server */
  397.         if (sg_control_msg_arrived) {

  398.             deal_down_stream_user_logic(client, &sg_ProductData);

  399.             /* control msg should reply, otherwise server treat device didn't receive and retain the msg which would be get by  get status*/
  400.             memset((char *)&replyPara, 0, sizeof(sReplyPara));
  401.             replyPara.code = eDEAL_SUCCESS;
  402.             replyPara.timeout_ms = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
  403.             replyPara.status_msg[0] = '\0';         //add extra info to replyPara.status_msg when error occured

  404.             rc = IOT_Template_ControlReply(client, sg_data_report_buffer, sg_data_report_buffersize, &replyPara);
  405.             if (rc == QCLOUD_RET_SUCCESS) {
  406.                 Log_d("Contol msg reply success");
  407.                 sg_control_msg_arrived = false;
  408.             } else {
  409.                 Log_e("Contol msg reply failed, err: %d", rc);
  410.             }
  411.         }   else {
  412.             Log_d("No control msg received...");
  413.         }

  414.         /*report msg to server*/
  415.         /*report the lastest properties's status*/
  416.         if (QCLOUD_RET_SUCCESS == deal_up_stream_user_logic(pReportDataList, &ReportCont)) {
  417.             rc = IOT_Template_JSON_ConstructReportArray(client, sg_data_report_buffer, sg_data_report_buffersize, ReportCont, pReportDataList);
  418.             if (rc == QCLOUD_RET_SUCCESS) {
  419.                 rc = IOT_Template_Report(client, sg_data_report_buffer, sg_data_report_buffersize,
  420.                                          OnReportReplyCallback, NULL, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
  421.                 if (rc == QCLOUD_RET_SUCCESS) {
  422.                     Log_i("data template reporte success");
  423.                 } else {
  424.                     Log_e("data template reporte failed, err: %d", rc);
  425.                 }
  426.             } else {
  427.                 Log_e("construct reporte data failed, err: %d", rc);
  428.             }

  429.         } else {
  430.             //Log_d("no data need to be reported or someting goes wrong");
  431.         }


  432. #ifdef EVENT_POST_ENABLED
  433.         eventPostCheck(client);
  434. #endif

  435.         HAL_SleepMs(3000);
  436.     }

  437. exit:

  438. #ifdef MULTITHREAD_ENABLED
  439.     IOT_Template_Stop_Yield_Thread(client);
  440. #endif
  441.     rc = IOT_Template_Destroy(client);
  442.     running_state = 0;

  443.     return rc;
  444. }

  445. extern struct rt_messagequeue sgp30_mq;

  446. static int recv_spg30_data_thread(void)
  447. {
  448.         typedef struct
  449. {
  450. int tvoc;
  451. int co2;
  452. }sgp30_msg_t;
  453. sgp30_msg_t msg;
  454. while (1)
  455.     {
  456.         /* 从消息队列中接收消息 */
  457.         if (rt_mq_recv(&sgp30_mq, &msg, sizeof(sgp30_msg_t), RT_WAITING_FOREVER) == RT_EOK)
  458.         {
  459.             rt_kprintf("thread1: recv msg from msg queue, the content:tvoc=%d co2=%d\n", msg.tvoc,msg.co2);
  460.                                                 sg_ProductData.m_tvoc = msg.tvoc;
  461.                                                 sg_ProductData.m_co2 = msg.co2;
  462.                   sg_DataTemplate[2].state = eCHANGED;
  463.                                           sg_DataTemplate[5].state = eCHANGED;
  464.         }
  465.         rt_thread_mdelay(10);
  466.     }
  467. }

  468. static int tc_data_template_example(void)
  469. {
  470.         rt_thread_mdelay(5000);
  471.     rt_thread_t tid;
  472.     int stack_size = DATA_TEMPLATE_THREAD_STACK_SIZE;

  473.                 int argc=2;
  474.          char *argv[3]={"none","start","stop"};
  475.     //init log level
  476.     IOT_Log_Set_Level(eLOG_DEBUG);
  477.     if (2 == argc) {
  478.         if (!strcmp("start", argv[1])) {
  479.             if (1 == running_state) {
  480.                 Log_d("tc_data_template_example is already running\n");
  481.                 return 0;
  482.             }
  483.         } else if (!strcmp("stop", argv[1])) {
  484.             if (0 == running_state) {
  485.                 Log_d("tc_data_template_example is already stopped\n");
  486.                 return 0;
  487.             }
  488.             running_state = 0;
  489.             return 0;
  490.         } else {
  491.             Log_d("Usage: tc_data_template_example start/stop");
  492.             return 0;
  493.         }
  494.     } else {
  495.         Log_e("Para err, usage: tc_data_template_example start/stop");
  496.         return 0;
  497.     }

  498.     tid = rt_thread_create("data_template", (void (*)(void *))data_template_thread,
  499.                            NULL, stack_size, RT_THREAD_PRIORITY_MAX / 2 - 2, 10);

  500.     if (tid != RT_NULL) {
  501.         rt_thread_startup(tid);
  502.     }
  503.                
  504.                 tid = rt_thread_create("get_data", (void (*)(void *))recv_spg30_data_thread,
  505.                            NULL, stack_size, RT_THREAD_PRIORITY_MAX / 2 - 3, 10);
  506.     if (tid != RT_NULL) {
  507.         rt_thread_startup(tid);
  508.     }

  509.     return 0;
  510. }

  511. INIT_APP_EXPORT(tc_data_template_example);
复制代码

程序运行正常的情况下,在云平台调试界面就可以看到设备发送的数据,进入腾讯连连小程序连接设备后也能看到之前设计的小程序界面。
IMG_20230730_202843.jpg

bb.png
qq.png

Screenshot_2023-07-30-20-28-30-692_com.tencent.mm.jpg

最后附上代码:
R6M5.part1.rar (10 MB, 下载次数: 6)
R6M5.part2.rar (5.3 MB, 下载次数: 5)
6、活动总结
    很幸运能够参加这次比赛,再次感谢火哥和瑞萨的活动支持,通过活动学习到了瑞萨单片机图形化非常简单傻瓜化的开发方式,火哥6M5开发板资料十分丰富。
由于本人能力水平不足,文章写的有误或者不清楚的地方敬请见谅,可在评论区留言以改正。


回复

使用道具 举报

发表于 2023-8-18 19:44:19 | 显示全部楼层
腾讯连连是不是要备案了
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-5-2 09:00 , Processed in 0.045605 second(s), 28 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表