一、概述
物联网( IoT ,Internet of things )即“万物相连的互联网”,是互联网基础上的延伸和扩展的网络,将各种信息传感设备与互联网结合起来而形成的一个巨大网络,实现在任何时间、任何地点,人、机、物的互联互通。把任何物品与互联网相连接,进行信息交换和通信,以实现对物品的智能化识别、定位、跟踪、监控和管理的一种网络。
随着多种技术的交互与融合,物联网的发展越来越迅速,物联网产品也变得越来越灵活多样。可以说,物联网是我们的生活产生了质的变化,特别是对于智能家居、智慧农业等,IoT技术的引入为环境的检测以及安全提供了巨大的帮助。
本文描述了一个基于TencentOS Tiny的智能环境检测系统,利用云平台与终端程序,使用户能够随时查看环境数据,并可以远程控制实现相关操作。
二、方案设计
本项目实现了一个基于TencentOS Tiny的智能环境检测系统,以腾讯云IoT Explorer平台为中间媒介,连接用户和设备,使得用户能够接收设备上报的数据,设备能够接收用户下发的命令。
该系统主要包括三部分:
- 设备端:利用EVB_MX开发板、ESP8266 WiFi通信扩展板、E53_IA1传感器扩展版以及TencentOS Tiny IoT操作系统实现。
- 云端:利用腾讯云IoT Explorer平台,接收设备上报信息和下发命令,建立用户与设备的连接。
- 用户端:实现一个微信小程序,使得用户可以直接通过小程序查看设备实时数据以及下发指令。
2.1 设备端
2.1.1 硬件部分
(1)主控制板
本次方案采用的是腾讯物联网操作系统TencentOS tiny团队联合南京厚德物联网有限公司设计的一款物联网评估版EVB_MX,该板使用STM32L431RCT6芯片,具有256K Flash和64KB SRAM,该开发板支持E53系列传感器扩展版和WiFi、LoRaWAN、NB-IoT、2G等通信方式。
本方案利用主控制板EVB_MX、E53_IA1传感器扩展板以及使用ESP8266模块进行WiFi通信。
(2)E53_IA1
E53_IA1扩展板采用了E53标准接口,包含了一个补光灯,一个BH1750光照强度传感器,一个小的电机,一个温湿度传感器SHT30,一个其中补光灯和贴片电机使用普通GPIO控制,BH1750和SHT30使用IIC接口通信。
(3)ESP8266
方案采用ESP8266实现设备与云平台之间通过WiFi进行通信,ESP8266 在较小尺寸封装中集成了业界领先的 Tensilica L106 超低功耗 32 位微型 MCU ,带有 16 位精简模式,主频支持 80 MHz 和160 MHz ,支持 RTOS ,集成 Wi Fi MAC/ BB/RF/PA/LNA ,板载天线。该模块支持标准的IEEE802.11 b/g/n 协议,完整的 TCP/IP 协议栈。用户可以使用该模块为现有的设备添加联网功能,也可以构建独立的网络控制器。
本文主要利用ESP8266使得主控制板芯片能够通过MQTT协议实现与云平台的通信。
(4)OLED显示屏
OLED液晶显示模块用来向用户显示系统状态、参数或者要输入系统的功能。本方案中,我们可以利用OLED显示屏来显示灯光和电机的状态,使得用户能够更清晰直接的获得其状态。此外,在某些时候,我们也可以利用OLED显示屏来显示相关信息,以方便对程序进行调试。
2.1.2 设备收集传感器数据
本方案利用E53_IA1传感器扩展版来实现对周围环境数据的监测和收集,E53_IA1包含一个补光灯、一个电机、一个光强传感器和一个温湿度传感器。
将其映射到实际应用中,我们可以利用光强传感器来收集环境中的光照强度,以此判断窗帘是否打开/关闭,或者当前是晴天还是阴天等等;利用温湿度传感器,我们可以收集环境中的温度和湿度数据,可以判断是否由意外事件发生(例如火灾时温度会骤变高,在水管破裂时湿度可能会变高等等),通过这些环境数据,用户可以采取进一步的操作命令;利用补光灯,我们可以在室内较暗、光强较低时,下发指令或使设备自动执行开灯操作;利用电机,我们可以将其当作一个电器(空调、电风扇等等),在室内温度较高或者其他状况时,下发指令或使设备自动执行打开/关闭电机操作。
借鉴官方提供的类似教程,我们可以很快速的实现上云和数据传输。下面是对TencentOS tiny源码进行修改以实现对传感器数据的收集和执行相关操作。
首先需要对传感器和相关变量值进行初始化,我们通过_init_data_template实现。
代码语言:javascript复制/*
_init_data_template主要用于初始化传感器数据。
根据上述功能描述,本方案包含5个数据属性:
电机开关motor_power_switch、电灯开关light_power_switch、光强luminance、温度temperature、湿度humidity
*/
static void _init_data_template(void)
{
Init_E53_IA1(); //初始化E53_IA1模块
E53_IA1_Read_Data(); //读取传感器数据
sg_ProductData.m_motor_power_switch = 0;
sg_DataTemplate[0].data_property.data = &sg_ProductData.m_motor_power_switch;
sg_DataTemplate[0].data_property.key = "motor_power_switch";
sg_DataTemplate[0].data_property.type = TYPE_TEMPLATE_BOOL;
sg_ProductData.m_light_power_switch = 0;
sg_DataTemplate[1].data_property.data = &sg_ProductData.m_light_power_switch;
sg_DataTemplate[1].data_property.key = "light_power_switch";
sg_DataTemplate[1].data_property.type = TYPE_TEMPLATE_BOOL;
sg_ProductData.m_luminance = (int)E53_IA1_Data.Lux;
sg_DataTemplate[2].data_property.data = &sg_ProductData.m_luminance;
sg_DataTemplate[2].data_property.key = "luminance";
sg_DataTemplate[2].data_property.type = TYPE_TEMPLATE_INT;
sg_ProductData.m_temperature = (int)E53_IA1_Data.Temperature;
sg_DataTemplate[3].data_property.data = &sg_ProductData.m_temperature;
sg_DataTemplate[3].data_property.key = "temperature";
sg_DataTemplate[3].data_property.type = TYPE_TEMPLATE_INT;
sg_ProductData.m_humidity = (int)E53_IA1_Data.Humidity;
sg_DataTemplate[4].data_property.data = &sg_ProductData.m_humidity;
sg_DataTemplate[4].data_property.key = "humidity";
sg_DataTemplate[4].data_property.type = TYPE_TEMPLATE_INT;
};
接下来是对电机和电灯的操作,这里我们只给出打开电机操作以及OLED显示,其余类似。
代码语言:javascript复制__weak void OLED_Clear(void) //清屏操作
{
printf("OLED Clearn");
}
__weak void OLED_ShowString(int x, int y, uint8_t *str, int bold) //显示字符串
{
printf("OLED ShowString: %sn", (char *)str);
}
static void motor_power_on(void) //打开电机操作
{
char *info = "motor on ";
//OLED_Clear();
OLED_ShowString(0, 0, (uint8_t *)info, 16); //OLED显示
HAL_GPIO_WritePin(IA1_Motor_GPIO_Port, IA1_Motor_Pin, GPIO_PIN_SET); //写入引脚,打开电机
}
2.1.3 设备通信实现
本方案利用ESP8266模块,通过WiFi实现设备与云端通信,修改TencentOS tiny源码中的qcloud_iot_hub_sdk_explorer.c文件中的WiFi名称和密码。
代码语言:javascript复制#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("wifi_name", "password");
#endif
与云端的通信是通过MQTT协议进行的,这里我们可以直接使用qcloud-iot-explorer-sdk中相关函数API来实现MQTT的初始化和数据传输,无需自己实现。
此外,我们还需要将在云平台获得到的产品和设备信息写入到程序中,以通过MQTT连接认证,代码在HAL_Device_tencentos_tiny.c中。
代码语言:javascript复制#ifdef DEBUG_DEV_INFO_USED
/* product Id */
static char sg_product_id[MAX_SIZE_OF_PRODUCT_ID 1] = "PRODUCT_ID";
/* device name */
static char sg_device_name[MAX_SIZE_OF_DEVICE_NAME 1] = "DEVICE_NAME";
#ifdef DEV_DYN_REG_ENABLED
/* product secret for device dynamic Registration */
static char sg_product_secret[MAX_SIZE_OF_PRODUCT_SECRET 1] = "YOUR_PRODUCT_SECRET";
#endif
#ifdef AUTH_MODE_CERT
/* public cert file name of certificate device */
static char sg_device_cert_file_name[MAX_SIZE_OF_DEVICE_CERT_FILE_NAME 1] = "YOUR_DEVICE_NAME_cert.crt";
/* private key file name of certificate device */
static char sg_device_privatekey_file_name[MAX_SIZE_OF_DEVICE_SECRET_FILE_NAME 1] = "YOUR_DEVICE_NAME_private.key";
#else
/* device secret of PSK device */
static char sg_device_secret[MAX_SIZE_OF_DEVICE_SECRET 1] = "DEVICE_SECRET";
#endif
2.1.3 设备上报数据实现
本方案中设备需要向云平台上报的传感器数据包含上述5个属性:电机状态(开/关)、电灯状态、光强、温度和湿度。
代码语言:javascript复制// 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;
}
2.1.4 设备接收下发指令
本方案中云平台(用户)能够向设备下发的指令包括开/关电机、开/关电灯。
代码语言:javascript复制//用户下发指令处理逻辑
void deal_down_stream_user_logic(void *client, ProductDataDefine * pData)
{
Log_d("someting about your own product logic wait to be done");
if (sg_ProductData.m_motor_power_switch == 1) {
motor_power_on();
} else {
motor_power_off();
}
if (sg_ProductData.m_light_power_switch == 1) {
light_power_on();
} else {
light_power_off();
}
}
//主处理函数
...{
...
/* 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] = '