diff --git a/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/CleanRuleProcessorManager.java b/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/CleanRuleProcessorManager.java index 86b184c..65de452 100644 --- a/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/CleanRuleProcessorManager.java +++ b/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/CleanRuleProcessorManager.java @@ -78,9 +78,9 @@ public class CleanRuleProcessorManager { *

* 事件上报的 params 结构: * { - * "identifier": "button_event", - * "eventTime": 1234567890, - * "params": { keyId: 1, keyState: 1 } + * "identifier": "button_event", + * "eventTime": 1234567890, + * "params": { keyId: 1, keyState: 1 } * } */ private void processEventData(Long deviceId, Map data) { @@ -95,8 +95,7 @@ public class CleanRuleProcessorManager { // 路由到对应处理器 switch (identifier) { - case "button_event" -> - buttonEventRuleProcessor.processPropertyChange(deviceId, identifier, params); + case "button_event" -> buttonEventRuleProcessor.processPropertyChange(deviceId, identifier, params); default -> { // 其他事件忽略 } @@ -118,12 +117,9 @@ public class CleanRuleProcessorManager { private void processDataSafely(Long deviceId, String identifier, Object value) { try { switch (identifier) { - case "people_in" -> - trafficThresholdRuleProcessor.processPropertyChange(deviceId, identifier, value); + case "people_in" -> trafficThresholdRuleProcessor.processPropertyChange(deviceId, identifier, value); case "bluetoothDevices" -> - beaconDetectionRuleProcessor.processPropertyChange(deviceId, identifier, value); - case "button_event" -> - buttonEventRuleProcessor.processPropertyChange(deviceId, identifier, value); + beaconDetectionRuleProcessor.processPropertyChange(deviceId, identifier, value); default -> { // 其他属性/事件忽略 } diff --git a/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/BeaconDetectionRuleProcessor.java b/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/BeaconDetectionRuleProcessor.java index 72a9d79..eaf84ff 100644 --- a/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/BeaconDetectionRuleProcessor.java +++ b/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/BeaconDetectionRuleProcessor.java @@ -70,16 +70,17 @@ public class BeaconDetectionRuleProcessor { log.debug("[BeaconDetection] 收到蓝牙属性:deviceId={}", deviceId); - // 2. 获取工牌设备的配置(包含区域ID) - CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper badgeConfigWrapper = configService - .getConfigWrapperByDeviceId(deviceId); + // 2. 先获取当前工单状态(从中获取正确的 areaId) + BadgeDeviceStatusRedisDAO.OrderInfo currentOrder = badgeDeviceStatusRedisDAO.getCurrentOrder(deviceId); - if (badgeConfigWrapper == null || badgeConfigWrapper.getAreaId() == null) { - log.debug("[BeaconDetection] 工牌设备无区域配置:deviceId={}", deviceId); + if (currentOrder == null || currentOrder.getAreaId() == null) { + log.debug("[BeaconDetection] 无当前工单,跳过检测:deviceId={}", deviceId); return; } - Long areaId = badgeConfigWrapper.getAreaId(); + Long areaId = currentOrder.getAreaId(); + log.debug("[BeaconDetection] 从工单状态获取区域:deviceId={}, areaId={}, orderId={}", + deviceId, areaId, currentOrder.getOrderId()); // 3. 获取该区域的信标配置(从 BEACON 类型的设备获取) CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper beaconConfigWrapper = configService @@ -96,24 +97,21 @@ public class BeaconDetectionRuleProcessor { return; } - // 3. 解析蓝牙数据,提取目标信标的 RSSI + // 4. 解析蓝牙数据,提取目标信标的 RSSI Integer targetRssi = detector.extractTargetRssi(propertyValue, beaconConfig.getBeaconMac()); - log.debug("[BeaconDetection] 提取RSSI:deviceId={}, beaconMac={}, rssi={}", - deviceId, beaconConfig.getBeaconMac(), targetRssi); + log.debug("[BeaconDetection] 提取RSSI:deviceId={}, areaId={}, beaconMac={}, rssi={}", + deviceId, areaId, beaconConfig.getBeaconMac(), targetRssi); - // 4. 更新滑动窗口(使用 enter 和 exit 中较大的窗口大小) + // 5. 更新滑动窗口(使用 enter 和 exit 中较大的窗口大小) int maxWindowSize = Math.max( beaconConfig.getEnter().getWindowSize(), beaconConfig.getExit().getWindowSize()); windowRedisDAO.updateWindow(deviceId, areaId, targetRssi, maxWindowSize); - // 5. 获取当前窗口样本 + // 6. 获取当前窗口样本 List window = windowRedisDAO.getWindow(deviceId, areaId); - // 6. 获取设备当前工单状态 - BadgeDeviceStatusRedisDAO.OrderInfo currentOrder = badgeDeviceStatusRedisDAO.getCurrentOrder(deviceId); - // 7. 确定当前状态 RssiSlidingWindowDetector.AreaState currentState = determineState(currentOrder, areaId, deviceId); @@ -127,7 +125,7 @@ public class BeaconDetectionRuleProcessor { // 9. 处理检测结果 switch (result) { case ARRIVE_CONFIRMED: - handleArriveConfirmed(deviceId, areaId, window, beaconConfig, badgeConfigWrapper); + handleArriveConfirmed(deviceId, areaId, window, beaconConfig, currentOrder); break; case LEAVE_CONFIRMED: handleLeaveConfirmed(deviceId, areaId, window, beaconConfig); @@ -142,8 +140,8 @@ public class BeaconDetectionRuleProcessor { * 处理到达确认 */ private void handleArriveConfirmed(Long deviceId, Long areaId, List window, - BeaconPresenceConfig beaconConfig, - CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper badgeConfigWrapper) { + BeaconPresenceConfig beaconConfig, + BadgeDeviceStatusRedisDAO.OrderInfo currentOrder) { log.info("[BeaconDetection] 到达确认:deviceId={}, areaId={}, window={}", deviceId, areaId, window); @@ -160,20 +158,20 @@ public class BeaconDetectionRuleProcessor { // 4. 获取当前最新的 RSSI 值(使用原窗口快照,因为已清理) Integer currentRssi = window.isEmpty() ? -999 : window.get(window.size() - 1); - // 4. 构建触发数据 + // 5. 构建触发数据 Map triggerData = new HashMap<>(); triggerData.put("beaconMac", beaconConfig.getBeaconMac()); triggerData.put("rssi", currentRssi); triggerData.put("windowSnapshot", window); triggerData.put("enterRssiThreshold", beaconConfig.getEnter().getRssiThreshold()); - // 5. 发布到岗事件 + // 6. 发布到岗事件 if (beaconConfig.getEnter().getAutoArrival()) { - publishArriveEvent(deviceId, badgeConfigWrapper.getDeviceKey(), areaId, triggerData); + publishArriveEvent(deviceId, currentOrder.getOrderId(), areaId, triggerData); } - // 6. 发布审计日志 - publishAuditEvent("BEACON_ARRIVE_CONFIRMED", deviceId, badgeConfigWrapper.getDeviceKey(), areaId, + // 7. 发布审计日志 + publishAuditEvent("BEACON_ARRIVE_CONFIRMED", deviceId, null, areaId, "蓝牙信标自动到岗确认", triggerData); } @@ -181,7 +179,7 @@ public class BeaconDetectionRuleProcessor { * 处理离开确认 */ private void handleLeaveConfirmed(Long deviceId, Long areaId, List window, - BeaconPresenceConfig beaconConfig) { + BeaconPresenceConfig beaconConfig) { log.info("[BeaconDetection] 离开确认:deviceId={}, areaId={}, window={}", deviceId, areaId, window); @@ -230,21 +228,13 @@ public class BeaconDetectionRuleProcessor { /** * 发布到岗事件 */ - private void publishArriveEvent(Long deviceId, String deviceKey, Long areaId, Map triggerData) { + private void publishArriveEvent(Long deviceId, Long orderId, Long areaId, Map triggerData) { try { - // 获取当前工单信息,没有工单不发布事件 - BadgeDeviceStatusRedisDAO.OrderInfo currentOrder = badgeDeviceStatusRedisDAO.getCurrentOrder(deviceId); - if (currentOrder == null || currentOrder.getOrderId() == null) { - log.warn("[BeaconDetection] 设备无当前工单,跳过到岗事件: deviceId={}, areaId={}", deviceId, areaId); - return; - } - CleanOrderArriveEvent event = CleanOrderArriveEvent.builder() .eventId(java.util.UUID.randomUUID().toString()) .orderType("CLEAN") - .orderId(currentOrder.getOrderId()) + .orderId(orderId) .deviceId(deviceId) - .deviceKey(deviceKey) .areaId(areaId) .triggerSource("IOT_BEACON") .triggerData(triggerData) @@ -253,7 +243,7 @@ public class BeaconDetectionRuleProcessor { rocketMQTemplate.syncSend(CleanOrderTopics.ORDER_ARRIVE, MessageBuilder.withPayload(event).build()); log.info("[BeaconDetection] 发布到岗事件:eventId={}, deviceId={}, areaId={}, orderId={}", - event.getEventId(), deviceId, areaId, currentOrder.getOrderId()); + event.getEventId(), deviceId, areaId, orderId); } catch (Exception e) { log.error("[BeaconDetection] 发布到岗事件失败:deviceId={}, areaId={}", deviceId, areaId, e); } @@ -263,7 +253,7 @@ public class BeaconDetectionRuleProcessor { * 发布审计事件 */ private void publishAuditEvent(String auditType, Long deviceId, String deviceKey, - Long areaId, String message, Map data) { + Long areaId, String message, Map data) { try { CleanOrderAuditEvent event = CleanOrderAuditEvent.builder() .eventId(java.util.UUID.randomUUID().toString()) diff --git a/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/ButtonEventRuleProcessor.java b/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/ButtonEventRuleProcessor.java index 5185b8b..1c3d40b 100644 --- a/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/ButtonEventRuleProcessor.java +++ b/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/ButtonEventRuleProcessor.java @@ -1,9 +1,11 @@ package com.viewsh.module.iot.service.rule.clean.processor; +import com.viewsh.framework.common.util.json.JsonUtils; import com.viewsh.module.iot.core.integration.constants.CleanOrderTopics; import com.viewsh.module.iot.dal.dataobject.integration.clean.ButtonEventConfig; import com.viewsh.module.iot.dal.redis.clean.BadgeDeviceStatusRedisDAO; -import com.viewsh.module.iot.service.integration.clean.CleanOrderIntegrationConfigService; +import com.viewsh.module.iot.service.device.IotDeviceService; +import com.viewsh.module.iot.dal.dataobject.device.IotDeviceDO; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.apache.rocketmq.spring.core.RocketMQTemplate; @@ -31,10 +33,10 @@ import java.util.UUID; public class ButtonEventRuleProcessor { @Resource - private CleanOrderIntegrationConfigService configService; + private BadgeDeviceStatusRedisDAO badgeDeviceStatusRedisDAO; @Resource - private BadgeDeviceStatusRedisDAO badgeDeviceStatusRedisDAO; + private IotDeviceService deviceService; @Resource private RocketMQTemplate rocketMQTemplate; @@ -56,16 +58,8 @@ public class ButtonEventRuleProcessor { log.debug("[ButtonEvent] 收到按键事件:deviceId={}, value={}", deviceId, propertyValue); - // 2. 获取配置 - CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper configWrapper = - getConfigWrapper(deviceId); - - if (configWrapper == null || configWrapper.getConfig() == null) { - log.debug("[ButtonEvent] 设备无配置:deviceId={}", deviceId); - return; - } - - ButtonEventConfig buttonConfig = configWrapper.getConfig().getButtonEvent(); + // 2. 获取设备按键配置(从设备 config 字段读取) + ButtonEventConfig buttonConfig = getButtonConfig(deviceId); if (buttonConfig == null || !buttonConfig.getEnabled()) { log.debug("[ButtonEvent] 未启用按键事件处理:deviceId={}", deviceId); return; @@ -83,10 +77,10 @@ public class ButtonEventRuleProcessor { // 4. 匹配按键类型并处理 if (buttonId.equals(buttonConfig.getConfirmKeyId())) { // 确认键 - handleConfirmButton(configWrapper, buttonId); + handleConfirmButton(deviceId, buttonId); } else if (buttonId.equals(buttonConfig.getQueryKeyId())) { // 查询键 - handleQueryButton(configWrapper, buttonId); + handleQueryButton(deviceId, buttonId); } else { log.debug("[ButtonEvent] 未配置的按键:deviceId={}, buttonId={}", deviceId, buttonId); } @@ -97,9 +91,7 @@ public class ButtonEventRuleProcessor { *

* 保洁员按下确认键,确认接收工单 */ - private void handleConfirmButton(CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper configWrapper, - Integer buttonId) { - Long deviceId = configWrapper.getDeviceId(); + private void handleConfirmButton(Long deviceId, Integer buttonId) { log.info("[ButtonEvent] 确认键按下:deviceId={}, buttonId={}", deviceId, buttonId); @@ -123,7 +115,7 @@ public class ButtonEventRuleProcessor { } // 3. 发布工单确认事件 - publishConfirmEvent(configWrapper, orderId, buttonId); + publishConfirmEvent(deviceId, orderId, buttonId); log.info("[ButtonEvent] 发布工单确认事件:deviceId={}, orderId={}", deviceId, orderId); } @@ -133,9 +125,7 @@ public class ButtonEventRuleProcessor { *

* 保洁员按下查询键,查询当前工单信息 */ - private void handleQueryButton(CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper configWrapper, - Integer buttonId) { - Long deviceId = configWrapper.getDeviceId(); + private void handleQueryButton(Long deviceId, Integer buttonId) { log.info("[ButtonEvent] 查询键按下:deviceId={}, buttonId={}", deviceId, buttonId); @@ -144,12 +134,12 @@ public class ButtonEventRuleProcessor { if (currentOrder == null) { log.info("[ButtonEvent] 设备无当前工单:deviceId={}", deviceId); // 发布查询结果事件(无工单) - publishQueryEvent(configWrapper, null, buttonId, "当前无工单"); + publishQueryEvent(deviceId, null, buttonId, "当前无工单"); return; } // 2. 发布查询事件 - publishQueryEvent(configWrapper, currentOrder.getOrderId(), buttonId, "查询当前工单"); + publishQueryEvent(deviceId, currentOrder.getOrderId(), buttonId, "查询当前工单"); log.info("[ButtonEvent] 发布工单查询事件:deviceId={}, orderId={}", deviceId, currentOrder.getOrderId()); } @@ -157,16 +147,17 @@ public class ButtonEventRuleProcessor { /** * 发布工单确认事件 */ - private void publishConfirmEvent(CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper configWrapper, - Long orderId, Integer buttonId) { + private void publishConfirmEvent(Long deviceId, Long orderId, Integer buttonId) { try { + String deviceKey = getDeviceKey(deviceId); + Map event = new HashMap<>(); event.put("eventId", UUID.randomUUID().toString()); event.put("orderType", "CLEAN"); event.put("orderId", orderId); - event.put("deviceId", configWrapper.getDeviceId()); - event.put("deviceKey", configWrapper.getDeviceKey()); - event.put("areaId", configWrapper.getAreaId()); + event.put("deviceId", deviceId); + event.put("deviceKey", deviceKey); + event.put("areaId", null); // areaId 由 Ops 模块从当前工单获取 event.put("triggerSource", "IOT_BUTTON_CONFIRM"); event.put("buttonId", buttonId); @@ -176,26 +167,27 @@ public class ButtonEventRuleProcessor { ); log.info("[ButtonEvent] 确认事件已发布:eventId={}, orderId={}, deviceId={}", - event.get("eventId"), orderId, configWrapper.getDeviceId()); + event.get("eventId"), orderId, deviceId); } catch (Exception e) { log.error("[ButtonEvent] 发布确认事件失败:deviceId={}, orderId={}", - configWrapper.getDeviceId(), orderId, e); + deviceId, orderId, e); } } /** * 发布工单查询事件 */ - private void publishQueryEvent(CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper configWrapper, - Long orderId, Integer buttonId, String message) { + private void publishQueryEvent(Long deviceId, Long orderId, Integer buttonId, String message) { try { + String deviceKey = getDeviceKey(deviceId); + Map event = new HashMap<>(); event.put("eventId", UUID.randomUUID().toString()); event.put("orderType", "CLEAN"); event.put("orderId", orderId); - event.put("deviceId", configWrapper.getDeviceId()); - event.put("deviceKey", configWrapper.getDeviceKey()); - event.put("areaId", configWrapper.getAreaId()); + event.put("deviceId", deviceId); + event.put("deviceKey", deviceKey); + event.put("areaId", null); // areaId 由 Ops 模块从当前工单获取 event.put("triggerSource", "IOT_BUTTON_QUERY"); event.put("buttonId", buttonId); event.put("message", message); @@ -206,18 +198,47 @@ public class ButtonEventRuleProcessor { ); log.info("[ButtonEvent] 查询事件已发布:eventId={}, orderId={}, deviceId={}, message={}", - event.get("eventId"), orderId, configWrapper.getDeviceId(), message); + event.get("eventId"), orderId, deviceId, message); } catch (Exception e) { log.error("[ButtonEvent] 发布查询事件失败:deviceId={}, orderId={}", - configWrapper.getDeviceId(), orderId, e); + deviceId, orderId, e); } } /** - * 获取配置包装器 + * 获取设备按键配置 + *

+ * 从设备的 config 字段读取按键事件配置 + * + * @param deviceId 设备ID + * @return 按键配置,如果未配置返回 null */ - private CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper getConfigWrapper(Long deviceId) { - return configService.getConfigWrapperByDeviceId(deviceId); + private ButtonEventConfig getButtonConfig(Long deviceId) { + try { + IotDeviceDO device = deviceService.getDeviceFromCache(deviceId); + if (device == null || device.getConfig() == null) { + log.debug("[ButtonEvent] 设备不存在或无配置:deviceId={}", deviceId); + return null; + } + + // 从设备 config JSON 中解析 buttonEvent 配置 + // 注意:使用 JsonUtils.parseObject 直接解析整个 config 为 Map,然后提取 buttonEvent + // 避免 先转JSON字符串再解析回对象 的双重转换 + @SuppressWarnings("unchecked") + Map configMap = JsonUtils.parseObject(device.getConfig(), Map.class); + if (configMap == null || !configMap.containsKey("buttonEvent")) { + log.debug("[ButtonEvent] 设备配置中无 buttonEvent:deviceId={}", deviceId); + return null; + } + + // 将 buttonEvent 对象转为 JSON 字符串再解析为目标类型 + // TODO: 后续可优化为直接转换,避免序列化/反序列化开销 + Object buttonEventObj = configMap.get("buttonEvent"); + return JsonUtils.parseObject(JsonUtils.toJsonString(buttonEventObj), ButtonEventConfig.class); + } catch (Exception e) { + log.error("[ButtonEvent] 获取按键配置失败:deviceId={}", deviceId, e); + return null; + } } /** @@ -259,6 +280,27 @@ public class ButtonEventRuleProcessor { return null; } + /** + * 获取设备 Key(从 IoT 设备缓存获取 serialNumber) + *

+ * deviceKey 在 ops_area_device_relation 表中是冗余字段, + * 实际来源是 iot_device.serialNumber + * + * @param deviceId 设备ID + * @return deviceKey(serialNumber),获取��败返回 null + */ + private String getDeviceKey(Long deviceId) { + try { + IotDeviceDO device = deviceService.getDeviceFromCache(deviceId); + if (device != null) { + return device.getSerialNumber(); + } + } catch (Exception e) { + log.warn("[ButtonEvent] 获取 deviceKey 失败:deviceId={}", deviceId, e); + } + return null; + } + @Resource private StringRedisTemplate stringRedisTemplate; } diff --git a/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/SignalLossRuleProcessor.java b/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/SignalLossRuleProcessor.java index b7fd3d9..e5685d0 100644 --- a/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/SignalLossRuleProcessor.java +++ b/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/SignalLossRuleProcessor.java @@ -9,6 +9,8 @@ import com.viewsh.module.iot.dal.redis.clean.BeaconArrivedTimeRedisDAO; import com.viewsh.module.iot.dal.redis.clean.BeaconRssiWindowRedisDAO; import com.viewsh.module.iot.dal.redis.clean.SignalLossRedisDAO; import com.viewsh.module.iot.service.integration.clean.CleanOrderIntegrationConfigService; +import com.viewsh.module.iot.service.device.IotDeviceService; +import com.viewsh.module.iot.dal.dataobject.device.IotDeviceDO; import com.xxl.job.core.handler.annotation.XxlJob; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -49,6 +51,9 @@ public class SignalLossRuleProcessor { @Resource private CleanOrderIntegrationConfigService configService; + @Resource + private IotDeviceService deviceService; + @Resource private RocketMQTemplate rocketMQTemplate; @@ -143,13 +148,10 @@ public class SignalLossRuleProcessor { BeaconPresenceConfig.ExitConfig exitConfig = beaconConfigWrapper.getConfig().getBeaconPresence().getExit(); - // 2. 获取工牌设备信息(用于获取 deviceKey) - CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper badgeConfigWrapper = configService - .getConfigWrapperByDeviceId(deviceId); + // 2. 获取 deviceKey(从 IoT 设备缓存获取 serialNumber) + String badgeDeviceKey = getDeviceKey(deviceId); - String badgeDeviceKey = (badgeConfigWrapper != null) ? badgeConfigWrapper.getDeviceKey() : null; - - // 2. 获取首次丢失时间 + // 3. 获取首次丢失时间 Long firstLossTime = signalLossRedisDAO.getFirstLossTime(deviceId, areaId); if (firstLossTime == null) { @@ -344,4 +346,25 @@ public class SignalLossRuleProcessor { BadgeDeviceStatusRedisDAO.OrderInfo currentOrder = badgeDeviceStatusRedisDAO.getCurrentOrder(deviceId); return currentOrder != null && !currentOrder.getAreaId().equals(areaId); } + + /** + * 获取设备 Key(从 IoT 设备缓存获取 serialNumber) + *

+ * deviceKey 在 ops_area_device_relation 表中是冗余字段, + * 实际来源是 iot_device.serialNumber + * + * @param deviceId 设备ID + * @return deviceKey(serialNumber),获取失败返回 null + */ + private String getDeviceKey(Long deviceId) { + try { + IotDeviceDO device = deviceService.getDeviceFromCache(deviceId); + if (device != null) { + return device.getSerialNumber(); + } + } catch (Exception e) { + log.warn("[SignalLoss] 获取 deviceKey 失败:deviceId={}", deviceId, e); + } + return null; + } } diff --git a/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/TrafficThresholdRuleProcessor.java b/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/TrafficThresholdRuleProcessor.java index 063343b..eefdfe7 100644 --- a/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/TrafficThresholdRuleProcessor.java +++ b/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/TrafficThresholdRuleProcessor.java @@ -56,7 +56,7 @@ public class TrafficThresholdRuleProcessor { log.debug("[TrafficThreshold] 收到客流属性:deviceId={}, value={}", deviceId, propertyValue); - // 2. 获取配置 + // 2. 获取设备关联信息(包含 areaId) CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper configWrapper = getConfigWrapper(deviceId); @@ -153,6 +153,8 @@ public class TrafficThresholdRuleProcessor { /** * 获取配置包装器 + *

+ * 通过 deviceId 直接获取配置(适用于一对一关系的设备,如 TRAFFIC_COUNTER) */ private CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper getConfigWrapper(Long deviceId) { return configService.getConfigWrapperByDeviceId(deviceId);