本文目录导读:

- 案例一:智能家居温度监控系统(基础版)
- 案例二:智能工厂设备监测系统(进阶版)
- 案例三:完整智慧农业解决方案(企业级)
- 案例四:车联网(Vehicle-to-Everything, V2X)平台
- 案例五:工业物联网数据采集与分析系统
智能家居温度监控系统(基础版)
场景描述
通过传感器收集室内温度数据,通过MQTT协议传输到服务器,后端进行存储和监控,支持Web端实时查看和报警通知。
技术栈
- 设备端:Java + Eclipse Paho MQTT Client
- 通信协议:MQTT
- 后端:Spring Boot + MySQL + WebSocket
- 前端:Vue/React + ECharts
设备端代码示例
import org.eclipse.paho.client.mqttv3.*;
import java.util.Random;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class TemperatureSensor {
private static final String BROKER_URL = "tcp://localhost:1883";
private static final String TOPIC = "home/livingroom/temperature";
private static final String CLIENT_ID = "sensor_temperature_001";
private MqttClient client;
private Random random = new Random();
public void connect() throws MqttException {
client = new MqttClient(BROKER_URL, CLIENT_ID);
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(true);
options.setConnectionTimeout(10);
options.setKeepAliveInterval(30);
client.setCallback(new MqttCallback() {
@Override
public void connectionLost(Throwable cause) {
System.out.println("连接丢失,尝试重连...");
reconnect();
}
@Override
public void messageArrived(String topic, MqttMessage message) {
// 接收控制指令
System.out.println("收到指令: " + new String(message.getPayload()));
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
// 发送完成
}
});
client.connect(options);
System.out.println("传感器连接成功");
// 订阅控制指令
client.subscribe("home/livingroom/control");
// 启动数据发送任务
startPublishing();
}
private void startPublishing() {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(() -> {
try {
if (client.isConnected()) {
double temperature = 20 + random.nextDouble() * 15; // 20-35度
String payload = String.format(
"{\"sensorId\":\"%s\",\"temperature\":%.2f,\"humidity\":%.2f,\"timestamp\":%d}",
CLIENT_ID,
temperature,
40 + random.nextDouble() * 40,
System.currentTimeMillis()
);
MqttMessage message = new MqttMessage(payload.getBytes());
message.setQos(1);
client.publish(TOPIC, message);
System.out.println("发布数据: " + payload);
}
} catch (MqttException e) {
e.printStackTrace();
}
}, 0, 10, TimeUnit.SECONDS); // 每10秒上报一次
}
private void reconnect() {
while (!client.isConnected()) {
try {
System.out.println("正在重连...");
client.connect();
System.out.println("重连成功");
} catch (MqttException e) {
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
public static void main(String[] args) {
TemperatureSensor sensor = new TemperatureSensor();
try {
sensor.connect();
} catch (MqttException e) {
e.printStackTrace();
}
}
}
后端服务(Spring Boot)
@RestController
@RequestMapping("/api/iot")
public class IotDataController {
@Autowired
private IoTDataService iotDataService;
@Autowired
private SimpMessagingTemplate messagingTemplate;
// MQTT配置
@Service
public static class MqttSubscriber {
@Autowired
private IoTDataService iotDataService;
@Autowired
private SimpMessagingTemplate messagingTemplate;
@PostConstruct
public void init() {
try {
MqttClient client = new MqttClient("tcp://localhost:1883", "server_" + UUID.randomUUID());
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(true);
client.setCallback(new MqttCallback() {
@Override
public void connectionLost(Throwable cause) {}
@Override
public void messageArrived(String topic, MqttMessage message) {
// 处理接收到的传感器数据
String payload = new String(message.getPayload());
System.out.println("收到数据: " + payload);
// 解析数据
IoTData data = parseData(payload);
// 存储到数据库
iotDataService.save(data);
// 实时推送给Web端
messagingTemplate.convertAndSend("/topic/sensor-data", data);
// 温度超过阈值报警
if (data.getTemperature() > 30.0) {
Alert alert = new Alert("HIGH_TEMPERATURE",
"温度过高: " + data.getTemperature() + "°C", data);
messagingTemplate.convertAndSend("/topic/alerts", alert);
}
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {}
});
client.connect(options);
client.subscribe("home/+/temperature");
} catch (MqttException e) {
e.printStackTrace();
}
}
private IoTData parseData(String payload) {
// 使用Jackson或Gson解析JSON
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(payload, IoTData.class);
}
}
// 供前端查询历史数据
@GetMapping("/history")
public List<IoTData> getHistory(
@RequestParam(required = false) String sensorId,
@RequestParam String startTime,
@RequestParam String endTime) {
return iotDataService.findByTimeRange(sensorId, startTime, endTime);
}
}
智能工厂设备监测系统(进阶版)
场景描述
监测工厂设备的运行状态(振动、噪音、温度、运行时长等),通过MQTT实时上传数据,后端进行设备健康度分析、预测性维护,通过Web界面展示设备状态看板,并通过短信/邮件/钉钉发送告警通知。
架构图
[传感器设备] --MQTT--> [EMQX Broker] --订阅--> [业务处理服务] --存储--> [InfluxDB/MySQL]
| |
|---WebSocket---> [Web看板]
|
---告警通知---> [钉钉/邮件/短信]
核心业务逻辑代码
@Service
public class DeviceMonitorService {
@Autowired
private DeviceRepository deviceRepository;
@Autowired
private AlertService alertService;
@Autowired
private InfluxDBClient influxDBClient;
// 接收设备数据并进行处理
public void processDeviceData(DeviceData deviceData) {
// 1. 校验数据
if (!validateDeviceData(deviceData)) {
log.warn("无效的设备数据: {}", deviceData);
return;
}
// 2. 存储时序数据到InfluxDB
saveToInfluxDB(deviceData);
// 3. 计算设备健康度
double healthScore = calculateHealthScore(deviceData);
deviceData.setHealthScore(healthScore);
// 4. 更新设备状态
updateDeviceStatus(deviceData.getDeviceId(), healthScore);
// 5. 判断是否需要告警
checkAndAlert(deviceData, healthScore);
}
// 计算健康度评分
private double calculateHealthScore(DeviceData data) {
double score = 100.0;
// 温度评分
if (data.getTemperature() > 85) {
score -= 30;
} else if (data.getTemperature() > 70) {
score -= 15;
}
// 振动评分
if (data.getVibration() > 10) {
score -= 40;
} else if (data.getVibration() > 5) {
score -= 20;
}
// 噪声评分
if (data.getNoise() > 120) {
score -= 20;
} else if (data.getNoise() > 90) {
score -= 10;
}
// 累计运行时间因素(设备老化)
if (data.getRunningHours() > 7200) { // 超过1年
score -= 5;
}
return Math.max(0, Math.min(100, score));
}
// 检查和触发告警
private void checkAndAlert(DeviceData data, double healthScore) {
AlertLevel level = null;
String message = null;
if (healthScore < 50) {
level = AlertLevel.CRITICAL;
message = String.format("设备%s严重异常,健康度仅%.1f%,需要立即检修",
data.getDeviceId(), healthScore);
} else if (healthScore < 70) {
level = AlertLevel.WARNING;
message = String.format("设备%s存在异常,健康度%.1f%,请关注",
data.getDeviceId(), healthScore);
}
if (level != null) {
// 检查是否已发送过相同告警(避免频繁发送)
if (!alertService.isDuplicatedAlert(data.getDeviceId(), level, 15)) {
alertService.sendAlert(data.getDeviceId(), level, message);
}
}
}
}
设备数据管理(InfluxDB集成)
@Configuration
public class InfluxDBConfig {
@Bean
public InfluxDBClient influxDBClient() {
InfluxDBClient client = InfluxDBClientFactory.create(
"http://localhost:8086",
"token".toCharArray(),
"myorg",
"devices"
);
return client;
}
}
@Repository
public class DeviceDataRepository {
@Autowired
private InfluxDBClient influxDBClient;
public void save(DeviceData data) {
String point = String.format(
"device_data,device_id=%s device_status=\"%s\",temperature=%.2f," +
"vibration=%.2f,noise=%.2f,health_score=%.1f,running_hours=%d %d",
data.getDeviceId(),
data.getStatus(),
data.getTemperature(),
data.getVibration(),
data.getNoise(),
data.getHealthScore(),
data.getRunningHours(),
data.getTimestamp() * 1000000L // 纳秒时间戳
);
try (WriteApi writeApi = influxDBClient.getWriteApi()) {
writeApi.writeRecord(point);
}
}
public List<DeviceData> queryHistory(String deviceId, String startTime, String endTime) {
String fluxQuery = String.format(
"from(bucket:\"devices\") \n" +
" |> range(start: %s, stop: %s) \n" +
" |> filter(fn: (r) => r._measurement == \"device_data\") \n" +
" |> filter(fn: (r) => r.device_id == \"%s\")",
startTime, endTime, deviceId
);
// 执行查询并转换为DeviceData对象
List<FluxTable> tables = influxDBClient.getQueryApi().query(fluxQuery);
return parseTables(tables);
}
}
完整智慧农业解决方案(企业级)
场景描述
智能大棚种植管理系统,实现光照、温湿度、土壤pH值、CO₂浓度监测,自动控制灌溉、通风、补光等设备,通过AI算法实现智能决策,提供App远程控制。
系统架构
┌─────────────────────────────────────────────────────────────┐
│ 客户端应用层 │
│ [微信小程序] [Android/iOS App] [Web管理后台] │
└──────────────────────────┬──────────────────────────────────┘
│
┌──────────────────────────▼──────────────────────────────────┐
│ 业务服务层 │
│ 用户管理 设备管理 数据服务 告警管理 │
│ 决策引擎 报表统计 远程控制 系统配置 │
└──────────────────────────┬──────────────────────────────────┘
│
┌──────────────────────────▼──────────────────────────────────┐
│ 基础设施层 │
│ MQTT Broker (EMQX) Kafka消息队列 Redis缓存 │
│ MySQL/PostgreSQL InfluxDB时序数据库 MinIO对象存储 │
└──────────────────────────┬──────────────────────────────────┘
│
┌──────────────────────────▼──────────────────────────────────┐
│ 设备接入层 │
│ 智能网关 摄像头 传感器节点 PLC控制器 │
│ 气象站 土壤墒情仪 虫情监测 水肥一体机 │
└─────────────────────────────────────────────────────────────┘
设备接入服务
@Component
public class DeviceGatewayService {
private static final String TOPIC_PREFIX = "agri/device/";
@Autowired
private DeviceRespository deviceRespository;
@Autowired
private CommandService commandService;
private MqttClient mqttClient;
private Map<String, DeviceSession> activeSessions = new ConcurrentHashMap<>();
@PostConstruct
public void init() {
try {
mqttClient = new MqttClient("tcp://localhost:1883",
"agri_server_" + UUID.randomUUID());
MqttConnectOptions options = new MqttConnectOptions();
options.setAutomaticReconnect(true);
options.setCleanSession(true);
options.setConnectionTimeout(30);
options.setKeepAliveInterval(60);
mqttClient.connect(options);
// 订阅设备上报主题
mqttClient.subscribe(TOPIC_PREFIX + "+/+/data", 1);
mqttClient.subscribe(TOPIC_PREFIX + "+/+/status", 1);
mqttClient.subscribe(TOPIC_PREFIX + "+/+/event", 1);
// 注册回调
mqttClient.setCallback(new MqttCallback() {
@Override
public void connectionLost(Throwable cause) {
// 自动重连由MqttConnectOptions配置
}
@Override
public void messageArrived(String topic, MqttMessage message) {
handleDeviceMessage(topic, message);
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {}
});
} catch (MqttException e) {
log.error("MQTT连接失败", e);
}
}
private void handleDeviceMessage(String topic, MqttMessage message) {
// 解析主题:agri/device/{deviceId}/{type}
String[] parts = topic.split("/");
if (parts.length < 4) {
log.warn("无效的MQTT主题: {}", topic);
return;
}
String deviceId = parts[2];
String messageType = parts[3];
String payload = new String(message.getPayload());
switch (messageType) {
case "data":
handleDeviceData(deviceId, payload);
break;
case "status":
handleDeviceStatus(deviceId, payload);
break;
case "event":
handleDeviceEvent(deviceId, payload);
break;
default:
log.warn("不支持的消息类型: {}", messageType);
}
}
}
智能决策引擎
@Service
public class IntelligentDecisionEngine {
@Autowired
private EnvDataService envDataService;
@Autowired
private DeviceControlService controlService;
@Autowired
private RuleEngine ruleEngine;
@Autowired
private MLModelService mlModelService;
/**
* 智能灌溉决策
* 综合土壤湿度、天气预测、作物生长阶段等多因素
*/
public IrrigationDecision decideIrrigation(String greenhouseId) {
// 获取当前环境数据
EnvData currentEnv = envDataService.getLatestData(greenhouseId);
// 获取作物信息
CropInfo crop = cropService.getCropByGreenhouse(greenhouseId);
// 获取天气预报
WeatherForecast forecast = weatherService.getForecast(greenhouseId);
// 获取历史灌水记录
List<IrrigationRecord> history = recordService.getRecentIrrigations(greenhouseId, 48);
// 方案1:基于规则的决策
RuleBasedResult ruleResult = ruleEngine.evaluateIrrigationRule(
currentEnv, crop, forecast
);
// 方案2:基于机器学习的预测模型
double soilMoisturePrediction = mlModelService.predictSoilMoisture(
currentEnv, history, forecast
);
// 综合决策
IrrigationDecision decision = new IrrigationDecision();
decision.setGreenhouseId(greenhouseId);
decision.setDecisionTime(new Date());
// 判断是否需要灌溉
if (ruleResult.isNeedIrrigation() || soilMoisturePrediction < crop.getMinSoilMoisture()) {
decision.setNeedIrrigation(true);
// 计算灌溉量
double irrigationAmount = calculateIrrigationAmount(
currentEnv, crop, ruleResult, soilMoisturePrediction
);
decision.setAmount(irrigationAmount);
decision.setTime(estimateIrrigationTime(irrigationAmount));
decision.setReason("土壤湿度不足,预测未来24小时无降雨");
// 执行灌溉
controlService.sendIrrigationCommand(greenhouseId, irrigationAmount);
} else {
decision.setNeedIrrigation(false);
decision.setReason("当前土壤湿度适宜,无需灌溉");
}
// 异步执行其他决策
CompletableFuture.runAsync(() -> {
// 通风决策
decideVentilation(greenhouseId, currentEnv, crop);
// 补光决策
decideSupplementaryLighting(greenhouseId, currentEnv, crop, forecast);
// 施肥决策
decideFertilization(greenhouseId, currentEnv, crop);
});
// 记录决策日志
logService.recordDecision(decision);
return decision;
}
/**
* 计算灌溉量(考虑作物类型、生长阶段、蒸腾速率等)
*/
private double calculateIrrigationAmount(EnvData env, CropInfo crop,
RuleBasedResult ruleResult,
double predictedMoisture) {
double baseAmount = crop.getIrrigationBaseAmount(); // 基础灌溉量
double coeffTomp = 1 + (env.getTemperature() - 25) * 0.02; // 温度系数
double coeffHumidity = 1 - (env.getHumidity() - 50) * 0.005; // 湿度系数
double coeffGrowth = crop.getGrowthStageCoefficient(); // 生长阶段系数
// 考虑近期降雨
double rainCoeff = ruleResult.getExpectedRainfall() > 10 ? 0.7 : 1.0;
return baseAmount * coeffTomp * coeffHumidity * coeffGrowth * rainCoeff;
}
}
设备控制服务
@Service
public class DeviceControlService {
@Autowired
private MqttGateway mqttGateway;
@Autowired
private CommandHistoryRepository historyRepo;
/**
* 发送灌溉命令(带状态确认)
*/
public asyncTask sendIrrigationCommand(String greenhouseId, double amount) {
// 创建命令
DeviceCommand command = new DeviceCommand();
command.setDeviceId(greenhouseId);
command.setCommandType(CommandType.IRRIGATION_START);
command.setParameters(Map.of("amount", amount, "unit", "L"));
command.setId(UUID.randomUUID().toString());
// 设置超时与重试
command.setTimeout(30);
command.setRetryTimes(3);
// 通过MQTT发送
mqttGateway.sendCommand(command);
// 记录命令历史
historyRepo.save(command);
// 等待设备响应(异步)
CompletableFuture<CommandResult> future = new CompletableFuture<>();
// 将future存入pendingCommands
pendingCommands.put(command.getId(), future);
return future.get(30, TimeUnit.SECONDS)
.whenComplete((result, error) -> {
if (error != null) {
log.error("命令执行失败", error);
// 触发重试或告警
} else {
log.info("命令执行成功: {}", result);
// 更新状态
}
});
}
/**
* 批量设备控制
*/
public void batchControl(List<DeviceCommand> commands) {
// 使用协程或并行流批量处理
commands.parallelStream().forEach(this::sendCommand);
}
/**
* 定时任务 - 轮询设备状态(心跳检测)
*/
@Scheduled(fixedDelay = 5000)
public void checkDeviceHealth() {
// 检查超过10分钟未上报的在线设备
List<Device> staleDevices = deviceService.getDevicesByStatus(DeviceStatus.ONLINE);
for (Device device : staleDevices) {
if (device.getLastReportTime().before(new Date(System.currentTimeMillis() - 600000))) {
// 设备可能离线,发送状态查询
DeviceCommand queryCommand = DeviceCommand.builder()
.deviceId(device.getId())
.commandType(CommandType.STATUS_QUERY)
.build();
sendCommand(queryCommand);
}
}
}
}
数据分析与预测模型
# Python端训练模型并导出(与Java配合)
import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestRegressor
import joblib
# 读取历史环境数据
env_data = pd.read_csv('env_data.csv', parse_dates=['timestamp'])
crop_data = pd.read_csv('crop_data.csv')
# 特征工程
features = env_data[['temperature', 'humidity', 'light', 'soil_moisture']]
target = env_data['irrigation_amount'].shift(-1) # 预测下一次灌溉量
# 训练模型
model = RandomForestRegressor(n_estimators=100, random_state=42)
model.fit(features, target)
# 保存模型
joblib.dump(model, 'irrigation_model.joblib')
// Java调用Python模型推理
@Service
public class MLModelService {
@Autowired
private HttpClient httpClient;
private static final String MODEL_SERVER_URL = "http://localhost:5001/predict";
public double predictSoilMoisture(EnvData currentEnv,
List<IrrigationRecord> history,
WeatherForecast forecast) {
// 构建特征向量
Map<String, Double> features = new HashMap<>();
features.put("temperature", currentEnv.getTemperature());
features.put("humidity", currentEnv.getHumidity());
features.put("light", currentEnv.getLight());
features.put("soil_moisture", currentEnv.getSoilMoisture());
features.put("hours_since_last_irrigation",
history.isEmpty() ? 24 : calcHoursSince(history.get(0)));
features.put("forecast_rain_probability", forecast.getRainProbability());
features.put("evapotranspiration", calcET(currentEnv));
// 调用模型服务
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(MODEL_SERVER_URL))
.POST(HttpRequest.BodyPublishers.ofString(JsonUtil.toJson(features)))
.build();
HttpResponse<String> response = httpClient.send(request, BodyHandlers.ofString());
PredictionResult result = JsonUtil.fromJson(response.body(), PredictionResult.class);
return result.getPrediction();
}
}
车联网(Vehicle-to-Everything, V2X)平台
场景描述
车辆实时定位追踪、行驶数据采集(车速、油耗、里程)、驾驶行为分析(急加速/急刹车)、远程控制(远程锁车/远程启动)和故障诊断。
设备侧模拟代码
import org.eclipse.paho.client.mqttv3.*;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
public class VehicleDevice {
private static final String BROKER_URL = "tcp://localhost:1883";
private static final String VIN = "LSVAM4187C2184847";
private MqttClient mqttClient;
private Random random = new Random();
private AtomicInteger speed = new AtomicInteger(0);
private AtomicInteger fuelLevel = new AtomicInteger(80);
public void start() throws MqttException {
mqttClient = new MqttClient(BROKER_URL, "veh_" + VIN);
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(true);
options.setAutomaticReconnect(true);
mqttClient.connect(options);
// 订阅远程控制指令
subscribeToCommands();
// 启动数据上报
startReportThread();
}
private void subscribeToCommands() throws MqttException {
mqttClient.subscribe("v2x/vehicle/" + VIN + "/command", (topic, message) -> {
String command = new String(message.getPayload());
handleCommand(command);
});
}
private void handleCommand(String command) {
JsonNode node = new ObjectMapper().readTree(command);
String cmdType = node.get("type").asText();
switch (cmdType) {
case "lock":
// 执行锁车
System.out.println("车辆被远程锁定");
publishStatus("locked", "success");
break;
case "unlock":
System.out.println("车辆被远程解锁");
publishStatus("unlocked", "success");
break;
case "start_engine":
System.out.println("远程启动引擎");
publishStatus("engine_started", "success");
break;
case "diagnostic":
// 返回诊断信息
publishDiagnostics();
break;
}
}
private void startReportThread() {
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(() -> {
try {
// 模拟车辆行驶数据
speed.set(0 + random.nextInt(120)); // 0-120km/h
double longitude = 121.4737 + (random.nextDouble() - 0.5) * 0.01;
double latitude = 31.2304 + (random.nextDouble() - 0.5) * 0.01;
// 构建GPS数据
GpsData gpsData = new GpsData();
gpsData.setVin(VIN);
gpsData.setLongitude(longitude);
gpsData.setLatitude(latitude);
gpsData.setSpeed(speed.get());
gpsData.setFuelLevel(fuelLevel.getAndDecrement());
gpsData.setEngineTemp(80 + random.nextInt(30));
gpsData.setBatteryVoltage(12.5 + random.nextDouble() * 2);
gpsData.setTimestamp(System.currentTimeMillis());
// 发布到主题
publishToTopic("v2x/vehicle/" + VIN + "/gps", JsonUtil.toJson(gpsData));
// 检测驾驶行为
if (random.nextInt(100) == 0) { // 1%概率触发急加速
publishEvent("v2x/vehicle/" + VIN + "/event",
"harsh_acceleration",
"急加速: 0-60km/h in 2.5s");
}
// 检测故障
if (fuelLevel.get() < 10) {
publishEvent("v2x/vehicle/" + VIN + "/event",
"low_fuel",
"燃油不足: " + fuelLevel.get() + "%");
}
} catch (Exception e) {
e.printStackTrace();
}
}, 0, 5, TimeUnit.SECONDS);
}
private void publishStatus(String status, String result) {
publishToTopic("v2x/vehicle/" + VIN + "/status",
String.format("{\"status\":\"%s\",\"result\":\"%s\",\"time\":%d}",
status, result, System.currentTimeMillis()));
}
private void publishEvent(String topic, String eventType, String message) {
String payload = String.format(
"{\"eventType\":\"%s\",\"message\":\"%s\",\"time\":%d}",
eventType, message, System.currentTimeMillis()
);
publishToTopic(topic, payload);
}
private void publishDiagnostics() {
Map<String, String> diags = Map.of(
"engine_health", "good",
"tire_pressure", "normal",
"battery", "charging",
"errors", "no errors found"
);
publishToTopic("v2x/vehicle/" + VIN + "/diagnostics", JsonUtil.toJson(diags));
}
private void publishToTopic(String topic, String payload) throws MqttException {
MqttMessage message = new MqttMessage(payload.getBytes());
message.setQos(1);
message.setRetained(false);
mqttClient.publish(topic, message);
}
public static void main(String[] args) {
VehicleDevice vehicle = new VehicleDevice();
try {
vehicle.start();
} catch (MqttException e) {
e.printStackTrace();
}
}
}
工业物联网数据采集与分析系统
场景描述
从PLC、仪表、仪器等工业设备中采集数据,通过Modbus、OPC-UA等协议接入,将数据发送到MQTT Broker,后端进行边缘计算、异常检测和数据可视化。
核心配置与代码
@Configuration
@EnableScheduling
public class IotDataCollector {
@Autowired
private MqttPublisher mqttPublisher;
// Modbus TCP客户端配置
private ModbusMaster getModbusMaster(String host, int port) {
IpParameters params = new IpParameters();
params.setHost(host);
params.setPort(port);
return new ModbusMaster(params);
}
/**
* 采集PLC数据任务
*/
@Scheduled(fixedDelay = 500) // 每500ms采集一次
public void collectPLCData() throws Exception {
List<String> deviceIPs = Arrays.asList("192.168.1.100", "192.168.1.101", "192.168.1.102");
for (String ip : deviceIPs) {
ModbusMaster plc = getModbusMaster(ip, 502);
plc.init();
try {
// 读取寄存器数据
ReadInputRegistersResponse response = plc.readInputRegisters(1, 0, 10);
// 提取关键参数
int[] values = response.getRegisters();
// 构建数据对象
PLCData data = new PLCData();
data.setDeviceIp(ip);
data.setPower(values[0]);
data.setSpeed(values[1]);
data.setTemperature(values[2] / 100.0); // 精确到0.01度
data.setPressure(values[3] / 10.0);
data.setFlowRate(values[4]);
data.setQuality(generateQualityCode());
// 发布到MQTT
mqttPublisher.publish("factory/plc/" + ip, data, 1);
} finally {
plc.disconnect();
}
}
}
/**
* 边缘计算 - 简单的异常检测
*/
private boolean anomalyDetection(PLCData data) {
// 温度报警阈值
if (data.getTemperature() > 85) {
log.error("设备温度过高: {}", data);
return true;
}
// 速率变化检测(判断速率突变)
if (calculateSpeedChangeRate(data) > 0.3) {
return true;
}
// 压力异常
if (data.getPressure() < 0.1 || data.getPressure() > 5.0) {
return true;
}
return false;
}
private double calculateSpeedChangeRate(PLCData current) {
// 使用Redis存储历史数据
String key = "plc:speed:" + current.getDeviceIp();
Double previousSpeed = redisTemplate.opsForValue().get(key);
if (previousSpeed != null && previousSpeed != 0) {
return Math.abs(current.getSpeed() - previousSpeed) / previousSpeed;
}
// 更新缓存
redisTemplate.opsForValue().set(key, current.getSpeed(), Duration.ofSeconds(5));
return 0;
}
}
Kafka集成(处理海量数据)
@Configuration
public class KafkaConfig {
@Bean
public KafkaTemplate<String, String> kafkaTemplate() {
Map<String, Object> props = new HashMap<>();
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
props.put(ProducerConfig.ACKS_CONFIG, "all");
props.put(ProducerConfig.RETRIES_CONFIG, 3);
props.put(ProducerConfig.BATCH_SIZE_CONFIG, 16384);
props.put(ProducerConfig.LINGER_MS_CONFIG, 1);
return new KafkaTemplate<>(new DefaultKafkaProducerFactory<>(props));
}
@Bean
public ConsumerFactory<String, String> consumerFactory() {
Map<String, Object> props = new HashMap<>();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ConsumerConfig.GROUP_ID_CONFIG, "iot-data-processor");
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, true);
props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
return new DefaultKafkaConsumerFactory<>(props,
new StringDeserializer(),
new StringDeserializer());
}
@Bean
public ConcurrentKafkaListenerContainerFactory<String, String> kafkaListenerContainerFactory() {
ConcurrentKafkaListenerContainerFactory<String, String> factory =
new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory());
factory.setConcurrency(5); // 并发消费线程数
factory.getContainerProperties().setPollTimeout(3000);
return factory;
}
}
@Component
public class KafkaIoTDataProcessor {
@Autowired
private InfluxDBClient influxDBClient;
@Autowired
private AlertService alertService;
/**
* 消费来自Kafka的IoT数据
*/
@KafkaListener(topics = "iot-raw-data",
concurrency = "5",
containerFactory = "kafkaListenerContainerFactory")
public void processRawData(String message) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
RawData data = mapper.readValue(message, RawData.class);
// 1. 数据校验与清洗
if (!validate(data)) {
log.warn("数据校验失败: {}", message);
return;
}
// 2. 数据转换
TimeSeriesData tsData = convertToTimeSeries(data);
// 3. 批量写入InfluxDB(提高性能)
writeToInfluxDB(tsData);