ESP32 蓝牙网关实践:BLE 设备数据采集与 MQTT 云平台发布(附代码示例)

摘要: 本文详细介绍了如何使用 ESP32 构建强大的蓝牙网关,实现蓝牙设备与 Wi-Fi/互联网之间的无缝连接和数据桥接。文章涵盖了连接和桥接功能、数据处理和分析能力,并提供了详细的代码示例和 Mermaid 生成的图表,助您轻松构建自己的蓝牙网关解决方案。

一、 引言

随着物联网 (IoT) 的快速发展,蓝牙技术凭借其低功耗、低成本和易用性,在连接各种传感器、设备和智能家居产品方面发挥着至关重要的作用。然而,蓝牙设备通常通信范围有限,且无法直接连接互联网。ESP32 是一款功能强大的微控制器,集成了 Wi-Fi 和蓝牙功能,使其成为构建蓝牙网关的理想选择,可以将蓝牙设备连接到互联网,实现远程监控和控制。

二、 ESP32 蓝牙网关功能

ESP32 蓝牙网关可以实现以下关键功能:

1. 连接和桥接:

  • 蓝牙到 Wi-Fi/互联网桥接: ESP32 可以连接到蓝牙传感器、设备或信标,并将收集的数据通过 Wi-Fi 传输到云平台或本地服务器,实现远程监控和控制。
  • 蓝牙到蓝牙桥接: 扩展蓝牙设备的通信范围,例如连接位于不同房间或楼层的蓝牙设备。
  • 支持多种蓝牙协议: ESP32 支持多种蓝牙协议,包括 Bluetooth Classic (SPP, HID) 和 Bluetooth Low Energy (BLE),以连接各种类型的蓝牙设备。

2. 数据处理和分析:

  • 数据过滤和聚合: ESP32 可以对从蓝牙设备收集的数据进行预处理,例如过滤噪声数据或聚合多个传感器的数据,以减少网络负载并提高效率。
  • 本地数据存储: 使用 SD 卡或外部存储器,ESP32 可以存储从蓝牙设备收集的数据,以便在网络连接不可用时进行缓存或离线分析。
  • 边缘计算: ESP32 可以执行简单的计算任务,例如数据转换、阈值警报和趋势分析,从而减少数据传输量并提高响应速度。

三、 系统架构

下图展示了 ESP32 蓝牙网关的典型系统架构:

架构说明:

  • 多个蓝牙设备(例如传感器、智能灯泡、智能门锁)通过蓝牙连接到 ESP32 蓝牙网关。
  • ESP32 蓝牙网关通过 Wi-Fi 或以太网连接到互联网或本地服务器。
  • ESP32 网关可以将数据转发到云平台或本地服务器,也可以在本地处理数据并执行边缘计算任务。

四、 代码示例

以下是一个简单的 ESP32 蓝牙网关代码示例,演示了如何使用 BLE 连接到蓝牙传感器并通过 Wi-Fi 将数据发送到 MQTT broker:

#include <Arduino.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
#include <WiFi.h>
#include <PubSubClient.h>

// 设置 Wi-Fi 和 MQTT broker 信息
const char* ssid = "your_wifi_ssid";
const char* password = "your_wifi_password";
const char* mqtt_server = "your_mqtt_broker_ip";
const int mqtt_port = 1883;

// 设置蓝牙服务和特征 UUID
static BLEUUID serviceUUID("your_service_uuid");
static BLEUUID characteristicUUID("your_characteristic_uuid");

// 创建 BLE 和 MQTT 客户端
BLEAdvertisedDevice* myDevice;
WiFiClient espClient;
PubSubClient client(espClient);

// 连接到 Wi-Fi
void setupWifi() {
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

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

  Serial.println("");
  Serial.println("WiFi connected!");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

// 连接到 MQTT broker
void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect("ESP32Client")) {
      Serial.println("connected");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

// 扫描蓝牙设备
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
  void onResult(BLEAdvertisedDevice advertisedDevice) {
    if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID)) {
      BLEDevice::getScan()->stop();
      myDevice = new BLEAdvertisedDevice(advertisedDevice);
    } 
  }
};

// 连接到蓝牙设备
bool connectToSensor() {
  BLEClient*  pClient  = BLEDevice::createClient();
  Serial.println(" - Created client");

  // 连接到 GATT 服务器
  Serial.println(" - Connecting to server...");
  if (!pClient->connect(myDevice)) {
    Serial.println(" - Failed to connect to server");
    return false;
  }
  Serial.println(" - Connected to server");

  // 获取服务
  BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
  if (pRemoteService == nullptr) {
    Serial.print(" - Failed to find our service UUID: ");
    Serial.println(serviceUUID.toString().c_str());
    return false;
  }
  Serial.println(" - Found our service");

  // 获取特征
  BLERemoteCharacteristic* pRemoteCharacteristic = pRemoteService->getCharacteristic(characteristicUUID);
  if (pRemoteCharacteristic == nullptr) {
    Serial.print(" - Failed to find our characteristic UUID: ");
    Serial.println(characteristicUUID.toString().c_str());
    return false;
  }
  Serial.println(" - Found our characteristic");

  // 读取特征值
  std::string value = pRemoteCharacteristic->readValue();
  Serial.print(" - The characteristic value was: ");
  Serial.println(value.c_str());

  // 发送数据到 MQTT broker
  if (client.connected()) {
    client.publish("sensor/data", value.c_str());
  }

  return true;
}

void setup() {
  Serial.begin(115200);
  setupWifi();
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);

  // 初始化蓝牙
  BLEDevice::init("ESP32_Gateway");
  BLEScan* pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setInterval(2000);
  pBLEScan->start(60, false);
}

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

  if (myDevice) {
    if (connectToSensor()) {
      Serial.println("Data sent to MQTT broker!");
    } else {
      Serial.println("Failed to connect to sensor!");
    }
    myDevice = nullptr;
    delay(5000); // 等待 5 秒后再次扫描
    BLEDevice::getScan()->start(60, false);
  }
}

代码说明:

  1. 设置 Wi-Fi 和 MQTT broker 信息: 替换 ssidpasswordmqtt_server 和 mqtt_port 为您的实际网络和 MQTT broker 信息。
  2. 设置蓝牙服务和特征 UUID: 替换 serviceUUID 和 characteristicUUID 为您要连接的蓝牙设备的服务和特征 UUID。
  3. 扫描蓝牙设备: 使用 BLEScan 类扫描附近的蓝牙设备,并查找与指定服务 UUID 匹配的设备。
  4. 连接到蓝牙设备: 使用 BLEClient 类连接到找到的蓝牙设备,并获取指定特征的值。
  5. 发送数据到 MQTT broker: 使用 PubSubClient 库将获取的蓝牙传感器数据发布到指定的 MQTT 主题。

五、 总结

本文介绍了如何使用 ESP32 构建蓝牙网关,实现蓝牙设备与 Wi-Fi/互联网之间的连接和数据桥接。通过结合 ESP32 强大的硬件功能和灵活的软件库,您可以轻松构建自定义的蓝牙网关解决方案,满足各种物联网应用的需求。

注意:

  • 本文提供的代码示例仅供参考,您需要根据实际需求进行修改和完善。
  • 在实际应用中,您可能需要考虑安全性、功耗优化和数据可靠性等方面的问题。

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/780383.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SCI一区TOP|准随机分形搜索算法(QRFS)原理及实现【免费获取Matlab代码】

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献5.代码获取 1.背景 2024年&#xff0c;LA Beltran受到分形几何、低差异序列启发&#xff0c;提出了准随机分形搜索算法&#xff08;Quasi-random Fractal Search, QRFS&#xff09;。 2.算法原理 2.1算法思…

【Python】搭建属于自己 AI 机器人

目录 前言 1 准备工作 1.1 环境搭建 1.2 获取 API KEY 2 写代码 2.1 引用库 2.2 创建用户 2.3 创建对话 2.4 输出内容 2.5 调试 2.6 全部代码 2.7 简短的总结 3 优化代码 3.1 规范代码 3.1.1 引用库 3.1.2 创建提示词 3.1.3 创建模型 3.1.4 规范输出&#xf…

SQL面试题-留存率计算

表定义&#xff1a; create table if not exists liuliang_detail (user_id string comment ,record_time string comment yyyymmdd hh:mi:ss ) comment 流量明细表 ; 方法一&#xff1a; 计算的是整段时间范围内&#xff0c;每一天为基准的所有的留存1、2、7天的用户数。 …

cs231n作业2 双层神经网络

双层神经网络 我们选用ReLU函数和softmax函数&#xff1a; 步骤&#xff1a; 1、LOSS损失函数&#xff08;前向传播&#xff09;与梯度&#xff08;后向传播&#xff09;计算 Forward: 计算score&#xff0c;再根据score计算loss Backward&#xff1a;分别对W2、b2、W1、b1求…

使用Charles mock服务端响应数据

背景 服务端未提供接口/服务端接口返回结果有逻辑限制&#xff08;次数限制&#xff09;&#xff0c;不能通过原始接口返回多次模拟预期的返回结果&#xff0c;例如边界值情况 客户端受到接口响应数据的限制&#xff0c;无法继续开发或测试&#xff0c;会极大影响开发测试效率…

Unity入门之重要组件和API(3) : Transform

前言 Transform类主要处理游戏对象(GameObject)的位移、旋转、缩放、父子关系和坐标转换。 1.位置和位移 1.1必备知识点&#xff1a;Vector3 Vector3 主要用来表示三维坐标系中的一个点或者一个向量。 【声明】 Vector3 v1 new Vector3(); Vector3 v2 new Vector3(10, 10…

谷粒商城----通过缓存和分布式锁获取数据。

高并发下缓存失效的问题 高并发下缓存失效的问题--缓存穿透 指查询一个一定不存在的数据&#xff0c;由于缓存是不命中&#xff0c;将去查询数据库&#xff0c;但是数据库也无此记录&#xff0c;我们没有将这次查询的不写入缓存&#xff0c;这将导致这个不存在的数据每次请求…

详解「一本通 5.1 练习 1」括号配对(区间DP经典题)

一.题目 二.思路 题目的大意是说:给你一个只由[ ] ( )构成的字符串&#xff0c;请问需要增加多少个字符才能使其变为一个合法的括号序列。 因为添加若干字符使其达到匹配的目的等价于将不匹配的字符去除使得字符串达到匹配的目的 所以这题只需计算出已匹配完成的括号数,再…

深度学习与CV入门

文章目录 前言历史 前言 历史 tensorflow可以安装Tensorboard第三方库用于展示效果 TensorFlow工作流程&#xff1a;p6-4:20 使用tf.data加载数据。使用tf.data实例化读取训练数据和测试数据模型的建立与调试:使用动态图模式Eager Execution和著名的神经网络高层API框架Ker…

mongoDB教程(五):命名规范

还是大剑师兰特&#xff1a;曾是美国某知名大学计算机专业研究生&#xff0c;现为航空航海领域高级前端工程师&#xff1b;CSDN知名博主&#xff0c;GIS领域优质创作者&#xff0c;深耕openlayers、leaflet、mapbox、cesium&#xff0c;canvas&#xff0c;webgl&#xff0c;ech…

拍桌子、甩脸子、抡棒子没用,带出一流战斗力团队用好3招就够了

拍桌子、甩脸子、抡棒子没用&#xff0c;带出一流战斗力团队用好3招就够了 第一招&#xff1a;及时激励 在现实中&#xff0c;绝大部分管理者管理手段缺乏&#xff0c;只知道用钱进行激励。 而真正的高手不仅会满足员工物质上的需求&#xff0c;更注重员工心理上的满足。 他…

cs231n作业1——Softmax

参考文章&#xff1a;cs231n assignment1——softmax Softmax softmax其实和SVM差别不大&#xff0c;两者损失函数不同&#xff0c;softmax就是把各个类的得分转化成了概率。 损失函数&#xff1a; def softmax_loss_naive(W, X, y, reg):loss 0.0dW np.zeros_like(W)num_…

知识社区在线提问小程序模板源码

蓝色的知识问答&#xff0c;问答交流&#xff0c;知识社区&#xff0c;在线提问手机app小程序网页模板。包含&#xff1a;社区主页、提问、我的、绑定手机&#xff0c;实名认证等。 知识社区在线提问小程序模板源码

**kwargs 字典解包传参的方式

字典解包传参 在Python中&#xff0c;****kwargs**是一种通过字典解包 (dictionary unpacking) 的方式进行参数传递的方式。它将一个字典的键值对解包并传递给函数的命名参数。 示例代码 kwargs实参: {name: "jordan", age: 18, score: [80, 85, 85]} get_info形…

U盘非安全退出后的格式化危机与高效恢复策略

在数字化时代&#xff0c;U盘作为数据存储与传输的重要工具&#xff0c;其数据安全备受关注。然而&#xff0c;一个常见的操作失误——U盘没有安全退出便直接拔出&#xff0c;随后再插入时却遭遇“需要格式化”的提示&#xff0c;这不仅让用户措手不及&#xff0c;更可能意味着…

windows内置的hyper-v虚拟机的屏幕分辨率很低,怎么办?

# windows内置的hyper-v虚拟机的屏幕分辨率很低&#xff0c;怎么办&#xff1f; 只能这么大了&#xff0c;全屏也只是把字体拉伸而已。 不得不说&#xff0c;这个hyper-v做的很烂。 直接复制粘贴也做不到。 但有一个办法可以破解。 远程桌面。 我们可以在外面的windows系统&…

科普文:构建可扩展的微服务架构设计方案

前言 微服务架构是一种新兴的软件架构风格&#xff0c;它将单个应用程序拆分成多个小的服务&#xff0c;每个服务都运行在自己的进程中&#xff0c;这些服务通过网络进行通信。这种架构的优势在于它可以提高应用程序的可扩展性、可维护性和可靠性。 在传统的应用程序架构中&…

minist数据集分类模型的训练

minist数据集训练 训练方法&#xff1a;利用pytorch来实现minist数据集的分类模型训练 训练模型如下图所示 模型代码&#xff1a; import torch from torch import nn from torch.nn import Flattenclass Net(nn.Module):def __init__(self):super().__init__()self.module …

grid布局下的展开/收缩过渡效果【vue/已验证可正常运行】

代码来自GPT4o&#xff1a;国内官方直连GPT4o <template><div class"container"><button class"butns" click"toggleShowMore">{{ showAll ? 收回 : 显示更多 }}</button><transition-group name"slide-fade&…

KDP数据分析实战:从0到1完成数据实时采集处理到可视化

智领云自主研发的开源轻量级Kubernetes数据平台&#xff0c;即Kubernetes Data Platform (简称KDP)&#xff0c;能够为用户提供在Kubernetes上的一站式云原生数据集成与开发平台。在最新的v1.1.0版本中&#xff0c;用户可借助 KDP 平台上开箱即用的 Airflow、AirByte、Flink、K…