树莓派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模块有三个或四个引脚:
- VCC (或 +):电源正极,接5V。
- GND (或 -):电源负极,接地。
- DATA (或 OUT/S):数据信号线。
- (可能有的)NC:空脚,不接。
接线步骤(这是最关键的一步):
- 给树莓派断电。在连接任何导线之前,请务必关闭树莓派电源。带电操作有短路风险,可能损坏你的树莓派或传感器。
- 连接电源线:
- 将DHT11模块的VCC引脚,用杜邦线连接到树莓派的物理引脚 2或物理引脚 4(这两个都是5V电源)。
- 将DHT11模块的GND引脚,连接到树莓派的物理引脚 6、9、14、20、25、30、34或39(任意一个GND引脚均可)。
- 连接数据线:
- 将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 -y3.2 Python3与Adafruit DHT库安装
我们的Java程序最终要通过调用Python脚本来读取传感器数据,所以Python环境是必须的。树莓派官方系统通常预装了Python3,但我们仍需安装专门的DHT库。
安装Python3和pip(如果未安装):
sudo apt install python3 python3-pip -y安装Adafruit DHT库的依赖:
sudo apt install python3-dev python3-pip sudo apt install libgpiod2 # 新的GPIO库依赖,非常重要!这里有个大坑!旧版的
RPi.GPIO库在新版系统(尤其是Bullseye及以后)上可能无法正常工作,而Adafruit库的安装会依赖这些底层驱动。安装libgpiod2是解决很多GPIO相关问题的关键。克隆并安装Adafruit DHT库:
cd ~ sudo git clone https://github.com/adafruit/Adafruit_Python_DHT.git cd Adafruit_Python_DHT sudo python3 setup.py install这个过程可能会花费几分钟时间进行编译。
验证安装: 安装完成后,我们可以直接运行库自带的测试脚本,来验证硬件连接和软件环境是否正确。假设你的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 项目结构设计思路
整个应用的核心职责非常清晰:
- 对外提供HTTP API:接收开始、停止、立即读取等指令。
- 调度与执行数据采集任务:根据API指令,调度一个后台任务,以固定频率调用Python脚本。
- 处理并持久化数据:解析Python脚本返回的原始字符串,转换为温度和湿度数值,并同时写入日志文件和MySQL数据库。
- 阈值监控与事件触发:检查每一次读取的数据,如果超过预设阈值,则触发事件(如记录错误日志、发送通知等)。
因此,项目结构可以设计如下:
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); } } }关键点解析:
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。进程与流管理:
Process、InputStream、ErrorStream必须被正确关闭,否则会导致资源泄露(“僵尸进程”或文件句柄耗尽)。使用try-with-resources语句或像上面代码一样在finally块中显式关闭是良好实践。错误处理:不能只检查
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.properties或logback-spring.xml中配置即可。
5. 项目部署、测试与问题排查
5.1 在树莓派上部署与运行
打包项目:在开发机器上,使用Maven打包。
mvn clean package -DskipTests这会在
target目录下生成一个your-project-name-0.0.1-SNAPSHOT.jar文件。传输Jar文件到树莓派:使用
scp命令。scp target/pi-env-monitor.jar pi@192.168.1.xxx:/home/pi/在树莓派上运行:
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 功能测试与验证
测试手动读取接口:
curl "http://树莓派IP:8080/api/sensor/read?gpio=4"预期返回:
Temp=24.0*C Humidity=41.0%或类似信息。测试启动自动采集:
curl -X POST "http://树莓派IP:8080/api/sensor/collection/start?interval=30000"预期返回成功信息,并且查看应用日志,应该每隔30秒出现一次采集记录。
测试停止采集:
curl -X POST "http://树莓派IP:8080/api/sensor/collection/stop"检查数据库:
mysql -u pi_env_user -p pi_environment SELECT * FROM temperature_humidity ORDER BY reading_time DESC LIMIT 5;应该能看到最新的几条温湿度记录。
5.3 常见问题与排查技巧实录
以下是我在实施过程中遇到的一些典型问题及解决方法:
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
调用接口返回ERROR: Script execution failed或Failed to get reading | 1. 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变量,确保其线程安全(使用volatile或AtomicBoolean)。 |
读取数据偶尔为null或格式异常 | 1. 传感器通信受干扰,数据校验失败。 2. Python脚本输出格式与预期不符。 | 1.增加重试机制:在readDHT11Once方法中,如果返回Failed,可以延迟几百毫秒后重试1-2次。2.增强数据解析的鲁棒性:使用正则表达式匹配 Temp=([\d.]+)\*C Humidity=([\d.]+)%,而不是简单的字符串分割。 |
| 应用运行一段时间后内存占用过高或崩溃 | 1. 资源未关闭导致内存泄露(如Process、InputStream)。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实现实时数据推送到前端仪表盘;或者结合摄像头,在温湿度异常时拍照留存。硬件上也可以接入更多传感器,如光照、空气质量传感器等,构建一个完整的室内环境监测站。
