1. 项目概述:无人共享宠物洗澡物联网系统
这个基于Java开发的物联网项目,解决了一个非常实际的痛点——现代都市人工作繁忙,带宠物去宠物店洗澡既费时又昂贵。我们设计了一套自助式宠物洗澡设备,用户通过手机APP预约使用,设备自动完成注水、调温、洗澡、烘干全流程。整套系统由三个核心部分组成:物联网硬件控制端(STM32单片机)、云端管理平台(SpringBoot)、用户小程序(Android/iOS)。
提示:这个项目特别适合想要学习物联网全栈开发的同学,涵盖了从硬件控制到云端服务的完整链路。
我在实际开发中发现,宠物洗澡设备有几个关键参数必须精确控制:水温(38-40℃最舒适)、水流强度(分三档可调)、洗澡时间(小型犬建议15分钟)。这些参数都需要在硬件和软件层面做双重校验,否则可能造成宠物不适甚至受伤。
2. 系统架构设计
2.1 硬件层设计
设备主体采用304不锈钢材质,核心控制器使用STM32F103系列单片机,通过继电器控制水泵、加热器等执行机构。传感器配置包括:
- DS18B20水温传感器(精度±0.5℃)
- 红外液位传感器(防溢出)
- 重量传感器(检测宠物是否在位)
- 霍尔传感器(门状态检测)
java复制// 硬件控制示例代码
public class HardwareController {
private static final int PUMP_PIN = 12;
private static final int HEATER_PIN = 13;
public void startPump(int duration) {
digitalWrite(PUMP_PIN, HIGH);
delay(duration);
digitalWrite(PUMP_PIN, LOW);
}
public void setTemperature(float targetTemp) {
while(readTempSensor() < targetTemp - 0.5f) {
digitalWrite(HEATER_PIN, HIGH);
delay(1000);
}
digitalWrite(HEATER_PIN, LOW);
}
}
2.2 通信协议选型
考虑到宠物店环境通常WiFi覆盖良好,我们选择了MQTT协议作为主要通信方式,相比HTTP更适合物联网场景:
| 协议特性 | MQTT优势 | HTTP劣势 |
|---|---|---|
| 实时性 | 支持发布/订阅模式 | 需要轮询 |
| 带宽 | 最小仅2字节开销 | 头部信息冗余 |
| 断线处理 | 自动重连机制 | 需要手动处理 |
| 功耗 | 心跳间隔可配置 | 每次完整握手 |
java复制// SpringBoot集成MQTT示例
@Configuration
public class MqttConfig {
@Value("${mqtt.broker}")
private String broker;
@Bean
public MqttPahoClientFactory mqttClientFactory() {
DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
MqttConnectOptions options = new MqttConnectOptions();
options.setServerURIs(new String[] {broker});
options.setKeepAliveInterval(60);
factory.setConnectionOptions(options);
return factory;
}
}
2.3 云端架构
后端采用经典的SpringCloud微服务架构:
code复制用户服务 → API网关 → 设备服务 → MySQL
↑
定时服务 ← 消息队列 → 支付服务 → Redis
特别设计了双缓存策略:本地缓存(Caffeine)存储设备实时状态,Redis缓存用户预约信息。实测这种架构可以支撑500+设备同时在线。
3. 核心功能实现细节
3.1 预约排队算法
为了解决高峰期设备争用问题,我们实现了动态时间片分配算法:
- 基础时间片=15分钟(小型犬标准时长)
- 根据宠物重量自动调整:
- <5kg:时间片×1.0
- 5-15kg:时间片×1.5
-
15kg:时间片×2.0
- 会员等级加成:
- 普通会员:+0分钟
- 黄金会员:+5分钟
- 铂金会员:+10分钟
java复制public class ScheduleService {
public TimeSlot calculateTimeSlot(Pet pet, User user) {
float base = 15f; // 基础15分钟
float weightFactor = pet.getWeight() < 5 ? 1 :
(pet.getWeight() < 15 ? 1.5f : 2f);
float vipBonus = switch(user.getLevel()) {
case GOLD -> 5f;
case PLATINUM -> 10f;
default -> 0f;
};
return new TimeSlot(base * weightFactor + vipBonus);
}
}
3.2 水温闭环控制
水温控制采用PID算法,参数经过200+次实测调优:
| 参数 | 初始值 | 优化值 | 说明 |
|---|---|---|---|
| Kp | 8.0 | 12.5 | 比例系数 |
| Ki | 0.5 | 0.3 | 积分系数 |
| Kd | 2.0 | 1.8 | 微分系数 |
实际测试表明,这套参数能在90秒内将水温稳定在设定值±0.3℃范围内。
3.3 安全防护机制
设备包含五重安全保护:
- 物理急停按钮(硬件级)
- 水温超过42℃自动断电
- 门未关闭禁止启动
- 水流持续3分钟无重量变化自动停机
- 云端心跳检测(30秒无响应触发告警)
4. 开发中的典型问题与解决方案
4.1 MQTT消息堆积
初期设计时忽略了消息确认机制,导致设备离线期间指令堆积,重新上线后指令乱序执行。解决方案:
- 增加消息QoS级别为1(至少送达一次)
- 每条指令附带时间戳
- 设备端实现指令去重队列
java复制// 改进后的消息处理
@MqttListener(topics = "/command/${deviceId}")
public void handleCommand(Message message) {
if(messageStore.exists(message.getId())) {
return; // 已处理过的消息直接忽略
}
executor.executeInOrder(
message.getTimestamp(),
() -> processCommand(message)
);
messageStore.save(message.getId());
}
4.2 数据库连接泄漏
压力测试时发现连接池经常耗尽,经排查是未正确关闭MyBatis的SqlSession。通过以下方式解决:
- 集成Spring Boot Actuator监控连接池
- 使用try-with-resources语法
- 添加连接泄漏检测配置:
yaml复制spring:
datasource:
hikari:
leak-detection-threshold: 5000 # 5秒未关闭连接视为泄漏
4.3 时间同步问题
设备端与服务器时间不同步导致预约冲突,最终解决方案:
- 设备启动时通过NTP同步时间
- 每次通信附带时间戳
- 云端实现时间漂移补偿算法
5. 性能优化实践
5.1 数据库分表策略
设备状态记录表按照设备ID哈希分10张表,查询性能提升8倍:
sql复制CREATE TABLE device_status_0 (
id BIGINT PRIMARY KEY,
device_id VARCHAR(32),
temp FLOAT,
-- 其他字段
) ENGINE=InnoDB;
-- 创建device_status_1到device_status_9...
5.2 缓存穿透防护
采用布隆过滤器+空值缓存解决不存在的设备查询:
java复制public DeviceInfo getDevice(String deviceId) {
// 第一层:布隆过滤器
if (!bloomFilter.mightContain(deviceId)) {
return null;
}
// 第二层:缓存查询
DeviceInfo cached = redisTemplate.opsForValue().get(deviceId);
if (cached != null) {
return cached == NULL_OBJECT ? null : cached;
}
// 第三层:数据库查询
DeviceInfo dbData = deviceMapper.selectById(deviceId);
if (dbData == null) {
redisTemplate.opsForValue().set(deviceId, NULL_OBJECT, 5, MINUTES);
bloomFilter.put(deviceId);
return null;
}
redisTemplate.opsForValue().set(deviceId, dbData, 30, MINUTES);
return dbData;
}
5.3 日志优化技巧
发现日志占用了30%的CPU资源,通过以下调整将影响降到5%以下:
- 异步日志(Log4j2 AsyncLogger)
- 关键路径禁用DEBUG日志
- 使用JSON格式替代文本格式
- 添加日志采样率配置
xml复制<!-- log4j2.xml配置片段 -->
<AsyncLogger name="com.petwash" level="info" includeLocation="false">
<AppenderRef ref="JsonFile"/>
<AppenderRef ref="Console"/>
</AsyncLogger>
6. 部署与运维方案
6.1 容器化部署
采用Docker Compose编排服务,关键配置:
yaml复制version: '3'
services:
gateway:
image: openjdk:17-jdk
ports:
- "8080:8080"
deploy:
resources:
limits:
cpus: '1'
memory: 1G
device-service:
image: openjdk:17-jdk
environment:
- SPRING_PROFILES_ACTIVE=prod
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8081/actuator/health"]
interval: 30s
6.2 监控体系搭建
使用Prometheus+Grafana监控关键指标:
- 设备在线率
- 平均响应时间
- 异常请求比例
- 资源使用率
java复制// 自定义指标示例
@Bean
MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
return registry -> registry.config().commonTags(
"application", "pet-wash",
"region", System.getenv("REGION")
);
}
6.3 灰度发布策略
通过Nginx+Redis实现按设备ID分流的灰度发布:
nginx复制# nginx配置片段
location /api {
set $group "prod";
if ($arg_deviceId ~* "^1") {
set $group "canary";
}
proxy_pass http://$group-upstream;
}
7. 项目演进方向
在实际运营中,我们发现可以进一步优化:
- 增加AI摄像头识别宠物品种,自动推荐洗澡方案
- 接入气象数据,雨天自动增加烘干时间
- 开发宠物社交功能,用户可分享洗澡视频
- 引入区块链技术实现设备共享分账
注意:物联网项目要特别注意固件升级方案,我们采用了差分升级技术,将升级包大小减少了70%。
