当前位置: 首页 > news >正文

树莓派Java调用Python驱动DHT11传感器实现物联网数据采集与告警

1. 项目概述与核心思路

最近在折腾一个物联网数据采集的小项目,核心目标是在树莓派上,通过Java程序去读取DHT11温湿度传感器的数据,并且提供一个Web接口来控制数据采集的节奏,还能在数据异常时触发告警。听起来像是智能家居或者环境监控的入门级应用,但麻雀虽小,五脏俱全,里面涉及到硬件接线、底层驱动调用、服务封装、数据持久化等一系列环节,踩的坑一个不少。

这个项目的核心价值在于,它不是一个简单的“点灯”Demo。它完整地展示了一个典型的边缘计算场景:在资源受限的设备(树莓派)上,用高级语言(Java)去桥接和控制底层硬件(Python脚本驱动的传感器),并通过网络服务(Spring Boot)将数据能力开放出去,最终落地到数据库(MySQL)和日志系统。对于想从纯软件转向物联网,或者想了解如何将Java生态应用到嵌入式场景的朋友来说,这是一个非常棒的练手项目。

整个流程可以概括为:DHT11传感器采集数据 -> Python脚本(Adafruit库)负责与硬件通信并读取原始数据 -> Java程序通过执行Shell命令调用Python脚本 -> Spring Boot将读取过程封装为REST API -> 数据同时写入日志文件和MySQL数据库 -> 设定阈值触发事件通知。下面,我就把这个过程拆开揉碎了,结合我实际部署时遇到的种种问题,给大家捋清楚。

2. 硬件准备与电路连接详解

硬件是这一切的基础,连接错了,后面的代码写得再漂亮也是白搭。这一部分我会详细到每个针脚,并解释为什么这么接。

2.1 硬件清单与选型考量

首先,我们得把家伙事儿准备齐了。清单如下:

  • 控制中心:树莓派 4B。选择4B主要是考虑到其性能足够(多核CPU,1GB以上内存),能流畅运行Java应用和MySQL,同时GPIO接口丰富且文档齐全。树莓派3B+或更新型号也完全可以。
  • 传感器:DHT11温湿度传感器模块。注意,我们通常购买的是三针或四针的模块,而非单独的DHT11芯片。模块已经集成了上拉电阻和信号调理电路,使用起来比裸芯片方便太多。这是新手最容易踩的第一个坑:买错了型号。
  • 连接线:母对母杜邦线若干。用于连接树莓派的GPIO针脚和传感器模块的针脚。
  • 电源:树莓派官方电源或5V/3A以上的可靠电源。电源不稳定会导致树莓派重启,进而导致数据采集中断,这是环境监控项目的大忌。

注意:为什么用模块而不是裸芯片?DHT11芯片本身输出的是单总线数字信号,需要外接一个4.7kΩ - 10kΩ的上拉电阻到VCC,信号才能被稳定读取。对于新手,焊接电阻和判断连接是否正确是个门槛。而模块板已经帮你做好了这一切,你只需要连接VCC, GND, DATA三根线即可,大大降低了入门难度和故障率。

2.2 树莓派GPIO引脚图与接线原理

树莓派的GPIO引脚有多种编号方式,最容易混淆的就是物理引脚序号(Board编号)BCM编号(GPIO编号)。物理编号就是看板子上的引脚排列顺序,而BCM编号是Broadcom芯片定义的GPIO逻辑编号。我们编程时(无论是Python的RPi.GPIO库还是Java的Pi4J)通常使用BCM编号。

下图清晰地展示了树莓派4B的40针GPIO引脚的两种编号对照关系,以及电源和地的位置。请务必保存这张图,它是硬件连接的“地图”

此处应有一张清晰的树莓派4B GPIO引脚定义图,标注物理引脚号、BCM号、5V/3.3V、GND等。由于我无法直接插入图片,请你在撰写时自行添加一张标准引脚图。

2.3 DHT11模块引脚与接线实操

常见的DHT11模块有三个或四个引脚:

  1. VCC (或 +):电源正极,接5V。
  2. GND (或 -):电源负极,接地。
  3. DATA (或 OUT/S):数据信号线。
  4. (可能有的)NC:空脚,不接。

接线步骤(这是最关键的一步):

  1. 给树莓派断电。在连接任何导线之前,请务必关闭树莓派电源。带电操作有短路风险,可能损坏你的树莓派或传感器。
  2. 连接电源线
    • 将DHT11模块的VCC引脚,用杜邦线连接到树莓派的物理引脚 2物理引脚 4(这两个都是5V电源)。
    • 将DHT11模块的GND引脚,连接到树莓派的物理引脚 69142025303439(任意一个GND引脚均可)。
  3. 连接数据线
    • 将DHT11模块的DATA引脚,连接到树莓派的物理引脚 7。查看上面的引脚图可知,物理引脚7对应的BCM编号是 GPIO 4
    • 为什么选择GPIO 4?没有特殊原因,它只是一个可用的通用数字输入输出引脚。你可以选择其他可用的GPIO,如GPIO 17(物理引脚11)、GPIO 27(物理引脚13)等,只要在后续的代码中相应修改即可。我选择GPIO 4是因为它远离电源引脚,减少干扰,且很多教程都用它,便于排查问题。

接线完成后的检查清单:

  • [ ] 树莓派已断电。
  • [ ] VCC (传感器) -> 5V (树莓派,如物理引脚2)。
  • [ ] GND (传感器) -> GND (树莓派,如物理引脚6)。
  • [ ] DATA (传感器) -> GPIO 4 (树莓派,物理引脚7)。
  • [ ] 所有杜邦线插接牢固,没有松动。

实操心得:电源与信号的稳定性我曾试过用树莓派的3.3V引脚给DHT11模块供电,发现偶尔读取会失败。虽然DHT11的工作电压范围是3.3V-5.5V,但使用5V供电时信号电平更高,抗干扰能力更强,读取成功率显著提升。因此,强烈建议使用5V引脚为DHT11供电。同时,尽量使用短的杜邦线,长的导线会引入噪声,可能导致数据读取错误。

3. 软件环境搭建与配置

硬件连接妥当后,我们就要在树莓派上搭建一个能让Java程序跑起来,并且能调用Python脚本的环境。

3.1 操作系统与基础环境

我使用的是树莓派官方64位操作系统(基于Debian),因为它对Java 11的支持更好,内存利用率也更高。通过sudo raspi-config可以确认和切换系统位数。

首先更新系统软件包,这是一个好习惯:

sudo apt update sudo apt upgrade -y

3.2 Python3与Adafruit DHT库安装

我们的Java程序最终要通过调用Python脚本来读取传感器数据,所以Python环境是必须的。树莓派官方系统通常预装了Python3,但我们仍需安装专门的DHT库。

  1. 安装Python3和pip(如果未安装)

    sudo apt install python3 python3-pip -y
  2. 安装Adafruit DHT库的依赖

    sudo apt install python3-dev python3-pip sudo apt install libgpiod2 # 新的GPIO库依赖,非常重要!

    这里有个大坑!旧版的RPi.GPIO库在新版系统(尤其是Bullseye及以后)上可能无法正常工作,而Adafruit库的安装会依赖这些底层驱动。安装libgpiod2是解决很多GPIO相关问题的关键。

  3. 克隆并安装Adafruit DHT库

    cd ~ sudo git clone https://github.com/adafruit/Adafruit_Python_DHT.git cd Adafruit_Python_DHT sudo python3 setup.py install

    这个过程可能会花费几分钟时间进行编译。

  4. 验证安装: 安装完成后,我们可以直接运行库自带的测试脚本,来验证硬件连接和软件环境是否正确。假设你的DATA线接在BCM GPIO 4上(对应我们之前的接线):

    cd ~/Adafruit_Python_DHT/examples sudo python3 AdafruitDHT.py 11 4

    命令解释11代表传感器类型是DHT11,4代表GPIO引脚是BCM 4。期望输出:如果一切正常,你会看到类似Temp=24.0*C Humidity=41.0%的输出。如果看到Failed to get reading. Try again!,请返回检查硬件连接和上述安装步骤。

注意事项:必须使用sudo运行直接访问GPIO硬件需要root权限。所以无论是测试还是后续Java程序调用,执行这个Python脚本都必须加上sudo。这引出了后续Java调用的一个关键点:如何让Java进程有权执行sudo命令。我们通常有两种做法:一是让整个Java程序以root身份运行(不推荐,不安全);二是配置sudoers文件,允许特定用户无需密码执行该特定命令(推荐)。我们会在Java程序部分详细处理这个问题。

3.3 Java运行环境(JDK 11)安装

树莓派官方仓库提供了OpenJDK,安装非常方便:

sudo apt install openjdk-11-jdk -y

安装完成后,验证一下:

java -version

应该能看到类似openjdk version "11.0.xx"的信息。

3.4 MySQL数据库安装与初始化

我们选择MySQL来存储历史温湿度数据。MariaDB是MySQL的一个流行分支,完全兼容。

sudo apt install mariadb-server mariadb-client -y

安装完成后,运行安全初始化脚本,设置root密码并移除一些不安全默认设置:

sudo mysql_secure_installation

接着,登录MySQL,为我们项目创建一个专用的数据库和用户:

sudo mysql -u root -p # 输入你刚才设置的root密码

在MySQL提示符下执行:

CREATE DATABASE pi_environment CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'pi_env_user'@'localhost' IDENTIFIED BY 'YourStrongPassword123!'; GRANT ALL PRIVILEGES ON pi_environment.* TO 'pi_env_user'@'localhost'; FLUSH PRIVILEGES; EXIT;

请务必将YourStrongPassword123!替换成一个强密码。

3.5 Maven与Git安装

Maven用于管理我们的Java项目依赖和构建,Git用于克隆项目代码。

sudo apt install maven git -y

至此,所有基础软件环境就准备完毕了。接下来是重头戏——Java应用程序的剖析与实现。

4. Spring Boot应用程序核心解析

项目采用Spring Boot框架,它能快速搭建一个独立的、生产级的Web应用。我们不需要复杂的应用服务器,一个打包好的Jar文件就能在树莓派上运行。

4.1 项目结构设计思路

整个应用的核心职责非常清晰:

  1. 对外提供HTTP API:接收开始、停止、立即读取等指令。
  2. 调度与执行数据采集任务:根据API指令,调度一个后台任务,以固定频率调用Python脚本。
  3. 处理并持久化数据:解析Python脚本返回的原始字符串,转换为温度和湿度数值,并同时写入日志文件和MySQL数据库。
  4. 阈值监控与事件触发:检查每一次读取的数据,如果超过预设阈值,则触发事件(如记录错误日志、发送通知等)。

因此,项目结构可以设计如下:

src/main/java/com/example/pi/env/ ├── controller/ # REST API控制器 │ └── SensorController.java ├── service/ # 核心业务逻辑 │ ├── SensorService.java │ └── impl/SensorServiceImpl.java ├── task/ # 数据采集定时任务 │ └── DataCollectionTask.java ├── entity/ # 数据库实体类 │ └── TemperatureHumidity.java ├── mapper/ # MyBatis Mapper接口或JPA Repository │ └── TemperatureHumidityMapper.java ├── event/ # 阈值事件处理 │ └── ThresholdAlertListener.java └── Application.java # Spring Boot主类

4.2 核心Service层实现:调用Python脚本

这是连接Java世界和硬件世界的桥梁。SensorServiceImpl中的readDTH11Result方法是关键。

@Service @Slf4j // 使用Lombok简化日志声明 public class SensorServiceImpl implements SensorService { @Value("${dht.python.script.path}") // 从配置文件读取脚本路径 private String adafruitScriptPath; @Autowired private TemperatureHumidityMapper mapper; @Override public String readDHT11Once(int gpioPin) { // 构建Shell命令 // 格式: sudo python3 /path/to/AdafruitDHT.py 11 <GPIO_PIN> String command = String.format("sudo python3 %s 11 %d", adafruitScriptPath, gpioPin); log.info("执行命令: {}", command); StringBuilder resultBuilder = new StringBuilder(); Process process = null; BufferedReader reader = null; try { // 执行命令 process = Runtime.getRuntime().exec(command); // 等待命令执行完成,并获取退出码 int exitCode = process.waitFor(); if (exitCode != 0) { log.error("Python脚本执行失败,退出码: {}, GPIO Pin: {}", exitCode, gpioPin); // 可以尝试读取错误流获取更多信息 BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream())); String errorLine; while ((errorLine = errorReader.readLine()) != null) { log.error("错误输出: {}", errorLine); } return "ERROR: Script execution failed with code " + exitCode; } // 读取脚本的标准输出(即温湿度数据) reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { resultBuilder.append(line).append("\n"); } String rawResult = resultBuilder.toString().trim(); log.info("GPIO {} 读取到原始数据: {}", gpioPin, rawResult); // 解析并保存数据 if (!rawResult.startsWith("Failed")) { saveSensorData(gpioPin, rawResult); return rawResult; } else { log.warn("读取失败,返回信息: {}", rawResult); return "READ_FAILED: " + rawResult; } } catch (IOException | InterruptedException e) { log.error("执行命令或读取输出时发生IO异常", e); return "ERROR: " + e.getMessage(); } finally { // 重要:关闭流,销毁进程,防止资源泄露 if (reader != null) { try { reader.close(); } catch (IOException e) { log.warn("关闭读取流异常", e); } } if (process != null) { process.destroy(); } } } private void saveSensorData(int gpioPin, String rawData) { // 解析 rawData,例如 "Temp=24.0*C Humidity=41.0%" // 这里需要简单的字符串处理 try { String[] parts = rawData.split(" "); float temperature = Float.parseFloat(parts[0].replace("Temp=", "").replace("*C", "")); float humidity = Float.parseFloat(parts[1].replace("Humidity=", "").replace("%", "")); TemperatureHumidity entity = new TemperatureHumidity(); entity.setGpioPin(gpioPin); entity.setTemperature(temperature); entity.setHumidity(humidity); entity.setReadingTime(new Timestamp(System.currentTimeMillis())); entity.setRawData(rawData); mapper.insert(entity); log.debug("数据已保存至数据库: {}", entity); // 触发阈值检查 checkThreshold(entity); } catch (Exception e) { log.error("解析或保存传感器数据失败,原始数据: {}", rawData, e); } } private void checkThreshold(TemperatureHumidity data) { // 这里实现阈值检查逻辑,例如从数据库或配置文件中读取阈值 float tempThreshold = 30.0f; // 示例阈值 float humidityThreshold = 80.0f; if (data.getTemperature() > tempThreshold) { log.warn("【温度告警】GPIO {} 温度 {}°C 超过阈值 {}°C", data.getGpioPin(), data.getTemperature(), tempThreshold); // 此处可以发布一个Spring应用事件,由专门的监听器处理(如发送邮件、MQTT消息等) // applicationContext.publishEvent(new TemperatureExceededEvent(this, data)); } if (data.getHumidity() > humidityThreshold) { log.warn("【湿度告警】GPIO {} 湿度 {}% 超过阈值 {}%", data.getGpioPin(), data.getHumidity(), humidityThreshold); } } }

关键点解析:

  1. sudo权限问题:命令中包含了sudo。为了让Java应用(通常以非root用户如pi运行)能执行它,我们需要编辑sudoers文件,允许pi用户无需密码执行该特定命令。

    sudo visudo

    在文件末尾添加:

    pi ALL=(ALL) NOPASSWD: /usr/bin/python3 /home/pi/Adafruit_Python_DHT/examples/AdafruitDHT.py

    警告visudo是唯一安全的编辑方式,它能检查语法错误。直接编辑/etc/sudoers文件可能导致系统无法使用sudo。

  2. 进程与流管理ProcessInputStreamErrorStream必须被正确关闭,否则会导致资源泄露(“僵尸进程”或文件句柄耗尽)。使用try-with-resources语句或像上面代码一样在finally块中显式关闭是良好实践。

  3. 错误处理:不能只检查waitFor()的退出码。Python脚本可能因为硬件通信失败而返回0(成功退出),但输出是Failed to get reading。因此,必须同时检查退出码和解析标准输出的内容

4.3 数据采集任务调度

我们使用Spring的@Scheduled注解来创建一个定时任务,实现周期性的数据采集。

@Component @Slf4j public class DataCollectionTask { @Autowired private SensorService sensorService; private volatile boolean collectionEnabled = false; private ScheduledFuture<?> scheduledFuture; @Autowired private TaskScheduler taskScheduler; // 需要配置一个TaskScheduler Bean private final int DEFAULT_GPIO_PIN = 4; private final long DEFAULT_INTERVAL_MS = 60000; // 默认每分钟采集一次 public void startCollection(long intervalMs) { if (collectionEnabled) { log.info("数据采集任务已在运行中。"); return; } log.info("启动数据采集任务,间隔: {} ms", intervalMs); collectionEnabled = true; scheduledFuture = taskScheduler.scheduleWithFixedDelay(() -> { if (collectionEnabled) { try { String result = sensorService.readDHT11Once(DEFAULT_GPIO_PIN); log.debug("定时任务采集结果: {}", result); } catch (Exception e) { log.error("定时数据采集任务执行失败", e); } } }, intervalMs); // 注意:scheduleWithFixedDelay是上一次任务结束后间隔指定时间再执行,更适合I/O操作。 } public void stopCollection() { log.info("停止数据采集任务。"); collectionEnabled = false; if (scheduledFuture != null) { scheduledFuture.cancel(false); // false表示不中断正在执行的任务 } } public boolean isCollectionEnabled() { return collectionEnabled; } }

Application.java或一个配置类中,需要配置TaskScheduler

@Configuration @EnableScheduling public class SchedulerConfig implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(2); // 根据任务数量设置 scheduler.setThreadNamePrefix("pi-sensor-scheduler-"); scheduler.initialize(); taskRegistrar.setTaskScheduler(scheduler); } }

4.4 REST API控制器设计

控制器提供简单的HTTP接口,用于手动触发读取、启停自动采集任务。

@RestController @RequestMapping("/api/sensor") @Slf4j public class SensorController { @Autowired private SensorService sensorService; @Autowired private DataCollectionTask dataCollectionTask; @GetMapping("/read") public ResponseEntity<String> readOnce(@RequestParam(defaultValue = "4") int gpio) { log.info("手动触发读取GPIO: {}", gpio); String result = sensorService.readDHT11Once(gpio); return ResponseEntity.ok(result); } @PostMapping("/collection/start") public ResponseEntity<String> startCollection(@RequestParam(defaultValue = "60000") long interval) { if (interval < 2000) { return ResponseEntity.badRequest().body("采集间隔太短,建议大于2000毫秒。"); } dataCollectionTask.startCollection(interval); return ResponseEntity.ok("数据采集任务已启动,间隔 " + interval + " 毫秒。"); } @PostMapping("/collection/stop") public ResponseEntity<String> stopCollection() { dataCollectionTask.stopCollection(); return ResponseEntity.ok("数据采集任务已停止。"); } @GetMapping("/collection/status") public ResponseEntity<Map<String, Object>> getCollectionStatus() { Map<String, Object> status = new HashMap<>(); status.put("enabled", dataCollectionTask.isCollectionEnabled()); // 可以返回更多状态信息,如最近一次采集时间等 return ResponseEntity.ok(status); } }

4.5 数据持久化与日志记录

数据库持久化:使用MyBatis或Spring Data JPA将TemperatureHumidity实体对象存入MySQL。表结构简单:

CREATE TABLE temperature_humidity ( id BIGINT AUTO_INCREMENT PRIMARY KEY, gpio_pin INT NOT NULL COMMENT 'GPIO引脚号', temperature FLOAT COMMENT '温度值', humidity FLOAT COMMENT '湿度值', raw_data VARCHAR(100) COMMENT '原始数据字符串', reading_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '读取时间' );

日志记录:使用Log4j2或SLF4J+Logback。除了在控制台输出,还应配置滚动文件日志,便于长期追踪和问题排查。在application.propertieslogback-spring.xml中配置即可。

5. 项目部署、测试与问题排查

5.1 在树莓派上部署与运行

  1. 打包项目:在开发机器上,使用Maven打包。

    mvn clean package -DskipTests

    这会在target目录下生成一个your-project-name-0.0.1-SNAPSHOT.jar文件。

  2. 传输Jar文件到树莓派:使用scp命令。

    scp target/pi-env-monitor.jar pi@192.168.1.xxx:/home/pi/
  3. 在树莓派上运行

    cd /home/pi # 前台运行,查看日志 java -jar pi-env-monitor.jar # 或者后台运行 nohup java -jar pi-env-monitor.jar > app.log 2>&1 &

    应用默认会在8080端口启动(可通过application.properties中的server.port修改)。

5.2 功能测试与验证

  1. 测试手动读取接口

    curl "http://树莓派IP:8080/api/sensor/read?gpio=4"

    预期返回:Temp=24.0*C Humidity=41.0%或类似信息。

  2. 测试启动自动采集

    curl -X POST "http://树莓派IP:8080/api/sensor/collection/start?interval=30000"

    预期返回成功信息,并且查看应用日志,应该每隔30秒出现一次采集记录。

  3. 测试停止采集

    curl -X POST "http://树莓派IP:8080/api/sensor/collection/stop"
  4. 检查数据库

    mysql -u pi_env_user -p pi_environment SELECT * FROM temperature_humidity ORDER BY reading_time DESC LIMIT 5;

    应该能看到最新的几条温湿度记录。

5.3 常见问题与排查技巧实录

以下是我在实施过程中遇到的一些典型问题及解决方法:

问题现象可能原因排查步骤与解决方案
调用接口返回ERROR: Script execution failedFailed to get reading1. Python脚本执行权限问题。
2. GPIO引脚占用或冲突。
3. 硬件连接问题或传感器损坏。
4. 电源不稳定。
1.检查sudoers配置sudo -u pi sudo python3 /path/to/AdafruitDHT.py 11 4看是否能成功。
2.检查GPIO占用:确保没有其他程序(如另一个Python脚本)正在使用同一个GPIO引脚。
3.硬件复查:断电后重新插拔所有杜邦线,确保接触良好。用万用表测量VCC和GND之间电压是否为稳定的5V。
4.更换传感器测试:DHT11质量参差不齐,个别容易损坏。
应用启动失败,提示端口被占用8080端口已被其他进程使用。`sudo netstat -tlnp
数据库连接失败1. MySQL服务未启动。
2. 数据库用户密码错误。
3. 用户权限不足。
1.sudo systemctl status mariadb检查服务状态。
2. 用mysql -u pi_env_user -p手动测试连接。
3. 在MySQL中重新授予权限:GRANT ALL ON pi_environment.* TO 'pi_env_user'@'localhost';
定时任务不执行或执行一次后停止1.TaskScheduler未正确配置。
2. 任务内部抛出未捕获的异常,导致调度线程终止。
3.collectionEnabled标志被意外修改。
1. 确认配置类@EnableScheduling注解已添加,且TaskSchedulerBean已定义。
2. 在DataCollectionTask的Runnable内部用try-catch捕获所有异常,并打印详细日志。
3. 检查是否有其他代码逻辑修改了collectionEnabled变量,确保其线程安全(使用volatileAtomicBoolean)。
读取数据偶尔为null或格式异常1. 传感器通信受干扰,数据校验失败。
2. Python脚本输出格式与预期不符。
1.增加重试机制:在readDHT11Once方法中,如果返回Failed,可以延迟几百毫秒后重试1-2次。
2.增强数据解析的鲁棒性:使用正则表达式匹配Temp=([\d.]+)\*C Humidity=([\d.]+)%,而不是简单的字符串分割。
应用运行一段时间后内存占用过高或崩溃1. 资源未关闭导致内存泄露(如ProcessInputStream)。
2. 数据库连接未关闭。
1. 严格确保在finally块中关闭所有打开的流和销毁进程。
2. 检查数据源配置,如使用HikariCP连接池,并监控连接泄露。使用jstat或VisualVM监控JVM堆内存。

一个关键的避坑技巧:关于Python库的版本Adafruit_Python_DHT库是一个较老的库,在新版树莓派OS上可能因为底层驱动变更而无法编译或工作。如果遇到编译错误或始终读取失败,可以尝试使用基于libgpiod的现代替代库,例如Adafruit_Blinka配合adafruit-circuitpython-dht。但这需要调整Python脚本。一个更简单直接的备用方案是使用**pigpio库**的DHT读取功能,它通常更稳定。

备用Python脚本示例(使用pigpio):

import pigpio import time pi = pigpio.pi() if not pi.connected: exit() SENSOR_PIN = 4 # BCM GPIO 4 def read_dht11(pin): # pigpio的dht_read函数返回 (状态码, 温度, 湿度) result = pi.read_DHT11(pin) if result[0] == 0: # 状态码0表示成功 temperature, humidity = result[1], result[2] return f"Temp={temperature}*C Humidity={humidity}%" else: return "Failed to get reading." if __name__ == "__main__": print(read_dht11(SENSOR_PIN)) pi.stop()

使用前需要安装pigpio库并启动守护进程:sudo apt install pigpio python3-pigpio && sudo systemctl start pigpiod。然后在Java中调用这个新脚本即可。这种方式往往比旧的Adafruit库更可靠。

最后,这个项目完全可以作为更复杂物联网应用的基础。你可以轻松地扩展它,例如:集成MQTT将数据上报到云端物联网平台(如阿里云IoT、ThingsBoard);增加WebSocket实现实时数据推送到前端仪表盘;或者结合摄像头,在温湿度异常时拍照留存。硬件上也可以接入更多传感器,如光照、空气质量传感器等,构建一个完整的室内环境监测站。

http://www.cnnetsun.cn/news/2474485.html

相关文章:

  • FreeRTOS在Cortex-M4上跑,为什么SysTick和PendSV优先级都得设成最低?一个嵌入式老鸟的实战踩坑记
  • 别再只用冷冻切片了!科研人必备:从TCGA批量下载高质量FFPE病理图像的完整流程
  • 零基础保姆级教程:用AutoDock Vina完成你的第一个分子对接(含蛋白质处理、小分子准备全流程)
  • 企业级单点登录(SSO)整合:若依RuoYi-Vue如何无缝对接第三方统一认证平台?
  • Skill 本质解构:OpenClaw 如何用结构化 Markdown 实现 5 类可复用操作文档
  • 新电脑到手第一件事:用Ventoy制作Kubuntu 23.04启动盘并完成安装(含驱动与输入法配置)
  • 从BN到CmBN:手把手教你给YOLOv4模型‘换芯’,提升小批量训练效果
  • ClawHavoc 安全事件复盘:OpenClaw 技能系统中 3 类高危调用链的识别与阻断方案
  • Binwalk解压固件翻车实录:从sasquatch报错到firmware-mod-kit救场的完整复盘
  • 基于OCR与深度学习的发票识别技术,重构报销系统效率
  • 游戏开发选TTF还是Fnt?从《原神》UI到独立小游戏,聊聊字体选择的实战避坑指南
  • 通过taotoken用量看板分析团队月度大模型api消耗趋势
  • Jetson Orin Nano到手后,除了装CUDA,这3个必装工具和配置你做了吗?(含jtop、JetPack、环境变量完整流程)
  • 终极SAR舰船检测指南:如何使用SSDD数据集快速构建AI模型
  • 从原理图到选型:手把手教你读懂ESP-WROOM-32开发板上的AMS1117和USB电路
  • 我把游戏策划桌搬进了 AI Agent:一次用 JiuwenSwarm 做创意协作的实验
  • AI演示生成系统深度解析:PPTAgent与DeepPresenter的技术演进与实践指南
  • 告别手抖!用ArcGIS 10.6的‘定长’与‘坐标’工具搞定CAD式精确绘图
  • Windows防火墙和OpenSSH服务设置避坑指南:解决xftp传文件失败和xshell连接超时
  • 用三菱FX2N PLC和GX Works2,从零搭建一个自动售货机控制程序(附完整梯形图)
  • ARMv7通用计时器实战指南:从寄存器配置到Linux内核应用
  • 保姆级教程:在嵌入式Linux设备上,用fw_printenv/fw_setenv搞定U-Boot环境变量读写
  • Gemini 实测对比:不同提示策略对输出质量的影响
  • 别只盯着树莓派!Purple Pi RK3566开发板多系统横评:OpenHarmony、Debian、Android 11谁更适合你?
  • ONLYOFFICE 文档9.4发布:许可证更新、电子表格的深色模式、水平分隔线、新幻灯片主题与切换等
  • 掌握电脑睡眠控制:从原理到实战的防休眠指南
  • 从手工到智能,气泡图软件重构质检工作流程
  • i.MX6ULL嵌入式Linux开发实战:从硬件解析到系统构建与优化
  • SqueezeNet的Fire Module设计,为什么今天看依然很巧妙?聊聊轻量化CNN的演进
  • Linux告警降噪策略实战指南