天天看點

基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)

1. 功能介紹

這是基于華為雲物聯網平台設計智能家居控制系統(模型),硬體采用STM32+ESP8266完成上雲組合;通過雲平台可以遠端控制家裡的各種電器開關,并且可以遠端收集家裡瓦斯、天然氣、煙霧、光照度、溫度濕度等資訊。

硬體介紹:

主要MCU:

STM32F103ZET6

煙霧檢測傳感器:

MQ2

天然氣檢測傳感:

MQ5

溫度濕度檢測傳感器:

DHT11

光照強度檢測傳感器:

BH1750

物聯網雲平台:

華為雲物聯網平台

電器開關模拟采用闆載的LED燈、繼電器。

WIFI:

ESP8266

這是支援序列槽AT指令控制的WIFI子產品,聯網比較友善。

與華為雲物聯網平台通信的協定:

MQTT

說明: 目前程式裡的MQTT協定代碼是參考MQTT官方文檔編寫的,不是使用ESP8266内置的,是以程式并不依賴ESP8266專用或者指定的SDK,使用任意可以上網的網卡都可以套用,并不是一定非要使用ESP8266。

2. 登入華為雲建立雲端裝置

2.1 建立産品

華為運官網:

https://www.huaweicloud.com/
基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)
基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)
基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)

在這裡可以檢視接入的協定的端口号和位址。

基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)
基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)
MQTT (1883)    a161a58a78.iot-mqtts.cn-north-4.myhuaweicloud.com               

我們裝置接入的協定選擇MQTT,端口對應是1883

接下來繼續建立産品,點選産品頁面,點選右上角建立産品:

基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)
基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)
基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)

2.2 建立裝置

基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)
基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)

這是我的裝置資訊:

裝置ID
61a580fad28ce3028832c2d8_esp8266_iot

裝置密鑰
1126626497
    
{
    "device_id": "61a580fad28ce3028832c2d8_esp8266_iot",
    "secret": "1126626497"
}           

2.3 産品模型定義

這一步就是設定上報裝置的屬性,也就是裝置的資料類型定義。

基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)
基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)
基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)
基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)

2.4 生成MQTT登入密匙

建立完産品、裝置之後,接下來就需要知道如何通過MQTT協定登陸華為雲伺服器。

官方的詳細介紹在這裡:

https://support.huaweicloud.com/devg-iothub/iot_01_2127.html#ZH-CN_TOPIC_0240834853__zh-cn_topic_0251997880_li365284516112
基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)
基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)

MQTT裝置登陸密匙生成位址:

https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/
基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)

下面就得到了MQTT協定裝置登入的參數。

2.5 使用MQTT用戶端軟體登入

所有的參數已經得到,接下來采用MQTT用戶端登入華為雲進行測試。

下面這個軟體是自己開發的,為了友善測試MQTT協定登入。

華為雲物聯網平台的域名是:

a161a58a78.iot-mqtts.cn-north-4.myhuaweicloud.com

華為雲物聯網平台的IP位址是:

121.36.42.100

基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)

在軟體裡參數填充正确之後,就看到裝置已經連接配接成功了。

接下來打開裝置頁面,可以看到裝置已經線上了。

基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)

2.6 上報資料

官方文檔:

在這個文檔裡介紹了MQTT上報資料的格式。

基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)
基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)
基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)

總結的格式:

//訂閱主題: 平台下發消息給裝置
$oc/devices/61a580fad28ce3028832c2d8_esp8266_iot/sys/messages/down

//裝置上報資料
$oc/devices/61a580fad28ce3028832c2d8_esp8266_iot/sys/properties/report

//上報的屬性消息 (一次可以上報多個屬性,在json裡增加就行了)
{"services": [{"service_id": "dht11","properties":{"DHT11-C":50}}]}           

下面采用MQTT軟體上報資料:

基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)
基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)

到此,裝置資料已經上報成功,如果需要增加更多的屬性,按照流程繼續增加即可。

3. STM32+ESP8266上報資料到華為雲

3.1 硬體裝置效果圖

基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)
基于華為物聯網雲平台設計的智能家居控制系統(STM32+ESP8266)

3.2 BH1750.c 光照度傳感器

#include "bh1750.h"
float Read_BH1750_Data()
{
    unsigned char t0;
    unsigned char t1;
    float t;
    u8 r_s=0;
    IIC_Start(); //發送起始信号
    IIC_WriteOneByteData(0x46);
    r_s=IIC_GetACK();//擷取應答
    if(r_s)printf("error:1\r\n");
    IIC_WriteOneByteData(0x01);
    r_s=IIC_GetACK();//擷取應答
     if(r_s)printf("error:2\r\n");
    IIC_Stop(); //停止信号 
    
    IIC_Start(); //發送起始信号
    IIC_WriteOneByteData(0x46);
    r_s=IIC_GetACK();//擷取應答
    if(r_s)printf("error:3\r\n");
    IIC_WriteOneByteData(0x01);
    r_s=IIC_GetACK();//擷取應答
    if(r_s)printf("error:4\r\n");
    IIC_Stop(); //停止信号 
    
    IIC_Start(); //發送起始信号
    IIC_WriteOneByteData(0x46);
    r_s=IIC_GetACK();//擷取應答
    if(r_s)printf("error:5\r\n");
    IIC_WriteOneByteData(0x10);
    r_s=IIC_GetACK();//擷取應答
    if(r_s)printf("error:6\r\n");
    IIC_Stop(); //停止信号 
    
    DelayMs(300); //等待
    
    IIC_Start(); //發送起始信号
    IIC_WriteOneByteData(0x47);
    r_s=IIC_GetACK();//擷取應答
    if(r_s)printf("error:7\r\n");
    
    t0=IIC_ReadOneByteData(); //接收資料
    IIC_SendACK(0); //發送應答信号
    t1=IIC_ReadOneByteData(); //接收資料
    IIC_SendACK(1); //發送非應答信号
    IIC_Stop(); //停止信号
    
     t=(((t0<<8)|t1)/1.2);
     return t;  
}           

3.3 ESP8266.c WIFI代碼

#include "esp8266.h"
u8 ESP8266_IP_ADDR[16]; //255.255.255.255
u8 ESP8266_MAC_ADDR[18]; //硬體位址
/*
函數功能: ESP8266指令發送函數
函數傳回值:0表示成功  1表示失敗
*/
u8 ESP8266_SendCmd(char *cmd)
{
    u8 i,j;
    for(i=0;i<10;i++) //檢測的次數--發送指令的次數
    {
        USARTx_StringSend(USART3,cmd);
        for(j=0;j<100;j++) //等待的時間
        {
            delay_ms(50);
            if(USART3_RX_FLAG)
            {
                USART3_RX_BUFFER[USART3_RX_CNT]='\0';
                USART3_RX_FLAG=0;
                USART3_RX_CNT=0;
                if(strstr((char*)USART3_RX_BUFFER,"OK"))
                {
                    return 0;
                }
            }
        }
    }
    return 1;
}

/*
函數功能: ESP8266硬體初始化檢測函數
函數傳回值:0表示成功  1表示失敗
*/
u8 ESP8266_Init(void)
{
    //退出透傳模式
    USARTx_StringSend(USART3,"+++");
    delay_ms(50);
    return ESP8266_SendCmd("AT\r\n");
}


/*
函數功能: TCP伺服器模式下的發送函數
發送指令: 
*/
u8 ESP8266_ServerSendData(u8 id,u8 *data,u16 len)
{
    u8 i,j,n;
    char ESP8266_SendCMD[100]; //組合發送過程中的指令
    for(i=0;i<10;i++)
    {
        sprintf(ESP8266_SendCMD,"AT+CIPSEND=%d,%d\r\n",id,len);
        USARTx_StringSend(USART3,ESP8266_SendCMD);
        for(j=0;j<10;j++)
        {
            delay_ms(50);
            if(USART3_RX_FLAG)
            {
                USART3_RX_BUFFER[USART3_RX_CNT]='\0';
                USART3_RX_FLAG=0;
                USART3_RX_CNT=0;
                if(strstr((char*)USART3_RX_BUFFER,">"))
                {
                    //繼續發送資料
                    USARTx_DataSend(USART3,data,len);
                    //等待資料發送成功
                    for(n=0;n<200;n++)
                    {
                        delay_ms(50);
                        if(USART3_RX_FLAG)
                        {
                            USART3_RX_BUFFER[USART3_RX_CNT]='\0';
                            USART3_RX_FLAG=0;
                            USART3_RX_CNT=0;
                            if(strstr((char*)USART3_RX_BUFFER,"SEND OK"))
                            {
                                return 0;
                            }
                         }            
                    }   
                }
            }
        }
    }
    return 1;
}

/*
函數功能: 配置WIFI為STA模式+TCP用戶端模式
函數參數:
char *ssid  建立的熱點名稱
char *pass  建立的熱點密碼 (最少8位)
char *p     将要連接配接的伺服器IP位址
u16 port    将要連接配接的伺服器端口号
u8 flag     1表示開啟透傳模式 0表示關閉透傳模式
函數傳回值:0表示成功  其他值表示對應的錯誤
*/
u8 ESP8266_STA_TCP_Client_Mode(char *ssid,char *pass,char *ip,u16 port,u8 flag)
{
    char ESP8266_SendCMD[100]; //組合發送過程中的指令
    //退出透傳模式
    //USARTx_StringSend(USART3,"+++");
    //delay_ms(50);
    /*1. 測試硬體*/
    if(ESP8266_SendCmd("AT\r\n"))return 1;
    /*2. 關閉回顯*/
    if(ESP8266_SendCmd("ATE0\r\n"))return 2;
    /*3. 設定WIFI模式*/
    if(ESP8266_SendCmd("AT+CWMODE=1\r\n"))return 3;
    /*4. 複位*/
    ESP8266_SendCmd("AT+RST\r\n");
    delay_ms(1000);
    delay_ms(1000);
    delay_ms(1000);
    /*5. 關閉回顯*/
    if(ESP8266_SendCmd("ATE0\r\n"))return 5;
    /*6. 配置将要連接配接的WIFI熱點資訊*/
    sprintf(ESP8266_SendCMD,"AT+CWJAP=\"%s\",\"%s\"\r\n",ssid,pass);
    if(ESP8266_SendCmd(ESP8266_SendCMD))return 6;
    /*7. 設定單連接配接*/
    if(ESP8266_SendCmd("AT+CIPMUX=0\r\n"))return 7;
    /*8. 配置要連接配接的TCP伺服器資訊*/
    sprintf(ESP8266_SendCMD,"AT+CIPSTART=\"TCP\",\"%s\",%d\r\n",ip,port);
    if(ESP8266_SendCmd(ESP8266_SendCMD))return 8;
    /*9. 開啟透傳模式*/
    if(flag)
    {
       if(ESP8266_SendCmd("AT+CIPMODE=1\r\n"))return 9; //開啟
       if(ESP8266_SendCmd("AT+CIPSEND\r\n"))return 10;  //開始透傳
       if(!(strstr((char*)USART3_RX_BUFFER,">")))
       {
            return 11;
       }
        //如果想要退出發送:  "+++"
    }
    
     //列印總體資訊
    USART1_Printf("WIFI模式:STA+TCP用戶端\n");
    USART1_Printf("Connect_WIFI熱點名稱:%s\n",ssid);
    USART1_Printf("Connect_WIFI熱點密碼:%s\n",pass);
    USART1_Printf("TCP伺服器端口号:%d\n",port);
    USART1_Printf("TCP伺服器IP位址:%s\n",ip);
    return 0;
}


/*
函數功能: TCP用戶端模式下的發送函數
發送指令: 
*/
u8 ESP8266_ClientSendData(u8 *data,u16 len)
{
    u8 i,j,n;
    char ESP8266_SendCMD[100]; //組合發送過程中的指令
    for(i=0;i<10;i++)
    {
        sprintf(ESP8266_SendCMD,"AT+CIPSEND=%d\r\n",len);
        USARTx_StringSend(USART3,ESP8266_SendCMD);
        for(j=0;j<10;j++)
        {
            delay_ms(50);
            if(USART3_RX_FLAG)
            {
                USART3_RX_BUFFER[USART3_RX_CNT]='\0';
                USART3_RX_FLAG=0;
                USART3_RX_CNT=0;
                if(strstr((char*)USART3_RX_BUFFER,">"))
                {
                    //繼續發送資料
                    USARTx_DataSend(USART3,data,len);
                    //等待資料發送成功
                    for(n=0;n<200;n++)
                    {
                        delay_ms(50);
                        if(USART3_RX_FLAG)
                        {
                            USART3_RX_BUFFER[USART3_RX_CNT]='\0';
                            USART3_RX_FLAG=0;
                            USART3_RX_CNT=0;
                            if(strstr((char*)USART3_RX_BUFFER,"SEND OK"))
                            {
                                return 0;
                            }
                         }            
                    }   
                }
            }
        }
    }
    return 1;
}           

3.4 main.c 主函數

#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "key.h"
#include "usart.h"
#include <string.h>
#include "timer.h"
#include "esp8266.h"
#include "mqtt.h"
#include "oled.h"
#include "fontdata.h"
#include "bh1750.h"
#include "iic.h"
#include "sht3x.h"


#define ESP8266_WIFI_AP_SSID  "CMCC-Cqvn"   //将要連接配接的路由器名稱 --不要出現中文、空格等特殊字元
#define ESP8266_AP_PASSWORD "99pu58cb"     //将要連接配接的路由器密碼


//華為雲伺服器的裝置資訊
#define MQTT_ClientID "61a580fad28ce3028832c2d8_esp8266_iot_0_0_2021113002"
#define MQTT_UserName "61a580fad28ce3028832c2d8_esp8266_iot"
#define MQTT_PassWord "74af3bf3024cf9c41b13d6c63fc86e25012b54141ecfcdff3516f08665140e6f"

//訂閱與釋出的主題
#define SET_TOPIC  "$oc/devices/61a580fad28ce3028832c2d8_esp8266_iot/sys/messages/down"  //訂閱
#define POST_TOPIC "$oc/devices/61a580fad28ce3028832c2d8_esp8266_iot/sys/properties/report"  //釋出


char mqtt_message[200];//上報資料緩存區
char OLED_ShowBuff[100];
u8 ESP8266_Stat=0;


/*
函數功能: 溫濕度\光強度顯示
*/
void ShowTemperatureAndHumidity(float temp,float humi,float light)
{
    sprintf(OLED_ShowBuff,"T: %.2f",temp);
    OLED_ShowString(40,16*0,16,OLED_ShowBuff); 
    sprintf(OLED_ShowBuff,"H: %.2f%%",humi);
    OLED_ShowString(40,16*1,16,OLED_ShowBuff);
    sprintf(OLED_ShowBuff,"L: %.2f%%",light);
    OLED_ShowString(40,16*2,16,OLED_ShowBuff); 
}

/*
函數功能: ESP8266顯示頁面
*/
void ESP8266_ShowPageTable(void)
{
    if(ESP8266_Stat)OLED_ShowString(0,16*0,16,"WIFI STAT:ERROR");
    else OLED_ShowString(0,16*0,16,"WIFI STAT:OK");

    //顯示字元串
    sprintf((char*)OLED_ShowBuff,"%s",ESP8266_WIFI_AP_SSID);
    OLED_ShowString(0,16*1,16,OLED_ShowBuff);    
    
    sprintf((char*)OLED_ShowBuff,"%s",ESP8266_AP_PASSWORD);   
    OLED_ShowString(0,16*2,16,OLED_ShowBuff);    
}


int main()
{
   u32 time_cnt=0;
   u32 i;
   u8 key;
   u8 page=0;
   float temp=0;
   float humi=0;
   float light=0;
   u8 motor_state=0;
   float Humidity;
   float Temperature;
    
   delay_ms(1000);
   delay_ms(1000);
    
   LED_Init();
   KEY_Init();
   IIC_Init();
    
    //OLED初始化
   OLED_Init(0xc8,0xa1); //OLED顯示屏初始化--正常顯示;
     //清屏
   OLED_Clear(0);
    
   USART1_Init(115200);
   TIMER1_Init(72,20000); //逾時時間20ms

   USART3_Init(115200);//序列槽-WIFI
   TIMER3_Init(72,20000); //逾時時間20ms
    
   Init_SHT30();
    
   USART1_Printf("正在初始化WIFI請稍等.\n");
   
   if(ESP8266_Init())
   {
      ESP8266_Stat=1;
      USART1_Printf("ESP8266硬體檢測錯誤.\n");  
   }
   else
   {
      //非加密端口
      USART1_Printf("WIFI:%d\n",ESP8266_STA_TCP_Client_Mode(ESP8266_WIFI_AP_SSID,ESP8266_AP_PASSWORD,"121.36.42.100",1883,1));
   }
   
    //2. MQTT協定初始化    
    MQTT_Init(); 
   
    //3. 連接配接華為雲IOT伺服器        
    while(MQTT_Connect(MQTT_ClientID,MQTT_UserName,MQTT_PassWord))
    {
        USART1_Printf("伺服器連接配接失敗,正在重試...\n");
        delay_ms(500);
    }
    USART1_Printf("伺服器連接配接成功.\n");
    
    
    //3. 訂閱主題
    if(MQTT_SubscribeTopic(SET_TOPIC,0,1))
    {
        USART1_Printf("主題訂閱失敗.\n");
    }
    else
    {
        USART1_Printf("主題訂閱成功.\n");
    }        
        
    while(1)
    {    
        //按鍵可以測試
        key=KEY_Scan(0);
        if(key==1)
        {
            //清屏
            OLED_Clear(0);
            
            //翻頁
            if(page>=1)
            {
                page=0;
            }
            else
            {
                 page++;
            }         
        
            LED1=!LED1;  //LEd狀态燈
        }
        else if(key==2)
        {
            LED1=!LED1;  //LEd狀态燈
            time_cnt=0;
            //電機狀态改變
            MOTOR_DEV=!MOTOR_DEV;
            //電機狀态
            motor_state=MOTOR_DEV;
            //補光燈
            LIGHT_DEV=!LIGHT_DEV;      
        }  
        
        //接收WIFI傳回的資料
        if(USART3_RX_FLAG)
        {
            USART3_RX_BUFFER[USART3_RX_CNT]='\0';
            
            //向序列槽列印傳回的資料
            for(i=0;i<USART3_RX_CNT;i++)
            {
                USART1_Printf("%c",USART3_RX_BUFFER[i]);
            }
            
            USART3_RX_CNT=0;
            USART3_RX_FLAG=0;
        }
              
        //定時與保持與華為雲物聯網的同步--1秒一次
        delay_ms(10);
        time_cnt++;
        if(time_cnt==50)
        {
            time_cnt=0;
            
            //狀态燈 --表示程式還活着
            LED2=!LED2;
            
            //讀取光強度
            light=Read_BH1750_Data();
           
            //讀取溫濕度
            SHT3x_ReadData(&Humidity,&Temperature);
            humi=Humidity;
            temp=Temperature;
            
            //上傳資料--溫度
            sprintf(mqtt_message,"{\"services\": [{\"service_id\": \"dht11\",\"properties\":{\"DHT11-C\":%d}}]}",temp);
            
            MQTT_PublishData(POST_TOPIC,mqtt_message,0);
            //根據濕度自動灌溉
            if(humi<50.0)  //小于50自動灌溉
            {
                 motor_state=1; //電機狀态更新
                 MOTOR_DEV=1;  //開電機
            } 
        }
         
        //OLED顯示屏
        if(page==0)
        {
            ShowTemperatureAndHumidity(temp,humi,light);
        }
        else if(page==1)
        {
            ESP8266_ShowPageTable();
        }
    }
}