实践项目

# 实践项目

# 1. 项目概述

本章将通过四个典型的物联网应用场景,展示完整的物联网系统设计和实现过程。每个项目都包含需求分析、架构设计、技术选型、核心代码实现和部署指南。

# 2. 学习目标

  • 掌握不同领域的物联网应用特点
  • 学会根据业务需求设计技术架构
  • 理解端到端的系统实现过程
  • 积累实际项目开发经验
  • 了解不同场景下的技术选型策略

# 3. 项目架构对比

graph TB
    subgraph "智能家居系统"
        A1["家庭网关"] --> A2["智能设备"]
        A1 --> A3["移动应用"]
        A2 --> A4["传感器"]
        A2 --> A5["执行器"]
    end
    
    subgraph "工业监控系统"
        B1["工业网关"] --> B2["生产设备"]
        B1 --> B3["监控中心"]
        B2 --> B4["传感器阵列"]
        B2 --> B5["控制系统"]
    end
    
    subgraph "车联网系统"
        C1["车载终端"] --> C2["车辆传感器"]
        C1 --> C3["云端平台"]
        C2 --> C4["行驶数据"]
        C2 --> C5["环境感知"]
    end
    
    subgraph "农业物联网"
        D1["农业网关"] --> D2["环境监测"]
        D1 --> D3["智能控制"]
        D2 --> D4["土壤传感器"]
        D2 --> D5["气象站"]
    end

# 项目一:智能家居系统

# 1. 项目需求分析

# 1.1 功能需求

  • 环境监控: 温度、湿度、空气质量、光照强度
  • 安全防护: 门窗监控、人体感应、烟雾报警
  • 智能控制: 灯光、空调、窗帘、家电控制
  • 场景联动: 回家模式、离家模式、睡眠模式
  • 远程管理: 手机APP远程监控和控制

# 1.2 非功能需求

  • 可靠性: 99.9%系统可用性
  • 实时性: 控制指令响应时间<500ms
  • 安全性: 数据加密传输,用户认证
  • 扩展性: 支持新设备接入
  • 易用性: 简洁直观的用户界面

# 2. 系统架构设计

graph TB
    subgraph "智能家居系统架构"
        subgraph "设备层"
            A1["温湿度传感器"]
            A2["门窗传感器"]
            A3["人体感应器"]
            A4["智能开关"]
            A5["智能插座"]
            A6["智能摄像头"]
        end
        
        subgraph "网关层"
            B1["家庭网关"]
            B2["协议转换"]
            B3["本地存储"]
            B4["边缘计算"]
        end
        
        subgraph "网络层"
            C1["WiFi"]
            C2["ZigBee"]
            C3["蓝牙"]
            C4["4G/5G"]
        end
        
        subgraph "云端平台"
            D1["设备管理"]
            D2["数据处理"]
            D3["规则引擎"]
            D4["用户管理"]
        end
        
        subgraph "应用层"
            E1["移动APP"]
            E2["Web控制台"]
            E3["语音助手"]
            E4["第三方集成"]
        end
    end
    
    A1 --> B1
    A2 --> B1
    A3 --> B1
    A4 --> B1
    A5 --> B1
    A6 --> B1
    
    B1 --> C1
    B1 --> C2
    B1 --> C3
    
    C4 --> D1
    D1 --> D2
    D2 --> D3
    D3 --> D4
    
    D4 --> E1
    D4 --> E2
    D4 --> E3
    D4 --> E4

# 3. 技术选型

# 3.1 硬件平台

# 技术选型配置
hardware:
  gateway:
    platform: "Raspberry Pi 4"
    os: "Ubuntu 20.04 LTS"
    storage: "32GB SD Card + 1TB SSD"
    connectivity: ["WiFi", "Ethernet", "ZigBee", "Bluetooth"]
  
  sensors:
    temperature_humidity: "DHT22"
    door_window: "Reed Switch"
    motion: "PIR Sensor"
    air_quality: "MQ-135"
    light: "BH1750"
  
  actuators:
    smart_switch: "ESP32 + Relay"
    smart_socket: "ESP8266 + Relay"
    led_strip: "WS2812B"
    servo_motor: "SG90"

software:
  gateway:
    runtime: "Node.js 16+"
    database: "SQLite + InfluxDB"
    message_queue: "MQTT (Mosquitto)"
    web_framework: "Express.js"
  
  cloud:
    backend: "Spring Boot + Spring Cloud"
    database: "MySQL + Redis + InfluxDB"
    message_queue: "Apache Kafka"
    container: "Docker + Kubernetes"
  
  frontend:
    mobile: "React Native"
    web: "React + Ant Design"
    charts: "ECharts"

# 4. 核心代码实现

# 4.1 设备数据采集

// 示例:传感器数据采集服务
const mqtt = require('mqtt');
const { InfluxDB, Point } = require('@influxdata/influxdb-client');
const config = require('./config');

class SensorDataCollector {
  constructor() {
    this.mqttClient = mqtt.connect(config.mqtt.broker);
    this.influxDB = new InfluxDB({
      url: config.influxdb.url,
      token: config.influxdb.token
    });
    this.writeApi = this.influxDB.getWriteApi(
      config.influxdb.org,
      config.influxdb.bucket
    );
    
    this.setupMqttHandlers();
  }

  setupMqttHandlers() {
    this.mqttClient.on('connect', () => {
      console.log('Connected to MQTT broker');
      
      // 订阅所有传感器主题
      this.mqttClient.subscribe('sensors/+/+', (err) => {
        if (err) {
          console.error('Failed to subscribe to sensors:', err);
        } else {
          console.log('Subscribed to sensor topics');
        }
      });
    });

    this.mqttClient.on('message', (topic, message) => {
      this.handleSensorData(topic, message);
    });

    this.mqttClient.on('error', (error) => {
      console.error('MQTT error:', error);
    });
  }

  handleSensorData(topic, message) {
    try {
      const topicParts = topic.split('/');
      const deviceId = topicParts[1];
      const sensorType = topicParts[2];
      const data = JSON.parse(message.toString());

      // 数据验证
      if (!this.validateSensorData(sensorType, data)) {
        console.warn(`Invalid sensor data for ${deviceId}:${sensorType}`, data);
        return;
      }

      // 存储到InfluxDB
      this.storeSensorData(deviceId, sensorType, data);

      // 实时数据处理
      this.processRealTimeData(deviceId, sensorType, data);

      // 规则引擎处理
      this.triggerRuleEngine(deviceId, sensorType, data);

    } catch (error) {
      console.error('Error handling sensor data:', error);
    }
  }

  validateSensorData(sensorType, data) {
    const validators = {
      temperature: (d) => typeof d.value === 'number' && d.value >= -40 && d.value <= 80,
      humidity: (d) => typeof d.value === 'number' && d.value >= 0 && d.value <= 100,
      motion: (d) => typeof d.detected === 'boolean',
      door: (d) => typeof d.open === 'boolean',
      air_quality: (d) => typeof d.ppm === 'number' && d.ppm >= 0,
      light: (d) => typeof d.lux === 'number' && d.lux >= 0
    };

    const validator = validators[sensorType];
    return validator ? validator(data) : false;
  }

  storeSensorData(deviceId, sensorType, data) {
    const point = new Point('sensor_data')
      .tag('device_id', deviceId)
      .tag('sensor_type', sensorType)
      .timestamp(new Date(data.timestamp || Date.now()));

    // 根据传感器类型添加字段
    switch (sensorType) {
      case 'temperature':
        point.floatField('temperature', data.value);
        break;
      case 'humidity':
        point.floatField('humidity', data.value);
        break;
      case 'motion':
        point.booleanField('detected', data.detected);
        break;
      case 'door':
        point.booleanField('open', data.open);
        break;
      case 'air_quality':
        point.floatField('ppm', data.ppm);
        break;
      case 'light':
        point.floatField('lux', data.lux);
        break;
    }

    this.writeApi.writePoint(point);
  }

  processRealTimeData(deviceId, sensorType, data) {
    // 发送实时数据到WebSocket客户端
    const realTimeData = {
      deviceId,
      sensorType,
      data,
      timestamp: Date.now()
    };

    // 通过WebSocket广播
    global.wsServer?.broadcast('sensor_data', realTimeData);

    // 更新设备状态缓存
    this.updateDeviceStatusCache(deviceId, sensorType, data);
  }

  updateDeviceStatusCache(deviceId, sensorType, data) {
    const redis = require('./redis');
    const cacheKey = `device:${deviceId}:${sensorType}`;
    const cacheData = {
      ...data,
      timestamp: Date.now()
    };

    redis.setex(cacheKey, 3600, JSON.stringify(cacheData)); // 缓存1小时
  }

  triggerRuleEngine(deviceId, sensorType, data) {
    const ruleEngine = require('./ruleEngine');
    ruleEngine.evaluate({
      deviceId,
      sensorType,
      data,
      timestamp: Date.now()
    });
  }

  async getHistoricalData(deviceId, sensorType, startTime, endTime) {
    const queryApi = this.influxDB.getQueryApi(config.influxdb.org);
    const query = `
      from(bucket: "${config.influxdb.bucket}")
        |> range(start: ${startTime}, stop: ${endTime})
        |> filter(fn: (r) => r._measurement == "sensor_data")
        |> filter(fn: (r) => r.device_id == "${deviceId}")
        |> filter(fn: (r) => r.sensor_type == "${sensorType}")
        |> sort(columns: ["_time"])
    `;

    const result = [];
    return new Promise((resolve, reject) => {
      queryApi.queryRows(query, {
        next(row, tableMeta) {
          const o = tableMeta.toObject(row);
          result.push({
            timestamp: o._time,
            value: o._value,
            field: o._field
          });
        },
        error(error) {
          reject(error);
        },
        complete() {
          resolve(result);
        }
      });
    });
  }

  close() {
    this.writeApi.close();
    this.mqttClient.end();
  }
}

module.exports = SensorDataCollector;

# 4.2 智能控制服务

// 示例:智能控制服务
class SmartControlService {
  constructor(mqttClient, ruleEngine) {
    this.mqttClient = mqttClient;
    this.ruleEngine = ruleEngine;
    this.deviceStates = new Map();
    this.scenes = new Map();
    
    this.initializeScenes();
  }

  initializeScenes() {
    // 回家模式
    this.scenes.set('home', {
      name: '回家模式',
      actions: [
        { deviceId: 'living_room_light', action: 'turn_on', brightness: 80 },
        { deviceId: 'entrance_light', action: 'turn_on', brightness: 100 },
        { deviceId: 'air_conditioner', action: 'set_temperature', temperature: 24 },
        { deviceId: 'curtains', action: 'open', position: 50 }
      ]
    });

    // 离家模式
    this.scenes.set('away', {
      name: '离家模式',
      actions: [
        { deviceId: 'all_lights', action: 'turn_off' },
        { deviceId: 'air_conditioner', action: 'turn_off' },
        { deviceId: 'tv', action: 'turn_off' },
        { deviceId: 'security_system', action: 'arm' }
      ]
    });

    // 睡眠模式
    this.scenes.set('sleep', {
      name: '睡眠模式',
      actions: [
        { deviceId: 'bedroom_light', action: 'turn_off' },
        { deviceId: 'living_room_light', action: 'turn_off' },
        { deviceId: 'tv', action: 'turn_off' },
        { deviceId: 'air_conditioner', action: 'set_temperature', temperature: 22 },
        { deviceId: 'curtains', action: 'close' }
      ]
    });

    // 观影模式
    this.scenes.set('movie', {
      name: '观影模式',
      actions: [
        { deviceId: 'living_room_light', action: 'dim', brightness: 20 },
        { deviceId: 'tv', action: 'turn_on' },
        { deviceId: 'sound_system', action: 'turn_on', volume: 60 },
        { deviceId: 'curtains', action: 'close' }
      ]
    });
  }

  // 执行设备控制命令
  async executeCommand(deviceId, command, parameters = {}) {
    try {
      const commandData = {
        deviceId,
        command,
        parameters,
        timestamp: Date.now(),
        requestId: this.generateRequestId()
      };

      // 发送MQTT命令
      const topic = `commands/${deviceId}`;
      this.mqttClient.publish(topic, JSON.stringify(commandData));

      // 记录命令历史
      await this.logCommand(commandData);

      // 更新设备状态预期值
      this.updateExpectedState(deviceId, command, parameters);

      return {
        success: true,
        requestId: commandData.requestId,
        message: 'Command sent successfully'
      };
    } catch (error) {
      console.error('Failed to execute command:', error);
      return {
        success: false,
        error: error.message
      };
    }
  }

  // 执行场景
  async executeScene(sceneId, userId) {
    const scene = this.scenes.get(sceneId);
    if (!scene) {
      throw new Error(`Scene ${sceneId} not found`);
    }

    console.log(`Executing scene: ${scene.name}`);
    const results = [];

    for (const action of scene.actions) {
      try {
        const result = await this.executeCommand(
          action.deviceId,
          action.action,
          action
        );
        results.push({ ...action, result });
        
        // 添加延迟以避免设备过载
        await this.delay(200);
      } catch (error) {
        console.error(`Failed to execute action for ${action.deviceId}:`, error);
        results.push({ ...action, error: error.message });
      }
    }

    // 记录场景执行历史
    await this.logSceneExecution(sceneId, userId, results);

    return {
      sceneId,
      sceneName: scene.name,
      results,
      timestamp: Date.now()
    };
  }

  // 智能联动规则
  setupAutomationRules() {
    // 人体感应自动开灯
    this.ruleEngine.addRule({
      id: 'motion_light_on',
      name: '人体感应开灯',
      condition: (data) => {
        return data.sensorType === 'motion' && 
               data.data.detected === true &&
               this.isNightTime();
      },
      action: async (data) => {
        const lightId = this.getLightForMotionSensor(data.deviceId);
        if (lightId) {
          await this.executeCommand(lightId, 'turn_on', { brightness: 60 });
        }
      }
    });

    // 门窗开启时关闭空调
    this.ruleEngine.addRule({
      id: 'window_ac_off',
      name: '开窗关空调',
      condition: (data) => {
        return data.sensorType === 'door' && 
               data.data.open === true &&
               this.isAirConditionerOn();
      },
      action: async (data) => {
        await this.executeCommand('air_conditioner', 'turn_off');
        // 发送通知
        this.sendNotification('空调已自动关闭,因为检测到门窗开启');
      }
    });

    // 温度过高自动开启空调
    this.ruleEngine.addRule({
      id: 'high_temp_ac_on',
      name: '高温开空调',
      condition: (data) => {
        return data.sensorType === 'temperature' && 
               data.data.value > 28 &&
               !this.isAirConditionerOn() &&
               this.isHomeOccupied();
      },
      action: async (data) => {
        await this.executeCommand('air_conditioner', 'turn_on');
        await this.executeCommand('air_conditioner', 'set_temperature', { temperature: 24 });
        this.sendNotification('空调已自动开启,当前温度过高');
      }
    });

    // 空气质量差时开启净化器
    this.ruleEngine.addRule({
      id: 'poor_air_purifier_on',
      name: '空气质量差开净化器',
      condition: (data) => {
        return data.sensorType === 'air_quality' && 
               data.data.ppm > 500;
      },
      action: async (data) => {
        await this.executeCommand('air_purifier', 'turn_on', { mode: 'auto' });
        this.sendNotification('空气净化器已自动开启,当前空气质量较差');
      }
    });
  }

  // 设备状态管理
  updateDeviceState(deviceId, state) {
    const currentState = this.deviceStates.get(deviceId) || {};
    const newState = { ...currentState, ...state, lastUpdate: Date.now() };
    this.deviceStates.set(deviceId, newState);

    // 广播状态更新
    global.wsServer?.broadcast('device_state', {
      deviceId,
      state: newState
    });
  }

  getDeviceState(deviceId) {
    return this.deviceStates.get(deviceId) || {};
  }

  // 辅助方法
  generateRequestId() {
    return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }

  updateExpectedState(deviceId, command, parameters) {
    const currentState = this.getDeviceState(deviceId);
    const expectedState = { ...currentState };

    switch (command) {
      case 'turn_on':
        expectedState.power = true;
        if (parameters.brightness) {
          expectedState.brightness = parameters.brightness;
        }
        break;
      case 'turn_off':
        expectedState.power = false;
        break;
      case 'set_temperature':
        expectedState.targetTemperature = parameters.temperature;
        break;
      case 'dim':
        expectedState.brightness = parameters.brightness;
        break;
    }

    this.updateDeviceState(deviceId, expectedState);
  }

  isNightTime() {
    const hour = new Date().getHours();
    return hour >= 18 || hour <= 6;
  }

  isAirConditionerOn() {
    const state = this.getDeviceState('air_conditioner');
    return state.power === true;
  }

  isHomeOccupied() {
    // 检查是否有人在家(基于最近的人体感应数据)
    const motionSensors = ['living_room_motion', 'bedroom_motion', 'kitchen_motion'];
    const recentTime = Date.now() - 30 * 60 * 1000; // 30分钟内

    return motionSensors.some(sensorId => {
      const state = this.getDeviceState(sensorId);
      return state.lastDetection && state.lastDetection > recentTime;
    });
  }

  getLightForMotionSensor(motionSensorId) {
    const mapping = {
      'living_room_motion': 'living_room_light',
      'bedroom_motion': 'bedroom_light',
      'kitchen_motion': 'kitchen_light',
      'bathroom_motion': 'bathroom_light'
    };
    return mapping[motionSensorId];
  }

  async logCommand(commandData) {
    // 记录到数据库
    const db = require('./database');
    await db.query(
      'INSERT INTO command_history (device_id, command, parameters, timestamp, request_id) VALUES (?, ?, ?, ?, ?)',
      [commandData.deviceId, commandData.command, JSON.stringify(commandData.parameters), 
       new Date(commandData.timestamp), commandData.requestId]
    );
  }

  async logSceneExecution(sceneId, userId, results) {
    const db = require('./database');
    await db.query(
      'INSERT INTO scene_history (scene_id, user_id, results, timestamp) VALUES (?, ?, ?, ?)',
      [sceneId, userId, JSON.stringify(results), new Date()]
    );
  }

  sendNotification(message) {
    // 发送推送通知
    global.notificationService?.send({
      title: '智能家居通知',
      message,
      timestamp: Date.now()
    });
  }

  delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}

module.exports = SmartControlService;

# 4.3 移动应用界面

// 示例:React Native移动应用主界面
import React, { useState, useEffect } from 'react';
import {
  View,
  Text,
  StyleSheet,
  ScrollView,
  TouchableOpacity,
  Switch,
  Alert,
  RefreshControl
} from 'react-native';
import { Card, Button, Slider, Icon } from 'react-native-elements';
import { useWebSocket } from '../hooks/useWebSocket';
import { deviceService } from '../services/deviceService';

interface Device {
  id: string;
  name: string;
  type: string;
  status: 'online' | 'offline';
  state: any;
}

interface SensorData {
  temperature?: number;
  humidity?: number;
  airQuality?: number;
  light?: number;
}

const SmartHomeScreen: React.FC = () => {
  const [devices, setDevices] = useState<Device[]>([]);
  const [sensorData, setSensorData] = useState<SensorData>({});
  const [loading, setLoading] = useState(false);
  const [refreshing, setRefreshing] = useState(false);

  const { isConnected, sendMessage, subscribe } = useWebSocket({
    url: 'ws://your-gateway-ip:8080/ws',
    autoConnect: true
  });

  useEffect(() => {
    loadDevices();
    setupWebSocketSubscriptions();
  }, []);

  const loadDevices = async () => {
    try {
      setLoading(true);
      const deviceList = await deviceService.getDevices();
      setDevices(deviceList);
    } catch (error) {
      Alert.alert('错误', '加载设备列表失败');
    } finally {
      setLoading(false);
    }
  };

  const setupWebSocketSubscriptions = () => {
    // 订阅传感器数据
    subscribe('sensor_data', (data: any) => {
      setSensorData(prev => ({
        ...prev,
        [data.sensorType]: data.data.value || data.data
      }));
    });

    // 订阅设备状态变化
    subscribe('device_state', (data: any) => {
      setDevices(prev => prev.map(device => 
        device.id === data.deviceId 
          ? { ...device, state: data.state }
          : device
      ));
    });
  };

  const handleDeviceControl = async (deviceId: string, command: string, parameters?: any) => {
    try {
      await deviceService.sendCommand(deviceId, command, parameters);
    } catch (error) {
      Alert.alert('错误', '设备控制失败');
    }
  };

  const handleSceneExecution = async (sceneId: string) => {
    try {
      await deviceService.executeScene(sceneId);
      Alert.alert('成功', '场景执行完成');
    } catch (error) {
      Alert.alert('错误', '场景执行失败');
    }
  };

  const onRefresh = async () => {
    setRefreshing(true);
    await loadDevices();
    setRefreshing(false);
  };

  const renderSensorCard = () => (
    <Card containerStyle={styles.card}>
      <Text style={styles.cardTitle}>环境监测</Text>
      <View style={styles.sensorGrid}>
        <View style={styles.sensorItem}>
          <Icon name="thermometer" type="font-awesome-5" color="#ff6b6b" />
          <Text style={styles.sensorValue}>
            {sensorData.temperature?.toFixed(1) || '--'}°C
          </Text>
          <Text style={styles.sensorLabel}>温度</Text>
        </View>
        <View style={styles.sensorItem}>
          <Icon name="tint" type="font-awesome-5" color="#4ecdc4" />
          <Text style={styles.sensorValue}>
            {sensorData.humidity?.toFixed(1) || '--'}%
          </Text>
          <Text style={styles.sensorLabel}>湿度</Text>
        </View>
        <View style={styles.sensorItem}>
          <Icon name="wind" type="font-awesome-5" color="#45b7d1" />
          <Text style={styles.sensorValue}>
            {sensorData.airQuality?.toFixed(0) || '--'}
          </Text>
          <Text style={styles.sensorLabel}>空气质量</Text>
        </View>
        <View style={styles.sensorItem}>
          <Icon name="sun" type="font-awesome-5" color="#f9ca24" />
          <Text style={styles.sensorValue}>
            {sensorData.light?.toFixed(0) || '--'}
          </Text>
          <Text style={styles.sensorLabel}>光照(lux)</Text>
        </View>
      </View>
    </Card>
  );

  const renderSceneCard = () => (
    <Card containerStyle={styles.card}>
      <Text style={styles.cardTitle}>场景控制</Text>
      <View style={styles.sceneGrid}>
        <TouchableOpacity 
          style={[styles.sceneButton, { backgroundColor: '#ff6b6b' }]}
          onPress={() => handleSceneExecution('home')}
        >
          <Icon name="home" type="font-awesome-5" color="white" size={24} />
          <Text style={styles.sceneText}>回家</Text>
        </TouchableOpacity>
        <TouchableOpacity 
          style={[styles.sceneButton, { backgroundColor: '#4ecdc4' }]}
          onPress={() => handleSceneExecution('away')}
        >
          <Icon name="lock" type="font-awesome-5" color="white" size={24} />
          <Text style={styles.sceneText}>离家</Text>
        </TouchableOpacity>
        <TouchableOpacity 
          style={[styles.sceneButton, { backgroundColor: '#45b7d1' }]}
          onPress={() => handleSceneExecution('sleep')}
        >
          <Icon name="moon" type="font-awesome-5" color="white" size={24} />
          <Text style={styles.sceneText}>睡眠</Text>
        </TouchableOpacity>
        <TouchableOpacity 
          style={[styles.sceneButton, { backgroundColor: '#f9ca24' }]}
          onPress={() => handleSceneExecution('movie')}
        >
          <Icon name="film" type="font-awesome-5" color="white" size={24} />
          <Text style={styles.sceneText}>观影</Text>
        </TouchableOpacity>
      </View>
    </Card>
  );

  const renderDeviceCard = (device: Device) => {
    const isOn = device.state?.power === true;
    const brightness = device.state?.brightness || 0;
    
    return (
      <Card key={device.id} containerStyle={styles.card}>
        <View style={styles.deviceHeader}>
          <View>
            <Text style={styles.deviceName}>{device.name}</Text>
            <Text style={styles.deviceType}>{device.type}</Text>
          </View>
          <View style={styles.deviceStatus}>
            <View style={[
              styles.statusDot, 
              { backgroundColor: device.status === 'online' ? '#52c41a' : '#ff4d4f' }
            ]} />
            <Text style={styles.statusText}>{device.status}</Text>
          </View>
        </View>
        
        <View style={styles.deviceControls}>
          {device.type === 'light' && (
            <>
              <View style={styles.controlRow}>
                <Text>开关</Text>
                <Switch
                  value={isOn}
                  onValueChange={(value) => 
                    handleDeviceControl(device.id, value ? 'turn_on' : 'turn_off')
                  }
                />
              </View>
              {isOn && (
                <View style={styles.controlRow}>
                  <Text>亮度: {brightness}%</Text>
                  <Slider
                    style={styles.slider}
                    value={brightness}
                    minimumValue={0}
                    maximumValue={100}
                    step={1}
                    onSlidingComplete={(value) => 
                      handleDeviceControl(device.id, 'set_brightness', { brightness: value })
                    }
                  />
                </View>
              )}
            </>
          )}
          
          {device.type === 'air_conditioner' && (
            <>
              <View style={styles.controlRow}>
                <Text>开关</Text>
                <Switch
                  value={isOn}
                  onValueChange={(value) => 
                    handleDeviceControl(device.id, value ? 'turn_on' : 'turn_off')
                  }
                />
              </View>
              {isOn && (
                <View style={styles.controlRow}>
                  <Text>温度: {device.state?.targetTemperature || 24}°C</Text>
                  <View style={styles.tempControls}>
                    <Button
                      title="-"
                      buttonStyle={styles.tempButton}
                      onPress={() => 
                        handleDeviceControl(device.id, 'set_temperature', {
                          temperature: (device.state?.targetTemperature || 24) - 1
                        })
                      }
                    />
                    <Button
                      title="+"
                      buttonStyle={styles.tempButton}
                      onPress={() => 
                        handleDeviceControl(device.id, 'set_temperature', {
                          temperature: (device.state?.targetTemperature || 24) + 1
                        })
                      }
                    />
                  </View>
                </View>
              )}
            </>
          )}
          
          {device.type === 'socket' && (
            <View style={styles.controlRow}>
              <Text>开关</Text>
              <Switch
                value={isOn}
                onValueChange={(value) => 
                  handleDeviceControl(device.id, value ? 'turn_on' : 'turn_off')
                }
              />
            </View>
          )}
        </View>
      </Card>
    );
  };

  return (
    <ScrollView 
      style={styles.container}
      refreshControl={
        <RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
      }
    >
      {/* 连接状态 */}
      <View style={styles.connectionStatus}>
        <View style={[
          styles.statusDot, 
          { backgroundColor: isConnected ? '#52c41a' : '#ff4d4f' }
        ]} />
        <Text style={styles.connectionText}>
          {isConnected ? '已连接' : '连接中...'}
        </Text>
      </View>

      {/* 传感器数据 */}
      {renderSensorCard()}

      {/* 场景控制 */}
      {renderSceneCard()}

      {/* 设备列表 */}
      <Text style={styles.sectionTitle}>设备控制</Text>
      {devices.map(renderDeviceCard)}
    </ScrollView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#f5f5f5',
    padding: 16
  },
  connectionStatus: {
    flexDirection: 'row',
    alignItems: 'center',
    marginBottom: 16,
    padding: 12,
    backgroundColor: 'white',
    borderRadius: 8
  },
  statusDot: {
    width: 8,
    height: 8,
    borderRadius: 4,
    marginRight: 8
  },
  connectionText: {
    fontSize: 14,
    color: '#666'
  },
  card: {
    borderRadius: 12,
    marginBottom: 16,
    elevation: 3,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4
  },
  cardTitle: {
    fontSize: 18,
    fontWeight: 'bold',
    marginBottom: 16,
    color: '#333'
  },
  sensorGrid: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    justifyContent: 'space-between'
  },
  sensorItem: {
    width: '48%',
    alignItems: 'center',
    padding: 16,
    backgroundColor: '#f8f9fa',
    borderRadius: 8,
    marginBottom: 8
  },
  sensorValue: {
    fontSize: 24,
    fontWeight: 'bold',
    marginVertical: 8,
    color: '#333'
  },
  sensorLabel: {
    fontSize: 12,
    color: '#666'
  },
  sceneGrid: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    justifyContent: 'space-between'
  },
  sceneButton: {
    width: '48%',
    aspectRatio: 1,
    borderRadius: 12,
    justifyContent: 'center',
    alignItems: 'center',
    marginBottom: 8
  },
  sceneText: {
    color: 'white',
    fontSize: 14,
    fontWeight: 'bold',
    marginTop: 8
  },
  sectionTitle: {
    fontSize: 20,
    fontWeight: 'bold',
    marginBottom: 16,
    color: '#333'
  },
  deviceHeader: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    marginBottom: 16
  },
  deviceName: {
    fontSize: 16,
    fontWeight: 'bold',
    color: '#333'
  },
  deviceType: {
    fontSize: 12,
    color: '#666',
    marginTop: 2
  },
  deviceStatus: {
    flexDirection: 'row',
    alignItems: 'center'
  },
  statusText: {
    fontSize: 12,
    color: '#666',
    marginLeft: 4
  },
  deviceControls: {
    gap: 12
  },
  controlRow: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center'
  },
  slider: {
    flex: 1,
    marginLeft: 16
  },
  tempControls: {
    flexDirection: 'row',
    gap: 8
  },
  tempButton: {
    width: 40,
    height: 40,
    borderRadius: 20
  }
});

export default SmartHomeScreen;

# 项目二:工业监控系统

# 1. 项目需求分析

# 1.1 功能需求

  • 设备监控: 生产设备状态、运行参数、故障诊断
  • 数据采集: 温度、压力、振动、电流等传感器数据
  • 报警管理: 实时告警、故障预警、维护提醒
  • 生产统计: 产量统计、效率分析、质量监控
  • 远程控制: 设备启停、参数调整、维护模式

# 1.2 系统特点

  • 高可靠性: 7×24小时不间断运行
  • 实时性: 毫秒级数据采集和响应
  • 安全性: 工业级安全防护
  • 扩展性: 支持大规模设备接入
  • 兼容性: 支持多种工业协议

# 2. 系统架构设计

graph TB
    subgraph "工业监控系统架构"
        subgraph "现场设备层"
            A1["PLC控制器"]
            A2["传感器阵列"]
            A3["执行器"]
            A4["工业摄像头"]
            A5["RFID读写器"]
        end
        
        subgraph "数据采集层"
            B1["工业网关"]
            B2["协议转换"]
            B3["数据预处理"]
            B4["边缘计算"]
        end
        
        subgraph "通信网络层"
            C1["工业以太网"]
            C2["Modbus"]
            C3["OPC UA"]
            C4["4G/5G"]
        end
        
        subgraph "数据处理层"
            D1["实时数据库"]
            D2["历史数据库"]
            D3["流处理引擎"]
            D4["规则引擎"]
        end
        
        subgraph "应用服务层"
            E1["设备管理"]
            E2["数据分析"]
            E3["报警服务"]
            E4["报表服务"]
        end
        
        subgraph "展示层"
            F1["监控大屏"]
            F2["Web控制台"]
            F3["移动APP"]
            F4["第三方系统"]
        end
    end
    
    A1 --> B1
    A2 --> B1
    A3 --> B1
    A4 --> B1
    A5 --> B1
    
    B1 --> C1
    B2 --> C2
    B3 --> C3
    B4 --> C4
    
    C1 --> D1
    C2 --> D2
    C3 --> D3
    C4 --> D4
    
    D1 --> E1
    D2 --> E2
    D3 --> E3
    D4 --> E4
    
    E1 --> F1
    E2 --> F2
    E3 --> F3
    E4 --> F4

# 3. 核心代码实现

# 3.1 工业协议适配器

// 示例:Modbus协议适配器
@Component
public class ModbusProtocolAdapter implements ProtocolAdapter {
    
    private static final Logger logger = LoggerFactory.getLogger(ModbusProtocolAdapter.class);
    
    @Autowired
    private DeviceDataService deviceDataService;
    
    @Autowired
    private AlarmService alarmService;
    
    private final Map<String, ModbusMaster> masterConnections = new ConcurrentHashMap<>();
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(10);
    
    @Override
    public void initialize(DeviceConfig config) {
        try {
            ModbusMaster master = createModbusMaster(config);
            masterConnections.put(config.getDeviceId(), master);
            
            // 启动数据采集任务
            startDataCollection(config);
            
            logger.info("Modbus adapter initialized for device: {}", config.getDeviceId());
        } catch (Exception e) {
            logger.error("Failed to initialize Modbus adapter for device: {}", 
                        config.getDeviceId(), e);
            throw new ProtocolAdapterException("Modbus adapter initialization failed", e);
        }
    }
    
    private ModbusMaster createModbusMaster(DeviceConfig config) throws Exception {
        ModbusFactory factory = new ModbusFactory();
        
        if ("TCP".equalsIgnoreCase(config.getConnectionType())) {
            // TCP连接
            IpParameters params = new IpParameters();
            params.setHost(config.getHost());
            params.setPort(config.getPort());
            params.setEncapsulated(false);
            
            return factory.createTcpMaster(params, true);
        } else if ("RTU".equalsIgnoreCase(config.getConnectionType())) {
            // RTU串口连接
            SerialParameters params = new SerialParameters();
            params.setCommPortId(config.getSerialPort());
            params.setBaudRate(config.getBaudRate());
            params.setDataBits(config.getDataBits());
            params.setStopBits(config.getStopBits());
            params.setParity(config.getParity());
            
            return factory.createRtuMaster(params);
        } else {
            throw new IllegalArgumentException("Unsupported connection type: " + 
                                             config.getConnectionType());
        }
    }
    
    private void startDataCollection(DeviceConfig config) {
        scheduler.scheduleAtFixedRate(() -> {
            try {
                collectDeviceData(config);
            } catch (Exception e) {
                logger.error("Data collection failed for device: {}", 
                           config.getDeviceId(), e);
                handleConnectionError(config.getDeviceId(), e);
            }
        }, 0, config.getCollectionInterval(), TimeUnit.MILLISECONDS);
    }
    
    private void collectDeviceData(DeviceConfig config) throws Exception {
        ModbusMaster master = masterConnections.get(config.getDeviceId());
        if (master == null) {
            throw new IllegalStateException("Modbus master not found for device: " + 
                                          config.getDeviceId());
        }
        
        List<RegisterConfig> registers = config.getRegisters();
        Map<String, Object> dataPoints = new HashMap<>();
        
        for (RegisterConfig register : registers) {
            try {
                Object value = readRegister(master, config.getSlaveId(), register);
                dataPoints.put(register.getName(), value);
            } catch (Exception e) {
                logger.warn("Failed to read register {} from device {}: {}", 
                          register.getName(), config.getDeviceId(), e.getMessage());
                // 记录读取失败的寄存器
                dataPoints.put(register.getName(), null);
            }
        }
        
        // 处理采集到的数据
        processCollectedData(config.getDeviceId(), dataPoints);
    }
    
    private Object readRegister(ModbusMaster master, int slaveId, RegisterConfig register) 
            throws Exception {
        
        switch (register.getType()) {
            case HOLDING_REGISTER:
                return readHoldingRegister(master, slaveId, register);
            case INPUT_REGISTER:
                return readInputRegister(master, slaveId, register);
            case COIL:
                return readCoil(master, slaveId, register);
            case DISCRETE_INPUT:
                return readDiscreteInput(master, slaveId, register);
            default:
                throw new IllegalArgumentException("Unsupported register type: " + 
                                                 register.getType());
        }
    }
    
    private Object readHoldingRegister(ModbusMaster master, int slaveId, RegisterConfig register) 
            throws Exception {
        
        ReadHoldingRegistersRequest request = new ReadHoldingRegistersRequest(
            slaveId, register.getAddress(), register.getLength());
        ReadHoldingRegistersResponse response = 
            (ReadHoldingRegistersResponse) master.send(request);
        
        if (response.isException()) {
            throw new ModbusException("Modbus exception: " + response.getExceptionMessage());
        }
        
        return convertRegisterValue(response.getShortData(), register.getDataType(), 
                                  register.getScale(), register.getOffset());
    }
    
    private Object readInputRegister(ModbusMaster master, int slaveId, RegisterConfig register) 
            throws Exception {
        
        ReadInputRegistersRequest request = new ReadInputRegistersRequest(
            slaveId, register.getAddress(), register.getLength());
        ReadInputRegistersResponse response = 
            (ReadInputRegistersResponse) master.send(request);
        
        if (response.isException()) {
            throw new ModbusException("Modbus exception: " + response.getExceptionMessage());
        }
        
        return convertRegisterValue(response.getShortData(), register.getDataType(), 
                                  register.getScale(), register.getOffset());
    }
    
    private Object readCoil(ModbusMaster master, int slaveId, RegisterConfig register) 
            throws Exception {
        
        ReadCoilsRequest request = new ReadCoilsRequest(
            slaveId, register.getAddress(), register.getLength());
        ReadCoilsResponse response = (ReadCoilsResponse) master.send(request);
        
        if (response.isException()) {
            throw new ModbusException("Modbus exception: " + response.getExceptionMessage());
        }
        
        return response.getBooleanData()[0]; // 假设只读取一个线圈
    }
    
    private Object readDiscreteInput(ModbusMaster master, int slaveId, RegisterConfig register) 
            throws Exception {
        
        ReadDiscreteInputsRequest request = new ReadDiscreteInputsRequest(
            slaveId, register.getAddress(), register.getLength());
        ReadDiscreteInputsResponse response = 
            (ReadDiscreteInputsResponse) master.send(request);
        
        if (response.isException()) {
            throw new ModbusException("Modbus exception: " + response.getExceptionMessage());
        }
        
        return response.getBooleanData()[0]; // 假设只读取一个输入
    }
    
    private Object convertRegisterValue(short[] data, DataType dataType, 
                                      double scale, double offset) {
        switch (dataType) {
            case INT16:
                return (int) (data[0] * scale + offset);
            case UINT16:
                return (int) ((data[0] & 0xFFFF) * scale + offset);
            case INT32:
                int int32Value = (data[0] << 16) | (data[1] & 0xFFFF);
                return (int) (int32Value * scale + offset);
            case UINT32:
                long uint32Value = ((long) (data[0] & 0xFFFF) << 16) | (data[1] & 0xFFFF);
                return (long) (uint32Value * scale + offset);
            case FLOAT32:
                int floatBits = (data[0] << 16) | (data[1] & 0xFFFF);
                return Float.intBitsToFloat(floatBits) * scale + offset;
            case BOOLEAN:
                return data[0] != 0;
            default:
                throw new IllegalArgumentException("Unsupported data type: " + dataType);
        }
    }
    
    private void processCollectedData(String deviceId, Map<String, Object> dataPoints) {
        try {
            // 创建设备数据对象
            DeviceData deviceData = DeviceData.builder()
                .deviceId(deviceId)
                .timestamp(Instant.now())
                .dataPoints(dataPoints)
                .build();
            
            // 保存数据
            deviceDataService.saveDeviceData(deviceData);
            
            // 检查告警条件
            checkAlarmConditions(deviceId, dataPoints);
            
            // 发送实时数据
            publishRealTimeData(deviceData);
            
        } catch (Exception e) {
            logger.error("Failed to process collected data for device: {}", deviceId, e);
        }
    }
    
    private void checkAlarmConditions(String deviceId, Map<String, Object> dataPoints) {
        for (Map.Entry<String, Object> entry : dataPoints.entrySet()) {
            String parameterName = entry.getKey();
            Object value = entry.getValue();
            
            if (value instanceof Number) {
                double numericValue = ((Number) value).doubleValue();
                alarmService.checkThresholdAlarm(deviceId, parameterName, numericValue);
            }
        }
    }
    
    private void publishRealTimeData(DeviceData deviceData) {
        // 发布到消息队列或WebSocket
        // 这里可以使用Spring的事件机制或消息队列
    }
    
    private void handleConnectionError(String deviceId, Exception error) {
        // 记录连接错误
        logger.error("Connection error for device {}: {}", deviceId, error.getMessage());
        
        // 创建连接告警
        alarmService.createConnectionAlarm(deviceId, error.getMessage());
        
        // 尝试重连
        scheduleReconnection(deviceId);
    }
    
    private void scheduleReconnection(String deviceId) {
        scheduler.schedule(() -> {
            try {
                // 重新初始化连接
                DeviceConfig config = deviceConfigService.getDeviceConfig(deviceId);
                initialize(config);
                logger.info("Reconnection successful for device: {}", deviceId);
            } catch (Exception e) {
                logger.error("Reconnection failed for device: {}", deviceId, e);
                // 继续重试
                scheduleReconnection(deviceId);
            }
        }, 30, TimeUnit.SECONDS); // 30秒后重试
    }
    
    @Override
    public void writeData(String deviceId, String parameterName, Object value) throws Exception {
        ModbusMaster master = masterConnections.get(deviceId);
        if (master == null) {
            throw new IllegalStateException("Modbus master not found for device: " + deviceId);
        }
        
        DeviceConfig config = deviceConfigService.getDeviceConfig(deviceId);
        RegisterConfig register = config.getRegisterByName(parameterName);
        
        if (register == null) {
            throw new IllegalArgumentException("Register not found: " + parameterName);
        }
        
        writeRegister(master, config.getSlaveId(), register, value);
    }
    
    private void writeRegister(ModbusMaster master, int slaveId, RegisterConfig register, 
                             Object value) throws Exception {
        
        switch (register.getType()) {
            case HOLDING_REGISTER:
                writeHoldingRegister(master, slaveId, register, value);
                break;
            case COIL:
                writeCoil(master, slaveId, register, value);
                break;
            default:
                throw new IllegalArgumentException("Cannot write to register type: " + 
                                                 register.getType());
        }
    }
    
    private void writeHoldingRegister(ModbusMaster master, int slaveId, RegisterConfig register, 
                                    Object value) throws Exception {
        
        short[] data = convertValueToRegister(value, register.getDataType(), 
                                            register.getScale(), register.getOffset());
        
        if (data.length == 1) {
            WriteSingleRegisterRequest request = new WriteSingleRegisterRequest(
                slaveId, register.getAddress(), data[0]);
            WriteSingleRegisterResponse response = 
                (WriteSingleRegisterResponse) master.send(request);
            
            if (response.isException()) {
                throw new ModbusException("Modbus exception: " + response.getExceptionMessage());
            }
        } else {
            WriteMultipleRegistersRequest request = new WriteMultipleRegistersRequest(
                slaveId, register.getAddress(), data);
            WriteMultipleRegistersResponse response = 
                (WriteMultipleRegistersResponse) master.send(request);
            
            if (response.isException()) {
                throw new ModbusException("Modbus exception: " + response.getExceptionMessage());
            }
        }
    }
    
    private void writeCoil(ModbusMaster master, int slaveId, RegisterConfig register, 
                          Object value) throws Exception {
        
        boolean boolValue = (Boolean) value;
        WriteSingleCoilRequest request = new WriteSingleCoilRequest(
            slaveId, register.getAddress(), boolValue);
        WriteSingleCoilResponse response = (WriteSingleCoilResponse) master.send(request);
        
        if (response.isException()) {
            throw new ModbusException("Modbus exception: " + response.getExceptionMessage());
        }
    }
    
    private short[] convertValueToRegister(Object value, DataType dataType, 
                                         double scale, double offset) {
        double adjustedValue = ((Number) value).doubleValue() / scale - offset;
        
        switch (dataType) {
            case INT16:
                return new short[] { (short) Math.round(adjustedValue) };
            case UINT16:
                return new short[] { (short) (Math.round(adjustedValue) & 0xFFFF) };
            case INT32:
                int int32Value = (int) Math.round(adjustedValue);
                return new short[] { 
                    (short) (int32Value >> 16), 
                    (short) (int32Value & 0xFFFF) 
                };
            case FLOAT32:
                float floatValue = (float) adjustedValue;
                int floatBits = Float.floatToIntBits(floatValue);
                return new short[] { 
                    (short) (floatBits >> 16), 
                    (short) (floatBits & 0xFFFF) 
                };
            default:
                throw new IllegalArgumentException("Unsupported data type for writing: " + dataType);
        }
    }
    
    @Override
    public void disconnect(String deviceId) {
        ModbusMaster master = masterConnections.remove(deviceId);
        if (master != null) {
            master.destroy();
            logger.info("Modbus connection closed for device: {}", deviceId);
        }
    }
    
    @PreDestroy
    public void shutdown() {
        scheduler.shutdown();
        masterConnections.values().forEach(ModbusMaster::destroy);
        masterConnections.clear();
    }
}

# 3.2 实时告警系统

// 示例:实时告警系统
@Service
public class IndustrialAlarmService {
    
    private static final Logger logger = LoggerFactory.getLogger(IndustrialAlarmService.class);
    
    @Autowired
    private AlarmRuleRepository alarmRuleRepository;
    
    @Autowired
    private AlarmRecordRepository alarmRecordRepository;
    
    @Autowired
    private NotificationService notificationService;
    
    @Autowired
    private WebSocketService webSocketService;
    
    private final Map<String, AlarmState> deviceAlarmStates = new ConcurrentHashMap<>();
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5);
    
    @PostConstruct
    public void initialize() {
        // 加载告警规则
        loadAlarmRules();
        
        // 启动告警状态检查任务
        startAlarmStateMonitoring();
    }
    
    public void checkThresholdAlarm(String deviceId, String parameterName, double value) {
        List<AlarmRule> rules = getAlarmRules(deviceId, parameterName);
        
        for (AlarmRule rule : rules) {
            if (rule.isEnabled()) {
                evaluateAlarmRule(rule, deviceId, parameterName, value);
            }
        }
    }
    
    private void evaluateAlarmRule(AlarmRule rule, String deviceId, 
                                 String parameterName, double value) {
        
        boolean alarmTriggered = false;
        String alarmMessage = "";
        
        switch (rule.getCondition()) {
            case GREATER_THAN:
                if (value > rule.getThreshold()) {
                    alarmTriggered = true;
                    alarmMessage = String.format("%s 超过上限: %.2f > %.2f", 
                                                parameterName, value, rule.getThreshold());
                }
                break;
            case LESS_THAN:
                if (value < rule.getThreshold()) {
                    alarmTriggered = true;
                    alarmMessage = String.format("%s 低于下限: %.2f < %.2f", 
                                                parameterName, value, rule.getThreshold());
                }
                break;
            case EQUALS:
                if (Math.abs(value - rule.getThreshold()) < 0.001) {
                    alarmTriggered = true;
                    alarmMessage = String.format("%s 等于告警值: %.2f", 
                                                parameterName, value);
                }
                break;
            case RANGE_OUT:
                if (value < rule.getMinThreshold() || value > rule.getMaxThreshold()) {
                    alarmTriggered = true;
                    alarmMessage = String.format("%s 超出范围: %.2f (范围: %.2f - %.2f)", 
                                                parameterName, value, 
                                                rule.getMinThreshold(), rule.getMaxThreshold());
                }
                break;
        }
        
        if (alarmTriggered) {
            handleAlarmTriggered(rule, deviceId, parameterName, value, alarmMessage);
        } else {
            handleAlarmCleared(rule, deviceId, parameterName, value);
        }
    }
    
    private void handleAlarmTriggered(AlarmRule rule, String deviceId, String parameterName, 
                                    double value, String message) {
        
        String alarmKey = generateAlarmKey(deviceId, parameterName, rule.getId());
        AlarmState currentState = deviceAlarmStates.get(alarmKey);
        
        if (currentState == null || currentState.getStatus() != AlarmStatus.ACTIVE) {
            // 新告警或告警重新触发
            AlarmRecord alarmRecord = createAlarmRecord(rule, deviceId, parameterName, 
                                                       value, message);
            
            // 保存告警记录
            alarmRecordRepository.save(alarmRecord);
            
            // 更新告警状态
            AlarmState newState = AlarmState.builder()
                .alarmId(alarmRecord.getId())
                .deviceId(deviceId)
                .parameterName(parameterName)
                .ruleId(rule.getId())
                .status(AlarmStatus.ACTIVE)
                .triggerTime(Instant.now())
                .triggerValue(value)
                .message(message)
                .build();
            
            deviceAlarmStates.put(alarmKey, newState);
            
            // 发送告警通知
            sendAlarmNotification(alarmRecord, rule);
            
            // 实时推送告警
            publishAlarmEvent(alarmRecord);
            
            logger.warn("Alarm triggered: {} - {}", deviceId, message);
        } else {
            // 更新现有告警的最后触发时间和值
            currentState.setLastTriggerTime(Instant.now());
            currentState.setTriggerValue(value);
        }
    }
    
    private void handleAlarmCleared(AlarmRule rule, String deviceId, String parameterName, 
                                  double value) {
        
        String alarmKey = generateAlarmKey(deviceId, parameterName, rule.getId());
        AlarmState currentState = deviceAlarmStates.get(alarmKey);
        
        if (currentState != null && currentState.getStatus() == AlarmStatus.ACTIVE) {
            // 告警恢复
            currentState.setStatus(AlarmStatus.CLEARED);
            currentState.setClearTime(Instant.now());
            currentState.setClearValue(value);
            
            // 更新数据库记录
            AlarmRecord alarmRecord = alarmRecordRepository.findById(currentState.getAlarmId())
                .orElse(null);
            
            if (alarmRecord != null) {
                alarmRecord.setStatus(AlarmStatus.CLEARED);
                alarmRecord.setClearTime(Instant.now());
                alarmRecord.setClearValue(value);
                alarmRecordRepository.save(alarmRecord);
                
                // 发送恢复通知
                sendAlarmClearNotification(alarmRecord, rule);
                
                // 实时推送恢复事件
                publishAlarmClearEvent(alarmRecord);
                
                logger.info("Alarm cleared: {} - {} 恢复正常", deviceId, parameterName);
            }
            
            // 移除告警状态
            deviceAlarmStates.remove(alarmKey);
        }
    }
    
    private String generateAlarmKey(String deviceId, String parameterName, Long ruleId) {
        return String.format("%s:%s:%d", deviceId, parameterName, ruleId);
    }
    
    private AlarmRecord createAlarmRecord(AlarmRule rule, String deviceId, 
                                        String parameterName, double value, String message) {
        return AlarmRecord.builder()
            .deviceId(deviceId)
            .parameterName(parameterName)
            .ruleId(rule.getId())
            .ruleName(rule.getName())
            .severity(rule.getSeverity())
            .triggerValue(value)
            .threshold(rule.getThreshold())
            .condition(rule.getCondition())
            .message(message)
            .status(AlarmStatus.ACTIVE)
            .triggerTime(Instant.now())
            .build();
    }
    
    private void sendAlarmNotification(AlarmRecord alarmRecord, AlarmRule rule) {
        // 根据告警级别和规则配置发送不同类型的通知
        NotificationRequest notification = NotificationRequest.builder()
            .title("工业设备告警")
            .message(alarmRecord.getMessage())
            .severity(alarmRecord.getSeverity())
            .deviceId(alarmRecord.getDeviceId())
            .timestamp(alarmRecord.getTriggerTime())
            .build();
        
        // 发送邮件、短信、微信等通知
        notificationService.sendNotification(notification, rule.getNotificationChannels());
    }
    
    private void publishAlarmEvent(AlarmRecord alarmRecord) {
        // 通过WebSocket实时推送告警事件
        AlarmEvent event = AlarmEvent.builder()
            .type("ALARM_TRIGGERED")
            .alarmRecord(alarmRecord)
            .timestamp(Instant.now())
            .build();
        
        webSocketService.broadcast("/topic/alarms", event);
    }
    
    @PreDestroy
    public void shutdown() {
        scheduler.shutdown();
    }
}

# 4. 车联网系统

# 4.1 系统架构

graph TB
    subgraph "车载终端层"
        A[OBD设备] --> B[车载网关]
        C[传感器] --> B
        D[GPS模块] --> B
        E[摄像头] --> B
    end
    
    subgraph "通信层"
        B --> F[4G/5G网络]
        B --> G[WiFi]
        B --> H[蓝牙]
    end
    
    subgraph "云端平台"
        F --> I[消息网关]
        G --> I
        I --> J[设备管理]
        I --> K[数据处理]
        I --> L[位置服务]
        I --> M[告警服务]
    end
    
    subgraph "应用层"
        J --> N[车队管理]
        K --> O[驾驶行为分析]
        L --> P[轨迹追踪]
        M --> Q[紧急救援]
    end
    
    subgraph "用户界面"
        N --> R[管理后台]
        O --> S[移动APP]
        P --> T[Web监控]
        Q --> U[告警中心]
    end

# 4.2 车辆数据采集

// 示例:车载数据采集系统
class VehicleDataCollector {
    constructor(config) {
        this.config = config;
        this.sensors = new Map();
        this.dataBuffer = [];
        this.isCollecting = false;
        this.uploadInterval = config.uploadInterval || 30000; // 30秒
        
        this.initializeSensors();
        this.setupDataUpload();
    }
    
    initializeSensors() {
        // 初始化OBD传感器
        this.sensors.set('obd', new OBDSensor({
            port: this.config.obdPort,
            baudRate: 38400,
            protocols: ['CAN', 'ISO9141', 'KWP2000']
        }));
        
        // 初始化GPS传感器
        this.sensors.set('gps', new GPSSensor({
            port: this.config.gpsPort,
            updateRate: 1000 // 1秒更新一次
        }));
        
        // 初始化加速度传感器
        this.sensors.set('accelerometer', new AccelerometerSensor({
            sensitivity: 'high',
            sampleRate: 100 // 100Hz
        }));
        
        // 初始化陀螺仪
        this.sensors.set('gyroscope', new GyroscopeSensor({
            range: 2000, // ±2000°/s
            sampleRate: 100
        }));
    }
    
    async startCollection() {
        if (this.isCollecting) {
            console.log('Data collection already started');
            return;
        }
        
        this.isCollecting = true;
        console.log('Starting vehicle data collection...');
        
        // 启动各个传感器
        for (const [name, sensor] of this.sensors) {
            try {
                await sensor.start();
                sensor.on('data', (data) => this.handleSensorData(name, data));
                console.log(`${name} sensor started successfully`);
            } catch (error) {
                console.error(`Failed to start ${name} sensor:`, error);
            }
        }
        
        // 启动数据收集循环
        this.collectionLoop();
    }
    
    handleSensorData(sensorType, data) {
        const timestamp = Date.now();
        const vehicleData = {
            vehicleId: this.config.vehicleId,
            timestamp,
            sensorType,
            data: this.processSensorData(sensorType, data)
        };
        
        // 添加到数据缓冲区
        this.dataBuffer.push(vehicleData);
        
        // 检查是否需要立即上传(紧急情况)
        if (this.isEmergencyData(vehicleData)) {
            this.uploadEmergencyData(vehicleData);
        }
    }
    
    processSensorData(sensorType, rawData) {
        switch (sensorType) {
            case 'obd':
                return this.processOBDData(rawData);
            case 'gps':
                return this.processGPSData(rawData);
            case 'accelerometer':
                return this.processAccelerometerData(rawData);
            case 'gyroscope':
                return this.processGyroscopeData(rawData);
            default:
                return rawData;
        }
    }
    
    processOBDData(data) {
        return {
            speed: data.speed || 0,
            rpm: data.rpm || 0,
            engineLoad: data.engineLoad || 0,
            coolantTemp: data.coolantTemp || 0,
            fuelLevel: data.fuelLevel || 0,
            throttlePosition: data.throttlePosition || 0,
            engineRunTime: data.engineRunTime || 0,
            distanceTraveled: data.distanceTraveled || 0,
            fuelConsumption: data.fuelConsumption || 0,
            diagnosticCodes: data.diagnosticCodes || []
        };
    }
    
    processGPSData(data) {
        return {
            latitude: data.latitude,
            longitude: data.longitude,
            altitude: data.altitude || 0,
            speed: data.speed || 0,
            heading: data.heading || 0,
            accuracy: data.accuracy || 0,
            satellites: data.satellites || 0,
            timestamp: data.timestamp
        };
    }
    
    processAccelerometerData(data) {
        const magnitude = Math.sqrt(data.x * data.x + data.y * data.y + data.z * data.z);
        
        return {
            x: data.x,
            y: data.y,
            z: data.z,
            magnitude,
            isHardBraking: magnitude > 8.0, // 急刹车检测
            isHardAcceleration: data.x > 4.0, // 急加速检测
            isSharpTurn: Math.abs(data.y) > 6.0 // 急转弯检测
        };
    }
    
    processGyroscopeData(data) {
        return {
            x: data.x, // 俯仰角速度
            y: data.y, // 横滚角速度
            z: data.z, // 偏航角速度
            isRapidRotation: Math.abs(data.z) > 100 // 快速转向检测
        };
    }
    
    isEmergencyData(vehicleData) {
        const { sensorType, data } = vehicleData;
        
        switch (sensorType) {
            case 'accelerometer':
                return data.isHardBraking || data.isHardAcceleration || data.magnitude > 15.0;
            case 'obd':
                return data.diagnosticCodes.length > 0 || data.coolantTemp > 110;
            case 'gyroscope':
                return data.isRapidRotation;
            default:
                return false;
        }
    }
    
    async uploadEmergencyData(vehicleData) {
        try {
            const response = await fetch(`${this.config.serverUrl}/api/vehicles/emergency`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${this.config.apiToken}`
                },
                body: JSON.stringify({
                    ...vehicleData,
                    priority: 'emergency'
                })
            });
            
            if (response.ok) {
                console.log('Emergency data uploaded successfully');
            } else {
                console.error('Failed to upload emergency data:', response.statusText);
            }
        } catch (error) {
            console.error('Error uploading emergency data:', error);
        }
    }
    
    setupDataUpload() {
        setInterval(() => {
            if (this.dataBuffer.length > 0) {
                this.uploadBatchData();
            }
        }, this.uploadInterval);
    }
    
    async uploadBatchData() {
        if (this.dataBuffer.length === 0) return;
        
        const batchData = [...this.dataBuffer];
        this.dataBuffer = []; // 清空缓冲区
        
        try {
            const response = await fetch(`${this.config.serverUrl}/api/vehicles/data/batch`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${this.config.apiToken}`
                },
                body: JSON.stringify({
                    vehicleId: this.config.vehicleId,
                    data: batchData,
                    timestamp: Date.now()
                })
            });
            
            if (response.ok) {
                console.log(`Uploaded ${batchData.length} data points successfully`);
            } else {
                console.error('Failed to upload batch data:', response.statusText);
                // 重新添加到缓冲区
                this.dataBuffer.unshift(...batchData);
            }
        } catch (error) {
            console.error('Error uploading batch data:', error);
            // 重新添加到缓冲区
            this.dataBuffer.unshift(...batchData);
        }
    }
    
    async stopCollection() {
        this.isCollecting = false;
        
        // 停止所有传感器
        for (const [name, sensor] of this.sensors) {
            try {
                await sensor.stop();
                console.log(`${name} sensor stopped`);
            } catch (error) {
                console.error(`Error stopping ${name} sensor:`, error);
            }
        }
        
        // 上传剩余数据
        if (this.dataBuffer.length > 0) {
            await this.uploadBatchData();
        }
        
        console.log('Vehicle data collection stopped');
    }
    
    collectionLoop() {
        if (!this.isCollecting) return;
        
        // 定期检查传感器状态
        setTimeout(() => {
            this.checkSensorHealth();
            this.collectionLoop();
        }, 5000); // 每5秒检查一次
    }
    
    checkSensorHealth() {
        for (const [name, sensor] of this.sensors) {
            if (!sensor.isHealthy()) {
                console.warn(`${name} sensor health check failed, attempting restart...`);
                sensor.restart().catch(error => {
                    console.error(`Failed to restart ${name} sensor:`, error);
                });
            }
        }
    }
}

// 使用示例
const collector = new VehicleDataCollector({
    vehicleId: 'VEHICLE_001',
    obdPort: '/dev/ttyUSB0',
    gpsPort: '/dev/ttyUSB1',
    serverUrl: 'https://api.vehicle-iot.com',
    apiToken: 'your-api-token',
    uploadInterval: 30000
});

collector.startCollection();