IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> CC2530/ESP32+传感器+ZigBee+MQTT+MYSQL+Springboot+Vue+Echarts的老人卫生间防摔倒自动报警系统 -> 正文阅读

[大数据]CC2530/ESP32+传感器+ZigBee+MQTT+MYSQL+Springboot+Vue+Echarts的老人卫生间防摔倒自动报警系统

写在前言

这是第一次发布也是我第一次制作一个软硬件结合的小系统。分为两个版本,一种是使用esp32作为开发板,使用红外、触控、温湿度、蜂鸣器等作为传感器获取数据。通过MQTT将数据发送,使用python接收并保存到mysql数据库中,后端使用Springboot,前端使用vue结合echarts制作了一个可视化大屏。另一个版本使用CC2530作为开发板,使用激光测距传感器、红外传感器、温湿度传感器、光敏传感器等获取数据,并使用zigbee协议进行组网,将整个感知层分为4个节点和一个协调器,个节点负责采集数据,使用zigbee将数据传送到协调器,协调器通过esp8266使用mqtt将数据发送出去。后面数据获取、保存、前后端展示和esp32模块相同。下文分为一代和二代进行讲解。内容很长,希望你能看完。

运行效果展示

废话不多说,先看运行效果。演示视频录得有点草率,请多包涵,将就着看。
演示视频

一代版本

一代版本使用了3个ESP32开发板,分别获取卫生间、马桶和淋浴的信息。整体架构图如下:
系统架构图

ESP32+MQTT读取红外传感器

首先使用红外传感器判断老人是否使用卫生间。引脚连接图如下:
在这里插入图片描述

代码如下:

#include <WiFi.h>
#include <PubSubClient.h>
// WiFi名及密码
const char* ssid = ""; //WiFi名
const char* password = ""; //WiFi密码
const char* mqtt_server = "broker.emqx.io"; //mqtt服务器ip地址
const int buzzpin = 16; //定义蜂鸣器16号引脚
const int ledpin = 2;//红外引脚
int infrared_value = 0;//红外传感器值
int infrared_hight = 0;//红外高电平
int infrared_low = 0;//红外低电平
int flag = 0;
boolean infrared_flag = false;//红外检测卫生间使用状态false表示无人、true表示有人

char attributes[1000];
#define LED_BUILTIN 13 //灯 13引脚

WiFiClient espClient; // 定义wifiClient实例
PubSubClient client(espClient); // 定义PubSubClient的实例

void setup_wifi() { //初始化WiFi
  delay(10);  // 板子通电后要启动,稍微等待一下让板子点亮
  Serial.println();  // 准备连接WiFi
  Serial.print("连接: ");
  Serial.println(ssid);  //输出连接WiFi名

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  randomSeed(micros());

  Serial.println("");
  Serial.println("WiFi连接成功!");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("消息来自: [");
  Serial.print(topic); // 打印主题信息
  Serial.print("] 主题,内容:");
  char str[100];
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);  // 打印主题内容
    str[i] = (char)payload[i];
  }
  Serial.println();

  if (strcmp(topic, "light_linfeng") == 0) { //判读信息来源主题
    if (strcmp(str, "开灯") == 0) { //判断命令
      digitalWrite(LED_BUILTIN, HIGH);   // 开灯
    } else if (strcmp(str, "关灯") == 0) {
      digitalWrite(LED_BUILTIN, LOW);   // 关灯
    }
  } else if (strcmp(topic, "alarm_linfeng") == 0) { //判读信息来源主题
    if (strcmp(str, "开始") == 0) {
      digitalWrite(buzzpin, HIGH); // 开始报警
    } else if (strcmp(str, "关闭") == 0) {
      digitalWrite(buzzpin, LOW); // 关闭报警
    }
  }
}

void reconnect() {
  while (!client.connected()) { // 保持连接mqtt
    Serial.print("尝试MQTT连接…");
    String clientId = "ESP8266Client-";    // 创建随机的客户端ID
    clientId += String(random(0xffff), HEX);
    if (client.connect(clientId.c_str())) {    // 尝试连接
      Serial.println("连接成功!");
      client.subscribe("linfeng_data"); //订阅消息
      client.subscribe("light_linfeng"); //订阅消息
      client.subscribe("alarm_linfeng"); //订阅消息
    } else { //连接失败
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);     // 初始化BUILTIN_LED引脚作为输出
  pinMode(buzzpin, OUTPUT);     // 初始化buzzpin引脚作为输出
  Serial.begin(115200); // 串口波特率
  setup_wifi(); //执行Wifi初始化,下文有具体描述
  client.setServer(mqtt_server, 1883); //设定MQTT服务器与使用的端口,1883是默认的MQTT端口
  client.setCallback(callback); //设定回调方式,当ESP8266收到订阅消息时会调用此方法
}

void loop() {

  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  infrared_value = digitalRead(ledpin); //读取红外传感器
  if (infrared_value == HIGH && flag == 0) //如果它的值为高电平,即检测到有人通过
  {
    flag = 1;
    infrared_hight = 1;
  }
  else if(infrared_value == LOW)
  {
    flag = 0;
  }
  if (infrared_hight == 1) {
    infrared_hight = 0;
    if (infrared_flag) {
      Serial.println("离开卫生间!");
      String payload = "{";
      payload += "\"place\":"; payload += "\"wc\",";
      payload += "\"IsWc\":"; payload += false;
      payload += "}";

      payload.toCharArray( attributes, 1000 );
      client.publish("linfeng_data", attributes); //MQTT发布消息
      client.publish("wc_linfeng", "不行"); //向马桶、淋浴发送指令表示不可以发布信息

    } else if (!infrared_flag) {
      Serial.println("进入卫生间!");
      String payload = "{";
      payload += "\"place\":"; payload += "\"wc\",";
      payload += "\"IsWc\":"; payload += true;
      payload += "}";

      payload.toCharArray( attributes, 1000 );
      client.publish("linfeng_data", attributes); //MQTT发布消息
      client.publish("wc_linfeng", "可以"); //向马桶、淋浴发送指令表示可以发布信息
    }
    infrared_flag = !infrared_flag;
    infrared_hight = 0;
  }
  delay(200);
}

使用串口调试助手可查看信息的收发,结果如下:
在这里插入图片描述

ESP32+MQTT读取触控传感器

使用触控传感器采集老人使用马桶的数据,引脚连接图如下:
在这里插入图片描述
关键代码如下:

void loop() {

  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  if (wc_flag == 1) {
    touch_value = digitalRead(TOUCH_PIN); //如果进入卫生间则读取触控传感器
  }
  if (touch_value == HIGH) //如果它的值为高电平,即检测到有人通过
  {
    touch_hight = 1;
    delay(100);
  }
  else
  {
    if (touch_hight == 1) {
      touch_low = 1;
    }
    delay(100);
  }
  if (touch_hight == 1 && touch_low == 1) {
    if (touch_flag) {
      String payload = "{";
      payload += "\"place\":"; payload += "\"toilet\",";
      payload += "\"IsToilet\":"; payload += false;
      payload += "}";

      payload.toCharArray( attributes, 1000 );
      client.publish("linfeng_data", attributes); //MQTT发布消息

      Serial.println("离开马桶!");

    } else if (!touch_flag) {
      String payload = "{";
      payload += "\"place\":"; payload += "\"toilet\",";
      payload += "\"IsToilet\":"; payload += true;
      payload += "}";

      payload.toCharArray( attributes, 1000 );
      client.publish("linfeng_data", attributes); //MQTT发布消息
      
      Serial.println("使用马桶!");
    }
    touch_flag = !touch_flag;
    touch_hight = 0;
    touch_low = 0;
  }
  delay(200);
}

使用串口调试助手可查看信息的收发,结果如下:
在这里插入图片描述

ESP32+MQTT读取温湿度传感器

前两个传感器采集了卫生间和马桶的信息。此处就采集淋浴的使用情况,淋浴的使用和马桶一样,通过触控传感器来采集,此处多了一个温湿度的采集。温湿度引脚连接图如下:
在这里插入图片描述
关键代码如下:

void getAndSendTemperatureAndHumidityData()
{

  // 大概1s读取一次
  delay(200);
  byte hum;
  byte tem;
  int err = SimpleDHTErrSuccess;
  if ((err = dht11.read(&tem, &hum, NULL)) != SimpleDHTErrSuccess) {
    Serial.print("读取数据失败, err="); Serial.println(err);delay(1000);
    return;
  }

  // 查看是否读取温湿度失败的
  if (isnan(hum) || isnan(tem)) {
    Serial.println("从DHT传感器读取失败!");
    return;
  }

  String temperature = String(tem);
  String humidity = String(hum);

  // 构建一个 JSON 格式的payload的字符串
  String payload = "{";
  payload += "\"temperature\":"; payload += temperature; payload += ",";
  payload += "\"humidity\":"; payload += humidity;
  payload += "}";
  payload.toCharArray( attributes, 100 );
  client.publish( "Tem_hum", attributes );
}

使用淋浴结果如下:
在这里插入图片描述

python订阅MQTT保存数据到MySQL

感知层的数据获取完成后,接下来就是数据的存储。使用python订阅感知层发送的MQTT主题,接收这些主题的信息,并将其保存到MySQL数据库中。关键代码如下:

# -*- encoding: utf-8 -*-
"""
@File    : 老人卫生间防摔倒自动报警系统.py
@Time    : 2022/5/22 16:32
@Author  : 林枫
@Software: PyCharm
"""
import time
import paho.mqtt.client as mqtt
import pymysql

broker = 'broker.emqx.io'
port = 1883

def saveMysql(tableName, data):
    conn = pymysql.connect(host='localhost',  # 调用MySQL 并命名为 conn
                           user='root',  # 输入用户名
                           password='',  # 输入初始密码
                           db='oldman',  # 调用数据库
                           charset='utf8')  # 定义格式
    cursor = conn.cursor()  # 创建游标   模拟鼠标
    if tableName == 'toilet':
        sql = """
                                insert into toilet(
                                    in_time, out_time
                                    )
                                    values(%s, %s)
                                """
        # sql语句向表名为林的表中插入值   这里的%s是占位符  等待匹配对应值
        cursor.execute(sql, (data[0], data[1]))  # 向占位符中输入对应值
        conn.commit()
        conn.rollback()
        time.sleep(1)  # 延时0.1秒,免得CPU出问题
    ..............
    print("保存成功!")
    conn.close()  # 关闭   数据库

def on_connect(client, userdata, flags, rc):
    if rc == 0:
        print("连接成功!")
        client.subscribe(topic='linfeng_data')
    else:
        print("Failed to connect, return code %dn", rc)
def on_message(client, userdata, msg):
    global wcs_time, toilet_times, showers_time
    message = []
    data = eval(msg.payload.decode())
    if data["place"] == "wc":
        if data["IsWc"] == 1:
            wcs_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())  # 规整本地时间的格式
            print(wcs_time)
            message.clear()
            message = [1, 0, 0, wcs_time]
            print("开始保存数据到state中......................")
            saveMysql("state", message)
        if data["IsWc"] == 0:
            wc_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())  # 规整本地时间的格式
            print(wc_time)
            message.clear()
            message.append(wcs_time)
            message.append(wc_time)
            print("开始保存数据到wc中......................")
            saveMysql("wc", message)
            message.clear()
            message = [0, 0, 0, wc_time]
            print("开始保存数据到state中......................")
            saveMysql("state", message)
            .....................................

def run():
    client = mqtt.Client()
    client.on_connect = on_connect
    client.on_message = on_message
    client.connect("broker.emqx.io", 1883, 60)
    client.loop_forever()
    
if __name__ == '__main__':
    run()

运行结果如下:
在这里插入图片描述
数据库部分信息如下:
在这里插入图片描述

Springboot后端读取MySQL

本系统较为简单,对数据库的操作只有添加和读取,添加使用python,读取部分使用Springboot框架和mybatis-plus。

State类:

package com.example.floodprevention.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * @author 林枫
 * @date 2022年05月22日 19:04
 */
@TableName("state")
@Data
public class State {
    @TableId(type = IdType.AUTO)
    private Integer id;
    private String wc;
    private String toilet;
    private String shower;
    private String nowTime;
}

StateMapper接口:

package com.example.floodprevention.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.floodprevention.entity.State;

public interface StateMapper extends BaseMapper<State> {
}

StateController方法:

package com.example.floodprevention.controller;

import com.example.floodprevention.common.Result;
import com.example.floodprevention.mapper.StateMapper;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @author 林枫
 * @date 2022年05月22日 19:07
 */
@RestController
@RequestMapping("/state")
public class StateController {
    @Resource
    StateMapper stateMapper;

    @GetMapping
    public Result<?> GetAll() {
        return Result.success(stateMapper.selectList(null));
    }
}

访问路由结果如下:
在这里插入图片描述

Vue+Axios+Echarts+js可视化大屏展示

由于前端代码过于复杂,就不进行代码展示,效果图如下:
在这里插入图片描述
注:由于截图时硬件没有运行,所以没有温湿度的数据!系统的整体运行效果可访问下面的连接。视频草率,请勿吐槽😂😂😂
演示视频

二代版本

二代版本作为一代版本的升级版,主要对硬件部分做了改变,使用更高级的CC2530作为开发板,在传感器的选型方面也做了改变,一代基于老人的摔倒主要是通过时间判断,通过比较老人在一个场所滞留的时间与这一周的平均使用时间作比较,若超过平均时间则黄色预警,若黄色预警一段时间后仍未离开,则判定为摔倒并发出红色警报。二代对于传感器的改变,使用激光测距传感器来判断老人是否使用卫生间,若老人摔倒,激光测距的值会发生剧变,以此来判断老人是否摔倒。
二代版本共使用4个CC2530开发板,将感知层布局为星状网络结构,分为4个终端节点和一个协调器,终端节点和协调器之间通过ZigBee进行通信,协调器将接收到的信息统一打包出来后使用串口发送到ESP8266,然后通过MQTT协议将数据发送出去。

CC2530读取红外传感器

对于使用卫生间的判断仍采用红外传感器。引脚连接图如下:
在这里插入图片描述
关键代码如下:

if(P0_4 == 1)
         {
           flage_count++;
           if(flage_count == 1)
           {
             TX_buff[1] = 1;
             basicRfSendPacket(RECEIVE_ADDR1, (uint8*)TX_buff, 7);  // 向汇聚节点发送数据 7字节
             Uart0_Send_String((uint8*)"come\r\n",7);
           }
           else if(flage_count == 2)
           {
             TX_buff[1] = 0;
             basicRfSendPacket(RECEIVE_ADDR1, (uint8*)TX_buff, 7);  // 向汇聚节点发送数据 7字节
             flage_count = 0;
             Uart0_Send_String((uint8*)"go\r\n",7);
           }
           LED3 = 0;
           delay_ms(20);
           LED3 = 1;
           delay_ms(200);
           delay_ms(200);
           delay_ms(200);
           while(P0_4);
         }

CC2530读取小车循迹传感器

此处采用小车循迹传感器采集马桶使用数据。当老人使用马桶时会接近传感器,此时传感器高电平,当老人离开时,传感器低电平,以此来采集数据。引脚连接图如下:
在这里插入图片描述
关键代码如下:

if(P0_4 == 0)
         {
            TX_buff[1] = 1;
             basicRfSendPacket(RECEIVE_ADDR1, (uint8*)TX_buff, 7);  // 向汇聚节点发送数据 7字节
            Uart0_Send_String((uint8*)"come\r\n",6);
            LED1 = 0;
            delay_ms(20);
            LED1 = 1;
            while(P0_4 == 0);
            delay_ms(20);
            while(P0_4 == 0);
            delay_ms(20);
            while(P0_4 == 0);
            delay_ms(20);
            while(P0_4 == 0);
         }
         else if(P0_4 == 1)
         {
           TX_buff[1] = 0;
           basicRfSendPacket(RECEIVE_ADDR1, (uint8*)TX_buff, 7);  // 向汇聚节点发送数据 7字节
           Uart0_Send_String((uint8*)"go\r\n",6);
           LED1 = 0;
           delay_ms(20);
           LED1 = 1;
           while(P0_4 == 1);
           delay_ms(20);
           while(P0_4 == 1);
           delay_ms(20);
           while(P0_4 == 1);
           delay_ms(20);
           while(P0_4 == 1);
         }

CC2530读取激光测距传感器

使用激光测距传感器采集老人进出卫生间的数据,以及判断老人是否摔倒。引脚连接图如下:
在这里插入图片描述
关键代码如下:

if(flage == 1)
         {
           flage = 0;
           old_distance6 = old_distance5;
           old_distance5 = old_distance4;
           old_distance4 = old_distance3;
           old_distance3 = old_distance2;
           old_distance2 = old_distance;
           old_distance = distance;
           distance = VL53LX_read();
           
           
           if(distance >= 100 && distance <= 600 && people_flage == 0)//老人到来
           {
             people_flage = 1;
             error_count = 0;
             TX_buff[1] = 1;
             basicRfSendPacket(RECEIVE_ADDR1, (uint8*)TX_buff, 7);  // 向汇聚节点发送数据 7字节
             sprintf(show_Buff1,"data:%d come\r\n",distance);
             Uart0_Send_String((uint8*)show_Buff1,20);
             LED3 = 1;
             delay_ms(20);
             LED3 = 0;
             
           }
           else if( (distance == 20 || distance == 8190)&& people_flage == 1)//老人离开
           {
             error_count++;
             if(error_count >= 3)
             {
               
               error_count = 0;
               people_flage = 0;
               if(old_distance5 < 500 && old_distance6 < 500 )
              {
                TX_buff[1] = 2;//摔倒
                basicRfSendPacket(RECEIVE_ADDR1, (uint8*)TX_buff, 7);  // 向汇聚节点发送数据 7字节
                sprintf(show_Buff1,"data:%d shuai\r\n",distance);
                LED1 = 1;
                tim_flag = 1;
              }
              else
              {
                TX_buff[1] = 0;//离开
                basicRfSendPacket(RECEIVE_ADDR1, (uint8*)TX_buff, 7);  // 向汇聚节点发送数据 7字节
                sprintf(show_Buff1,"data:%d go\r\n",distance);
              }

CC2530读取温湿度传感器

使用DHT11温湿度传感器读取卫生间温湿度信息。引脚连接图如下:
在这里插入图片描述
关键代码如下:

if(flage == 1)
         {
           flage = 0;
           dht11ReadDat(datBuf);
           sprintf(show_Buff1,"tem:%d.%d hum:%d.%d",datBuf[2],datBuf[3],datBuf[0],datBuf[1]);
           tem = datBuf[2]+datBuf[3]*0.1;
           hum = datBuf[0]+datBuf[1]*0.1;
           
           TX_buff[3] = datBuf[0];
           TX_buff[4] = datBuf[1];
           TX_buff[5] = datBuf[2];
           TX_buff[6] = datBuf[3];
           light = gy30_read();
           
           check();
           TX_buff[1] = light & 0XFF;
           TX_buff[2] = light >> 8;
           sprintf(show_Buff2,"light:%d lx   ",TX_buff[2]*256 + TX_buff[1]);
           TX_buff[0] = 1; //指定报文头
           basicRfSendPacket(RECEIVE_ADDR1, (uint8*)TX_buff, 7);  // 向第一个汇聚节点发送数据 7字节
           LED3 = 1;
           delay_ms(20);
           LED3 = 0;
         }

python订阅MQTT保存数据到MySQL

二代版本数据存储和一代相似,不过对于python的代码进行了分类增加了邮件报警功能。整体结构如下:
在这里插入图片描述
代码就不赘述了。

Springboot后端读取MySQL

和一代类似,后端并没有做更改,在此就不赘述。

Vue+Axios+Echarts+js可视化大屏展示

二代版本因为传感器的选择变换,判断老人摔倒由原来的时间判断改为传感器判断,所以逻辑更改了一部分,但是界面整体并没有改变。
演示视频

总结

因为学年设计和课程设计,第一次做一个软硬件结合的系统,整体用了一个星期。各部分的功能也并不怎么完美,但是涉及到了传感器的读取、无线数据传输、MySQL存储数据、前后端交互、可视化展示等等。也就想把它给发出来,第一次写这么长的文章,非常感谢你能看到这里。有需要源码学习交流的可以加我qq3090677003 。

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-06-21 21:28:50  更:2022-06-21 21:30:09 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 0:02:31-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码