# smartHome
基于ZigBee+ESP32+MQTT+EMQX+TomCat+Servlet接口+MySQL+安卓app的物联网项目
## 一、写在前面
在放寒假前,自己也说过了,这个寒假一定好好复盘一下大三上学期的一个项目。
## 二、课设简介
我的课设想法:因为自己已经大三了,也不年轻了,技术也学得很广泛也很烂(物联网专业也算得上是一个万金油专业),综合自己学过的技术和对自己专业的认知,当时萌生了做一个很普通的适合物联网三层架构思想的一个小课设,不求有多高级多厉害多实用,但求技术稍微全面一点,所以我只用到了一些简单的传感器,比如烟雾、光照、温湿度、执行器使用led灯,自己打算从底层到传输层,传输层到应用层,一层一层地来实现,尽量不使用或者少使用第三方的技术。
![我的整个想法-系统框图](https://img-blog.csdnimg.cn/20210212180614658.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzYyNzAyMg==,size_16,color_FFFFFF,t_70)
**课设名称:** 智能家居数据上传和远程控制系统
**花费时间:** 20天
**成本价格:** 180元
## 三、不眠夜开始了
### 1、基于zigbee网络数据采集的底层实现
因为课程要求需要用到zigbee模块和esp32模块,所以采集传感器的数据理所当然地由zigbee节点完成了。
**原理:** 如图所示,节点1负责采集烟雾和光强的数据,节点2负责采集温室度数据,同时这两个节点上自带了led灯,后面的开灯操作就是直接控制板子上的led灯。两个节点采集到的数据将通过zigbee网络发送给协调器(zigbee网络的构建者和管理者),协调器收到两个子节点发来的数据,然后通过串口(杜邦线连接)把数据发送给ESP32网关。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210212173620282.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzYyNzAyMg==,size_16,color_FFFFFF,t_70)
关于zigbee的学习,可以用**挣扎**两字来形容,大家都学得很吃力,甚至大多数人包括我都是一知半解,直接看函数的解释来使用的,毕竟能力就到这了。老师规定使用zigbee要使用SimpleApi框架,能看懂函数,就应该都会用!
**节点1读取烟雾浓度和光强数据的部分代码:**
```c
//读取adc的值,参数是通道数
unsigned int readAdc(unsigned char channal);
unsigned int readAdc(unsigned char channal)
{
unsigned int value ;
APCFG |= 1 << channal ;
ADCIF = 0 ;
ADCCON3 = channal;
while ( !ADCIF ) ;
value = ADCL;
value |= ((unsigned int) ADCH) << 8 ;
value>>=2;
return value;
}
//上电执行,构建网络使用,加入网络成功时status==ZSUCCESS。
void zb_StartConfirm( uint8 status )
{
if(status==ZSUCCESS)
{
//可把节点所包含的led灯的ID号发送过去
zb_SendDataRequest(0X0,LEDJOINNET_CMD_ID,LEDNUM,ledIdList,0,FALSE,AF_DEFAULT_RADIUS);
osal_start_timerEx(sapi_TaskID,TIMER_TIMEOUT_EVT,2000); //每两秒给协调器发送一个心跳包
osal_start_timerEx(sapi_TaskID,READ_MQ2_EVENT,5000);//每5秒采集一次烟雾浓度数据
osal_start_timerEx(sapi_TaskID,READ_LIGHT_EVENT,5000);//每5秒采集一次光照强度数据
}
}
//事件处理函数
void zb_HandleOsalEvent( uint16 event )
{
if(event&READ_MQ2_EVENT){//读取烟雾浓度数据的事件
osal_start_timerEx(sapi_TaskID,READ_MQ2_EVENT,5000);//定时下一次采集烟雾浓度的事件,也是5秒
unsigned char mq2value[4];
unsigned int AdcValue=0;
AdcValue=readAdc(5);//采集第5通道的adc值
sprintf(mq2value,"%d\r\n", AdcValue);//把数值放到char类型的数组
//把读取到的烟雾浓度值通过zigbee网络发给协调器,协调器默认的网络地址是0
zb_SendDataRequest(0X0,MQ2_CMD_ID,osal_strlen(mq2value),mq2value,0,FALSE,AF_DEFAULT_RADIUS);
}
}
```
**节点2读取温湿度数据部分代码:**
```c
void Read_Byte(void);//从DHT11读取一个字节函数
void Read_Byte(void)
{
uchar i;
for (i = 0; i < 8; i++) //循环8次,读取8bit的数据
{
Overtime_counter = 2; //读取并等待DHT11发出的12-14us低电平开始信号
P0DIR &= ~0x10;
while ((!DHT11_DATA) && Overtime_counter++);
//Delay_10us(80); //26-28us的低电平判断门限
MicroWait(27);
bit_value = 0; //跳过门限后判断总线是高还是低,高为1,低为0
if(DHT11_DATA)
bit_value = 1;
Overtime_counter=2; //等待1bit的电平信号结束,不管是0是1在118us后都变为低电平,否则错误超时
while (DHT11_DATA && Overtime_counter++); //当U8FLAG加到255后溢出为0,跳出循环,并后加加为1
if (Overtime_counter == 1)
break; //超时则跳出for循环
comdata <<= 1; //左移1位,LSB补0
comdata |= bit_value;//LSB赋值
}
}
void zb_StartConfirm( uint8 status )
{
if(status==ZSUCCESS)
{
//可把节点所包含的led灯的ID号发送过去
zb_SendDataRequest(0X0,LEDJOINNET_CMD_ID,LEDNUM,ledIdList,0,FALSE,AF_DEFAULT_RADIUS);
osal_start_timerEx(sapi_TaskID,TIMER_TIMEOUT_EVT,2000);
osal_start_timerEx(sapi_TaskID,READ_DHT11_EVENT,5000);
}
}
//事件处理函数
void zb_HandleOsalEvent( uint16 event )
{
if(event&READ_DHT11_EVENT){//读取温湿度数据的事件
unsigned char temphumi[2];
Read_DHT11(temphumi,temphumi+1);//参数是一级指针变量,数组名也是首地址,可以传!
if(temphumi!=NULL)//上一行执行完,temphumi里保存的就是温湿度的值
{
osal_start_timerEx(sapi_TaskID,READ_DHT11_EVENT,5000);//定时下一个读取温湿度数据的事件
//把温湿度数据发送给协调器
zb_SendDataRequest(0X0,TEMP_HUMI_CMD_ID,osal_strlen(temphumi),temphumi,0,FALSE,AF_DEFAULT_RADIUS);
}
}
}
```
看上面的两段代码会发现没有任何关于灯或风扇的代码,是因为当时把整个系统调通之后,第二天就要答辩了,来不及了,所以就直接控制了协调器板子上的led灯。
节点1和节点2采集的数据发送给协调器后,协调器需要接收数据,还可以对数据进行一定的格式处理,再通过串口发送给ESP32网关。
**协调器的代码:**
```c
//当构建网络或加入网络成功时被调用
void zb_StartConfirm( uint8 status )
{
halUARTCfg_t uartcfg;
uartcfg.baudRate=HAL_UART_BR_115200;
uartcfg.flowControl=FALSE;
uartcfg.callBackFunc=uart_receive;
HalUARTOpen(HAL_UART_PORT_1,&uartcfg);
HalLedSet(HAL_LED_1, HAL_LED_MODE_OFF);//初始化关闭led
HalLedSet(HAL_LED_2, HAL_LED_MODE_OFF);//初始化关闭led
if(status==ZSUCCESS)
{
char buf[]="Coordinator is created successfully!\r\n";//协调器构建网络成功
HalUARTWrite(HAL_UART_PORT_1,buf,osal_strlen(buf));
osal_start_timerEx(sapi_TaskID,TIMER_TIMEOUT_EVT,2000);//定时心跳包事件
}
}
//执行时机:接收到数据包时被调用
void zb_ReceiveDataIndication( uint16 source, uint16 command, uint16 len, uint8 *pData ){
.....省略部分代码
}else if(command==TEMP_HUMI_CMD_ID){//收到节点2发来的温湿度数据包
sprintf(buf,"{\"t\":\"th\",\"temp\":\"%d\",\"humi\":\"%d\"}",pData[0],pData[1]);//把数据整合成json格式
HalUARTWrite(HAL_UART_PORT_1,buf,osal_strlen(buf));//通过串口发送给ESP32网关
HalUARTWrite(HAL_UART_PORT_1,"\r\n",2);
}else if(command==MQ2_CMD_ID){//收到节点1发来的烟雾浓度数据包
sprintf(buf,"{\"t\":\"mq2\",\"mq2\":\"%c%c%c%c\"}",pData[0],pData[1],pData[2],pData[3]);//整合成json格式
HalUARTWrite(HAL_UART_PORT_1,buf,osal_strlen(buf));//通过串口