这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【树莓派Zero2W】物联网智能家居终端

共2条 1/1 1 跳转至

【树莓派Zero2W】物联网智能家居终端

工程师
2025-12-21 15:07:01     打赏

【树莓派Zero 2W】物联网智能家居终端

本文介绍了树莓派 Zero 2W 驱动 BMP280 传感器获取环境温度压强数据,并通过 MQTT 协议上传至 Home Assistant 智能家居平台的物联网项目设计。

项目介绍

树莓派 Zero 2W 驱动 BMP280 获取数据,通过 MQTT 协议上传至 HA 平台。

  • 准备工作:包括系统安装、软件包部署、硬件连接等;

  • BMP280:通过 smbus 库驱动 BMP280 传感器模块,终端打印环境温度压强数据;

  • MQTT:结合板载 WiFi 模块,实现 MQTT 报文发送、EMQX 订阅测试;

  • Home Assistant:将 BMP280 数据通过 MQTT 发送至 HA 并自动识别添加传感器设备,实现物联网终端。

准备工作

  • 连接 WiFi 实现无线网络通信;

  • 使用 Micro-USB 数据线实现设备供电;

hardware_connect.jpg

系统安装

Micro-SD 卡需烧录 RaspberryPi 官方操作系统;

详见:【树莓派Zero2W】介绍、系统安装、人脸检测 .

软件包部署

  • 安装 IIC  通信所需的 smbus 库,以及排针定义环境 RPI.GPIO 库;

sudo apt-get update
sudo apt-get install python3-smbus
sudo apt-get install python3-RPi.GPIO
  • 使能板端 IIC 配置

终端执行指令 raspi-config 打开配置界面;

依次选择 Interface - IIC - Enable - Yes 即可。

硬件连接

BMP280 模块接线方式如下

BMP280 模块树莓派 Zero 2W



VCC3.3V
GNDGND
SDA40Pin-3 (SDA)
SCL40Pin-5 (SCL)

终端执行 i2cdetect -y 1 指令,检索 BMP280 传感器设备,识别对应的 IIC 设备地址 0x77;

bmp280_address.jpg

BMP280

BMP280 是一种专门用于移动用途的绝对气压传感器,可同时获取环境的温度和大气压强数据。

aht20_bmp280.jpg

这里介绍了 IIC 协议驱动 BMP280 传感器并终端打印温度和大气压强的相关流程,包括关键代码、效果演示等。

代码

终端执行指令 touch bmp280.py 新建程序文件,并添加如下代码

import time
import smbus

# BMP280 iic address.
BMP280_I2C_ADDRESS = 0x77        # SDO = 0

# Registers value
BMP280_ID_Value = 0x58           # BMP280 ID
BMP280_RESET_VALUE = 0xB6

# BMP280 Registers definition
BMP280_TEMP_XLSB_REG = 0xFC      # Temperature XLSB Register
BMP280_TEMP_LSB_REG = 0xFB       # Temperature LSB Register
BMP280_TEMP_MSB_REG = 0xFA       # Temperature LSB Register
BMP280_PRESS_XLSB_REG = 0xF9     # Pressure XLSB  Register
BMP280_PRESS_LSB_REG = 0xF8      # Pressure LSB Register
BMP280_PRESS_MSB_REG = 0xF7      # Pressure MSB Register
BMP280_CONFIG_REG = 0xF5         # Configuration Register
BMP280_CTRL_MEAS_REG = 0xF4      # Ctrl Measure Register
BMP280_STATUS_REG = 0xF3         # Status Register
BMP280_RESET_REG = 0xE0          # Softreset Register
BMP280_ID_REG = 0xD0             # Chip ID Register

# calibration parameters
BMP280_DIG_T1_LSB_REG = 0x88
BMP280_DIG_T1_MSB_REG = 0x89
BMP280_DIG_T2_LSB_REG = 0x8A
BMP280_DIG_T2_MSB_REG = 0x8B
BMP280_DIG_T3_LSB_REG = 0x8C
BMP280_DIG_T3_MSB_REG = 0x8D
BMP280_DIG_P1_LSB_REG = 0x8E
BMP280_DIG_P1_MSB_REG = 0x8F
BMP280_DIG_P2_LSB_REG = 0x90
BMP280_DIG_P2_MSB_REG = 0x91
BMP280_DIG_P3_LSB_REG = 0x92
BMP280_DIG_P3_MSB_REG = 0x93
BMP280_DIG_P4_LSB_REG = 0x94
BMP280_DIG_P4_MSB_REG = 0x95
BMP280_DIG_P5_LSB_REG = 0x96
BMP280_DIG_P5_MSB_REG = 0x97
BMP280_DIG_P6_LSB_REG = 0x98
BMP280_DIG_P6_MSB_REG = 0x99
BMP280_DIG_P7_LSB_REG = 0x9A
BMP280_DIG_P7_MSB_REG = 0x9B
BMP280_DIG_P8_LSB_REG = 0x9C
BMP280_DIG_P8_MSB_REG = 0x9D
BMP280_DIG_P9_LSB_REG = 0x9E
BMP280_DIG_P9_MSB_REG = 0x9F


class BMP180(object):
    def __init__(self, address=BMP280_I2C_ADDRESS):
        self._address = address
        self._bus = smbus.SMBus(1)    # 1: iic编号为1(根据自己的硬件接口选择对应的编号)
        # Load calibration values.
        if self._read_byte(BMP280_ID_REG) == BMP280_ID_Value: # read bmp280 id
            self._load_calibration()                          # load calibration data
            # BMP280_T_MODE_1 << 5 | BMP280_P_MODE_1 << 2 | BMP280_SLEEP_MODE;
            ctrlmeas = 0xFF
            # BMP280_T_SB1 << 5 | BMP280_FILTER_MODE_1 << 2;
            config = 0x14
            self._write_byte(BMP280_CTRL_MEAS_REG, ctrlmeas)  # write bmp280 config
            # sets the data acquisition options
            self._write_byte(BMP280_CONFIG_REG, config)
        else:
            print("Read BMP280 id error!\r\n")

    def _read_byte(self, cmd):
        return self._bus.read_byte_data(self._address, cmd)

    def _read_u16(self, cmd):
        LSB = self._bus.read_byte_data(self._address, cmd)
        MSB = self._bus.read_byte_data(self._address, cmd+1)
        return (MSB << 8) + LSB

    def _read_s16(self, cmd):
        result = self._read_u16(cmd)
        if result > 32767:
            result -= 65536
        return result

    def _write_byte(self, cmd, val):
        self._bus.write_byte_data(self._address, cmd, val)

    def _load_calibration(self):                           # load calibration data
        "load calibration"

        """ read the temperature calibration parameters """
        self.dig_T1 = self._read_u16(BMP280_DIG_T1_LSB_REG)
        self.dig_T2 = self._read_s16(BMP280_DIG_T2_LSB_REG)
        self.dig_T3 = self._read_s16(BMP280_DIG_T3_LSB_REG)
        """ read the pressure calibration parameters """
        self.dig_P1 = self._read_u16(BMP280_DIG_P1_LSB_REG)
        self.dig_P2 = self._read_s16(BMP280_DIG_P2_LSB_REG)
        self.dig_P3 = self._read_s16(BMP280_DIG_P3_LSB_REG)
        self.dig_P4 = self._read_s16(BMP280_DIG_P4_LSB_REG)
        self.dig_P5 = self._read_s16(BMP280_DIG_P5_LSB_REG)
        self.dig_P6 = self._read_s16(BMP280_DIG_P6_LSB_REG)
        self.dig_P7 = self._read_s16(BMP280_DIG_P7_LSB_REG)
        self.dig_P8 = self._read_s16(BMP280_DIG_P8_LSB_REG)
        self.dig_P9 = self._read_s16(BMP280_DIG_P9_LSB_REG)

        # print(self.dig_T1)
        # print(self.dig_T2)
        # print(self.dig_T3)
        # print(self.dig_P1)
        # print(self.dig_P2)
        # print(self.dig_P3)
        # print(self.dig_P4)
        # print(self.dig_P5)
        # print(self.dig_P6)
        # print(self.dig_P7)
        # print(self.dig_P8)
        # print(self.dig_P9)

    def compensate_temperature(self, adc_T):
        """Returns temperature in DegC, double precision. Output value of "1.23"equals 51.23 DegC."""
        var1 = ((adc_T) / 16384.0 - (self.dig_T1) / 1024.0) * (self.dig_T2)
        var2 = (((adc_T) / 131072.0 - (self.dig_T1) / 8192.0) *
                ((adc_T) / 131072.0 - (self.dig_T1) / 8192.0)) * (self.dig_T3)
        self.t_fine = var1 + var2
        temperature = (var1 + var2) / 5120.0
        return temperature

    def compensate_pressure(self, adc_P):
        """Returns pressure in Pa as double. Output value of "6386.2"equals 96386.2 Pa = 963.862 hPa."""
        var1 = (self.t_fine / 2.0) - 64000.0
        var2 = var1 * var1 * (self.dig_P6) / 32768.0
        var2 = var2 + var1 * (self.dig_P5) * 2.0
        var2 = (var2 / 4.0) + ((self.dig_P4) * 65536.0)
        var1 = ((self.dig_P3) * var1 * var1 / 524288.0 +
                (self.dig_P2) * var1) / 524288.0
        var1 = (1.0 + var1 / 32768.0) * (self.dig_P1)

        if var1 == 0.0:
            return 0  # avoid exception caused by division by zero

        pressure = 1048576.0 - adc_P
        pressure = (pressure - (var2 / 4096.0)) * 6250.0 / var1
        var1 = (self.dig_P9) * pressure * pressure / 2147483648.0
        var2 = pressure * (self.dig_P8) / 32768.0
        pressure = pressure + (var1 + var2 + (self.dig_P7)) / 16.0

        return pressure

    def get_temperature_and_pressure(self):
        """Returns pressure in Pa as double. Output value of "6386.2"equals 96386.2 Pa = 963.862 hPa."""
        xlsb = self._read_byte(BMP280_TEMP_XLSB_REG)
        lsb = self._read_byte(BMP280_TEMP_LSB_REG)
        msb = self._read_byte(BMP280_TEMP_MSB_REG)

        adc_T = (msb << 12) | (lsb << 4) | (
            xlsb >> 4)      # temperature registers data
        temperature = self.compensate_temperature(
            adc_T)    # temperature compensate

        xlsb = self._read_byte(BMP280_PRESS_XLSB_REG)
        lsb = self._read_byte(BMP280_PRESS_LSB_REG)
        msb = self._read_byte(BMP280_PRESS_MSB_REG)

        adc_P = (msb << 12) | (lsb << 4) | (
            xlsb >> 4)      # pressure registers data
        pressure = self.compensate_pressure(
            adc_P)          # pressure compensate
        return temperature, pressure


if __name__ == '__main__':

    import time

    print("BMP280 Test Program ...")

    bmp280 = BMP180()

    while True:
        time.sleep(1)
        temperature, pressure = bmp280.get_temperature_and_pressure()
        print('Temperature = %.2f C Pressure = %.3f kPa' %
              (temperature, pressure/1000))

保存代码。

效果

终端执行指令 python bmp280.py 运行程序,连续打印温度和压强数据

bmp280_print.jpg

MQTT

MQTT,即消息队列遥测传输协议 (Message Queuing Telemetry Transport),是一种基于发布/订阅(publish/subscribe)模式的轻量级通讯协议,构建于TCP/IP协议上。

MQTT 以有限的带宽为连接远程设备提供实时可靠的消息服务。MQTT 作为一种即时通讯协议,在物联网、小型设备、移动应用等方面有广泛的应用。

这里介绍了将 BMP280 获取的数据通过 MQTT 协议上传至 EMQX 服务器并远程订阅测试的相关流程,包括关键代码和效果演示。

代码

终端执行指令 touch bmp280_mqtt.py 新建程序文件,并添加如下代码

#!/usr/bin/env python3
import time
import json
import bmp280                 # 导入上面的驱动
import paho.mqtt.client as mqtt

# ----------------- 参数 -----------------
MQTT_BROKER = "192.168.1.107"   # MQTT 服务器
MQTT_PORT   = 1883
MQTT_TOPIC  = "rpi/sensor/bmp280"
CLIENT_ID   = "rpi_bmp280"
USERNAME    = "xxx"               # 认证信息
PASSWORD    = "xxx"
PUBLISH_INTERVAL = 2            # 秒
# ------------------------------------------------

def on_connect(client, userdata, flags, rc):
    if rc == 0:
        print("MQTT 已连接")
    else:
        print("MQTT 连接失败,rc =", rc)

def on_disconnect(client, userdata, rc):
    print("MQTT 断开,rc =", rc)
    while True:
        try:
            client.reconnect()
            print("重连成功")
            break
        except Exception as e:
            print("重连失败:", e)
            time.sleep(5)

client = mqtt.Client(client_id=CLIENT_ID, clean_session=True)
client.username_pw_set(USERNAME, PASSWORD)
client.on_connect = on_connect
client.on_disconnect = on_disconnect
client.connect(MQTT_BROKER, MQTT_PORT, keepalive=60)
client.loop_start()          # 后台线程自动保活

# 初始化传感器
sensor = bmp280.BMP280()

try:
    while True:
        t, p = sensor.get_temperature_and_pressure()
        payload = json.dumps({
            "temperature": round(t, 2),
            "pressure"   : round(p / 1000, 3),
            "ts"         : int(time.time())
        })
        print("→", payload)
        client.publish(MQTT_TOPIC, payload, qos=1)
        time.sleep(PUBLISH_INTERVAL)
except KeyboardInterrupt:
    print("用户中断,程序退出")
finally:
    client.loop_stop()
    client.disconnect()


保存代码。

效果

终端执行指令 python bmp280_mqtt.py 运行程序,打印 MQTT 报文信息

bmp280_mqtt_print.jpg



消息订阅

浏览器访问 http://192.168.31.107:18083 进入 EMQX 控制终端;

左侧工具栏 - 诊断工具 - WebSocket 客户端

填写 ip 地址、端口、用户名、密码,点击 连接 按钮;

在 订阅 面板中填写主题 rpi/sensor/bmp280 ;

bmp280_emqx_connect.jpg


下方 已接收 消息框立刻收到 BMP280 温度和压强的 JSON 报文;

bmp280_emqx_payload.jpg


Home Assistant

Home Assistant 是一个开源的智能家居平台,旨在通过集成各种智能设备和服务,提供一个统一的、可自定义的家庭自动化解决方案。

下面介绍 BMP280 温度压强数据通过 MQTT 协议上传至 Home Assistant 平台的相关流程,包括流程图、代码、效果演示等。

流程图


flowchart_bmp280_ha.png

代码

终端执行指令 touch bmp280_mqtt_ha.py 新建程序文件,并添加如下代码

#!/usr/bin/env python3
import time
import json
import bmp280
import paho.mqtt.client as mqtt
import uuid

# ---------- 参数 ----------
BROKER, PORT = "192.168.1.107", 1883
USERNAME = "xxx"          # 认证
PASSWORD = "xxx"
NODE_ID   = "rpi_bmp280"          # 节点唯一标识
SEND_EVERY = 2        # 秒
# ------------------------------

# 生成全局唯一 ID,避免重复
uid = uuid.uuid4().hex[:8]

def on_connect(client, userdata, flags, rc):
    if rc == 0:
        print("MQTT 已连接")
        # 发布自动发现配置
        publish_discovery(client)
    else:
        print("MQTT 连接失败,rc =", rc)

def publish_discovery(client):
    """向 HA 注册两个传感器实体"""
    base_topic = f"homeassistant/sensor/{NODE_ID}"
    # 温度
    temp_cfg = {
        "name": "BMP280 Temperature",
        "uniq_id": f"{NODE_ID}_temp_{uid}",
        "state_topic": f"{base_topic}/temp/state",
        "unit_of_meas": "°C",
        "device_class": "temperature",
        "device": {
            "identifiers": [NODE_ID],
            "name": "Raspberry Pi BMP280",
            "model": "BMP280",
            "manufacturer": "Bosch"
        }
    }
    # 气压
    pres_cfg = {
        "name": "BMP280 Pressure",
        "uniq_id": f"{NODE_ID}_pres_{uid}",
        "state_topic": f"{base_topic}/pres/state",
        "unit_of_meas": "hPa",
        "device_class": "pressure",
        "device": {
            "identifiers": [NODE_ID],
            "name": "Raspberry Pi BMP280",
            "model": "BMP280",
            "manufacturer": "Bosch"
        }
    }
    client.publish(f"{base_topic}/temp/config", json.dumps(temp_cfg), qos=1, retain=True)
    client.publish(f"{base_topic}/pres/config", json.dumps(pres_cfg), qos=1, retain=True)
    print("→ 自动发现配置已推送")

client = mqtt.Client()
if USERNAME:
    client.username_pw_set(USERNAME, PASSWORD)
client.on_connect = on_connect
client.connect(BROKER, PORT, keepalive=60)
client.loop_start()

sensor = bmp280.BMP280()

try:
    while True:
        t, p = sensor.get_temperature_and_pressure()
        # 发布状态
        client.publish(f"homeassistant/sensor/{NODE_ID}/temp/state", f"{t:.2f}", qos=1)
        client.publish(f"homeassistant/sensor/{NODE_ID}/pres/state",  f"{p/100:.2f}", qos=1)
        print(f"→ 温度 {t:.2f} °C  气压 {p/100:.2f} hPa")
        time.sleep(SEND_EVERY)
except KeyboardInterrupt:
    print("用户中断,程序退出")
finally:
    client.loop_stop()
    client.disconnect()


保存代码。

效果

终端执行指令 python bmp280_mqtt_ha.py 运行程序,打印通过 MQTT 上传至 HA 的报文信息

打开 HA 主页,进入 设置 - 设备与服务 - MQTT,点击 Raspberry Pi BMP280 设备选项

bmp280_ha_device-info.jpg

点击 添加到仪表盘 链接,选择目标区域,点击添加按钮;

bmp280_ha_add.jpg

进入 概览 标签页,可看到已添加的 BMP280 传感器卡片;

bmp280_ha_card.jpg

点击卡片,获取历史数据

bmp280_ha_history.jpg

总结

本文介绍了树莓派 Zero 2W 驱动 BMP280 传感器获取环境温度压强数据,并通过 MQTT 协议上传至 Home Assistant 智能家居平台的物联网项目设计,为相关产品在物联网 IoT 领域的快速开发和应用设计提供了参考。






关键词: 树莓派     IoT     物联网     HA     MQTT    

院士
2025-12-21 15:21:05     打赏
2楼

谢谢分享。


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]