Error[8]: Undefined offset: 2125, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

1. 设计需求、硬件环境介绍 1.1 项目背景

近几年,物联网、智能家居、AI人工智能技术发送非常迅速。在物联网技术的支撑下,如今农业逐渐走向现代化,自动化、现在智能化的农业生产成为了主流。告别“刀耕火种”的传统农业后,现代农业也正在向智慧型转变,当前智慧农业模式已经深入到农业生产的各个环节,灌溉、施肥、植保等细分领域都将与物联网、信息技术等先进科技相结合,效率、效果也将得到大大提高。

要知道,所谓的“智慧农业”就是充分应用现代信息技术成果,集成应用计算机技术与网络技术、物联网技术、无线通信技术以及专家智慧与知识等,实现农业可视化远程诊断、远程控制、灾变预警等智能管理。那么融入物联网的智慧农业的有以下几个优点:

1、低成本化

众所周知,目前想要购买一套全面的智慧农业设备的成本都较高,这是普通农户难以承受的,因此,想要实现全面智慧农业,那么低成本的智慧农业设备将成为智慧农业趋势之一。

2、 *** 作简单化 智慧农业的根本是服务于农业、服务于农户,所以想要做到让农户更快地与智慧农业接轨就必须要把系统做得易 *** 作、易学。要知道,当前我国农民普遍文化程度较低,只有将 *** 作简单化才能够让每个农民都能熟练 *** 作。

智慧农业也是一个大范围,比如: 智慧鱼塘、智慧大棚、智慧园林、城市绿化、智能果园等等都属于智慧农业的范围。

有了智能设备的加持:可以实现自动浇水灌溉、实时检测土壤养分、水分、环境温度、自动补光等一系列联动 *** 作。

本篇文章就利用华为云IOT物联网平台实践搭建一个智慧农业智慧大脑,设备平台采用小熊开发板,搭载的CPU是意法半导体的STM32L431芯片,这是意法半导体推出的低功耗芯片;配合外部的一些专业传感器,能够获取空气中的温湿度数据,光照度数据等,根据种植区的空气温湿度数据,判断是否进行灌溉。

1.2 实现功能

本项目是利用意法半导体的STM32L431+ESP8266 WIFI ,配合华为云物联网平台服务器,组建一个智慧农业控制系统,结合外部传感器采集的数据,并利用这些数据判断是否进行灌溉,补光等信息提示。

考虑到以学习、实践为目的,当前项目采用了ESP8266无线WIFI网卡作为联网设备,ESP8266价钱便宜,支持串口编程,有标准的一套AT资料,资料多,作为学习而言,非常适合。可以通过对ESP8266的编程实验,了解TCP、MQTT网络编程相关知识点。

当前项目主要分为六个功能模块,分别是:基础系统模块、温度采集模块、湿度采集模块、光照采集模块、无线传感器网络模块、OLED显示屏模块。

(1)基础系统模块:进行各个数据的接收与转发,控制扫水作业是否进行,浇水作业是采用板载的电机模拟

(2)温度采集模块:采集监测区域的温度数据,传输到微控制器

(3)湿度采集模块:采集监测区域的湿度数据,传输到微控制器

(4)光照采集模块:采集监测区域的光照数据,传输到微控制器

(5)无线传感器网络模块:数据上传至云平台,数据下发交互等

(6)LCD显示屏模块:实时显示所监测到的各项数据

小熊开发板的扩展板上自带了光敏传感器、温湿度传感器、直流电机模块,可以很方便的实现上面的这些功能需求。

本项目设备的源代码里,连接华为云的MQTT协议是按照MQTT的官方中文手册编写的,不依赖任何外部SDK,不依赖ESP8266设备,只要能联网的设备都可以连接华为云IOT,非常适合移植到其他单片机平台;不管是采用51,STM32F1系列,都可以直接参考代码移植。

华为云物联网平台提供了API接口,可以通过API开发配套的上位机,方便实现数据查看,手动灌溉等 *** 作。

提供的API除了可以查询设备属性信息之外,还可以创建产品、设备、对开发上位机来讲非常方便,可以开发出从底层设备到云端服务器、再到应用APP软件,完成3层数据交互。

下面是开发的上位机APP运行效果。

当前文章主要完成3个任务的实践:

(1)云端产品的创建、设备的创建

(2)设备上云,完成服务器登录、数据上传

(3)手机APP、电脑上位机软件的开发,可以通过云端API接口与设备、服务器之前通讯

1.3 设备实物图

目前联网的设备采用的ESP8266(手上没有现成的NBIOT模块,暂时使用ESP8266代替,核心原理是一样的),正常项目里会使用NBIOT模块联网作为数据传输源。

小熊开发板的设备相关实物图如下:

2. 创建IOT服务器端产品

需要先创建产品、在产品下再创建设备。产品是一个大框架,产品下的设备可以有很多,在应用层,可以通过华为云平台提供的API创建设备,删除设备,查询设备属性,在做产品时,软件端可以做一个设备注册的引导界面,完成产品下的设备注册,再将数据传递给设备端,这个过程叫“配网“,具体逻辑需要配合设备端完成。最终完成自动化设备创建,注册,上线等 *** 作。

下面先介绍如何手动创建产品,创建设备,了解创建产品创建设备的过程中需要填充什么参数,理解之后,再使用API时才更加理解参数含义。

2.1 创建产品

直接打开物联网产品页面: https://www.huaweicloud.com/product/iothub.html

打开产品页面,选择右上角创建产品。

根据自己情况填写信息。就是填写自己产品的一些参数信息。

创建成功后打开产品详情页面,拉到最下面,点击创建自定义模型文件。

这里创建模型文件主要就是为了MQTT客户端能够正确的上传传感器数据上来,每个传感器设置一个属性,这个属性就是表示了传感器的数据值类型。

比如: 先添加一个电机,这个电机就是浇水电机,能上报开关状态,云端也能下发命令控制电机,所以需要添加属性和下发的命令。

添加属性:

添加命令: 因为电机需要云端远程控制。

接下来就创建温度、湿度、光照度传感器的属性,这些传感器只是向云端上传数据,不需要下发指令控制,选择只读就可以了,电机要先实现远程浇灌控制,属性就选择读写。

创建完毕效果,一共有4个属性,电机、温度、湿度、光强度:

2.2 创建设备

选择设备页面,注册设备。

创建后保持设备密匙等信息,接下来登录服务器时,生成MQTT账号密匙需要用到这些参数。

当前创建的设备信息如下:

 {
     "device_id": "61cd1d97078a93029b84e7b6_1126626497",
     "secret": "1126626497"
 }
2.3 生成MQTT登录账号信息

官微提供的在线小工具: https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/

按照提示填入数据,生成,非常方便。

当前生成的信息如下:

 ClientId 61cd1d97078a93029b84e7b6_1126626497_0_0_2021123003
 Username 61cd1d97078a93029b84e7b6_1126626497
 Password b219f3a0099fa0284a2671a5c699b67a7cf6d5f7355d9ee8190011f3b64f71b5
3. 使用MQTT客户端模拟测试

为了验证服务器配置是否OK,先使用MQTT客户端软件进行连接测试。

3.1 华为云IOT服务器地址与端口

 端口: 1883
 域名: a161a58a78.iot-mqtts.cn-north-4.myhuaweicloud.com
 IP地址: 121.36.42.100
3.2 订阅主题

在产品页面,可以看到主题管理页面,能看到当前设备可以订阅的主题有哪些。

一般订阅下发的数据:

 格式: $oc/devices/{device_id}/sys/messages/down
 //订阅主题: 平台下发消息给设备
 $oc/devices/61cd1d97078a93029b84e7b6_1126626497/sys/messages/down
3.3 上报主题数据

官方文档介绍: https://support.huaweicloud.com/devg-iothub/iot_01_2127.html

服务ID,属性ID在产品页面查看,2.1小节创建产品里就讲了这个属性的作用。

每次可以单个属性上报,也可以一起上报。

 格式: $oc/devices/{device_id}/sys/properties/report
 //设备上报主题请求
 $oc/devices/61cd1d97078a93029b84e7b6_1126626497/sys/properties/report
 
 //上报的数据格式如下
     
 //电机开状态反馈
 {"services": [{"service_id": "motor","properties":{"motor":1}}]}
 
 //电机关状态反馈
 {"services": [{"service_id": "motor","properties":{"motor":0}}]}
 
 //温度上报
 {"services": [{"service_id": "motor","properties":{"SHT30_H":14}}]}
 
 //湿度上报
 {"services": [{"service_id": "motor","properties":{"SHT30_L":70}}]}
 
 //光照强度上报
 {"services": [{"service_id": "motor","properties":{"BH1750":80}}]}
 
 //也可以一起上报
 {"services": [{"service_id": "motor","properties":{"motor":1}},{"service_id": "motor","properties":{"SHT30_H":15}},{"service_id": "motor","properties":{"SHT30_L":70}},{"service_id": "motor","properties":{"BH1750":80}}]}
3.4 登录服务器

按照软件提示,填入相关数据即可。

如需要也需要使用和我一样的同款软件,打开百度搜索MQTT客户端_v2.4(协议3.1.1).exe 即可找到下载地址。

发送数据后查看云端,已经登录成功,数据已经上传成功。

3.5 下发命令

电机设备支持读写,支持下发命令,在设备页面测试。

点击确定之后,参看MQTT客户端软件,已经收到了下发的数据。

 len:174,Data:l$oc/devices/61cd1d97078a93029b84e7b6_1126626497/sys/commands/request_id=390ce15d-6e69-4021-b83a-5e953eea874c{"paras":{"motor":1},"service_id":"motor","command_name":"motor"}
4. 设备端上华为云IOT 4.1 安装keil软件

MCU采用的STM32芯片,设备端代码编写开发就采用的keil5。

keil5安装包下载地址: http://www.myir-tech.com/download.asp

安装keil时,软件要放在英文目录下,电脑的用户名必须是英文,否则会出现一些奇怪问题。

安装过程中,根据提示下一步下一步点击即可。

4.2 编写代码

工程代码:

STM32连接华为云IOT的工程代码Get: https://download.csdn.net/download/xiaolong1126626497/81993720

工程代码:

 #include "main.h"
 #include "stm32l4xx_hal.h"
 #include "i2c.h"
 #include "usart.h"
 #include "gpio.h"
 #include "E53_IA1.h"
 #include "lcd.h"
 #include "spi.h"
 #include "mqtt.h"
 #include "esp8266.h"
 
 
 /* USER CODE BEGIN Includes */
 #include "stdio.h"
 /* USER CODE END Includes */
 
 void SystemClock_Config(void);
 
 
 #define ESP8266_WIFI_AP_SSID  "CMCC-Cqvn"   //将要连接的路由器名称 --不要出现中文、空格等特殊字符
 #define ESP8266_AP_PASSWORD "99pu58cb"     //将要连接的路由器密码
 
 
 //华为云IOT物联网服务器的设备信息
 #define MQTT_ClientID "61cd1d97078a93029b84e7b6_1126626497_0_0_2021123003"
 #define MQTT_UserName "61cd1d97078a93029b84e7b6_1126626497"
 #define MQTT_PassWord "b219f3a0099fa0284a2671a5c699b67a7cf6d5f7355d9ee8190011f3b64f71b5"
  
 //订阅与发布的主题
 #define SET_TOPIC  "$oc/devices/61cd1d97078a93029b84e7b6_1126626497/sys/messages/down"  //订阅
 #define POST_TOPIC "$oc/devices/61cd1d97078a93029b84e7b6_1126626497/sys/properties/report"  //发布
 
 
 //保存温湿度、光照强度
 E53_IA1_Data_TypeDef E53_IA1_Data;
 
 //显示文本
 char lcd_text_str[50];
 
 
 UART_HandleTypeDef at_usart;
 
 //低功耗串口初始化
 int32_t at_usart_init(void)
 {
     at_usart.Instance = LPUART1;
     at_usart.Init.BaudRate = 115200;
 
     at_usart.Init.WordLength = UART_WORDLENGTH_8B;
     at_usart.Init.StopBits = UART_STOPBITS_1;
     at_usart.Init.Parity = UART_PARITY_NONE;
     at_usart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
     at_usart.Init.Mode = UART_MODE_RX | UART_MODE_TX;
     
     if(HAL_UART_Init(&at_usart) != HAL_OK)
     {
         _Error_Handler(__FILE__, __LINE__);
     }
    // __HAL_UART_CLEAR_FLAG(usart, UART_FLAG_TC);
     __HAL_UART_ENABLE_IT(&at_usart, UART_IT_IDLE);
     __HAL_UART_ENABLE_IT(&at_usart, UART_IT_RXNE);
     HAL_NVIC_EnableIRQ(LPUART1_IRQn);                   //使能USART1中断通道
     HAL_NVIC_SetPriority(LPUART1_IRQn, 3, 3);               //抢占优先级3,子优先级3
     return 0;
 }
 
 unsigned char ESP8266_RecvBuf[MAX_RECV_CNT];
 unsigned int ESP8266_Recv_cnt=0;
 unsigned int ESP8266_Recv_flag=0;
 void LPUART1_IRQHandler()
 {
     //接收到数据
     if(__HAL_UART_GET_FLAG(&at_usart, UART_FLAG_RXNE) != RESET)
     {
         if(ESP8266_Recv_cnt<MAX_RECV_CNT-1)
         {
             ESP8266_RecvBuf[ESP8266_Recv_cnt++] = (uint8_t)(at_usart.Instance->RDR & 0x00FF);
         } 
         else
         {
              ESP8266_Recv_flag=1;
         }
     }  
     else if (__HAL_UART_GET_FLAG(&at_usart, UART_FLAG_IDLE) != RESET)
     {
         __HAL_UART_CLEAR_IDLEFLAG(&at_usart);
         
          ESP8266_Recv_flag=1;
     }
 }
 
 
 void AT_SendData(unsigned char *p,unsigned int len)
 {
     int i=0;
     for(i=0;i<len;i++)
     {
         while((LPUART1->ISR & 0X40) == 0); //循环发送,直到发送完毕
         LPUART1->TDR = p[i];
     }
 }
 
 
 char mqtt_message[200];
 int main(void)
 {
     int i=0;
     int cnt=0;
     int motor_state=0;
     HAL_Init();
     SystemClock_Config();
     MX_GPIO_Init();
     MX_I2C1_Init();
     MX_SPI2_Init();
     MX_USART1_UART_Init();
     at_usart_init();
     
     //初始化硬件
     Init_E53_IA1();
 
     LCD_Init();                 
     LCD_Clear(BLACK);//清屏为黑色
     LCD_ShowString(0, 00, 240, 32, 32, "Init ESP8266");//显示字符串,字体大小32*32
 
     if(ESP8266_Init())
    {
       printf("ESP8266硬件检测错误.\n");
       LCD_Clear(BLACK);//清屏为黑色
       LCD_ShowString(0, 00, 240, 32, 32, "ESP8266 ERROR");//显示字符串,字体大小32*32
    }
    else
    {
        LCD_Clear(BLACK);//清屏为黑色
        LCD_ShowString(0, 00, 240, 32, 32, "ESP8266 OK");//显示字符串,字体大小32*32
        printf("准备连接到指定的服务器.\n");
       //非加密端口
       printf("WIFI:%d\r\n",ESP8266_STA_TCP_Client_Mode(ESP8266_WIFI_AP_SSID,ESP8266_AP_PASSWORD,"106.55.124.154",1883,1));
    }
    
     //2. MQTT协议初始化  
     MQTT_Init(); 
    
     //3. 连接华为云IOT服务器        
     while(MQTT_Connect(MQTT_ClientID,MQTT_UserName,MQTT_PassWord))
     {
         printf("服务器连接失败,正在重试...\n");
         HAL_Delay(500);
     }
     printf("服务器连接成功.\n");
     
     //3. 订阅主题
     if(MQTT_SubscribeTopic(SET_TOPIC,0,1))
     {
         printf("主题订阅失败.\n");
     }
     else
     {
         printf("主题订阅成功.\n");
     }        
     
       while (1)
       {
             if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==GPIO_PIN_RESET)//查询按键KEY1低电平
             {
                 HAL_Delay(10);//消抖
                 if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==GPIO_PIN_RESET)//查询按键KEY1低电平
                 {
                     HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET);//亮
                     
                     //补光灯亮
                     HAL_GPIO_WritePin(IA1_Light_GPIO_Port, IA1_Light_Pin, GPIO_PIN_SET);
                     
                     //电机转
                     HAL_GPIO_WritePin(IA1_Motor_GPIO_Port, IA1_Motor_Pin, GPIO_PIN_SET);
                     
                     motor_state=1;
                 }
             }
                 
             if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==GPIO_PIN_RESET)//查询按键KEY2低电平
             {
                 HAL_Delay(10);//消抖
                 if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==GPIO_PIN_RESET)//查询按键KEY2低电平
                 {
                     HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET);//灭
                     
                      //补光灯灭
                     HAL_GPIO_WritePin(IA1_Light_GPIO_Port, IA1_Light_Pin, GPIO_PIN_RESET);
                     
                      //电机停
                     HAL_GPIO_WritePin(IA1_Motor_GPIO_Port, IA1_Motor_Pin, GPIO_PIN_RESET);
                     
                     motor_state=0;
                 }
             }
      
          cnt++;
          HAL_Delay(10);   
          
          if(cnt>=100)
          {
             cnt=0;
             E53_IA1_Read_Data();
             printf("光照强度:%d %%\r\n", (int)E53_IA1_Data.Lux);
             printf("湿度:%d %%\r\n",(int)E53_IA1_Data.Humidity);
             printf("温度:%d ℃\r\n", (int)E53_IA1_Data.Temperature);
 
 
             sprintf(lcd_text_str,"L: %d %%",(int)E53_IA1_Data.Lux);
             LCD_ShowString(40, 50+10+32*1, 240, 32, 32,lcd_text_str);
 
 
             sprintf(lcd_text_str,"H: %d %%",(int)E53_IA1_Data.Humidity);
             LCD_ShowString(40, 50+10+32*2, 240, 32, 32,lcd_text_str);
              
 
             sprintf(lcd_text_str,"T: %d C",(int)E53_IA1_Data.Temperature);
             LCD_ShowString(40, 50+10+32*3, 240, 32, 32,lcd_text_str);
 
             //切换引脚的状态
             HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
              
                //上传数据
             sprintf(mqtt_message,"{\"services\": [{\"service_id\": \"motor\",\"properties\":{\"motor\":%d}},"
             "{\"service_id\": \"motor\",\"properties\":{\"SHT30_H\":%d}},{\"service_id\": \"motor\",\"properties\":"
             "{\"SHT30_L\":%d}},{\"service_id\": \"motor\",\"properties\":{\"BH1750\":%d}}]}",
             motor_state,(int)E53_IA1_Data.Humidity,(int)E53_IA1_Data.Temperature,(int)E53_IA1_Data.Lux);
             
             MQTT_PublishData(POST_TOPIC,mqtt_message,0);
             
             //根据湿度自动灌溉
             if((int)E53_IA1_Data.Humidity<50)  //小于50自动灌溉
             {
                  printf("自动灌溉....\n");
                  motor_state=1; //电机状态更新
                  //电机转
                  HAL_GPIO_WritePin(IA1_Motor_GPIO_Port, IA1_Motor_Pin, GPIO_PIN_SET);
             }  
          }
 
           //接收到数据
           if(ESP8266_Recv_flag)
           {
                //如果是下发了属性,判断是开锁还是关锁
                 if(ESP8266_Recv_cnt>5)
                 {
                     ESP8266_RecvBuf[ESP8266_Recv_cnt]=';'//使用字符串查找函数
              
                     if
                     (strstr((*char)&[ESP8266_RecvBuf5],"\"machine\":1"))=
                     {
                          motor_state1;//电机状态更新 //电机转
                          HAL_GPIO_WritePin
                          (,IA1_Motor_GPIO_Port, IA1_Motor_PinGPIO_PIN_SET );printf  
                          ("开启电机...\n");}
                     else
                     if (strstr((*char)&[ESP8266_RecvBuf5],"\"machine\":0"))//电机停
                     {
                         HAL_GPIO_WritePin
                         (,IA1_Motor_GPIO_Port, IA1_Motor_PinGPIO_PIN_RESET );=
                     
                         motor_state0;printf
                         ("关闭电机...\n");}
                     for
                     
                     (=i0;<i;ESP8266_Recv_cnt++i)printf("%c",[ESP8266_RecvBuf]i);=
                     
                     ESP8266_Recv_cnt0;}    
                 =
                 ESP8266_Recv_flag0;}
           }
       }
 void
 
 
 SystemClock_Config (void);
 {
 
   RCC_OscInitTypeDef RCC_OscInitStruct;
   RCC_ClkInitTypeDef RCC_ClkInitStruct;
   RCC_PeriphCLKInitTypeDef PeriphClkInit/**Initializes the CPU, AHB and APB busses clocks 
     */
 
     .
   RCC_OscInitStruct=OscillatorType RCC_OSCILLATORTYPE_HSI |RCC_OSCILLATORTYPE_MSI;.
   RCC_OscInitStruct=HSIState RCC_HSI_ON ;.
   RCC_OscInitStruct=HSICalibrationValue 16 ;.
   RCC_OscInitStruct=MSIState RCC_MSI_ON ;.
   RCC_OscInitStruct=MSICalibrationValue 0 ;.
   RCC_OscInitStruct=MSIClockRange RCC_MSIRANGE_6 ;.
   RCC_OscInitStructPLL.=PLLState RCC_PLL_ON ;.
   RCC_OscInitStructPLL.=PLLSource RCC_PLLSOURCE_MSI ;.
   RCC_OscInitStructPLL.PLLM= 1 ;.
   RCC_OscInitStructPLL.PLLN= 40 ;.
   RCC_OscInitStructPLL.PLLP= RCC_PLLP_DIV7 ;.
   RCC_OscInitStructPLL.PLLQ= RCC_PLLQ_DIV2 ;.
   RCC_OscInitStructPLL.PLLR= RCC_PLLR_DIV2 ;if
   ( HAL_RCC_OscConfig(&)RCC_OscInitStruct!= HAL_OK )_Error_Handler
   {
     (,__FILE__) __LINE__;}
   /**Initializes the CPU, AHB and APB busses clocks 
     */
 
     .
   RCC_ClkInitStruct=ClockType RCC_CLOCKTYPE_HCLK |RCC_CLOCKTYPE_SYSCLK|
                               RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;.
   RCC_ClkInitStruct=SYSCLKSource RCC_SYSCLKSOURCE_PLLCLK ;.
   RCC_ClkInitStruct=AHBCLKDivider RCC_SYSCLK_DIV1 ;.
   RCC_ClkInitStruct=APB1CLKDivider RCC_HCLK_DIV1 ;.
   RCC_ClkInitStruct=APB2CLKDivider RCC_HCLK_DIV1 ;if
 
   ( HAL_RCC_ClockConfig(&,RCC_ClkInitStructFLASH_LATENCY_4 )!= HAL_OK )_Error_Handler
   {
     (,__FILE__) __LINE__;}
   .
 
   PeriphClkInit=PeriphClockSelection RCC_PERIPHCLK_USART1 |RCC_PERIPHCLK_I2C1;.
   PeriphClkInit=Usart1ClockSelection RCC_USART1CLKSOURCE_PCLK2 ;.
   PeriphClkInit=I2c1ClockSelection RCC_I2C1CLKSOURCE_HSI ;if
   ( HAL_RCCEx_PeriphCLKConfig(&)PeriphClkInit!= HAL_OK )_Error_Handler
   {
     (,__FILE__) __LINE__;}
   /**Configure the main internal regulator output voltage 
     */
 
     if
   ( HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1)!= HAL_OK )_Error_Handler
   {
     (,__FILE__) __LINE__;}
   /**Configure the Systick interrupt time 
     */
 
     HAL_SYSTICK_Config
   (HAL_RCC_GetHCLKFreq()/1000);/**Configure the Systick 
     */
 
     HAL_SYSTICK_CLKSourceConfig
   (SYSTICK_CLKSOURCE_HCLK);/* SysTick_IRQn interrupt configuration */
 
   HAL_NVIC_SetPriority
   (,SysTick_IRQn0 ,0 );}
 /* USER CODE BEGIN 4 */
 
 /* USER CODE END 4 */
 
 /**
   * @brief  This function is executed in case of error occurrence.
   * @param  file: The file name as string.
   * @param  line: The line in file as a number.
   * @retval None
   */
 
 void
 _Error_Handler (*char ,file) int line/* USER CODE BEGIN Error_Handler_Debug */
 {
   /* User can add his own implementation to report the HAL error return state */
   while
   (1)}
   {
   /* USER CODE END Error_Handler_Debug */
   }
 USE_FULL_ASSERT
 
 #ifdef  /**
   * @brief  Reports the name of the source file and the source line number
   *         where the assert_param error has occurred.
   * @param  file: pointer to the source file name
   * @param  line: assert_param error line source number
   * @retval None
   */
 void
 assert_failed (*uint8_t, file) uint32_t line/* USER CODE BEGIN 6 */
 { 
   /* User can add his own implementation to report the file name and line number,
      tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
   /* USER CODE END 6 */
   }
 /* USE_FULL_ASSERT */
 #endif X-Auth-Token
5. 上位机软件开发

上位机与设备之间通信,需要通过服务器完成,服务器提供了对应的API接口,所以对于上位机而言通信主要是对HTTP请求进行处理,返回的数据进行解析等 *** 作。

当前的软件采用是采用QT设计的,实现了产品注册、设备注册、获取在线设备,获取设备属性,远程指令发送等主要功能。

访问华为云的接口都需要填一个X-Auth-Token参数,这个参数获取需要IAM账号,下面第一步就先介绍,如何创建IAM账号,如何获取/* 功能: 获取token */参数。

5.1 创建IAM账户

创建一个IAM账户,方便接下来使用API接口访问华为云服务时,生成token登录密匙。

地址: https://console.huaweicloud.com/iam/?region=cn-north-4#/iam/users

账户创建好之后,代码里就可以编写一个获取Token的函数。

 void
 Widget ::GetToken()//表示获取token
 {
     =
     function_select3;;
 
     QString requestUrl;
     QNetworkRequest request//设置请求地址
 
     ;
     QUrl url//获取token请求地址
 
     =
     requestUrl QString ("https://iam.%1.myhuaweicloud.com/v3/auth/tokens").
                  arg(SERVER_ID);//自己创建的TCP服务器,测试用
 
     //requestUrl="http://10.0.0.6:8080";
     //设置数据提交格式
 
     .
     requestsetHeader(:QNetworkRequest:,ContentTypeHeaderQVariant ("application/json;charset=UTF-8"));//构造请求
 
     .
     urlsetUrl()requestUrl;.
 
     requestsetUrl()url;=
 
     QString text QString("{\"auth\":{\"identity\":{\"methods\":[\"password\"],\"password\":""{\"user\":{\"domain\": {"
     "\"name\":\"%1\"},\"name\": \"%2\",\"password\": \"%3\"}}},"
     "\"scope\":{\"project\":{\"name\":\"%4\"}}}}"
     ).
             arg(MAIN_USER).
             arg(IAM_USER).
             arg(IAM_PASSWORD).
             arg(SERVER_ID);//发送请求
 
     -
     managerpost>(,request. texttoUtf8());}
 URL
5.2 查询设备列表

帮助文档地址: https://support.huaweicloud.com/api-iothub/iot_06_v5_0048.html

官方提供了API接口,可以直接获取产品下面的所有设备详细信息返回。

关于请求参数,返回结果的字段含义,在帮助文档里有详细介绍。

格式:/ /v5/iot}{project_id/示例devices

:https  

://.iotda-cn-north4..myhuaweicloud/com/v5/iot/0f2d61e43600f4e22f74c003616710bc?devices=product_id&6210e8acde9933029be8facf=is_cascade_queryfalse&=limit10&=marker&ffffffffffffffffffffffff=offset0"devices"

接口的在线调试地址:https://apiexplorer.developer.huaweicloud.com/apiexplorer/debug?product=IoTDA&api=ListDevices

返回的结果:

{
 :[ "app_id"
  {
   :"1af45e3938bb4482bc0be0a5cb3089e3" ,"app_name"
   :"DefaultApp_620esbs1" ,"device_id"
   :"6210e8acde9933029be8facf_dev2" ,"node_id"
   :"dev2" ,"gateway_id"
   :"6210e8acde9933029be8facf_dev2" ,"device_name"
   :"dev2" ,"node_type"
   :"GATEWAY" ,"description"
   :null ,"fw_version"
   :null ,"sw_version"
   :null ,"device_sdk_version"
   :null ,"product_id"
   :"6210e8acde9933029be8facf" ,"product_name"
   :"DHT11" ,"status"
   :"INACTIVE" ,"tags"
   :[ ]}
  ,"app_id"
  {
   :"1af45e3938bb4482bc0be0a5cb3089e3" ,"app_name"
   :"DefaultApp_620esbs1" ,"device_id"
   :"6210e8acde9933029be8facf_dev1" ,"node_id"
   :"dev1" ,"gateway_id"
   :"6210e8acde9933029be8facf_dev1" ,"device_name"
   :"dev1" ,"node_type"
   :"GATEWAY" ,"description"
   :null ,"fw_version"
   :null ,"sw_version"
   :null ,"device_sdk_version"
   :null ,"product_id"
   :"6210e8acde9933029be8facf" ,"product_name"
   :"DHT11" ,"status"
   :"OFFLINE" ,"tags"
   :[ ]}
  ]
 ,"page"
 :"count" {
  :2 ,"marker"
  :"6210efa980c60c11be19ead1" }
 }
//查询所有设备

上面的返回结果里通过JSON数组保存了设备信息,每一个设备就是一个独立的对象,上面的数据里返回了两个设备的信息,说明产品的目录下创建了两个设备。

应用层编写代码完成设备列表获取:

void
Widget ::Get_AllDevice()//查询设备列表
{
    =
    function_select1;;

    QString requestUrl;
    QNetworkRequest request//设置请求地址

    ;
    QUrl url//设备列表请求地址

    =
    requestUrl QString ("https://iotda.%1.myhuaweicloud.com/v5/iot/%2/devices?product_id=%3&is_cascade_query=false&limit=10&marker=ffffffffffffffffffffffff&offset=0").
                 arg(SERVER_ID).
            arg(PROJECT_ID).
            arg()Product_id;//设置数据提交格式

    .
    requestsetHeader(:QNetworkRequest:,ContentTypeHeaderQVariant ("application/json"));//设置token

    .
    requestsetRawHeader("X-Auth-Token",)Token;//构造请求

    .
    urlsetUrl()requestUrl;.

    requestsetUrl()url;//发送请求

    -
    managerget>()request;}
//查询设备列表

服务器返回的结果解析:

if
    (==function_select1)//清空原来的设备列表
    {
        -
        ui->comboBoxclear>();.
        device_id_lisclear();//解析数据

        ;
        QJsonParseError json_error=
        QJsonDocument document : QJsonDocument:fromJson(,replyData& )json_error;if
        (.json_error==error : QJsonParseError:)NoError=
        {
            QJsonObject obj . documentobject();//判断是否是对象,然后开始解析数据

            if
            (.documentisObject())=
            {
                QJsonObject obj . documentobject();if
                (.objcontains("devices"))=
                {
                    QJsonArray array.objtake("devices").toArray();for
                    (=int i0;<i.arraysize();++i)=
                    {
                        QJsonObject obj1.arrayat()i.toObject();//得到设备ID

                        if
                        (.obj1contains("device_id"))=
                        {
                            QString device_id.obj1take("device_id").toString();.
                            device_id_lisappend()device_id;-
                            ui->comboBoxaddItem>()device_id;qDebug

                            ()<<"device_id:"<<;device_id}
                        }
                    }
                }
            }
         return
        ;}
    查询设备属性
5.3 查询设备属性

(1)应用端查询设备属性的请求

帮助文档地址: https://support.huaweicloud.com/api-iothub/iot_06_v5_0034.html

(2)在线调试地址

接口的在线调试地址: https://apiexplorer.developer.huaweicloud.com/apiexplorer/debug?product=IoTDA&api=ListProperties

(3)设备端响应的数据格式

帮助文档: https://support.huaweicloud.com/api-iothub/iot_06_v5_3011.html

(4)使用总结

上位机APP向设备端请求/时,设备端会收到如下的消息:

$oc/devices/6210e8acde9933029be8facf_dev1/sys/properties/get=request_id-5f359b5c-542f-460e-9f51"service_id"85e82150ff4a{:"DHT11"}request_id=5f359b5c-542f-460e-9f51-85e82150ff4a

设备端需要解析这个字符串,得到里面的设备端响应的主题格式 值。在向服务器回应时,要带上这个请求ID。

:/ $oc/devices}{device_id//sys/properties/get/response=request_id}{request_id:

示    例/
$oc/devices/6210e8acde9933029be8facf_dev1/sys/properties/get/response=request_id-6c36c85e68e1--4d01-a2a3设备端响应的数据格式b89f09bd0427

:"services"
{:[ "service_id"{:"gps" ,"properties":"DHT11_t"{:12,"DHT11_h":33}}]}应用端上位机收到设备端的响应数据


:"{\"response\":{\"services\":[{\"service_id\":\"temp\",\"properties\":{\"DHT11_t\":13,\"DHT11_h\":33.345}}]}}"
//查询设备属性

(5)应用端获取设备属性

   void
Widget ::Get_device_properties()//表示获取token
{
    =
    function_select0;;

    QString requestUrl;
    QNetworkRequest request//设置请求地址

    ;
    QUrl urlif

    (.device_id_lissize()<=0)//显示错误代码
    {
        QMessageBox
        ::information(this,"提示","未选择设备,请先获取设备列表\n选择设备后重试.",QMessageBox::,OkQMessageBox::)Ok;return
        ;}
    //获取token请求地址

    =
    requestUrl QString ("https://iotda.%1.myhuaweicloud.com/v5/iot/%2/devices/%3/properties?service_id=%4").
                 arg(SERVER_ID).
            arg(PROJECT_ID).
            arg(.device_id_lisat(-ui->comboBoxcurrentIndex>())).
            arg()service_id;//自己创建的TCP服务器,测试用

    //requestUrl="http://10.0.0.6:8080";
    //设置数据提交格式

    .
    requestsetHeader(:QNetworkRequest:,ContentTypeHeaderQVariant ("application/json"));//设置token

    .
    requestsetRawHeader("X-Auth-Token",)Token;//构造请求

    .
    urlsetUrl()requestUrl;.

    requestsetUrl()url;//发送请求

    -
    managerget>()request;}
//查询设备属性

(6)应用端解析数据

    if
    (==function_select0)//解析数据
    {
        ;
        QJsonParseError json_error=
        QJsonDocument document : QJsonDocument:fromJson(,replyData& )json_error;if
        (.json_error==error : QJsonParseError:)NoError//判断是否是对象,然后开始解析数据
        {
            if
            (.documentisObject())=
            {
                QJsonObject obj . documentobject();if
                (.objcontains("response"))=
                {
                    QJsonObject obj1.objtake("response").toObject();if
                    (.obj1contains("services"))=
                    {
                         QJsonArray array.obj1take("services").toArray();}

                         
                    }
                }
            }
         return
        ;}
    [+++]
5.4 上位机开发环境搭建

上位机软件是采用QT开发的,Qt是一个1991年由QtCompany开发的跨平台C++图形用户界面应用程序开发框架。它既可以开发GUI程序,也可用于开发非GUI程序,比如控制台工具和服务器。QT在发布 Qt 4.6 的同时,作为 Qt 开发跨平台 IDE 的Qt Creator也发布了更新版本。Qt Creator是一个用于Qt开发的轻量级跨平台集成开发环境。Qt Creator可带来两大关键益处:提供首个专为支持跨平台开发而设计的集成开发环境 (IDE),并确保首次接触Qt框架的开发人员能迅速上手和 *** 作。即使不开发Qt应用程序,Qt Creator也是一个简单易用且功能强大的IDE。

目前QT在嵌入式领域、桌面端都用的非常多,开发桌面,嵌入式的上位机还是非常方便。 嵌入式领域包括: 车机主机、嵌入式Linux设备等。

QT官网: https://resources.qt.io/cn

QT5.12.6安装包下载地址: https://download.qt.io/archive/qt/5.12/5.12.6/

QT学习专栏: https://blog.csdn.net/xiaolong1126626497/category_11400392.html

QT环境搭建文章:https://xiaolong.blog.csdn.net/article/details/120654599

6. 总结

整个项目的实现主要分为两个大部分:1. 设备上云 2. 应用侧的软件开发

(1)设备上云: 目前通过STM32、ESP8266已经完了华为云物联网云平台的连接,ESP8266上云的过程主要是MQTT协议的理解,目前采用的ESP8266没有内置MQTT协议相关的AT指令,需要自己实现MQTT协议,这个过程稍微麻烦一点,需要安装官网的MQTT协议手册拼接结构完成协议构造。对于设备端而言,只要是通信采用标准的MQTT协议,不管连接哪一个物联网云平台,过程是没有多大区别的。

(2)应用层软件开发: 应用侧软件开发主要是方便远程管理设备,目前华为云物联网平台没有提供在线web设计功能、没有提供公版的APP;所以,在设备上云之后,想要方便的对设备的属性进行查看,管理,都需要自己开发上位机才行。

)
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 166, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)
物联网应用开发实践案例-智慧农业_mysql_内存溢出

物联网应用开发实践案例-智慧农业

物联网应用开发实践案例-智慧农业,第1张

1. 设计需求、硬件环境介绍 1.1 项目背景

近几年,物联网、智能家居、AI人工智能技术发送非常迅速。在物联网技术的支撑下,如今农业逐渐走向现代化,自动化、现在智能化的农业生产成为了主流。告别“刀耕火种”的传统农业后,现代农业也正在向智慧型转变,当前智慧农业模式已经深入到农业生产的各个环节,灌溉、施肥、植保等细分领域都将与物联网、信息技术等先进科技相结合,效率、效果也将得到大大提高。

要知道,所谓的“智慧农业”就是充分应用现代信息技术成果,集成应用计算机技术与网络技术、物联网技术、无线通信技术以及专家智慧与知识等,实现农业可视化远程诊断、远程控制、灾变预警等智能管理。那么融入物联网的智慧农业的有以下几个优点:

1、低成本化

众所周知,目前想要购买一套全面的智慧农业设备的成本都较高,这是普通农户难以承受的,因此,想要实现全面智慧农业,那么低成本的智慧农业设备将成为智慧农业趋势之一。

2、 *** 作简单化 智慧农业的根本是服务于农业、服务于农户,所以想要做到让农户更快地与智慧农业接轨就必须要把系统做得易 *** 作、易学。要知道,当前我国农民普遍文化程度较低,只有将 *** 作简单化才能够让每个农民都能熟练 *** 作。

智慧农业也是一个大范围,比如: 智慧鱼塘、智慧大棚、智慧园林、城市绿化、智能果园等等都属于智慧农业的范围。

有了智能设备的加持:可以实现自动浇水灌溉、实时检测土壤养分、水分、环境温度、自动补光等一系列联动 *** 作。

本篇文章就利用华为云IOT物联网平台实践搭建一个智慧农业智慧大脑,设备平台采用小熊开发板,搭载的CPU是意法半导体的STM32L431芯片,这是意法半导体推出的低功耗芯片;配合外部的一些专业传感器,能够获取空气中的温湿度数据,光照度数据等,根据种植区的空气温湿度数据,判断是否进行灌溉。

1.2 实现功能

本项目是利用意法半导体的STM32L431+ESP8266 WIFI ,配合华为云物联网平台服务器,组建一个智慧农业控制系统,结合外部传感器采集的数据,并利用这些数据判断是否进行灌溉,补光等信息提示。

考虑到以学习、实践为目的,当前项目采用了ESP8266无线WIFI网卡作为联网设备,ESP8266价钱便宜,支持串口编程,有标准的一套AT资料,资料多,作为学习而言,非常适合。可以通过对ESP8266的编程实验,了解TCP、MQTT网络编程相关知识点。

当前项目主要分为六个功能模块,分别是:基础系统模块、温度采集模块、湿度采集模块、光照采集模块、无线传感器网络模块、OLED显示屏模块。

(1)基础系统模块:进行各个数据的接收与转发,控制扫水作业是否进行,浇水作业是采用板载的电机模拟

(2)温度采集模块:采集监测区域的温度数据,传输到微控制器

(3)湿度采集模块:采集监测区域的湿度数据,传输到微控制器

(4)光照采集模块:采集监测区域的光照数据,传输到微控制器

(5)无线传感器网络模块:数据上传至云平台,数据下发交互等

(6)LCD显示屏模块:实时显示所监测到的各项数据

小熊开发板的扩展板上自带了光敏传感器、温湿度传感器、直流电机模块,可以很方便的实现上面的这些功能需求。

本项目设备的源代码里,连接华为云的MQTT协议是按照MQTT的官方中文手册编写的,不依赖任何外部SDK,不依赖ESP8266设备,只要能联网的设备都可以连接华为云IOT,非常适合移植到其他单片机平台;不管是采用51,STM32F1系列,都可以直接参考代码移植。

华为云物联网平台提供了API接口,可以通过API开发配套的上位机,方便实现数据查看,手动灌溉等 *** 作。

提供的API除了可以查询设备属性信息之外,还可以创建产品、设备、对开发上位机来讲非常方便,可以开发出从底层设备到云端服务器、再到应用APP软件,完成3层数据交互。

下面是开发的上位机APP运行效果。

当前文章主要完成3个任务的实践:

(1)云端产品的创建、设备的创建

(2)设备上云,完成服务器登录、数据上传

(3)手机APP、电脑上位机软件的开发,可以通过云端API接口与设备、服务器之前通讯

1.3 设备实物图

目前联网的设备采用的ESP8266(手上没有现成的NBIOT模块,暂时使用ESP8266代替,核心原理是一样的),正常项目里会使用NBIOT模块联网作为数据传输源。

小熊开发板的设备相关实物图如下:

2. 创建IOT服务器端产品

需要先创建产品、在产品下再创建设备。产品是一个大框架,产品下的设备可以有很多,在应用层,可以通过华为云平台提供的API创建设备,删除设备,查询设备属性,在做产品时,软件端可以做一个设备注册的引导界面,完成产品下的设备注册,再将数据传递给设备端,这个过程叫“配网“,具体逻辑需要配合设备端完成。最终完成自动化设备创建,注册,上线等 *** 作。

下面先介绍如何手动创建产品,创建设备,了解创建产品创建设备的过程中需要填充什么参数,理解之后,再使用API时才更加理解参数含义。

2.1 创建产品

直接打开物联网产品页面: https://www.huaweicloud.com/product/iothub.html

打开产品页面,选择右上角创建产品。

根据自己情况填写信息。就是填写自己产品的一些参数信息。

创建成功后打开产品详情页面,拉到最下面,点击创建自定义模型文件。

这里创建模型文件主要就是为了MQTT客户端能够正确的上传传感器数据上来,每个传感器设置一个属性,这个属性就是表示了传感器的数据值类型。

比如: 先添加一个电机,这个电机就是浇水电机,能上报开关状态,云端也能下发命令控制电机,所以需要添加属性和下发的命令。

添加属性:

添加命令: 因为电机需要云端远程控制。

接下来就创建温度、湿度、光照度传感器的属性,这些传感器只是向云端上传数据,不需要下发指令控制,选择只读就可以了,电机要先实现远程浇灌控制,属性就选择读写。

创建完毕效果,一共有4个属性,电机、温度、湿度、光强度:

2.2 创建设备

选择设备页面,注册设备。

创建后保持设备密匙等信息,接下来登录服务器时,生成MQTT账号密匙需要用到这些参数。

当前创建的设备信息如下:

 {
     "device_id": "61cd1d97078a93029b84e7b6_1126626497",
     "secret": "1126626497"
 }
2.3 生成MQTT登录账号信息

官微提供的在线小工具: https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/

按照提示填入数据,生成,非常方便。

当前生成的信息如下:

 ClientId 61cd1d97078a93029b84e7b6_1126626497_0_0_2021123003
 Username 61cd1d97078a93029b84e7b6_1126626497
 Password b219f3a0099fa0284a2671a5c699b67a7cf6d5f7355d9ee8190011f3b64f71b5
3. 使用MQTT客户端模拟测试

为了验证服务器配置是否OK,先使用MQTT客户端软件进行连接测试。

3.1 华为云IOT服务器地址与端口

 端口: 1883
 域名: a161a58a78.iot-mqtts.cn-north-4.myhuaweicloud.com
 IP地址: 121.36.42.100
3.2 订阅主题

在产品页面,可以看到主题管理页面,能看到当前设备可以订阅的主题有哪些。

一般订阅下发的数据:

 格式: $oc/devices/{device_id}/sys/messages/down
 //订阅主题: 平台下发消息给设备
 $oc/devices/61cd1d97078a93029b84e7b6_1126626497/sys/messages/down
3.3 上报主题数据

官方文档介绍: https://support.huaweicloud.com/devg-iothub/iot_01_2127.html

服务ID,属性ID在产品页面查看,2.1小节创建产品里就讲了这个属性的作用。

每次可以单个属性上报,也可以一起上报。

 格式: $oc/devices/{device_id}/sys/properties/report
 //设备上报主题请求
 $oc/devices/61cd1d97078a93029b84e7b6_1126626497/sys/properties/report
 
 //上报的数据格式如下
     
 //电机开状态反馈
 {"services": [{"service_id": "motor","properties":{"motor":1}}]}
 
 //电机关状态反馈
 {"services": [{"service_id": "motor","properties":{"motor":0}}]}
 
 //温度上报
 {"services": [{"service_id": "motor","properties":{"SHT30_H":14}}]}
 
 //湿度上报
 {"services": [{"service_id": "motor","properties":{"SHT30_L":70}}]}
 
 //光照强度上报
 {"services": [{"service_id": "motor","properties":{"BH1750":80}}]}
 
 //也可以一起上报
 {"services": [{"service_id": "motor","properties":{"motor":1}},{"service_id": "motor","properties":{"SHT30_H":15}},{"service_id": "motor","properties":{"SHT30_L":70}},{"service_id": "motor","properties":{"BH1750":80}}]}
3.4 登录服务器

按照软件提示,填入相关数据即可。

如需要也需要使用和我一样的同款软件,打开百度搜索MQTT客户端_v2.4(协议3.1.1).exe 即可找到下载地址。

发送数据后查看云端,已经登录成功,数据已经上传成功。

3.5 下发命令

电机设备支持读写,支持下发命令,在设备页面测试。

点击确定之后,参看MQTT客户端软件,已经收到了下发的数据。

 len:174,Data:l$oc/devices/61cd1d97078a93029b84e7b6_1126626497/sys/commands/request_id=390ce15d-6e69-4021-b83a-5e953eea874c{"paras":{"motor":1},"service_id":"motor","command_name":"motor"}
4. 设备端上华为云IOT 4.1 安装keil软件

MCU采用的STM32芯片,设备端代码编写开发就采用的keil5。

keil5安装包下载地址: http://www.myir-tech.com/download.asp

安装keil时,软件要放在英文目录下,电脑的用户名必须是英文,否则会出现一些奇怪问题。

安装过程中,根据提示下一步下一步点击即可。

4.2 编写代码

工程代码:

STM32连接华为云IOT的工程代码Get: https://download.csdn.net/download/xiaolong1126626497/81993720

工程代码:

 #include "main.h"
 #include "stm32l4xx_hal.h"
 #include "i2c.h"
 #include "usart.h"
 #include "gpio.h"
 #include "E53_IA1.h"
 #include "lcd.h"
 #include "spi.h"
 #include "mqtt.h"
 #include "esp8266.h"
 
 
 /* USER CODE BEGIN Includes */
 #include "stdio.h"
 /* USER CODE END Includes */
 
 void SystemClock_Config(void);
 
 
 #define ESP8266_WIFI_AP_SSID  "CMCC-Cqvn"   //将要连接的路由器名称 --不要出现中文、空格等特殊字符
 #define ESP8266_AP_PASSWORD "99pu58cb"     //将要连接的路由器密码
 
 
 //华为云IOT物联网服务器的设备信息
 #define MQTT_ClientID "61cd1d97078a93029b84e7b6_1126626497_0_0_2021123003"
 #define MQTT_UserName "61cd1d97078a93029b84e7b6_1126626497"
 #define MQTT_PassWord "b219f3a0099fa0284a2671a5c699b67a7cf6d5f7355d9ee8190011f3b64f71b5"
  
 //订阅与发布的主题
 #define SET_TOPIC  "$oc/devices/61cd1d97078a93029b84e7b6_1126626497/sys/messages/down"  //订阅
 #define POST_TOPIC "$oc/devices/61cd1d97078a93029b84e7b6_1126626497/sys/properties/report"  //发布
 
 
 //保存温湿度、光照强度
 E53_IA1_Data_TypeDef E53_IA1_Data;
 
 //显示文本
 char lcd_text_str[50];
 
 
 UART_HandleTypeDef at_usart;
 
 //低功耗串口初始化
 int32_t at_usart_init(void)
 {
     at_usart.Instance = LPUART1;
     at_usart.Init.BaudRate = 115200;
 
     at_usart.Init.WordLength = UART_WORDLENGTH_8B;
     at_usart.Init.StopBits = UART_STOPBITS_1;
     at_usart.Init.Parity = UART_PARITY_NONE;
     at_usart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
     at_usart.Init.Mode = UART_MODE_RX | UART_MODE_TX;
     
     if(HAL_UART_Init(&at_usart) != HAL_OK)
     {
         _Error_Handler(__FILE__, __LINE__);
     }
    // __HAL_UART_CLEAR_FLAG(usart, UART_FLAG_TC);
     __HAL_UART_ENABLE_IT(&at_usart, UART_IT_IDLE);
     __HAL_UART_ENABLE_IT(&at_usart, UART_IT_RXNE);
     HAL_NVIC_EnableIRQ(LPUART1_IRQn);                   //使能USART1中断通道
     HAL_NVIC_SetPriority(LPUART1_IRQn, 3, 3);               //抢占优先级3,子优先级3
     return 0;
 }
 
 unsigned char ESP8266_RecvBuf[MAX_RECV_CNT];
 unsigned int ESP8266_Recv_cnt=0;
 unsigned int ESP8266_Recv_flag=0;
 void LPUART1_IRQHandler()
 {
     //接收到数据
     if(__HAL_UART_GET_FLAG(&at_usart, UART_FLAG_RXNE) != RESET)
     {
         if(ESP8266_Recv_cnt<MAX_RECV_CNT-1)
         {
             ESP8266_RecvBuf[ESP8266_Recv_cnt++] = (uint8_t)(at_usart.Instance->RDR & 0x00FF);
         } 
         else
         {
              ESP8266_Recv_flag=1;
         }
     }  
     else if (__HAL_UART_GET_FLAG(&at_usart, UART_FLAG_IDLE) != RESET)
     {
         __HAL_UART_CLEAR_IDLEFLAG(&at_usart);
         
          ESP8266_Recv_flag=1;
     }
 }
 
 
 void AT_SendData(unsigned char *p,unsigned int len)
 {
     int i=0;
     for(i=0;i<len;i++)
     {
         while((LPUART1->ISR & 0X40) == 0); //循环发送,直到发送完毕
         LPUART1->TDR = p[i];
     }
 }
 
 
 char mqtt_message[200];
 int main(void)
 {
     int i=0;
     int cnt=0;
     int motor_state=0;
     HAL_Init();
     SystemClock_Config();
     MX_GPIO_Init();
     MX_I2C1_Init();
     MX_SPI2_Init();
     MX_USART1_UART_Init();
     at_usart_init();
     
     //初始化硬件
     Init_E53_IA1();
 
     LCD_Init();                 
     LCD_Clear(BLACK);//清屏为黑色
     LCD_ShowString(0, 00, 240, 32, 32, "Init ESP8266");//显示字符串,字体大小32*32
 
     if(ESP8266_Init())
    {
       printf("ESP8266硬件检测错误.\n");
       LCD_Clear(BLACK);//清屏为黑色
       LCD_ShowString(0, 00, 240, 32, 32, "ESP8266 ERROR");//显示字符串,字体大小32*32
    }
    else
    {
        LCD_Clear(BLACK);//清屏为黑色
        LCD_ShowString(0, 00, 240, 32, 32, "ESP8266 OK");//显示字符串,字体大小32*32
        printf("准备连接到指定的服务器.\n");
       //非加密端口
       printf("WIFI:%d\r\n",ESP8266_STA_TCP_Client_Mode(ESP8266_WIFI_AP_SSID,ESP8266_AP_PASSWORD,"106.55.124.154",1883,1));
    }
    
     //2. MQTT协议初始化  
     MQTT_Init(); 
    
     //3. 连接华为云IOT服务器        
     while(MQTT_Connect(MQTT_ClientID,MQTT_UserName,MQTT_PassWord))
     {
         printf("服务器连接失败,正在重试...\n");
         HAL_Delay(500);
     }
     printf("服务器连接成功.\n");
     
     //3. 订阅主题
     if(MQTT_SubscribeTopic(SET_TOPIC,0,1))
     {
         printf("主题订阅失败.\n");
     }
     else
     {
         printf("主题订阅成功.\n");
     }        
     
       while (1)
       {
             if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==GPIO_PIN_RESET)//查询按键KEY1低电平
             {
                 HAL_Delay(10);//消抖
                 if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==GPIO_PIN_RESET)//查询按键KEY1低电平
                 {
                     HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET);//亮
                     
                     //补光灯亮
                     HAL_GPIO_WritePin(IA1_Light_GPIO_Port, IA1_Light_Pin, GPIO_PIN_SET);
                     
                     //电机转
                     HAL_GPIO_WritePin(IA1_Motor_GPIO_Port, IA1_Motor_Pin, GPIO_PIN_SET);
                     
                     motor_state=1;
                 }
             }
                 
             if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==GPIO_PIN_RESET)//查询按键KEY2低电平
             {
                 HAL_Delay(10);//消抖
                 if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==GPIO_PIN_RESET)//查询按键KEY2低电平
                 {
                     HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET);//灭
                     
                      //补光灯灭
                     HAL_GPIO_WritePin(IA1_Light_GPIO_Port, IA1_Light_Pin, GPIO_PIN_RESET);
                     
                      //电机停
                     HAL_GPIO_WritePin(IA1_Motor_GPIO_Port, IA1_Motor_Pin, GPIO_PIN_RESET);
                     
                     motor_state=0;
                 }
             }
      
          cnt++;
          HAL_Delay(10);   
          
          if(cnt>=100)
          {
             cnt=0;
             E53_IA1_Read_Data();
             printf("光照强度:%d %%\r\n", (int)E53_IA1_Data.Lux);
             printf("湿度:%d %%\r\n",(int)E53_IA1_Data.Humidity);
             printf("温度:%d ℃\r\n", (int)E53_IA1_Data.Temperature);
 
 
             sprintf(lcd_text_str,"L: %d %%",(int)E53_IA1_Data.Lux);
             LCD_ShowString(40, 50+10+32*1, 240, 32, 32,lcd_text_str);
 
 
             sprintf(lcd_text_str,"H: %d %%",(int)E53_IA1_Data.Humidity);
             LCD_ShowString(40, 50+10+32*2, 240, 32, 32,lcd_text_str);
              
 
             sprintf(lcd_text_str,"T: %d C",(int)E53_IA1_Data.Temperature);
             LCD_ShowString(40, 50+10+32*3, 240, 32, 32,lcd_text_str);
 
             //切换引脚的状态
             HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
              
                //上传数据
             sprintf(mqtt_message,"{\"services\": [{\"service_id\": \"motor\",\"properties\":{\"motor\":%d}},"
             "{\"service_id\": \"motor\",\"properties\":{\"SHT30_H\":%d}},{\"service_id\": \"motor\",\"properties\":"
             "{\"SHT30_L\":%d}},{\"service_id\": \"motor\",\"properties\":{\"BH1750\":%d}}]}",
             motor_state,(int)E53_IA1_Data.Humidity,(int)E53_IA1_Data.Temperature,(int)E53_IA1_Data.Lux);
             
             MQTT_PublishData(POST_TOPIC,mqtt_message,0);
             
             //根据湿度自动灌溉
             if((int)E53_IA1_Data.Humidity<50)  //小于50自动灌溉
             {
                  printf("自动灌溉....\n");
                  motor_state=1; //电机状态更新
                  //电机转
                  HAL_GPIO_WritePin(IA1_Motor_GPIO_Port, IA1_Motor_Pin, GPIO_PIN_SET);
             }  
          }
 
           //接收到数据
           if(ESP8266_Recv_flag)
           {
                //如果是下发了属性,判断是开锁还是关锁
                 if(ESP8266_Recv_cnt>5)
                 {
                     ESP8266_RecvBuf[ESP8266_Recv_cnt]=';'//使用字符串查找函数
              
                     if
                     (strstr((*char)&[ESP8266_RecvBuf5],"\"machine\":1"))=
                     {
                          motor_state1;//电机状态更新 //电机转
                          HAL_GPIO_WritePin
                          (,IA1_Motor_GPIO_Port, IA1_Motor_PinGPIO_PIN_SET );printf  
                          ("开启电机...\n");}
                     else
                     if (strstr((*char)&[ESP8266_RecvBuf5],"\"machine\":0"))//电机停
                     {
                         HAL_GPIO_WritePin
                         (,IA1_Motor_GPIO_Port, IA1_Motor_PinGPIO_PIN_RESET );=
                     
                         motor_state0;printf
                         ("关闭电机...\n");}
                     for
                     
                     (=i0;<i;ESP8266_Recv_cnt++i)printf("%c",[ESP8266_RecvBuf]i);=
                     
                     ESP8266_Recv_cnt0;}    
                 =
                 ESP8266_Recv_flag0;}
           }
       }
 void
 
 
 SystemClock_Config (void);
 {
 
   RCC_OscInitTypeDef RCC_OscInitStruct;
   RCC_ClkInitTypeDef RCC_ClkInitStruct;
   RCC_PeriphCLKInitTypeDef PeriphClkInit/**Initializes the CPU, AHB and APB busses clocks 
     */
 
     .
   RCC_OscInitStruct=OscillatorType RCC_OSCILLATORTYPE_HSI |RCC_OSCILLATORTYPE_MSI;.
   RCC_OscInitStruct=HSIState RCC_HSI_ON ;.
   RCC_OscInitStruct=HSICalibrationValue 16 ;.
   RCC_OscInitStruct=MSIState RCC_MSI_ON ;.
   RCC_OscInitStruct=MSICalibrationValue 0 ;.
   RCC_OscInitStruct=MSIClockRange RCC_MSIRANGE_6 ;.
   RCC_OscInitStructPLL.=PLLState RCC_PLL_ON ;.
   RCC_OscInitStructPLL.=PLLSource RCC_PLLSOURCE_MSI ;.
   RCC_OscInitStructPLL.PLLM= 1 ;.
   RCC_OscInitStructPLL.PLLN= 40 ;.
   RCC_OscInitStructPLL.PLLP= RCC_PLLP_DIV7 ;.
   RCC_OscInitStructPLL.PLLQ= RCC_PLLQ_DIV2 ;.
   RCC_OscInitStructPLL.PLLR= RCC_PLLR_DIV2 ;if
   ( HAL_RCC_OscConfig(&)RCC_OscInitStruct!= HAL_OK )_Error_Handler
   {
     (,__FILE__) __LINE__;}
   /**Initializes the CPU, AHB and APB busses clocks 
     */
 
     .
   RCC_ClkInitStruct=ClockType RCC_CLOCKTYPE_HCLK |RCC_CLOCKTYPE_SYSCLK|
                               RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;.
   RCC_ClkInitStruct=SYSCLKSource RCC_SYSCLKSOURCE_PLLCLK ;.
   RCC_ClkInitStruct=AHBCLKDivider RCC_SYSCLK_DIV1 ;.
   RCC_ClkInitStruct=APB1CLKDivider RCC_HCLK_DIV1 ;.
   RCC_ClkInitStruct=APB2CLKDivider RCC_HCLK_DIV1 ;if
 
   ( HAL_RCC_ClockConfig(&,RCC_ClkInitStructFLASH_LATENCY_4 )!= HAL_OK )_Error_Handler
   {
     (,__FILE__) __LINE__;}
   .
 
   PeriphClkInit=PeriphClockSelection RCC_PERIPHCLK_USART1 |RCC_PERIPHCLK_I2C1;.
   PeriphClkInit=Usart1ClockSelection RCC_USART1CLKSOURCE_PCLK2 ;.
   PeriphClkInit=I2c1ClockSelection RCC_I2C1CLKSOURCE_HSI ;if
   ( HAL_RCCEx_PeriphCLKConfig(&)PeriphClkInit!= HAL_OK )_Error_Handler
   {
     (,__FILE__) __LINE__;}
   /**Configure the main internal regulator output voltage 
     */
 
     if
   ( HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1)!= HAL_OK )_Error_Handler
   {
     (,__FILE__) __LINE__;}
   /**Configure the Systick interrupt time 
     */
 
     HAL_SYSTICK_Config
   (HAL_RCC_GetHCLKFreq()/1000);/**Configure the Systick 
     */
 
     HAL_SYSTICK_CLKSourceConfig
   (SYSTICK_CLKSOURCE_HCLK);/* SysTick_IRQn interrupt configuration */
 
   HAL_NVIC_SetPriority
   (,SysTick_IRQn0 ,0 );}
 /* USER CODE BEGIN 4 */
 
 /* USER CODE END 4 */
 
 /**
   * @brief  This function is executed in case of error occurrence.
   * @param  file: The file name as string.
   * @param  line: The line in file as a number.
   * @retval None
   */
 
 void
 _Error_Handler (*char ,file) int line/* USER CODE BEGIN Error_Handler_Debug */
 {
   /* User can add his own implementation to report the HAL error return state */
   while
   (1)}
   {
   /* USER CODE END Error_Handler_Debug */
   }
 USE_FULL_ASSERT
 
 #ifdef  /**
   * @brief  Reports the name of the source file and the source line number
   *         where the assert_param error has occurred.
   * @param  file: pointer to the source file name
   * @param  line: assert_param error line source number
   * @retval None
   */
 void
 assert_failed (*uint8_t, file) uint32_t line/* USER CODE BEGIN 6 */
 { 
   /* User can add his own implementation to report the file name and line number,
      tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
   /* USER CODE END 6 */
   }
 /* USE_FULL_ASSERT */
 #endif X-Auth-Token
5. 上位机软件开发

上位机与设备之间通信,需要通过服务器完成,服务器提供了对应的API接口,所以对于上位机而言通信主要是对HTTP请求进行处理,返回的数据进行解析等 *** 作。

当前的软件采用是采用QT设计的,实现了产品注册、设备注册、获取在线设备,获取设备属性,远程指令发送等主要功能。

访问华为云的接口都需要填一个X-Auth-Token参数,这个参数获取需要IAM账号,下面第一步就先介绍,如何创建IAM账号,如何获取/* 功能: 获取token */参数。

5.1 创建IAM账户

创建一个IAM账户,方便接下来使用API接口访问华为云服务时,生成token登录密匙。

地址: https://console.huaweicloud.com/iam/?region=cn-north-4#/iam/users

账户创建好之后,代码里就可以编写一个获取Token的函数。

 void
 Widget ::GetToken()//表示获取token
 {
     =
     function_select3;;
 
     QString requestUrl;
     QNetworkRequest request//设置请求地址
 
     ;
     QUrl url//获取token请求地址
 
     =
     requestUrl QString ("https://iam.%1.myhuaweicloud.com/v3/auth/tokens").
                  arg(SERVER_ID);//自己创建的TCP服务器,测试用
 
     //requestUrl="http://10.0.0.6:8080";
     //设置数据提交格式
 
     .
     requestsetHeader(:QNetworkRequest:,ContentTypeHeaderQVariant ("application/json;charset=UTF-8"));//构造请求
 
     .
     urlsetUrl()requestUrl;.
 
     requestsetUrl()url;=
 
     QString text QString("{\"auth\":{\"identity\":{\"methods\":[\"password\"],\"password\":""{\"user\":{\"domain\": {"
     "\"name\":\"%1\"},\"name\": \"%2\",\"password\": \"%3\"}}},"
     "\"scope\":{\"project\":{\"name\":\"%4\"}}}}"
     ).
             arg(MAIN_USER).
             arg(IAM_USER).
             arg(IAM_PASSWORD).
             arg(SERVER_ID);//发送请求
 
     -
     managerpost>(,request. texttoUtf8());}
 URL
5.2 查询设备列表

帮助文档地址: https://support.huaweicloud.com/api-iothub/iot_06_v5_0048.html

官方提供了API接口,可以直接获取产品下面的所有设备详细信息返回。

关于请求参数,返回结果的字段含义,在帮助文档里有详细介绍。

格式:/ /v5/iot}{project_id/示例devices

:https  

://.iotda-cn-north4..myhuaweicloud/com/v5/iot/0f2d61e43600f4e22f74c003616710bc?devices=product_id&6210e8acde9933029be8facf=is_cascade_queryfalse&=limit10&=marker&ffffffffffffffffffffffff=offset0"devices"

接口的在线调试地址:https://apiexplorer.developer.huaweicloud.com/apiexplorer/debug?product=IoTDA&api=ListDevices

返回的结果:

{
 :[ "app_id"
  {
   :"1af45e3938bb4482bc0be0a5cb3089e3" ,"app_name"
   :"DefaultApp_620esbs1" ,"device_id"
   :"6210e8acde9933029be8facf_dev2" ,"node_id"
   :"dev2" ,"gateway_id"
   :"6210e8acde9933029be8facf_dev2" ,"device_name"
   :"dev2" ,"node_type"
   :"GATEWAY" ,"description"
   :null ,"fw_version"
   :null ,"sw_version"
   :null ,"device_sdk_version"
   :null ,"product_id"
   :"6210e8acde9933029be8facf" ,"product_name"
   :"DHT11" ,"status"
   :"INACTIVE" ,"tags"
   :[ ]}
  ,"app_id"
  {
   :"1af45e3938bb4482bc0be0a5cb3089e3" ,"app_name"
   :"DefaultApp_620esbs1" ,"device_id"
   :"6210e8acde9933029be8facf_dev1" ,"node_id"
   :"dev1" ,"gateway_id"
   :"6210e8acde9933029be8facf_dev1" ,"device_name"
   :"dev1" ,"node_type"
   :"GATEWAY" ,"description"
   :null ,"fw_version"
   :null ,"sw_version"
   :null ,"device_sdk_version"
   :null ,"product_id"
   :"6210e8acde9933029be8facf" ,"product_name"
   :"DHT11" ,"status"
   :"OFFLINE" ,"tags"
   :[ ]}
  ]
 ,"page"
 :"count" {
  :2 ,"marker"
  :"6210efa980c60c11be19ead1" }
 }
//查询所有设备

上面的返回结果里通过JSON数组保存了设备信息,每一个设备就是一个独立的对象,上面的数据里返回了两个设备的信息,说明产品的目录下创建了两个设备。

应用层编写代码完成设备列表获取:

void
Widget ::Get_AllDevice()//查询设备列表
{
    =
    function_select1;;

    QString requestUrl;
    QNetworkRequest request//设置请求地址

    ;
    QUrl url//设备列表请求地址

    =
    requestUrl QString ("https://iotda.%1.myhuaweicloud.com/v5/iot/%2/devices?product_id=%3&is_cascade_query=false&limit=10&marker=ffffffffffffffffffffffff&offset=0").
                 arg(SERVER_ID).
            arg(PROJECT_ID).
            arg()Product_id;//设置数据提交格式

    .
    requestsetHeader(:QNetworkRequest:,ContentTypeHeaderQVariant ("application/json"));//设置token

    .
    requestsetRawHeader("X-Auth-Token",)Token;//构造请求

    .
    urlsetUrl()requestUrl;.

    requestsetUrl()url;//发送请求

    -
    managerget>()request;}
//查询设备列表

服务器返回的结果解析:

if
    (==function_select1)//清空原来的设备列表
    {
        -
        ui->comboBoxclear>();.
        device_id_lisclear();//解析数据

        ;
        QJsonParseError json_error=
        QJsonDocument document : QJsonDocument:fromJson(,replyData& )json_error;if
        (.json_error==error : QJsonParseError:)NoError=
        {
            QJsonObject obj . documentobject();//判断是否是对象,然后开始解析数据

            if
            (.documentisObject())=
            {
                QJsonObject obj . documentobject();if
                (.objcontains("devices"))=
                {
                    QJsonArray array.objtake("devices").toArray();for
                    (=int i0;<i.arraysize();++i)=
                    {
                        QJsonObject obj1.arrayat()i.toObject();//得到设备ID

                        if
                        (.obj1contains("device_id"))=
                        {
                            QString device_id.obj1take("device_id").toString();.
                            device_id_lisappend()device_id;-
                            ui->comboBoxaddItem>()device_id;qDebug

                            ()<<"device_id:"<<;device_id}
                        }
                    }
                }
            }
         return
        ;}
    查询设备属性
5.3 查询设备属性

(1)应用端查询设备属性的请求

帮助文档地址: https://support.huaweicloud.com/api-iothub/iot_06_v5_0034.html

(2)在线调试地址

接口的在线调试地址: https://apiexplorer.developer.huaweicloud.com/apiexplorer/debug?product=IoTDA&api=ListProperties

(3)设备端响应的数据格式

帮助文档: https://support.huaweicloud.com/api-iothub/iot_06_v5_3011.html

(4)使用总结

上位机APP向设备端请求/时,设备端会收到如下的消息:

$oc/devices/6210e8acde9933029be8facf_dev1/sys/properties/get=request_id-5f359b5c-542f-460e-9f51"service_id"85e82150ff4a{:"DHT11"}request_id=5f359b5c-542f-460e-9f51-85e82150ff4a

设备端需要解析这个字符串,得到里面的设备端响应的主题格式 值。在向服务器回应时,要带上这个请求ID。

:/ $oc/devices}{device_id//sys/properties/get/response=request_id}{request_id:

示    例/
$oc/devices/6210e8acde9933029be8facf_dev1/sys/properties/get/response=request_id-6c36c85e68e1--4d01-a2a3设备端响应的数据格式b89f09bd0427

:"services"
{:[ "service_id"{:"gps" ,"properties":"DHT11_t"{:12,"DHT11_h":33}}]}应用端上位机收到设备端的响应数据


:"{\"response\":{\"services\":[{\"service_id\":\"temp\",\"properties\":{\"DHT11_t\":13,\"DHT11_h\":33.345}}]}}"
//查询设备属性

(5)应用端获取设备属性

   void
Widget ::Get_device_properties()//表示获取token
{
    =
    function_select0;;

    QString requestUrl;
    QNetworkRequest request//设置请求地址

    ;
    QUrl urlif

    (.device_id_lissize()<=0)//显示错误代码
    {
        QMessageBox
        ::information(this,"提示","未选择设备,请先获取设备列表\n选择设备后重试.",QMessageBox::,OkQMessageBox::)Ok;return
        ;}
    //获取token请求地址

    =
    requestUrl QString ("https://iotda.%1.myhuaweicloud.com/v5/iot/%2/devices/%3/properties?service_id=%4").
                 arg(SERVER_ID).
            arg(PROJECT_ID).
            arg(.device_id_lisat(-ui->comboBoxcurrentIndex>())).
            arg()service_id;//自己创建的TCP服务器,测试用

    //requestUrl="http://10.0.0.6:8080";
    //设置数据提交格式

    .
    requestsetHeader(:QNetworkRequest:,ContentTypeHeaderQVariant ("application/json"));//设置token

    .
    requestsetRawHeader("X-Auth-Token",)Token;//构造请求

    .
    urlsetUrl()requestUrl;.

    requestsetUrl()url;//发送请求

    -
    managerget>()request;}
//查询设备属性

(6)应用端解析数据

    if
    (==function_select0)//解析数据
    {
        ;
        QJsonParseError json_error=
        QJsonDocument document : QJsonDocument:fromJson(,replyData& )json_error;if
        (.json_error==error : QJsonParseError:)NoError//判断是否是对象,然后开始解析数据
        {
            if
            (.documentisObject())=
            {
                QJsonObject obj . documentobject();if
                (.objcontains("response"))=
                {
                    QJsonObject obj1.objtake("response").toObject();if
                    (.obj1contains("services"))=
                    {
                         QJsonArray array.obj1take("services").toArray();}

                         
                    }
                }
            }
         return
        ;}
    
5.4 上位机开发环境搭建

上位机软件是采用QT开发的,Qt是一个1991年由QtCompany开发的跨平台C++图形用户界面应用程序开发框架。它既可以开发GUI程序,也可用于开发非GUI程序,比如控制台工具和服务器。QT在发布 Qt 4.6 的同时,作为 Qt 开发跨平台 IDE 的Qt Creator也发布了更新版本。Qt Creator是一个用于Qt开发的轻量级跨平台集成开发环境。Qt Creator可带来两大关键益处:提供首个专为支持跨平台开发而设计的集成开发环境 (IDE),并确保首次接触Qt框架的开发人员能迅速上手和 *** 作。即使不开发Qt应用程序,Qt Creator也是一个简单易用且功能强大的IDE。

目前QT在嵌入式领域、桌面端都用的非常多,开发桌面,嵌入式的上位机还是非常方便。 嵌入式领域包括: 车机主机、嵌入式Linux设备等。

QT官网: https://resources.qt.io/cn

QT5.12.6安装包下载地址: https://download.qt.io/archive/qt/5.12/5.12.6/

QT学习专栏: https://blog.csdn.net/xiaolong1126626497/category_11400392.html

QT环境搭建文章:https://xiaolong.blog.csdn.net/article/details/120654599

6. 总结

整个项目的实现主要分为两个大部分:1. 设备上云 2. 应用侧的软件开发

(1)设备上云: 目前通过STM32、ESP8266已经完了华为云物联网云平台的连接,ESP8266上云的过程主要是MQTT协议的理解,目前采用的ESP8266没有内置MQTT协议相关的AT指令,需要自己实现MQTT协议,这个过程稍微麻烦一点,需要安装官网的MQTT协议手册拼接结构完成协议构造。对于设备端而言,只要是通信采用标准的MQTT协议,不管连接哪一个物联网云平台,过程是没有多大区别的。

(2)应用层软件开发: 应用侧软件开发主要是方便远程管理设备,目前华为云物联网平台没有提供在线web设计功能、没有提供公版的APP;所以,在设备上云之后,想要方便的对设备的属性进行查看,管理,都需要自己开发上位机才行。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/991124.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存