瀏覽代碼

Merge branch 'dev' into 'main'

Merge dev into main

See merge request hfln/hfln-device-service!1
唐家韩 2 月之前
父節點
當前提交
283cbb1ac0
共有 37 個文件被更改,包括 3353 次插入1172 次删除
  1. 2 2
      device-service-application/src/main/java/com/hfln/device/application/service/DeviceSchedulerService.java
  2. 5 0
      device-service-application/src/main/java/com/hfln/device/application/service/impl/DeviceCommandServiceImpl.java
  3. 6 0
      device-service-application/src/main/java/com/hfln/device/application/service/impl/DeviceEventServiceExtendImpl.java
  4. 70 23
      device-service-application/src/main/java/com/hfln/device/application/service/impl/DeviceEventServiceImpl.java
  5. 1 1
      device-service-application/src/main/java/com/hfln/device/application/service/impl/PoseAnalysisServiceImpl.java
  6. 4 4
      device-service-application/src/main/java/com/hfln/device/application/task/DeviceStatusCheckTask.java
  7. 5 0
      device-service-common/pom.xml
  8. 7 1
      device-service-common/src/main/java/com/hfln/device/common/constant/mqtt/topic/MqttTopics.java
  9. 6 5
      device-service-common/src/main/java/com/hfln/device/common/constant/redis/RedisCacheConstant.java
  10. 4 4
      device-service-domain/pom.xml
  11. 0 118
      device-service-domain/src/main/java/com/hfln/device/domain/customer/util/MsgClient.java
  12. 28 18
      device-service-domain/src/main/java/com/hfln/device/domain/entity/Device.java
  13. 1611 0
      device-service-domain/src/main/java/com/hfln/device/domain/entity/DeviceCache.java
  14. 3 0
      device-service-domain/src/main/java/com/hfln/device/domain/gateway/DeviceGateway.java
  15. 0 15
      device-service-domain/src/main/java/com/hfln/device/domain/gateway/sms/SmsGateway.java
  16. 2 1
      device-service-domain/src/main/java/com/hfln/device/domain/port/DeviceEventPort.java
  17. 14 0
      device-service-domain/src/main/java/com/hfln/device/domain/service/DeviceManagerService.java
  18. 181 181
      device-service-domain/src/main/java/com/hfln/device/domain/service/impl/DeviceManagerServiceImpl.java
  19. 584 0
      device-service-domain/src/main/java/com/hfln/device/domain/service/impl/DeviceRedisManagerServiceImpl.java
  20. 6 0
      device-service-infrastructure/pom.xml
  21. 44 0
      device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/config/FastJson2JsonRedisSerializer.java
  22. 20 13
      device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/config/MqttConfig.java
  23. 32 0
      device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/config/RedisConfig.java
  24. 35 0
      device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/config/TopicDealExecutor.java
  25. 6 4
      device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/gateway/MqttGatewayImpl.java
  26. 44 1
      device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/gateway/impl/DeviceGatewayImpl.java
  27. 469 469
      device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/gateway/impl/DeviceGatewaySimpleImpl.java
  28. 0 161
      device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/gateway/impl/UserGatewayImpl.java
  29. 0 29
      device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/gateway/impl/sms/SmsGatewayImpl.java
  30. 1 1
      device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/mqtt/handler/AppMessageHandler.java
  31. 94 58
      device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/mqtt/handler/DeviceMessageHandler.java
  32. 30 0
      device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/mqtt/handler/ExecutorTest.java
  33. 26 24
      device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/mqtt/handler/MpsMessageHandler.java
  34. 7 22
      device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/po/DevInfo.java
  35. 0 16
      device-service-server/src/main/resources/bootstrap-local.yml
  36. 1 1
      device-service-server/src/main/resources/bootstrap.yml
  37. 5 0
      pom.xml

+ 2 - 2
device-service-application/src/main/java/com/hfln/device/application/service/DeviceSchedulerService.java

@@ -31,7 +31,7 @@ public class DeviceSchedulerService {
      * 定时检查设备保活状态
      * 每30秒执行一次
      */
-//    @Scheduled(fixedRate = 30000)
+    @Scheduled(fixedRate = 30000)
     public void checkDeviceKeepAlive() {
         try {
             log.debug("开始执行设备保活状态检查任务");
@@ -47,7 +47,7 @@ public class DeviceSchedulerService {
      * 定时检查设备告警确认状态
      * 每分钟执行一次
      */
-//    @Scheduled(fixedRate = 60000)
+    @Scheduled(fixedRate = 10000)
     public void checkDeviceAlarmAck() {
         try {
             log.debug("开始执行设备告警确认状态检查任务");

+ 5 - 0
device-service-application/src/main/java/com/hfln/device/application/service/impl/DeviceCommandServiceImpl.java

@@ -668,6 +668,11 @@ public class DeviceCommandServiceImpl implements DeviceCommandService {
             // 6. 更新确认时间(对应Python版本:now = get_utc_time_ms(); device.set_last_alarm_ack_time(now))
             long now = System.currentTimeMillis();
             device.setLastAlarmAckTime(now);
+
+            Map<String, Object> updateMap = new HashMap<>();
+            updateMap.put("alarmAck", Boolean.TRUE.toString());
+            updateMap.put("lastAlarmAckTime", now);
+            deviceManagerService.updateDeviceMapInCache(deviceId, updateMap);
             
         } catch (Exception e) {
             // 对应Python版本的异常处理逻辑

+ 6 - 0
device-service-application/src/main/java/com/hfln/device/application/service/impl/DeviceEventServiceExtendImpl.java

@@ -96,6 +96,12 @@ public class DeviceEventServiceExtendImpl implements DeviceEventServiceExtend, D
     // ========== DeviceEventPort接口方法空实现 ==========
     @Override
     public void handleDeviceLogin(String deviceId, Map<String, Object> deviceInfo, Map<String, Object> fullPayload) {}
+
+    @Override
+    public void handleDeviceDisconnect(String deviceId, Map<String, Object> fullPayload) {
+
+    }
+
     @Override
     public void handleDeviceKeepAlive(String deviceId) {}
     @Override

+ 70 - 23
device-service-application/src/main/java/com/hfln/device/application/service/impl/DeviceEventServiceImpl.java

@@ -1,7 +1,9 @@
 package com.hfln.device.application.service.impl;
 
+import com.alibaba.fastjson2.JSON;
 import com.hfln.device.application.service.DeviceEventService;
 import com.hfln.device.application.service.DebugConfigService;
+import com.hfln.device.common.constant.redis.RedisCacheConstant;
 import com.hfln.device.domain.entity.Device;
 import com.hfln.device.domain.gateway.DeviceGateway;
 import com.hfln.device.domain.gateway.MqttGateway;
@@ -19,14 +21,10 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
 
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
+import javax.annotation.Resource;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -44,7 +42,7 @@ public class DeviceEventServiceImpl implements DeviceEventService {
     @Autowired
     private MqttGateway mqttGateway;
 
-    @Autowired
+    @Resource(name = "deviceRedisManagerService")
     private DeviceManagerService deviceManagerService;
 
     @Autowired
@@ -238,6 +236,8 @@ public class DeviceEventServiceImpl implements DeviceEventService {
                 Device device = deviceOpt.get();
                 
                 if (device.getOnline() == 1) {
+
+                    deviceManagerService.updateDeviceKeepAliveInCache(deviceId, System.currentTimeMillis());
                     // 重复上线 (对应Python: 重复上线)
                     mqttGateway.sendDeviceLoginResponseMessage(deviceId, DeviceConstants.DeviceErrorCode.SUCCEED.getCode());
                     log.info("设备重复登录: deviceId={}", deviceId);
@@ -248,8 +248,11 @@ public class DeviceEventServiceImpl implements DeviceEventService {
                     device.setKeepaliveTime(System.currentTimeMillis());
                     
                     // 更新设备缓存
-                    deviceManagerService.updateDeviceInCache(device);
-                    
+//                    deviceManagerService.updateDeviceInCache(device);
+                    deviceManagerService.updateDeviceAliveStatusInCache(device.getDevId());
+
+                    // 更新数据库在线状态 (对应Python版本的数据库更新)
+                    deviceGateway.updateDeviceOnlineStatus(deviceId, 1);
                     log.info("设备重新上线: deviceId={}", deviceId);
                     
                     // 发送登录响应 (对应Python: mqtt_send.resp_dev_login(dev_id, DEV_EC.succeed))
@@ -311,7 +314,25 @@ public class DeviceEventServiceImpl implements DeviceEventService {
             log.error("处理设备登录异常: deviceId={}, error={}", deviceId, e.getMessage(), e);
         }
     }
-    
+
+    @Override
+    public void handleDeviceDisconnect(String deviceId, Map<String, Object> fullPayload) {
+
+        log.info("处理设备下线事件: deviceId={}", deviceId);
+
+        boolean exist = deviceManagerService.existInCache(deviceId);
+        if (!exist) {
+            log.info("check device exist , no devices in cache");
+            return;
+        }
+
+        Map<String, Object> map = new HashMap<>();
+        map.put("online", 0);
+        deviceManagerService.updateDeviceMapInCache(deviceId, map);
+
+        deviceGateway.updateDeviceOfflineStatus(deviceId);
+    }
+
     /**
      * 处理设备心跳保活事件
      * 对应Python版本的deal_dev_keepalive方法
@@ -357,10 +378,10 @@ public class DeviceEventServiceImpl implements DeviceEventService {
                     
                     // 4. 更新保活时间戳(参考Python版本的device.set_keepalive())
                     long currentTime = System.currentTimeMillis();
-                    device.updateKeepAliveTime(currentTime);
+//                    device.updateKeepAliveTime(currentTime);
                     
                     // 更新设备缓存
-                    deviceManagerService.updateDeviceInCache(device);
+                    deviceManagerService.updateDeviceKeepAliveInCache(deviceId, currentTime);
                     
                     log.debug("设备保活成功: deviceId={}, keepaliveTime={}", deviceId, currentTime);
                 } else {
@@ -952,21 +973,30 @@ public class DeviceEventServiceImpl implements DeviceEventService {
                 List<List<Float>> rawPoints = Collections.emptyList();  // raw_points = []
                 List<List<Float>> targets = trackerTargetsFloat;         // targets = tracker_targets
                 List<List<Float>> stableTargets = device.updateTargets(targets);  // stable_targets:list = device.update_targets(targets)
+                // todo 对接算法服务 获取pose 接口
                 List<Integer> pose = device.getRealtimePose();           // pose = device.realtime_pose()
                 
                 // === 发送实时位置姿态消息 (对应Python: mqtt_send.realtime_pos_msg(dev_id, raw_points, pose, targets)) ===
                 mqttGateway.sendRealtimePosMessage(deviceId, rawPoints, pose, targets);
                 
                 // === 更新停留时长 (对应Python的时间更新逻辑) ===
-                long ts = System.currentTimeMillis();  // ts = get_utc_time_ms()
-                if (device.getEnterTime() < 0) {       // if device.enter_ts() < 0:
-                    device.setEnterTime(ts);            // device.set_enter_ts(ts)
-                    log.info("{} target enter, {}", deviceId, ts);  // LOGINFO(f"{dev_id} target enter, {ts}")
+                // todo 停留时长 不在当前项目更新
+                Map<String, Object> updateMap = new HashMap<>();
+//                long ts = System.currentTimeMillis();  // ts = get_utc_time_ms()
+//                if (device.getEnterTime() < 0) {       // if device.enter_ts() < 0:
+//                    device.setEnterTime(ts);            // device.set_enter_ts(ts)
+//                    log.info("{} target enter, {}", deviceId, ts);  // LOGINFO(f"{dev_id} target enter, {ts}")
+//                }
+//                device.setLeaveTime(ts);                // device.set_leave_ts(ts)
+//                updateMap.put("leave")
+                if (!CollectionUtils.isEmpty(targets)) {
+                    updateMap.put("lastTargetStr", JSON.toJSONString(targets));
+                    updateMap.put("lastTargetTime", System.currentTimeMillis());
                 }
-                device.setLeaveTime(ts);                // device.set_leave_ts(ts)
-                
+
+                deviceManagerService.updateDeviceMapInCache(deviceId, updateMap);
                 // === 更新报警目标信息 (对应Python: device.update_alarm_targets(targets)) ===
-                device.updateAlarmTargets(trackerTargetsFloat);
+//                device.updateAlarmTargets(trackerTargetsFloat);
                 
                 log.debug("处理tracker_targets完成: deviceId={}, targetCount={}", deviceId, trackerTargetsFloat.size());
             }
@@ -1035,6 +1065,9 @@ public class DeviceEventServiceImpl implements DeviceEventService {
                 mqttGateway.sendEventMessage(deviceId, Collections.emptyList(), pose, targets, event);
                 
                 device.setLastFallTime(event, now);      // device.set_last_fall_time(event, now)
+                Map<String, Object> updateMap = new HashMap<>();
+                updateMap.put(event, now);
+                deviceManagerService.updateDeviceMapInCache(deviceId, updateMap);
                 String text = String.format("设备上报跌倒事件:躺, dev_id:%s, event:%s", deviceId, event);
                 log.debug(text);  // LOGDBG(text)
                 
@@ -1056,6 +1089,9 @@ public class DeviceEventServiceImpl implements DeviceEventService {
                 mqttGateway.sendEventMessage(deviceId, Collections.emptyList(), realtimePose.get(0).intValue(), targets, event);
                 
                 device.setLastReportFallTime(now);      // device.set_last_report_fall_time(now)
+                Map<String, Object> updateMap = new HashMap<>();
+                updateMap.put("lastReportFallTime", now);
+                deviceManagerService.updateDeviceMapInCache(deviceId, updateMap);
                 String text = String.format("设备上报跌倒事件:躺, dev_id:%s, event:%s", deviceId, event);
                 log.debug(text);  // LOGDBG(text)
             }
@@ -1220,6 +1256,10 @@ public class DeviceEventServiceImpl implements DeviceEventService {
                 String text = String.format("设备上报跌倒事件:躺, dev_id:%s, event:%s", deviceId, event);
                 log.debug(text); // LOGDBG(text)
             }
+
+            Map<String, Object> updateMap = new HashMap<>();
+            updateMap.put("lastReportFallTime", device.getLastFallTime());
+            deviceManagerService.updateDeviceMapInCache(deviceId, updateMap);
             
             log.info("跌倒事件处理完成: deviceId={}, event={}, type={}", deviceId, event, type);
             
@@ -1246,8 +1286,12 @@ public class DeviceEventServiceImpl implements DeviceEventService {
             //     mqtt_send.exist_msg(dev_id=dev_id, event=event)
             
             // 验证设备是否已注册(对应Python版本的设备检查)
-            Optional<Device> deviceOpt = deviceManagerService.getDeviceFromCache(deviceId);
-            if (!deviceOpt.isPresent()) {
+//            Optional<Device> deviceOpt = deviceManagerService.getDeviceFromCache(deviceId);
+//            if (!deviceOpt.isPresent()) {
+//                log.warn("设备未注册,忽略存在事件: deviceId={}", deviceId);
+//                return;
+//            }
+            if (!deviceManagerService.existInCache(deviceId)) {
                 log.warn("设备未注册,忽略存在事件: deviceId={}", deviceId);
                 return;
             }
@@ -1546,7 +1590,8 @@ public class DeviceEventServiceImpl implements DeviceEventService {
             if (software != null && !software.trim().isEmpty()) {
                 device.setSoftware(software);            // device.set_software(software)
             }
-            
+
+            deviceManagerService.updateDeviceInCache(device);
             // === 发送设备信息更新通知 (对应Python: mqtt_send.update_dev_info_msg(device)) ===
             mqttGateway.sendDeviceInfoUpdateNotification(device);
             
@@ -1607,6 +1652,8 @@ public class DeviceEventServiceImpl implements DeviceEventService {
                 if (device.getOnline() != 1) {
                     // 若设备离线,使其重新上线 (对应Python: 若设备离线,使其重新上线)
                     device.setOnline(1);
+                    device.setKeepaliveTime(System.currentTimeMillis());
+                    deviceManagerService.updateDeviceAliveStatusInCache(deviceId);
                     
                     // 发送登录响应 (对应Python: mqtt_send.resp_dev_login(dev_id, device.online()))
                     mqttGateway.sendDeviceLoginResponseMessage(deviceId, device.getOnline());

+ 1 - 1
device-service-application/src/main/java/com/hfln/device/application/service/impl/PoseAnalysisServiceImpl.java

@@ -20,7 +20,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
  * 姿态分析服务实现
  * 对应Python版本的post_process.py线程功能
  */
-@Service
+//@Service
 @Slf4j
 public class PoseAnalysisServiceImpl implements PoseAnalysisService {
 

+ 4 - 4
device-service-application/src/main/java/com/hfln/device/application/task/DeviceStatusCheckTask.java

@@ -37,7 +37,7 @@ public class DeviceStatusCheckTask {
      * 检查设备心跳超时 (参考Python版本的check_dev_keepalive函数)
      * 每5秒执行一次 - 平衡性能和及时性
      */
-    @Scheduled(fixedRate = 5000) // 5秒检查一次
+//    @Scheduled(fixedRate = 5000) // 5秒检查一次
     public void checkDeviceKeepAlive() {
         try {
             long currentTime = System.currentTimeMillis();
@@ -72,7 +72,7 @@ public class DeviceStatusCheckTask {
      * 检查设备告警确认超时 (参考Python版本的check_dev_alarm_ack函数)
      * 每10秒执行一次 - 平衡性能和及时性
      */
-    @Scheduled(fixedRate = 10000) // 10秒检查一次
+//    @Scheduled(fixedRate = 10000) // 10秒检查一次
     public void checkDeviceAlarmAck() {
         try {
             log.debug("开始检查设备告警确认状态...");
@@ -102,7 +102,7 @@ public class DeviceStatusCheckTask {
      * 检查所有设备停留时间 (参考Python版本的check_all_dev_stay_time函数)
      * 每30秒执行一次
      */
-    @Scheduled(fixedRate = 30000) // 30秒检查一次
+//    @Scheduled(fixedRate = 30000) // 30秒检查一次
     public void checkAllDeviceStayTime() {
         try {
             log.debug("开始检查所有设备停留时间...");
@@ -167,7 +167,7 @@ public class DeviceStatusCheckTask {
      * 检查所有设备告警计划 (参考Python版本的check_all_dev_alarm_plan函数)
      * 每秒执行一次 - 与Python版本保持一致
      */
-    @Scheduled(fixedRate = 1000) // 1秒检查一次 - 对应Python版本每秒检查
+//    @Scheduled(fixedRate = 1000) // 1秒检查一次 - 对应Python版本每秒检查
     public void checkAllDeviceAlarmPlan() {
         try {
             long currentTime = System.currentTimeMillis();

+ 5 - 0
device-service-common/pom.xml

@@ -57,6 +57,11 @@
             <artifactId>junit-jupiter-engine</artifactId>
             <scope>test</scope>
         </dependency>
+
+        <dependency>
+            <groupId>cn.hfln.framework</groupId>
+            <artifactId>redis-spring-boot-starter</artifactId>
+        </dependency>
     </dependencies>
 
 

+ 7 - 1
device-service-common/src/main/java/com/hfln/device/common/constant/mqtt/topic/MqttTopics.java

@@ -17,13 +17,19 @@ public class MqttTopics {
      */
     public static final String DEV_ALL = "/dev/#";
     public static final String DEV_LOGIN = "/dev/+/login";
+    public static final String SHARE_DEV_LOGIN = "$share/device//dev/+/login";
     public static final String DEV_KEEPALIVE = "/dev/+/keepalive";
+    public static final String SHARE_DEV_KEEPALIVE = "$share/device//dev/+/keepalive";
     public static final String DEV_REP_DEV_INFO = "/dev/+/report_device_info";
     public static final String DEV_REP_DEV_PARAM = "/dev/+/report_device_param";
+    public static final String SHARE_DEV_REP_DEV_PARAM = "$share/device//dev/+/report_device_param";
     public static final String DEV_CLOUDPOINT = "/dev/+/cloudpoint";
     public static final String DEV_REP_FALL_EVENT = "/dev/+/report_falling_event";
     public static final String DEV_REP_PRES_EVENT = "/dev/+/report_presence_event";
     public static final String DEV_DSP_DATA = "/dev/+/dsp_data";
+    public static final String SHARE_DEV_DSP_DATA = "$share/device//dev/+/dsp_data";
+    public static final String DEV_DISCONNECT = "/dev/+/disconnect";
+    public static final String SHARE_DEV_DISCONNECT = "$share/device//dev/+/disconnect";
     public static final String DEV_UPDATE_FIRMWARE = "/dev/+/update_firmware";
     public static final String DEV_REBOOT = "/dev/+/reboot";
     public static final String DEV_REP_DEBUG_PARAM = "/dev/+/report_debug_param";
@@ -56,7 +62,7 @@ public class MqttTopics {
     public static final String DAS_CLOUDPOINT = "/das/cloudpoint";
     public static final String DAS_REALTIME_POS = "/das/realtime_pos";
     public static final String DAS_EVENT = "/das/event";
-    public static final String DAS_EXIST_EVENT = "/das/existence_event";
+    public static final String DAS_EXIST_EVENT = "/das/exist";
     public static final String DAS_ALARM_EVENT = "/das/alarm_event";
     public static final String DAS_BEHAVIOR_ANALYSIS = "/das/behavior_analysis";
     public static final String DAS_SET_DEV_PARAM = "/das/set_device_param";

+ 6 - 5
device-service-common/src/main/java/com/hfln/device/common/constant/redis/RedisCacheConstant.java

@@ -5,13 +5,14 @@ package com.hfln.device.common.constant.redis;
  */
 public interface RedisCacheConstant {
 
+
     /**
-     * 登录验证码
+     * redis缓存设备 key
      */
-    String SMS_LOGIN_CODE = "sms:login:";
-    String SMS_SIGNUP_CODE = "sms:signup:";
-    String SMS_SEND_LOGIN_TIME = "sms:login:frequency:";
-    String SMS_SEND_SIGNUP_TIME = "sms:signup:frequency:";
+    String KEY_DEVICE_pre = "hfln:device:";
+    String KEY_DEVICE_ID = "hfln:device:id";
+    String KEY_DEVICE_DEBUG_PARAM_PRE = "hfln:device:debugParam-";
+
 
 
 

+ 4 - 4
device-service-domain/pom.xml

@@ -17,10 +17,10 @@
             <groupId>com.hfln.device</groupId>
             <artifactId>device-service-client-starter</artifactId>
         </dependency>
-        <dependency>
-            <groupId>cn.hfln.framework</groupId>
-            <artifactId>hfln-framework-common</artifactId>
-        </dependency>
+<!--        <dependency>-->
+<!--            <groupId>cn.hfln.framework</groupId>-->
+<!--            <artifactId>hfln-framework-common</artifactId>-->
+<!--        </dependency>-->
 
         <dependency>
             <groupId>com.alibaba.fastjson2</groupId>

+ 0 - 118
device-service-domain/src/main/java/com/hfln/device/domain/customer/util/MsgClient.java

@@ -1,118 +0,0 @@
-package com.hfln.device.domain.customer.util;
-
-import cn.hfln.framework.extension.BizException;
-import com.tencentcloudapi.common.AbstractModel;
-import com.tencentcloudapi.common.Credential;
-import com.tencentcloudapi.common.profile.ClientProfile;
-import com.tencentcloudapi.sms.v20210111.SmsClient;
-import com.tencentcloudapi.sms.v20210111.models.*;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-import org.springframework.web.client.RestTemplate;
-
-import javax.validation.constraints.NotBlank;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-
-@Slf4j
-@Component
-public class MsgClient {
-
-	@Autowired
-	private RestTemplate restTemplate;
-
-	@NotBlank
-	@Value("${lnxx.sms.tencent.secretId}")
-	private String secretId;
-
-	@NotBlank
-	@Value("${lnxx.sms.tencent.secretKey}")
-	private String secretKey;
-
-	@NotBlank
-	@Value("${lnxx.sms.tencent.loginId}")
-	private String loginId;
-
-	@NotBlank
-	@Value("${lnxx.sms.tencent.registerId}")
-	private String registerId;
-
-	@NotBlank
-	@Value("${lnxx.sms.tencent.notifyId}")
-	private String notifyId;
-
-	@NotBlank
-	@Value("${lnxx.sms.tencent.sdkAppId}")
-	private String sdkAppId;
-
-	@NotBlank
-	@Value("${lnxx.sms.tencent.region}")
-	private String region;
-
-	public String sendMsg(String mobile, String content, String signName) {
-		if (isValidMobile(mobile)) {
-			return "手机号格式不正确";
-		}
-		if (StringUtils.isEmpty(signName)) {
-			signName = "安徽柒零玖";
-		}
-		try {
-			String encodedContent = URLEncoder.encode(content + "【" + signName + "】", "GB2312");
-			String url = String.format(
-					"https://mb345.com/ws/BatchSend2.aspx?CorpID=HFLKJ0006642&Pwd=zh9527@&Mobile=%s&Content=%s&Cell=&SendTime=",
-					mobile, encodedContent);
-
-			log.info("发送短信内容: {}", content);
-			return restTemplate.getForObject(url, String.class);
-
-		} catch (UnsupportedEncodingException e) {
-			log.error("短信内容编码失败", e);
-		} catch (Exception e) {
-			log.error("调用短信接口异常", e);
-		}
-		return "发送失败";
-	}
-
-	public String sendLoginMsg(String mobile, String captcha) {
-		return sendTencentMsg(mobile, loginId, new String[]{captcha, "5"});
-	}
-
-	public String sendRegisterMsg(String mobile, String captcha) {
-		return sendTencentMsg(mobile, registerId, new String[]{captcha});
-	}
-
-	public String sendNotifyMsg(String mobile, String devName) {
-		String nowTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
-		String[] timeParts = nowTime.split("[- :]");
-		return sendTencentMsg(mobile, notifyId, new String[]{devName, timeParts[0], timeParts[1], timeParts[2], timeParts[3], timeParts[4], timeParts[5]});
-	}
-
-	private String sendTencentMsg(String mobile, String templateId, String[] templateParams) {
-		if (isValidMobile(mobile)) {
-			throw new BizException("手机号码格式有误");
-		}
-		try {
-			SmsClient client = new SmsClient(new Credential(secretId, secretKey), region, new ClientProfile());
-			SendSmsRequest req = new SendSmsRequest();
-			req.setPhoneNumberSet(new String[]{mobile});
-			req.setSignName("雷能守护小程序");
-			req.setTemplateId(templateId);
-			req.setTemplateParamSet(templateParams);
-			req.setSmsSdkAppId(sdkAppId);
-			SendSmsResponse resp = client.SendSms(req);
-			return AbstractModel.toJsonString(resp);
-		} catch (Exception e) {
-			log.error("发送腾讯云短信失败", e);
-		}
-		return null;
-	}
-
-	private boolean isValidMobile(String mobile) {
-		return mobile == null || !mobile.matches("^1[3-9]\\d{9}$");
-	}
-}

+ 28 - 18
device-service-domain/src/main/java/com/hfln/device/domain/entity/Device.java

@@ -522,8 +522,9 @@ public class Device {
         try {
             lock.lock();
             // 模拟Python版本的bug:设置局部变量而不是实例变量
-            @SuppressWarnings("unused")
-            boolean alarmAck = ack;  // 对应Python: alarm_ack_ = ack (缺少self.)
+//            @SuppressWarnings("unused")
+//            boolean alarmAck = ack;  // 对应Python: alarm_ack_ = ack (缺少self.)
+            alarmAck = ack;  // 对应Python: alarm_ack_ = ack (缺少self.)
             // 注意:这里故意不写 this.alarmAck = ack; 来模拟Python的bug
         } finally {
             lock.unlock();
@@ -534,14 +535,14 @@ public class Device {
      * 获取告警确认状态 (对应Python版本的get_alarm_ack方法)
      * @return 告警确认状态
      */
-    public boolean getAlarmAck() {
-        try {
-            lock.lock();
-            return Boolean.TRUE.equals(alarmAck);
-        } finally {
-            lock.unlock();
-        }
-    }
+//    public boolean getAlarmAck() {
+//        try {
+//            lock.lock();
+//            return Boolean.TRUE.equals(alarmAck);
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
     
     /**
      * 设置最后告警确认时间 (对应Python版本的set_last_alarm_ack_time方法)
@@ -560,14 +561,14 @@ public class Device {
      * 获取最后告警确认时间 (对应Python版本的get_last_alarm_ack_time方法)
      * @return 最后告警确认时间
      */
-    public long getLastAlarmAckTime() {
-        try {
-            lock.lock();
-            return lastAlarmAckTime != null ? lastAlarmAckTime : 0L;
-        } finally {
-            lock.unlock();
-        }
-    }
+//    public long getLastAlarmAckTime() {
+//        try {
+//            lock.lock();
+//            return lastAlarmAckTime != null ? lastAlarmAckTime : 0L;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
     
     /**
      * 设置最后上报跌倒时间 (对应Python版本的set_last_report_fall_time方法)
@@ -1479,6 +1480,15 @@ public class Device {
             lock.unlock();
         }
     }
+
+    public void setLastFallTime(Map<String, Long> map) {
+        try {
+            lock.lock();
+            lastFallTimeByEvent.putAll(map);
+        } finally {
+            lock.unlock();
+        }
+    }
     
     /**
      * 获取当前跌倒状态 (对应Python版本的device.falling_)

+ 1611 - 0
device-service-domain/src/main/java/com/hfln/device/domain/entity/DeviceCache.java

@@ -0,0 +1,1611 @@
+//package com.hfln.device.domain.entity;
+//
+//import com.hfln.device.domain.vo.BehaviorPattern;
+//import lombok.*;
+//import org.springframework.util.CollectionUtils;
+//
+//import java.util.*;
+//
+///**
+// * 设备实体类 - 聚合根(Aggregate Root)
+// *
+// * 作为聚合根,Device 封装了设备相关的业务属性、行为和不变性,
+// * 其生命周期内可包含多个子实体(如 Region)和值对象(如 InstallParam、TrackingRegion、NetworkInfo)。
+// */
+//@Getter
+//@Setter
+//@Builder
+//@NoArgsConstructor
+//@AllArgsConstructor
+//public class DeviceCache {
+//
+//    /**
+//     * 设备ID
+//     */
+//    private String devId;                // 设备ID
+//    private String devType;              // 设备类型
+//    private String software;             // 软件版本
+//    private String hardware;             // 硬件版本
+//    private String bluVer;               // 蓝牙版本
+//
+////    private NetworkInfo network;         // 网络信息
+//    private String ssid;             // WIFI SSID
+//    private String password;         // WIFI 密码
+//    private String ip;               // IP地址
+////    private InstallParam installParam;   // 安装参数
+//private String mountPlain;       // 安装面
+//    private Integer isCeiling;       // 是否天花板安装
+//    private Float height;            // 安装高度
+////    private TrackingRegion trackingRegion; // 跟踪区域
+//    private Integer startX;          // 起始X
+//    private Integer startY;          // 起始Y
+//    private Integer startZ;          // 起始Z
+//    private Integer stopX;           // 终止X
+//    private Integer stopY;           // 终止Y
+//    private Integer stopZ;           // 终止Z
+//
+//    private List<Float> targets;         // 实时目标位置
+//    //    private List<Integer> realtimePose;  // 实时姿态
+//    //
+////    private Long enterTs;                // 进入时间戳
+////    private Long leaveTs;                // 离开时间戳
+////    private Long stayTime;               // 停留时间
+//
+////    private Long retentionTime;          // 滞留时间
+////    private Long retentionKeepTime;      // 滞留保持时间
+////    private Long retentionAlarmTime;     // 滞留告警时间
+//private Integer online;              // 在线状态:0-离线,1-在线
+//
+//    private Long keepaliveTime;          // 最后一次心跳时间
+//    private Long expireTime;             // 超时时间(毫秒),默认90秒
+//        private Boolean alarmAck;            // 告警确认
+//        private Long lastAlarmAckTime;       // 最后告警确认时间
+//    //
+//    private Long lastReportFallTime;     // 最后上报跌倒时间
+////
+////    private String lastAlarmType;        // 最后一次告警类型
+////    private Long lastAlarmTime;          // 最后一次告警时间
+//
+//    // 跌倒状态记录 (对应Python版本的device.falling_)
+//    private Integer falling_;            // 当前跌倒状态:0-无跌倒,1-检测到跌倒,2-跌倒确认,3-跌倒呼救
+//
+//    // 告警间隔相关属性 (参考Python版本)
+//    private Long alarmInterval;          // 告警间隔时间(毫秒),默认30秒
+//    private Long alarmAckInterval;       // 告警确认间隔时间(毫秒),默认5分钟
+//
+//    // 调试参数 (参考Python版本的g_dev_dbg_map)
+//    private Map<String, Object> debugParams = new HashMap<>();
+//
+////    // 姿态分析相关属性
+////    private PoseAnalysisResult lastPoseResult;  // 最近一次姿态分析结果
+////    private Long lastPoseChangeTime;            // 最近一次姿态变化时间
+////    private Map<Integer, Long> poseDurations;   // 各姿态持续时间(姿态ID -> 持续时间毫秒)
+////    private Map<Integer, Float> poseDistribution; // 姿态分布(姿态ID -> 占比百分比)
+//
+////    // 行为分析相关属性
+////    private Long lastActivityDetectTime;        // 最近一次活动检测时间
+////    private Long lastRestTime;                  // 最近一次休息时间
+////    private Long lastFallTime;                  // 最近一次跌倒时间
+////    private Integer currentActivityLevel;       // 当前活动级别
+////    private Map<String, Long> areaRetentionTimes; // 各区域滞留时间(区域名称 -> 开始滞留时间毫秒)
+//
+////    // 历史行为模式记录
+////    private final List<BehaviorPattern> behaviorHistory = new ArrayList<>();
+////
+////    // 告警历史记录
+////    private final List<Alarm> alarmHistory = new ArrayList<>();
+////
+////    // 设备最近的活动记录
+////    private final Map<String, Long> lastActivityTime = new HashMap<>();
+//
+//    // 每个事件类型的最后跌倒时间 (对应Python版本的last_fall_time_)
+//    private final Map<String, Long> lastFallTimeByEvent = new HashMap<>();
+//
+////    // 告警计划管理
+////    private Map<String, AlarmPlan> alarmPlanMap = new HashMap<>();
+////
+////    // 区域管理
+////    private List<Region> regions = new ArrayList<>();
+//
+//    // 完整的设备参数信息 (对应Python版本的param_)
+//    private Map<String, Object> param = new HashMap<>();
+//
+////    // 点云数据队列 (对应Python版本的put_cloud_points_que方法)
+////    private final Queue<List<List<Float>>> cloudPointsQueue = new LinkedList<>();
+////    private static final int MAX_CLOUD_POINTS_QUEUE_SIZE = 10; // 最大队列大小
+////
+////    private final ReentrantLock lock = new ReentrantLock();
+//
+////    /**
+////     * 告警计划
+////     */
+////    private Map<String, Object> alarmSchedule;
+//
+//    /**
+//     * 目标稳定器 - 对应Python版本的TargetStabilizer类
+//     * 动态阈值调整的目标稳定算法
+//     */
+////    private static class TargetStabilizer {
+////        private final java.util.Deque<List<Float>> targetList;
+////        private final float baseThreshold;
+////
+////        public TargetStabilizer(int queueLength, float baseThreshold) {
+////            this.targetList = new java.util.ArrayDeque<>(queueLength);
+////            this.baseThreshold = baseThreshold;
+////        }
+////
+////        /**
+////         * 优化目标点 (对应Python版本的optimize_target方法)
+////         * @param newTarget 新接收到的目标点 [x, y, z, snr]
+////         * @return 优化后的目标点
+////         */
+////        public List<Float> optimizeTarget(List<Float> newTarget) {
+////            if (targetList.isEmpty()) {
+////                return new ArrayList<>(newTarget);
+////            }
+////
+////            // 计算队列中点的平均值 (对应Python版本的avg_x, avg_y, avg_z计算)
+////            float avgX = 0.0f, avgY = 0.0f, avgZ = 0.0f;
+////            for (List<Float> target : targetList) {
+////                avgX += target.get(0);
+////                avgY += target.get(1);
+////                avgZ += target.get(2);
+////            }
+////            avgX /= targetList.size();
+////            avgY /= targetList.size();
+////            avgZ /= targetList.size();
+////
+////            // 动态阈值调整 (对应Python版本的dynamic_threshold计算)
+////            float dx = newTarget.get(0) - avgX;
+////            float dy = newTarget.get(1) - avgY;
+////            float distanceToAvg = (float) Math.sqrt(dx * dx + dy * dy);
+////            float dynamicThreshold = baseThreshold + (distanceToAvg * 0.3f);
+////
+////            // 如果与均值的偏差超过动态阈值,则平滑处理 (对应Python版本的平滑逻辑)
+////            if (distanceToAvg > dynamicThreshold) {
+////                float smoothedX = (newTarget.get(0) + avgX) / 2.0f;
+////                float smoothedY = (newTarget.get(1) + avgY) / 2.0f;
+////                float smoothedZ = (newTarget.get(1) + avgZ) / 2.0f;  // 保持与Python版本完全一致,包括这个bug:使用newTarget.get(1)而不是get(2)
+////
+////                List<Float> optimizedTarget = new ArrayList<>();
+////                optimizedTarget.add(smoothedX);
+////                optimizedTarget.add(smoothedY);
+////                optimizedTarget.add(smoothedZ);
+////                return optimizedTarget;
+////            } else {
+////                return new ArrayList<>(newTarget);
+////            }
+////        }
+////
+////        /**
+////         * 更新目标列表 (对应Python版本的update_target_list方法)
+////         * @param newTarget 原始目标点 [x, y, z, snr]
+////         * @return 优化后的目标点
+////         */
+////        public List<Float> updateTargetList(List<Float> newTarget) {
+////            if (newTarget.size() < 3) {
+////                // 对应Python: LOGDBG(f"update_target_list error: invlid target:{new_target}")
+////                return new ArrayList<>(newTarget);
+////            }
+////
+////            List<Float> optimizedTarget = optimizeTarget(newTarget);
+////
+////            // 如果队列已满,移除最老的目标 (对应Python的deque maxlen行为)
+////            if (targetList.size() >= 10) {  // queueLength
+////                targetList.removeFirst();
+////            }
+////            targetList.addLast(optimizedTarget);
+////
+////            return optimizedTarget;
+////        }
+////    }
+////
+////    // 目标稳定器实例 (对应Python版本device中的stabilizer)
+////    private TargetStabilizer stabilizer = new TargetStabilizer(10, 1.0f);
+//
+//    /**
+//     * 构造函数,设置默认值
+//     * @param devId 设备ID
+//     */
+//    public DeviceCache(String devId) {
+//        this.devId = devId;
+//        this.online = 0;
+//        this.expireTime = 90000L; // 默认90秒
+//        this.alarmAck = false;
+//        this.alarmInterval = 30000L; // 默认30秒告警间隔
+//        this.alarmAckInterval = 300000L; // 默认5分钟告警确认间隔
+////        this.realtimePose = new ArrayList<>();
+////        this.poseDurations = new HashMap<>();
+////        this.poseDistribution = new HashMap<>();
+////        this.areaRetentionTimes = new HashMap<>();
+////        this.alarmPlanMap = new HashMap<>();
+////        this.regions = new ArrayList<>();
+//        this.debugParams = new HashMap<>();
+//
+////        // 初始化时间戳
+////        this.enterTs = -1L;
+////        this.leaveTs = -1L;
+////        this.stayTime = -1L;
+////
+////        // 初始化滞留相关参数 (参考Python版本)
+////        this.retentionTime = 60000L;     // 默认60秒
+////        this.retentionKeepTime = 30000L; // 默认30秒
+////        this.retentionAlarmTime = 180000L; // 默认180秒(3分钟)
+//
+//        // 初始化跌倒状态 (对应Python版本)
+//        this.falling_ = 0; // 默认无跌倒状态
+//    }
+//
+//    /**
+//     * 安装参数 - 值对象(Value Object)
+//     * 不可变对象,描述设备的安装参数。
+//     */
+//    @Getter
+//    @Setter
+//    @NoArgsConstructor
+//    @AllArgsConstructor
+//    @Builder
+//    public static class InstallParam {
+//        private String mountPlain;       // 安装面
+//        private Integer isCeiling;       // 是否天花板安装
+//        private Float height;            // 安装高度
+//        private TrackingRegion trackingRegion; // 跟踪区域
+//
+//        /**
+//         * TODO: 完善安装参数类,参考dev_mng.py中的InstallParam类
+//         * 1. 添加安装面属性 (参考dev_mng.py中的mount_plain和isCeiling属性)
+//         * 2. 完善跟踪区域属性 (参考dev_mng.py中的tracking_region属性)
+//         */
+//    }
+//
+//    /**
+//     * 跟踪区域 - 值对象(Value Object)
+//     * 不可变对象,描述设备的跟踪区域。
+//     */
+//    @Getter
+//    @Setter
+//    @NoArgsConstructor
+//    @AllArgsConstructor
+//    public static class TrackingRegion {
+//        private Integer startX;          // 起始X
+//        private Integer startY;          // 起始Y
+//        private Integer startZ;          // 起始Z
+//        private Integer stopX;           // 终止X
+//        private Integer stopY;           // 终止Y
+//        private Integer stopZ;           // 终止Z
+//
+//        /**
+//         * TODO: 完善跟踪区域类,参考dev_mng.py中的TrackingRegion类
+//         * 1. 添加线程安全访问机制 (参考dev_mng.py中的lock_机制)
+//         * 2. 完善区域属性 (参考dev_mng.py中的TrackingRegion类属性)
+//         */
+//    }
+//
+//    /**
+//     * 网络信息 - 值对象(Value Object)
+//     * 不可变对象,描述设备的网络配置。
+//     */
+//    @Getter
+//    @Setter
+//    @NoArgsConstructor
+//    @AllArgsConstructor
+//    @Builder
+//    public static class NetworkInfo {
+//        private String ssid;             // WIFI SSID
+//        private String password;         // WIFI 密码
+//        private String ip;               // IP地址
+//
+//        /**
+//         * TODO: 完善网络信息类,参考dev_mng.py中的Network类
+//         * 1. 添加线程安全访问机制 (参考dev_mng.py中的lock_机制)
+//         * 2. 增加更多网络属性 (参考dev_mng.py中的Network类属性)
+//         */
+//    }
+//
+//    /**
+//     * 告警实体
+//     */
+//    @Getter
+//    @Setter
+//    @NoArgsConstructor
+//    @AllArgsConstructor
+//    @Builder
+//    public static class Alarm {
+//        private Long id;                 // 告警ID
+//        private String type;             // 告警类型
+//        private String description;      // 告警描述
+//        private Integer severity;        // 严重程度
+//        private Long timestamp;          // 时间戳
+//        private Boolean acknowledged;    // 是否已确认
+//        private Long acknowledgedTime;   // 确认时间
+//        private Long userId;             // 确认用户ID
+//
+//        /**
+//         * 确认告警
+//         * @param userId 用户ID
+//         * @param timestamp 确认时间
+//         */
+//        public void acknowledge(Long userId, Long timestamp) {
+//            this.acknowledged = true;
+//            this.acknowledgedTime = timestamp;
+//            this.userId = userId;
+//        }
+//    }
+//
+//    /**
+//     * 更新设备保活时间
+//     * @param keepaliveTime 保活时间戳
+//     */
+//    public void updateKeepAliveTime(Long keepaliveTime) {
+//        try {
+//            lock.lock();
+//            this.keepaliveTime = keepaliveTime;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 更新设备在线状态
+//     * @param online 在线状态
+//     * @return 返回旧的在线状态
+//     */
+//    public Integer updateOnlineStatus(Integer online) {
+//        try {
+//            lock.lock();
+//            Integer oldStatus = this.online;
+//            this.online = online;
+//            return oldStatus;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 更新停留时间
+//     */
+//    public void updateStayTime() {
+//        try {
+//            lock.lock();
+//            if (enterTs != null && leaveTs != null) {
+//                stayTime = leaveTs - enterTs;
+//            }
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 重置进入时间
+//     */
+//    public void resetEnterTs() {
+//        try {
+//            lock.lock();
+//            this.enterTs = null;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 重置离开时间
+//     */
+//    public void resetLeaveTs() {
+//        try {
+//            lock.lock();
+//            this.leaveTs = null;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 重置停留时间
+//     */
+//    public void resetStayTime() {
+//        try {
+//            lock.lock();
+//            this.stayTime = 0L;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 检查设备是否超时
+//     * @param currentTime 当前时间
+//     * @return 是否超时
+//     */
+//    public boolean isExpired(long currentTime) {
+//        if (online != null && online == 1 && keepaliveTime != null && expireTime != null) {
+//            return (currentTime - keepaliveTime) > expireTime;
+//        }
+//        return false;
+//    }
+//
+//    /**
+//     * 设置告警确认状态
+//     * @param ack 确认状态
+//     * @param timestamp 确认时间
+//     */
+//    public void setAlarmAcknowledgement(boolean ack, long timestamp) {
+//        try {
+//            lock.lock();
+//            this.alarmAck = ack;
+//            this.lastAlarmAckTime = timestamp;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 设置最后上报跌倒时间 (对应Python版本的set_last_report_fall_time方法)
+//     * @param timestamp 时间戳
+//     */
+//    public void setLastReportFallTime(Long timestamp) {
+//        try {
+//            lock.lock();
+//            this.lastReportFallTime = timestamp;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 获取最后上报跌倒时间 (对应Python版本的last_report_fall_time方法)
+//     * @return 最后上报跌倒时间
+//     */
+//    public Long getLastReportFallTime() {
+//        try {
+//            lock.lock();
+//            return lastReportFallTime != null ? lastReportFallTime : 0L;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 添加告警记录
+//     * @param alarm 告警对象
+//     */
+//    public void addAlarm(Alarm alarm) {
+//        try {
+//            lock.lock();
+//            alarmHistory.add(alarm);
+//            lastAlarmType = alarm.getType();
+//            lastAlarmTime = alarm.getTimestamp();
+//
+//            // 更新最近活动时间
+//            updateLastActivityTime(alarm.getType(), alarm.getTimestamp());
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 添加行为模式
+//     * @param pattern 行为模式
+//     */
+//    public void addBehaviorPattern(BehaviorPattern pattern) {
+//        try {
+//            lock.lock();
+//            behaviorHistory.add(pattern);
+//
+//            // 如果是异常行为,更新相关状态
+//            if (pattern.getBehaviorType() != null &&
+//                    pattern.getBehaviorType() == 3) { // 3表示异常行为
+//
+//                // 更新最近活动时间
+//                updateLastActivityTime(pattern.getDescription(), pattern.getTimestamp());
+//            }
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 更新最近活动时间
+//     * @param activityType 活动类型
+//     * @param timestamp 时间戳
+//     */
+//    private void updateLastActivityTime(String activityType, Long timestamp) {
+//        if (activityType != null && timestamp != null) {
+//            lastActivityTime.put(activityType, timestamp);
+//        }
+//    }
+//
+//    /**
+//     * 确认告警
+//     * @param alarmId 告警ID
+//     * @param userId 用户ID
+//     * @param timestamp 确认时间
+//     * @return 是否成功确认
+//     */
+//    public boolean acknowledgeAlarm(Long alarmId, Long userId, Long timestamp) {
+//        try {
+//            lock.lock();
+//            for (Alarm alarm : alarmHistory) {
+//                if (alarm.getId() != null && alarm.getId().equals(alarmId)) {
+//                    alarm.acknowledge(userId, timestamp);
+//                    return true;
+//                }
+//            }
+//            return false;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 获取未确认的告警
+//     * @return 未确认的告警列表
+//     */
+//    public List<Alarm> getUnacknowledgedAlarms() {
+//        try {
+//            lock.lock();
+//            List<Alarm> unacknowledgedAlarms = new ArrayList<>();
+//            for (Alarm alarm : alarmHistory) {
+//                if (alarm.getAcknowledged() == null || !alarm.getAcknowledged()) {
+//                    unacknowledgedAlarms.add(alarm);
+//                }
+//            }
+//            return unacknowledgedAlarms;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 检查是否应该发送告警
+//     * @param alarmType 告警类型
+//     * @param timestamp 当前时间戳
+//     * @param intervalThreshold 告警间隔阈值(毫秒)
+//     * @return 是否应该发送告警
+//     */
+//    public boolean shouldSendAlarm(String alarmType, Long timestamp, Long intervalThreshold) {
+//        try {
+//            lock.lock();
+//
+//            // 如果没有最近活动记录,应该发送告警
+//            if (!lastActivityTime.containsKey(alarmType)) {
+//                return true;
+//            }
+//
+//            // 获取上次该类型告警的时间
+//            Long lastTime = lastActivityTime.get(alarmType);
+//            if (lastTime == null) {
+//                return true;
+//            }
+//
+//            // 检查告警间隔是否超过阈值
+//            return (timestamp - lastTime) > intervalThreshold;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 检查设备是否存在持续滞留
+//     * @param currentTime 当前时间
+//     * @param areaName 区域名称
+//     * @param retentionThreshold 滞留阈值(毫秒)
+//     * @return 是否滞留
+//     */
+//    public boolean checkRetention(Long currentTime, String areaName, Long retentionThreshold) {
+//        if (enterTs == null || currentTime == null) {
+//            return false;
+//        }
+//
+//        long stayDuration = currentTime - enterTs;
+//
+//        // 如果滞留时间超过阈值且未发送过滞留告警,则需要发送告警
+//        if (stayDuration > retentionThreshold) {
+//            // 如果没有发送过滞留告警或者距离上次告警时间已经超过阈值
+//            if (retentionAlarmTime == null || (currentTime - retentionAlarmTime) > retentionThreshold) {
+//                return true;
+//            }
+//        }
+//
+//        return false;
+//    }
+//
+//    /**
+//     * 更新设备姿态
+//     *
+//     * @param pose 姿态
+//     * @param timestamp 时间戳
+//     */
+//    public void updatePose(Integer pose, Long timestamp) {
+//        try {
+//            lock.lock();
+//
+//            // 检查姿态是否变化
+//            boolean poseChanged = false;
+//            if (realtimePose == null) {
+//                realtimePose = new ArrayList<>();
+//            }
+//
+//            if (realtimePose.isEmpty() || !pose.equals(realtimePose.get(0))) {
+//                poseChanged = true;
+//            }
+//
+//            // 添加新姿态到列表开头
+//            realtimePose.add(0, pose);
+//
+//            // 保持列表长度不超过10
+//            if (realtimePose.size() > 10) {
+//                realtimePose.remove(realtimePose.size() - 1);
+//            }
+//
+//            // 如果姿态发生变化,更新姿态变化时间
+//            if (poseChanged) {
+//                lastPoseChangeTime = timestamp;
+//
+//                // 更新姿态持续时间
+//                updatePoseDuration(pose, timestamp);
+//            }
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 更新姿态持续时间
+//     *
+//     * @param pose 姿态
+//     * @param timestamp 当前时间戳
+//     */
+//    private void updatePoseDuration(Integer pose, Long timestamp) {
+//        if (poseDurations == null) {
+//            poseDurations = new HashMap<>();
+//        }
+//
+//        // 初始化姿态持续时间
+//        if (!poseDurations.containsKey(pose)) {
+//            poseDurations.put(pose, 0L);
+//        }
+//    }
+//
+//    /**
+//     * 更新区域滞留时间
+//     *
+//     * @param areaName 区域名称
+//     * @param timestamp 时间戳
+//     */
+//    public void updateAreaRetentionTime(String areaName, Long timestamp) {
+//        try {
+//            lock.lock();
+//
+//            if (areaRetentionTimes == null) {
+//                areaRetentionTimes = new HashMap<>();
+//            }
+//
+//            // 记录区域滞留开始时间
+//            if (!areaRetentionTimes.containsKey(areaName)) {
+//                areaRetentionTimes.put(areaName, timestamp);
+//            }
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 重置区域滞留时间
+//     *
+//     * @param areaName 区域名称
+//     */
+//    public void resetAreaRetentionTime(String areaName) {
+//        try {
+//            lock.lock();
+//
+//            if (areaRetentionTimes != null && areaRetentionTimes.containsKey(areaName)) {
+//                areaRetentionTimes.remove(areaName);
+//            }
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 获取区域滞留时间
+//     *
+//     * @param areaName 区域名称
+//     * @param currentTime 当前时间
+//     * @return 滞留时间(毫秒)
+//     */
+//    public Long getAreaRetentionDuration(String areaName, Long currentTime) {
+//        try {
+//            lock.lock();
+//
+//            if (areaRetentionTimes == null || !areaRetentionTimes.containsKey(areaName)) {
+//                return 0L;
+//            }
+//
+//            Long startTime = areaRetentionTimes.get(areaName);
+//            if (startTime == null) {
+//                return 0L;
+//            }
+//
+//            return currentTime - startTime;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 添加告警计划
+//     *
+//     * @param alarmPlan 告警计划
+//     */
+//    public void addAlarmPlan(AlarmPlan alarmPlan) {
+//        try {
+//            lock.lock();
+//
+//            if (alarmPlan != null && alarmPlan.getName() != null) {
+//                alarmPlanMap.put(alarmPlan.getName(), alarmPlan);
+//            }
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 移除告警计划
+//     *
+//     * @param planName 计划名称
+//     * @return 被移除的告警计划
+//     */
+//    public AlarmPlan removeAlarmPlan(String planName) {
+//        try {
+//            lock.lock();
+//
+//            return alarmPlanMap.remove(planName);
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 获取告警计划
+//     *
+//     * @param planName 计划名称
+//     * @return 告警计划
+//     */
+//    public AlarmPlan getAlarmPlan(String planName) {
+//        try {
+//            lock.lock();
+//
+//            return alarmPlanMap.get(planName);
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 获取所有告警计划
+//     *
+//     * @return 告警计划列表
+//     */
+//    public List<AlarmPlan> getAllAlarmPlans() {
+//        try {
+//            lock.lock();
+//
+//            return new ArrayList<>(alarmPlanMap.values());
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 更新告警计划目标
+//     *
+//     * @param targets 目标点列表
+//     */
+//    public void updateAlarmTargets(List<List<Float>> targets) {
+//        if (targets == null || targets.isEmpty()) {
+//            return;
+//        }
+//
+//        try {
+//            lock.lock();
+//
+//            long currentTime = System.currentTimeMillis();
+//
+//            // 更新所有告警计划的目标
+//            if (CollectionUtils.isEmpty(alarmPlanMap)) {
+//                return;
+//            }
+//            for (AlarmPlan plan : alarmPlanMap.values()) {
+//                plan.updateTarget(targets, currentTime);
+//            }
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 检查所有告警计划
+//     *
+//     * @return 需要触发告警的计划列表
+//     */
+//    public List<AlarmPlan> checkAlarmPlans() {
+//        try {
+//            lock.lock();
+//
+//            List<AlarmPlan> alarmedPlans = new ArrayList<>();
+//            long currentTime = System.currentTimeMillis();
+//
+//            // 检查所有告警计划
+//            for (AlarmPlan plan : alarmPlanMap.values()) {
+//                if (plan.checkRetention(currentTime)) {
+//                    alarmedPlans.add(plan);
+//                }
+//            }
+//
+//            return alarmedPlans;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 添加区域
+//     *
+//     * @param region 区域
+//     */
+//    public void addRegion(Region region) {
+//        try {
+//            lock.lock();
+//
+//            if (region != null) {
+//                // 检查是否已存在相同ID的区域
+//                for (int i = 0; i < regions.size(); i++) {
+//                    if (regions.get(i).getId().equals(region.getId())) {
+//                        // 更新现有区域
+//                        regions.set(i, region);
+//                        return;
+//                    }
+//                }
+//
+//                // 添加新区域
+//                regions.add(region);
+//            }
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 移除区域
+//     *
+//     * @param regionId 区域ID
+//     * @return 是否成功移除
+//     */
+//    public boolean removeRegion(String regionId) {
+//        try {
+//            lock.lock();
+//
+//            for (int i = 0; i < regions.size(); i++) {
+//                if (regions.get(i).getId().equals(regionId)) {
+//                    regions.remove(i);
+//                    return true;
+//                }
+//            }
+//
+//            return false;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 获取区域
+//     *
+//     * @param regionId 区域ID
+//     * @return 区域
+//     */
+//    public Region getRegion(String regionId) {
+//        try {
+//            lock.lock();
+//
+//            for (Region region : regions) {
+//                if (region.getId().equals(regionId)) {
+//                    return region;
+//                }
+//            }
+//
+//            return null;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 获取所有区域
+//     *
+//     * @return 区域列表
+//     */
+//    public List<Region> getAllRegions() {
+//        try {
+//            lock.lock();
+//
+//            return new ArrayList<>(regions);
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 查找包含指定点的区域
+//     *
+//     * @param x 点的x坐标
+//     * @param y 点的y坐标
+//     * @return 包含该点的区域列表
+//     */
+//    public List<Region> findRegionsContainingPoint(float x, float y) {
+//        try {
+//            lock.lock();
+//
+//            List<Region> result = new ArrayList<>();
+//
+//            for (Region region : regions) {
+//                if (region.containsPoint(x, y)) {
+//                    result.add(region);
+//                }
+//            }
+//
+//            return result;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 更新告警配置
+//     *
+//     * @param retentionTime 停留时间阈值(毫秒)
+//     * @param retentionKeepTime 停留保持时间(毫秒)
+//     * @param retentionAlarmTime 停留告警时间(毫秒)
+//     */
+//    public void updateAlarmConfig(long retentionTime, long retentionKeepTime, long retentionAlarmTime) {
+//        try {
+//            lock.lock();
+//            this.retentionTime = retentionTime;
+//            this.retentionKeepTime = retentionKeepTime;
+//            this.retentionAlarmTime = retentionAlarmTime;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 检查是否应该发送跌倒告警 (参考Python版本的deal_report_falling_event逻辑)
+//     * @param currentTime 当前时间
+//     * @return true如果应该发送告警
+//     */
+//    public boolean shouldSendFallAlarm(long currentTime) {
+//        try {
+//            lock.lock();
+//            // 检查告警确认状态
+//            if (Boolean.TRUE.equals(alarmAck)) {
+//                return false;
+//            }
+//
+//            // 检查告警间隔
+//            if (lastReportFallTime != null) {
+//                long timeSinceLastAlarm = currentTime - lastReportFallTime;
+//                if (timeSinceLastAlarm < alarmInterval) {
+//                    return false;
+//                }
+//            }
+//
+//            return true;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 检查心跳是否被调试参数拒绝 (参考Python版本的deal_dev_keepalive逻辑)
+//     * @return true如果应该拒绝心跳
+//     */
+//    public boolean shouldRejectKeepAlive() {
+//        try {
+//            lock.lock();
+//            Object keepaliveDebug = debugParams.get("keepalive");
+//            return keepaliveDebug != null && Integer.valueOf(0).equals(keepaliveDebug);
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 设置设备参数信息
+//     * 对应Python版本的set_param(self, param)方法
+//     * @param param 完整的设备参数信息
+//     */
+//    public void setParam(Map<String, Object> param) {
+//        try {
+//            lock.lock();
+//            this.param = param;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 获取设备参数信息
+//     * 对应Python版本的param(self)方法
+//     * @return 完整的设备参数信息
+//     */
+//    public Map<String, Object> getParam() {
+//        try {
+//            lock.lock();
+//            return param;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 设置调试参数
+//     * @param key 参数键
+//     * @param value 参数值
+//     */
+//    public void setDebugParam(String key, Object value) {
+//        try {
+//            lock.lock();
+//            debugParams.put(key, value);
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 获取调试参数
+//     * @param key 参数键
+//     * @return 参数值
+//     */
+//    public Object getDebugParam(String key) {
+//        try {
+//            lock.lock();
+//            return debugParams.get(key);
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 检查停留时间并处理滞留告警 (参考Python版本的check_stay_time逻辑)
+//     * @param currentTime 当前时间
+//     * @return 如果检测到滞留事件返回滞留记录,否则返回null
+//     */
+//    public StayTimeRecord checkStayTime(long currentTime) {
+//        try {
+//            lock.lock();
+//
+//            if (enterTs == null || enterTs == -1 || leaveTs == null || leaveTs == -1) {
+//                return null;
+//            }
+//
+//            // 保留时间内,不认为停留事件结束
+//            long timeSinceLeave = currentTime - leaveTs;
+//            if (timeSinceLeave <= retentionKeepTime) {
+//                return null;
+//            }
+//
+//            // 时间少于最小时间尺,忽略本次事件,并重置计时
+//            long stayTimeMs = leaveTs - enterTs;
+//            if (stayTimeMs < retentionTime) {
+//                // 重置计时
+//                this.enterTs = -1L;
+//                this.leaveTs = -1L;
+//                this.stayTime = -1L;
+//                return null;
+//            }
+//
+//            // 创建停留时间记录
+//            StayTimeRecord record = new StayTimeRecord();
+//            record.setDevId(devId);
+//            record.setEnterTime(enterTs);
+//            record.setLeaveTime(leaveTs);
+//            record.setStayTime(stayTimeMs);
+//
+//            // 检查是否需要创建滞留告警 (超过3分钟视为异常滞留)
+//            long stayTimeSeconds = stayTimeMs / 1000;
+//            if (stayTimeSeconds >= (retentionAlarmTime / 1000)) {
+//                record.setNeedAlarm(true);
+//                record.setAlarmType("alarm_retention");
+//                record.setAlarmDescription("设备滞留时间过长");
+//            }
+//
+//            // 重置计时
+//            this.enterTs = -1L;
+//            this.leaveTs = -1L;
+//            this.stayTime = -1L;
+//
+//            return record;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 检查告警确认是否超时 (参考Python版本的check_dev_alarm_ack逻辑)
+//     * @param currentTime 当前时间
+//     * @return true如果告警确认超时需要清除
+//     */
+//    public boolean shouldClearAlarmAck(long currentTime) {
+//        try {
+//            lock.lock();
+//            if (Boolean.TRUE.equals(alarmAck) && lastAlarmAckTime != null) {
+//                long timeSinceAck = currentTime - lastAlarmAckTime;
+//                return timeSinceAck > alarmAckInterval;
+//            }
+//            return false;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 清除告警确认状态
+//     */
+//    public void clearAlarmAck() {
+//        try {
+//            lock.lock();
+//            this.alarmAck = false;
+//            this.lastAlarmAckTime = null;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//         /**
+//      * 更新实时位置(平滑算法) - 重写以对应Python版本的update_targets方法
+//      * @param newTargets 新的目标位置列表
+//      * @return 稳定的目标位置列表
+//      */
+//     public List<List<Float>> updateTargets(List<List<Float>> newTargets) {
+//        try {
+//            lock.lock();
+//
+//            // 对应Python版本的输入验证
+//            if (newTargets == null || newTargets.isEmpty() ||
+//                newTargets.get(0).size() < 3) {
+//                // 对应Python: LOGERR(f"update_targets error: invalid new_targets")
+//                return new ArrayList<>();
+//            }
+//
+//            // 对应Python: new_target = new_targets[0]
+//            List<Float> newTarget = newTargets.get(0);
+//
+//            // 对应Python: stable_target = self.stabilizer.update_target_list(new_target)
+//            List<Float> stableTarget = stabilizer.updateTargetList(newTarget);
+//
+//            // 更新targets字段
+//            this.targets = stableTarget;
+//
+//            // 对应Python: return [stable_target]
+//            List<List<Float>> result = new ArrayList<>();
+//            result.add(stableTarget);
+//            return result;
+//
+//        } catch (Exception e) {
+//            // 对应Python: except Exception as e: LOGERR(f"update_targets error: {e}")
+//            return new ArrayList<>();
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 获取实时姿态 (对应Python版本的realtime_pose方法)
+//     * @return 实时姿态列表
+//     */
+//    public List<Integer> getRealtimePose() {
+//        try {
+//            lock.lock();
+//            return realtimePose != null ? new ArrayList<>(realtimePose) : new ArrayList<>();
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 设置实时姿态 (对应Python版本的set_realtime_pose方法)
+//     * @param pose 姿态列表
+//     */
+//    public void setRealtimePose(List<Integer> pose) {
+//        try {
+//            lock.lock();
+//            this.realtimePose = pose != null ? new ArrayList<>(pose) : new ArrayList<>();
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 获取进入时间 (对应Python版本的enter_ts方法)
+//     * @return 进入时间戳,如果未设置返回-1
+//     */
+//    public Long getEnterTime() {
+//        try {
+//            lock.lock();
+//            return enterTs != null ? enterTs : -1L;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 设置进入时间 (对应Python版本的set_enter_ts方法)
+//     * @param timestamp 时间戳
+//     */
+//    public void setEnterTime(Long timestamp) {
+//        try {
+//            lock.lock();
+//            this.enterTs = timestamp;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 获取离开时间 (对应Python版本的leave_ts方法)
+//     * @return 离开时间戳,如果未设置返回-1
+//     */
+//    public Long getLeaveTime() {
+//        try {
+//            lock.lock();
+//            return leaveTs != null ? leaveTs : -1L;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 设置离开时间 (对应Python版本的set_leave_ts方法)
+//     * @param timestamp 时间戳
+//     */
+//    public void setLeaveTime(Long timestamp) {
+//        try {
+//            lock.lock();
+//            this.leaveTs = timestamp;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 检查告警间隔 (对应Python版本的告警间隔检查逻辑)
+//     * @param eventType 事件类型
+//     * @param currentTime 当前时间
+//     * @return 是否应该发送告警
+//     */
+//    public boolean shouldSendAlarmForEvent(String eventType, Long currentTime) {
+//        try {
+//            lock.lock();
+//            // 如果已经确认告警,则不发送
+//            if (Boolean.TRUE.equals(alarmAck)) {
+//                return false;
+//            }
+//
+//            // 检查告警间隔 (对应Python: now - device.last_fall_time(event) < device.alarm_interval())
+//            Long lastEventTime = lastFallTimeByEvent.get(eventType);
+//            if (lastEventTime != null && currentTime != null) {
+//                long timeSinceLastAlarm = currentTime - lastEventTime;
+//                return timeSinceLastAlarm >= (alarmInterval != null ? alarmInterval : 30000L); // 默认30秒间隔
+//            }
+//
+//            return true;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 设置最后跌倒时间 (对应Python版本的set_last_fall_time方法)
+//     * @param eventType 事件类型
+//     * @param timestamp 时间戳
+//     */
+//    public void setLastFallTime(String eventType, Long timestamp) {
+//        try {
+//            lock.lock();
+//            this.lastReportFallTime = timestamp;
+//            // 为每个事件类型单独记录时间 (对应Python版本的last_fall_time_[event] = time)
+//            lastFallTimeByEvent.put(eventType, timestamp);
+//            lastActivityTime.put("fall_" + eventType, timestamp);
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 获取指定事件类型的最后跌倒时间 (对应Python版本的last_fall_time(event))
+//     * @param eventType 事件类型
+//     * @return 最后跌倒时间,如果没有记录返回0
+//     */
+//    public Long getLastFallTime(String eventType) {
+//        try {
+//            lock.lock();
+//            return lastFallTimeByEvent.getOrDefault(eventType, 0L);
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 获取当前跌倒状态 (对应Python版本的device.falling_)
+//     * @return 跌倒状态:0-无跌倒,1-检测到跌倒,2-跌倒确认,3-跌倒呼救
+//     */
+//    public Integer getFalling() {
+//        try {
+//            lock.lock();
+//            return falling_ != null ? falling_ : 0;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 设置当前跌倒状态 (对应Python版本的device.falling_)
+//     * @param falling 跌倒状态:0-无跌倒,1-检测到跌倒,2-跌倒确认,3-跌倒呼救
+//     */
+//    public void setFalling(Integer falling) {
+//        try {
+//            lock.lock();
+//            this.falling_ = falling;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 检查LNA设备的告警间隔 (对应Python版本的LNA特殊逻辑)
+//     *
+//     * Python真实逻辑:
+//     * - device.falling_字段永远为0(从不更新)
+//     * - 当falling==0(无跌倒)时:falling_ == falling为true,检查报警间隔
+//     * - 当falling!=0(有跌倒)时:falling_ == falling为false,跳过报警间隔检查,立即发送
+//     * - 简化理解:只有无跌倒状态才检查报警间隔,任何跌倒状态都立即发送
+//     *
+//     * @param newFalling 新的跌倒状态
+//     * @param currentTime 当前时间
+//     * @return 是否应该发送告警
+//     */
+//    public boolean shouldSendAlarmForLNA(Integer newFalling, Long currentTime) {
+//        try {
+//            lock.lock();
+//            // 如果已经确认告警,则不发送
+//            if (Boolean.TRUE.equals(alarmAck)) {
+//                return false;
+//            }
+//
+//            // 对应Python逻辑:if device.falling_ == falling
+//            // 由于falling_永远为0,所以只有当newFalling==0时才检查报警间隔
+//            if (Objects.equals(falling_, newFalling)) {
+//                // 检查报警间隔(使用lastReportFallTime,对应Python: device.last_report_fall_time())
+//                if (lastReportFallTime != null && currentTime != null) {
+//                    long timeSinceLastAlarm = currentTime - lastReportFallTime;
+//                    return timeSinceLastAlarm >= (alarmInterval != null ? alarmInterval : 30000L);
+//                }
+//            }
+//
+//            // 当falling_不等于newFalling时(即newFalling!=0时),或者没有历史时间时,直接发送
+//            return true;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 根据设备类型处理跌倒事件 (参考Python版本的设备类型区分逻辑)
+//     * @param event 事件类型
+//     * @param pose 姿态
+//     * @param location 位置坐标
+//     * @return 处理结果
+//     */
+//    public FallEventResult processFallEvent(String event, int pose, List<Float> location) {
+//        try {
+//            lock.lock();
+//            FallEventResult result = new FallEventResult();
+//            result.setDevId(devId);
+//            result.setEvent(event);
+//
+//            if ("LNB".equals(devType)) {
+//                // LNB设备的处理逻辑 (参考Python版本)
+//                result.setPose("no_fall".equals(event) ? 4 : 0); // POSE_4 或 POSE_0
+//                // 转换位置坐标格式 (参考Python版本的targets格式)
+//                if (location != null && location.size() >= 3) {
+//                    float[] targetPoint = {location.get(0)/100f, location.get(1)/100f, location.get(2)/100f};
+//                    result.setLocation(targetPoint);
+//                }
+//                result.setShouldProcess(true);
+//            } else if ("LNA".equals(devType)) {
+//                // LNA设备的处理逻辑 (参考Python版本)
+//                if (realtimePose == null || realtimePose.isEmpty() || !Integer.valueOf(0).equals(realtimePose.get(0))) {
+//                    result.setShouldProcess(false);
+//                    return result;
+//                }
+//                result.setPose(realtimePose.get(0));
+//                // 转换位置坐标格式
+//                if (location != null && location.size() >= 3) {
+//                    float[] targetPoint = {location.get(0)/100f, location.get(1)/100f, location.get(2)/100f};
+//                    result.setLocation(targetPoint);
+//                }
+//                result.setShouldProcess(true);
+//            } else {
+//                result.setShouldProcess(false);
+//            }
+//
+//            return result;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 放入点云数据到队列 (对应Python版本的put_cloud_points_que方法)
+//     * @param cloudPoints 点云数据
+//     */
+//    public void putCloudPointsQueue(List<List<Float>> cloudPoints) {
+//        try {
+//            lock.lock();
+//            if (cloudPoints != null && !cloudPoints.isEmpty()) {
+//                // 如果队列已满,移除最老的数据
+//                while (cloudPointsQueue.size() >= MAX_CLOUD_POINTS_QUEUE_SIZE) {
+//                    cloudPointsQueue.poll();
+//                }
+//                cloudPointsQueue.offer(new ArrayList<>(cloudPoints));
+//            }
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 获取点云数据队列 (用于调试和分析)
+//     * @return 点云数据队列的副本
+//     */
+//    public List<List<List<Float>>> getCloudPointsQueue() {
+//        try {
+//            lock.lock();
+//            return new ArrayList<>(cloudPointsQueue);
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 清空点云数据队列
+//     */
+//    public void clearCloudPointsQueue() {
+//        try {
+//            lock.lock();
+//            cloudPointsQueue.clear();
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 检查跌倒告警间隔 (对应Python版本的告警间隔检查逻辑)
+//     * @param currentTime 当前时间
+//     * @return true如果可以发送跌倒告警
+//     */
+//    public boolean checkFallAlarmInterval(Long currentTime) {
+//        try {
+//            lock.lock();
+//            // 检查告警确认状态 (对应Python: device.get_alarm_ack())
+//            if (Boolean.TRUE.equals(alarmAck)) {
+//                return false;
+//            }
+//
+//            // 检查告警间隔 (对应Python: now - device.last_report_fall_time() < device.alarm_interval())
+//            if (lastReportFallTime != null && currentTime != null) {
+//                long timeSinceLastFall = currentTime - lastReportFallTime;
+//                return timeSinceLastFall >= (alarmInterval != null ? alarmInterval : 30000L); // 默认30秒间隔
+//            }
+//
+//            return true; // 第一次跌倒或时间信息不完整时允许发送
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 设置调试参数集合 (对应应用层的setDebugParams需求)
+//     * @param debugParams 调试参数集合
+//     */
+//    public void setDebugParams(Map<String, Object> debugParams) {
+//        try {
+//            lock.lock();
+//            if (debugParams != null) {
+//                this.debugParams.clear();
+//                this.debugParams.putAll(debugParams);
+//            }
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 获取调试参数集合 (对应应用层的getDebugParams需求)
+//     * @return 调试参数集合
+//     */
+//    public Map<String, Object> getDebugParams() {
+//        try {
+//            lock.lock();
+//            return new HashMap<>(debugParams); // 返回副本确保线程安全
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//
+//    /**
+//     * 停留时间记录
+//     */
+//    @Getter
+//    @Setter
+//    @NoArgsConstructor
+//    @AllArgsConstructor
+//    public static class StayTimeRecord {
+//        private String devId;
+//        private Long enterTime;
+//        private Long leaveTime;
+//        private Long stayTime;
+//        private boolean needAlarm;
+//        private String alarmType;
+//        private String alarmDescription;
+//    }
+//
+//    /**
+//     * 跌倒事件处理结果
+//     */
+//    @Getter
+//    @Setter
+//    @NoArgsConstructor
+//    @AllArgsConstructor
+//    public static class FallEventResult {
+//        private String devId;
+//        private String event;
+//        private Integer pose;
+//        private Object location;  // 修改为Object类型,匹配MqttGateway接口
+//        private boolean shouldProcess;
+//    }
+//
+//    /**
+//     * 获取数据量最多的一组点云数据,然后清空cloud_points_que_
+//     * (对应Python版本的get_max_len_cloud_points方法)
+//     * @return 数据量最多的点云list,失败返回null
+//     */
+//    public List<List<Float>> getMaxLenCloudPoints() {
+//        try {
+//            lock.lock();
+//
+//            // 对应Python: if self.dev_type_ == "LNB": return None
+//            if ("LNB".equals(devType)) {
+//                return null;
+//            }
+//
+//            // 对应Python: 取出数据量最多的的点云,成功返回点云list,失败返回None
+//            int maxLen = 0;
+//            List<List<Float>> maxLenList = null;
+//
+//            // 对应Python: while not self.cloud_points_que_.empty():
+//            while (!cloudPointsQueue.isEmpty()) {
+//                List<List<Float>> currentList = cloudPointsQueue.poll();
+//                // 对应Python: if len(current_list) >= max_len:
+//                if (currentList != null && currentList.size() >= maxLen) {
+//                    maxLen = currentList.size();
+//                    maxLenList = currentList;
+//                }
+//            }
+//
+//            return maxLenList;
+//        } finally {
+//            lock.unlock();
+//        }
+//    }
+//}

+ 3 - 0
device-service-domain/src/main/java/com/hfln/device/domain/gateway/DeviceGateway.java

@@ -69,6 +69,9 @@ public interface DeviceGateway {
      */
     boolean updateDeviceOnlineStatus(String devId, Integer online);
 
+
+    boolean updateDeviceOfflineStatus(String devId);
+
     /**
      * 更新设备保活时间
      * @param devId 设备ID

+ 0 - 15
device-service-domain/src/main/java/com/hfln/device/domain/gateway/sms/SmsGateway.java

@@ -1,15 +0,0 @@
-package com.hfln.device.domain.gateway.sms;
-
-/**
- * 验证码相关
- */
-public interface SmsGateway {
-
-    Boolean sendLoginSmsCode(String phone);
-
-
-    Boolean sendSignupSmsCode(String phone);
-
-
-
-}

+ 2 - 1
device-service-domain/src/main/java/com/hfln/device/domain/port/DeviceEventPort.java

@@ -21,7 +21,8 @@ public interface DeviceEventPort {
      * @param fullPayload 完整的消息载荷
      */
     void handleDeviceLogin(String deviceId, Map<String, Object> deviceInfo, Map<String, Object> fullPayload);
-    
+    void handleDeviceDisconnect(String deviceId, Map<String, Object> fullPayload);
+
     /**
      * 处理设备保活事件
      * 对应Python版本的deal_dev_keepalive方法

+ 14 - 0
device-service-domain/src/main/java/com/hfln/device/domain/service/DeviceManagerService.java

@@ -3,6 +3,7 @@ package com.hfln.device.domain.service;
 import com.hfln.device.domain.entity.Device;
 
 import java.util.Collection;
+import java.util.Map;
 import java.util.Optional;
 
 /**
@@ -23,12 +24,25 @@ public interface DeviceManagerService {
      * @param device 设备信息
      */
     void addDeviceToCache(Device device);
+
+    boolean existInCache(String deviceId);
     
     /**
      * 更新设备缓存
      * @param device 设备对象
      */
     void updateDeviceInCache(Device device);
+
+    void updateDeviceKeepAliveInCache(String devId,  Long keepaliveTime);
+
+    void updateDeviceAliveStatusInCache(String devId);
+
+    /**
+     * 更新设备缓存
+     * @param devId 设备ID
+     * @param map   设备更新属性
+     */
+    void updateDeviceMapInCache(String devId, Map<String, Object> map);
     
     /**
      * 从缓存中删除设备

+ 181 - 181
device-service-domain/src/main/java/com/hfln/device/domain/service/impl/DeviceManagerServiceImpl.java

@@ -1,181 +1,181 @@
-package com.hfln.device.domain.service.impl;
-
-import com.hfln.device.domain.entity.Device;
-import com.hfln.device.domain.constant.DeviceConstants;
-import com.hfln.device.domain.service.DeviceManagerService;
-import com.hfln.device.domain.service.DeviceStatusService;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.Collection;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-/**
- * 设备管理服务实现类
- * 负责设备状态管理、保活检查等功能
- */
-@Slf4j
-@Service
-public class DeviceManagerServiceImpl implements DeviceManagerService {
-
-    /**
-     * 设备缓存,用于保存所有在线设备信息
-     */
-    private final Map<String, Device> deviceCache = new ConcurrentHashMap<>();
-
-    @Autowired
-    private DeviceStatusService deviceStatusService;
-
-    @Override
-    public Optional<Device> getDeviceFromCache(String devId) {
-        return Optional.ofNullable(deviceCache.get(devId));
-    }
-
-    /**
-     * 将设备添加到缓存
-     * 
-     * @param device 设备信息
-     */
-    public void addDeviceToCache(Device device) {
-        deviceCache.put(device.getDevId(), device);
-        log.info("Device added to cache: {}", device.getDevId());
-    }
-
-    @Override
-    public void updateDeviceInCache(Device device) {
-        deviceCache.put(device.getDevId(), device);
-        log.debug("Device updated in cache: {}", device.getDevId());
-    }
-
-    @Override
-    public void removeDeviceFromCache(String devId) {
-        deviceCache.remove(devId);
-        log.info("Device removed from cache: {}", devId);
-    }
-
-    @Override
-    public void checkDeviceKeepAlive(long currentTimeMillis, long timeoutMillis) {
-        deviceCache.forEach((devId, device) -> {
-            // 只检查在线设备
-            if (device.getOnline() != null && device.getOnline() == 1) {
-                Long lastKeepAliveTime = device.getKeepaliveTime();
-                
-                // 如果设备无保活时间或超时,则设置为离线
-                if (lastKeepAliveTime == null || (currentTimeMillis - lastKeepAliveTime) > timeoutMillis) {
-                    log.info("Device keepalive timeout: {}, last keepalive: {}", devId, lastKeepAliveTime);
-                    deviceStatusService.handleDeviceOffline(device);
-                }
-            }
-        });
-    }
-
-    /**
-     * 检查设备告警确认状态
-     * 如果设备告警状态长时间未确认,可以执行特定的业务逻辑
-     * 
-     * @param currentTimeMillis 当前时间戳
-     * @param timeoutMillis 超时时间(毫秒)
-     */
-    @Override
-    public void checkDeviceAlarmAck(long currentTimeMillis, long timeoutMillis) {
-        deviceCache.forEach((devId, device) -> {
-            // 只检查未确认的告警
-            if (!device.getAlarmAck()) {
-                Long lastAckTime = device.getLastAlarmAckTime();
-                
-                // 如果有告警且超时未确认,则自动确认
-                if (lastAckTime > 0 && currentTimeMillis - lastAckTime > timeoutMillis) {
-                    log.info("Device alarm auto acknowledge: {}, last alarm: {}", devId, lastAckTime);
-                    device.setAlarmAcknowledgement(true, currentTimeMillis);
-                    updateDeviceInCache(device);
-                    
-                    // 更新数据库中的告警确认状态
-                    // 这里应该调用相应的网关方法
-                }
-            }
-        });
-    }
-
-    /**
-     * 检查所有设备的停留时间
-     * 根据设备报告的进入和离开时间计算停留时间
-     */
-    @Override
-    public void checkAllDeviceStayTime() {
-        deviceCache.forEach((devId, device) -> {
-            checkDeviceStayTime(device);
-        });
-    }
-
-    /**
-     * 检查单个设备的停留时间
-     * 
-     * @param device 设备信息
-     */
-    private void checkDeviceStayTime(Device device) {
-        try {
-            // 如果有进入时间和离开时间,计算停留时间
-            if (device.getEnterTs() != null && device.getLeaveTs() != null) {
-                device.updateStayTime();
-                // 这里可以增加业务逻辑,例如记录停留时间到数据库
-                log.debug("Device stay time updated: {}, stay time: {}", 
-                        device.getDevId(), device.getStayTime());
-            }
-        } catch (Exception e) {
-            log.error("Error checking device stay time: {}", device.getDevId(), e);
-        }
-    }
-
-    /**
-     * 检查所有设备的告警计划
-     * 可以根据设备的各种状态触发不同类型的告警
-     */
-    @Override
-    public void checkAllDeviceAlarmPlan() {
-        deviceCache.forEach((devId, device) -> {
-            checkDeviceRetention(device);
-        });
-    }
-
-    /**
-     * 检查设备的滞留状态
-     * 
-     * @param device 设备信息
-     */
-    private void checkDeviceRetention(Device device) {
-        try {
-            // 滞留检测逻辑
-            Long retentionTime = device.getRetentionTime();
-            if (retentionTime != null) {
-                long currentTime = System.currentTimeMillis();
-                long retentionKeepTime = device.getRetentionKeepTime() != null ? 
-                        device.getRetentionKeepTime() : 
-                        DeviceConstants.AlarmConfig.DEFAULT_RETENTION_KEEP_TIME * 1000L;
-                
-                if (currentTime - retentionTime > retentionKeepTime) {
-                    // 滞留时间超过阈值,触发告警
-                    log.warn("Device retention time exceeded threshold: {}", device.getDevId());
-                    // 这里可以增加告警逻辑
-                }
-            }
-        } catch (Exception e) {
-            log.error("Error checking device retention: {}", device.getDevId(), e);
-        }
-    }
-
-    @Override
-    public Collection<Device> getAllDevicesFromCache() {
-        return deviceCache.values();
-    }
-
-    @Override
-    public void checkDevicesTimeout() {
-        long currentTimeMillis = System.currentTimeMillis();
-        long timeoutMillis = 90000L; // 默认90秒超时
-        checkDeviceKeepAlive(currentTimeMillis, timeoutMillis);
-    }
-} 
+//package com.hfln.device.domain.service.impl;
+//
+//import com.hfln.device.domain.entity.Device;
+//import com.hfln.device.domain.constant.DeviceConstants;
+//import com.hfln.device.domain.service.DeviceManagerService;
+//import com.hfln.device.domain.service.DeviceStatusService;
+//import lombok.extern.slf4j.Slf4j;
+//
+//import java.util.Map;
+//import java.util.Optional;
+//import java.util.concurrent.ConcurrentHashMap;
+//import java.util.Collection;
+//
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.stereotype.Service;
+//
+///**
+// * 设备管理服务实现类
+// * 负责设备状态管理、保活检查等功能
+// */
+//@Slf4j
+////@Service
+//public class DeviceManagerServiceImpl implements DeviceManagerService {
+//
+//    /**
+//     * 设备缓存,用于保存所有在线设备信息
+//     */
+//    private final Map<String, Device> deviceCache = new ConcurrentHashMap<>();
+//
+//    @Autowired
+//    private DeviceStatusService deviceStatusService;
+//
+//    @Override
+//    public Optional<Device> getDeviceFromCache(String devId) {
+//        return Optional.ofNullable(deviceCache.get(devId));
+//    }
+//
+//    /**
+//     * 将设备添加到缓存
+//     *
+//     * @param device 设备信息
+//     */
+//    public void addDeviceToCache(Device device) {
+//        deviceCache.put(device.getDevId(), device);
+//        log.info("Device added to cache: {}", device.getDevId());
+//    }
+//
+//    @Override
+//    public void updateDeviceInCache(Device device) {
+//        deviceCache.put(device.getDevId(), device);
+//        log.debug("Device updated in cache: {}", device.getDevId());
+//    }
+//
+//    @Override
+//    public void removeDeviceFromCache(String devId) {
+//        deviceCache.remove(devId);
+//        log.info("Device removed from cache: {}", devId);
+//    }
+//
+//    @Override
+//    public void checkDeviceKeepAlive(long currentTimeMillis, long timeoutMillis) {
+//        deviceCache.forEach((devId, device) -> {
+//            // 只检查在线设备
+//            if (device.getOnline() != null && device.getOnline() == 1) {
+//                Long lastKeepAliveTime = device.getKeepaliveTime();
+//
+//                // 如果设备无保活时间或超时,则设置为离线
+//                if (lastKeepAliveTime == null || (currentTimeMillis - lastKeepAliveTime) > timeoutMillis) {
+//                    log.info("Device keepalive timeout: {}, last keepalive: {}", devId, lastKeepAliveTime);
+//                    deviceStatusService.handleDeviceOffline(device);
+//                }
+//            }
+//        });
+//    }
+//
+//    /**
+//     * 检查设备告警确认状态
+//     * 如果设备告警状态长时间未确认,可以执行特定的业务逻辑
+//     *
+//     * @param currentTimeMillis 当前时间戳
+//     * @param timeoutMillis 超时时间(毫秒)
+//     */
+//    @Override
+//    public void checkDeviceAlarmAck(long currentTimeMillis, long timeoutMillis) {
+//        deviceCache.forEach((devId, device) -> {
+//            // 只检查未确认的告警
+//            if (!device.getAlarmAck()) {
+//                Long lastAckTime = device.getLastAlarmAckTime();
+//
+//                // 如果有告警且超时未确认,则自动确认
+//                if (lastAckTime > 0 && currentTimeMillis - lastAckTime > timeoutMillis) {
+//                    log.info("Device alarm auto acknowledge: {}, last alarm: {}", devId, lastAckTime);
+//                    device.setAlarmAcknowledgement(true, currentTimeMillis);
+//                    updateDeviceInCache(device);
+//
+//                    // 更新数据库中的告警确认状态
+//                    // 这里应该调用相应的网关方法
+//                }
+//            }
+//        });
+//    }
+//
+//    /**
+//     * 检查所有设备的停留时间
+//     * 根据设备报告的进入和离开时间计算停留时间
+//     */
+//    @Override
+//    public void checkAllDeviceStayTime() {
+//        deviceCache.forEach((devId, device) -> {
+//            checkDeviceStayTime(device);
+//        });
+//    }
+//
+//    /**
+//     * 检查单个设备的停留时间
+//     *
+//     * @param device 设备信息
+//     */
+//    private void checkDeviceStayTime(Device device) {
+//        try {
+//            // 如果有进入时间和离开时间,计算停留时间
+//            if (device.getEnterTs() != null && device.getLeaveTs() != null) {
+//                device.updateStayTime();
+//                // 这里可以增加业务逻辑,例如记录停留时间到数据库
+//                log.debug("Device stay time updated: {}, stay time: {}",
+//                        device.getDevId(), device.getStayTime());
+//            }
+//        } catch (Exception e) {
+//            log.error("Error checking device stay time: {}", device.getDevId(), e);
+//        }
+//    }
+//
+//    /**
+//     * 检查所有设备的告警计划
+//     * 可以根据设备的各种状态触发不同类型的告警
+//     */
+//    @Override
+//    public void checkAllDeviceAlarmPlan() {
+//        deviceCache.forEach((devId, device) -> {
+//            checkDeviceRetention(device);
+//        });
+//    }
+//
+//    /**
+//     * 检查设备的滞留状态
+//     *
+//     * @param device 设备信息
+//     */
+//    private void checkDeviceRetention(Device device) {
+//        try {
+//            // 滞留检测逻辑
+//            Long retentionTime = device.getRetentionTime();
+//            if (retentionTime != null) {
+//                long currentTime = System.currentTimeMillis();
+//                long retentionKeepTime = device.getRetentionKeepTime() != null ?
+//                        device.getRetentionKeepTime() :
+//                        DeviceConstants.AlarmConfig.DEFAULT_RETENTION_KEEP_TIME * 1000L;
+//
+//                if (currentTime - retentionTime > retentionKeepTime) {
+//                    // 滞留时间超过阈值,触发告警
+//                    log.warn("Device retention time exceeded threshold: {}", device.getDevId());
+//                    // 这里可以增加告警逻辑
+//                }
+//            }
+//        } catch (Exception e) {
+//            log.error("Error checking device retention: {}", device.getDevId(), e);
+//        }
+//    }
+//
+//    @Override
+//    public Collection<Device> getAllDevicesFromCache() {
+//        return deviceCache.values();
+//    }
+//
+//    @Override
+//    public void checkDevicesTimeout() {
+//        long currentTimeMillis = System.currentTimeMillis();
+//        long timeoutMillis = 90000L; // 默认90秒超时
+//        checkDeviceKeepAlive(currentTimeMillis, timeoutMillis);
+//    }
+//}

+ 584 - 0
device-service-domain/src/main/java/com/hfln/device/domain/service/impl/DeviceRedisManagerServiceImpl.java

@@ -0,0 +1,584 @@
+package com.hfln.device.domain.service.impl;
+
+import cn.hfln.framework.redis.util.RedisUtil;
+import com.hfln.device.common.constant.redis.RedisCacheConstant;
+import com.hfln.device.domain.constant.DeviceConstants;
+import com.hfln.device.domain.entity.Device;
+import com.hfln.device.domain.gateway.DeviceGateway;
+import com.hfln.device.domain.service.DeviceManagerService;
+import com.hfln.device.domain.service.DeviceStatusService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 设备管理服务实现类
+ * 负责设备状态管理、保活检查等功能
+ */
+@Slf4j
+@Service("deviceRedisManagerService")
+public class DeviceRedisManagerServiceImpl implements DeviceManagerService {
+
+    /**
+     * 设备缓存,用于保存所有在线设备信息
+     */
+    private final Map<String, Device> deviceCache = new ConcurrentHashMap<>();
+
+//    @Autowired
+//    private DeviceStatusService deviceStatusService;
+
+    @Autowired
+    private RedisUtil redisService;
+
+    @Autowired
+    private DeviceGateway deviceGateway;
+
+    @Override
+    public Optional<Device> getDeviceFromCache(String devId) {
+
+        Map<Object, Object> deviceMap = redisService.hGetAll(RedisCacheConstant.KEY_DEVICE_pre + devId);
+        if (CollectionUtils.isEmpty(deviceMap)) {
+            return Optional.empty();
+        }
+
+        Device device = new Device();
+        if (deviceMap.get("devId") != null) {
+            device.setDevId(deviceMap.get("devId").toString());
+        }
+        if (deviceMap.get("devType") != null) {
+            device.setDevType(deviceMap.get("devType").toString());
+        }
+        if (deviceMap.get("software") != null) {
+            device.setSoftware(deviceMap.get("software").toString());
+        }
+        if (deviceMap.get("hardware") != null) {
+            device.setHardware(deviceMap.get("hardware").toString());
+        }
+        if (deviceMap.get("bluVer") != null) {
+            device.setBluVer(deviceMap.get("bluVer").toString());
+        }
+
+        Device.NetworkInfo network = new Device.NetworkInfo();
+        if (deviceMap.get("ssid") != null) {
+            network.setSsid(deviceMap.get("ssid").toString());
+        }
+        if (deviceMap.get("ip") != null) {
+            network.setIp(deviceMap.get("ip").toString());
+        }
+        if (deviceMap.get("password") != null) {
+            network.setPassword(deviceMap.get("password").toString());
+        }
+        device.setNetwork(network);
+
+        Device.InstallParam installParam = new Device.InstallParam();
+        if (deviceMap.get("mountPlain") != null) {
+            installParam.setMountPlain(deviceMap.get("mountPlain").toString());
+        }
+        if (deviceMap.get("isCeiling") != null) {
+            installParam.setIsCeiling((int) deviceMap.get("isCeiling"));
+        }
+        if (deviceMap.get("height") != null) {
+            installParam.setHeight((float) deviceMap.get("height"));
+        }
+        Device.TrackingRegion trackingRegion = new Device.TrackingRegion();
+        if (deviceMap.get("startX") != null) {
+            trackingRegion.setStartX((int) deviceMap.get("startX"));
+        }
+        if (deviceMap.get("startY") != null) {
+            trackingRegion.setStartY((int) deviceMap.get("startY"));
+        }
+        if (deviceMap.get("startZ") != null) {
+            trackingRegion.setStartZ((int) deviceMap.get("startZ"));
+        }
+        if (deviceMap.get("stopX") != null) {
+            trackingRegion.setStopX((int) deviceMap.get("stopX"));
+        }
+        if (deviceMap.get("stopY") != null) {
+            trackingRegion.setStopY((int) deviceMap.get("stopY"));
+        }
+        if (deviceMap.get("stopZ") != null) {
+            trackingRegion.setStopZ((int) deviceMap.get("stopZ"));
+        }
+        installParam.setTrackingRegion(trackingRegion);
+        device.setInstallParam(installParam);
+
+        if (deviceMap.get("online") != null) {
+            device.setOnline((int) deviceMap.get("online"));
+        }
+        if (deviceMap.get("keepAliveTime") != null) {
+            device.setKeepaliveTime((long) deviceMap.get("keepAliveTime"));
+        }
+        if (deviceMap.get("expireTime") != null) {
+            device.setKeepaliveTime((long) deviceMap.get("expireTime"));
+        }
+
+        if (deviceMap.get("lastReportFallTime") != null) {
+            device.setLastReportFallTime((long) deviceMap.get("lastReportFallTime"));
+        }
+        if (deviceMap.get("alarmInterval") != null) {
+            device.setAlarmInterval((long) deviceMap.get("alarmInterval"));
+        }
+        if (deviceMap.get("alarmAck") != null) {
+            device.setAlarmAck(Boolean.parseBoolean((String) deviceMap.get("alarmAck")));
+        }
+        if (deviceMap.get("lastAlarmAckTime") != null) {
+            device.setLastAlarmAckTime((long) deviceMap.get("lastAlarmAckTime"));
+        }
+        if (deviceMap.get("alarmAckInterval") != null) {
+            device.setAlarmAckInterval((long) deviceMap.get("alarmAckInterval"));
+        }
+        if (deviceMap.get("falling") != null) {
+            device.setFalling((int) deviceMap.get("falling"));
+        }
+
+        Map<String, Long> lastFallTimeByEvent = new HashMap<>();
+        if (deviceMap.get("no_fall") != null) {
+            lastFallTimeByEvent.put("no_fall", (Long) deviceMap.get("no_fall"));
+        }
+        if (deviceMap.get("fall_detected") != null) {
+            lastFallTimeByEvent.put("fall_detected", (Long) deviceMap.get("fall_detected"));
+        }
+        // fall_confirmed
+        if (deviceMap.get("fall_confirmed") != null) {
+            lastFallTimeByEvent.put("fall_confirmed", (Long) deviceMap.get("fall_confirmed"));
+        }
+        // fall_calling
+        if (deviceMap.get("fall_calling") != null) {
+            lastFallTimeByEvent.put("fall_calling", (Long) deviceMap.get("fall_calling"));
+        }
+        device.setLastFallTime(lastFallTimeByEvent);
+
+        return Optional.ofNullable(device);
+    }
+
+    /**
+     * 将设备添加到缓存
+     * 
+     * @param device 设备信息
+     */
+    public void addDeviceToCache(Device device) {
+
+        // 设置redis 存储设备的 hash对象的属性
+        Map<String, Object> deviceMap = new HashMap<>();
+
+        // 设置设备属性
+        deviceMap.put("devId", device.getDevId());
+        deviceMap.put("devType", device.getDevType());
+        deviceMap.put("software", device.getSoftware());
+        deviceMap.put("hardware", device.getHardware());
+        deviceMap.put("bluVer", device.getBluVer());
+
+        // 添加网络信息
+        if (device.getNetwork() != null) {
+            deviceMap.put("ssid", device.getNetwork().getSsid());
+            deviceMap.put("ip", device.getNetwork().getIp());
+            deviceMap.put("password", device.getNetwork().getPassword());
+        }
+
+        // 添加安装参数
+        if (device.getInstallParam() != null) {
+            deviceMap.put("mountPlain", device.getInstallParam().getMountPlain());
+            deviceMap.put("isCeiling", device.getInstallParam().getIsCeiling());
+            deviceMap.put("height", device.getInstallParam().getHeight());
+
+            // 添加跟踪区域
+            if (device.getInstallParam().getTrackingRegion() != null) {
+                deviceMap.put("startX", device.getInstallParam().getTrackingRegion().getStartX());
+                deviceMap.put("startY", device.getInstallParam().getTrackingRegion().getStartY());
+                deviceMap.put("startZ", device.getInstallParam().getTrackingRegion().getStartZ());
+                deviceMap.put("stopX", device.getInstallParam().getTrackingRegion().getStopX());
+                deviceMap.put("stopY", device.getInstallParam().getTrackingRegion().getStopY());
+                deviceMap.put("stopZ", device.getInstallParam().getTrackingRegion().getStopZ());
+            }
+        }
+
+        // 实时点位
+        // List<Float> targets = new ArrayList<>();
+        // String targetsStr = JsonUtil.toJson(targets);
+//        deviceMap.put("targets", targetsStr);
+
+        // 在线状态
+        deviceMap.put("online", device.getOnline());
+        // 最后心跳时间戳
+        deviceMap.put("keepAliveTime", device.getKeepaliveTime());
+        // 超时时间 默认90秒
+        deviceMap.put("expireTime", device.getExpireTime());
+
+        // 跌倒信息
+        // 最后上报跌倒时间
+        deviceMap.put("lastReportFallTime", device.getLastReportFallTime());
+        // 告警时间间隔(毫秒),默认30秒
+        deviceMap.put("alarmInterval", device.getAlarmInterval());
+        // 告警确认
+        deviceMap.put("alarmAck", String.valueOf(device.getAlarmAck()));
+        // 最后告警确认时间
+        deviceMap.put("lastAlarmAckTime", device.getLastAlarmAckTime());
+        // 告警确认时间间间隔(毫秒),默认5分钟
+        deviceMap.put("alarmAckInterval", device.getAlarmAckInterval());
+        // 最后上报跌倒信息 跌倒状态
+        deviceMap.put("falling", device.getFalling());
+        if (!CollectionUtils.isEmpty(device.getLastFallTimeByEvent())) {
+            // 没有检测到跌倒
+            deviceMap.put("no_fall", device.getLastFallTimeByEvent().get("no_fall"));
+            // 检测到跌倒
+            deviceMap.put("fall_detected", device.getLastFallTimeByEvent().get("fall_detected"));
+            // 跌倒确认
+            deviceMap.put("fall_confirmed", device.getLastFallTimeByEvent().get("fall_confirmed"));
+            // 跌倒呼救
+            deviceMap.put("fall_calling", device.getLastFallTimeByEvent().get("fall_calling"));
+        }
+
+        // 设备调试参数
+//        deviceMap.put(RedisCacheConstant.KEY_DEVICE_DEBUG_PARAM_PRE + "", device.getDebugParam(""));
+
+
+        redisService.sAdd(RedisCacheConstant.KEY_DEVICE_ID, device.getDevId());
+        redisService.hSetAll(RedisCacheConstant.KEY_DEVICE_pre + device.getDevId(), deviceMap);
+        log.info("Device added to cache: {}", device.getDevId());
+    }
+
+    @Override
+    public boolean existInCache(String deviceId) {
+        return redisService.sIsMember(RedisCacheConstant.KEY_DEVICE_ID, deviceId);
+    }
+
+    @Override
+    public void updateDeviceInCache(Device device) {
+
+        if (!redisService.sIsMember(RedisCacheConstant.KEY_DEVICE_ID, device.getDevId())) {
+            log.info("Device not found in cache: {}", device.getDevId());
+            return;
+        }
+
+        // 设置redis 存储设备的 hash对象的属性
+        Map<String, Object> deviceMap = new HashMap<>();
+
+        // 设置设备属性
+        if (StringUtils.hasText(device.getDevId())) {
+            deviceMap.put("devId", device.getDevId());
+        }
+        if (StringUtils.hasText(device.getDevType())) {
+            deviceMap.put("devType", device.getDevType());
+        }
+        if (StringUtils.hasText(device.getSoftware())) {
+            deviceMap.put("software", device.getSoftware());
+        }
+        if (StringUtils.hasText(device.getHardware())) {
+            deviceMap.put("hardware", device.getHardware());
+        }
+        if (StringUtils.hasText(device.getBluVer())) {
+            deviceMap.put("bluVer", device.getBluVer());
+        }
+
+        // 添加网络信息
+        if (device.getNetwork() != null) {
+            if (StringUtils.hasText(device.getNetwork().getSsid())) {
+                deviceMap.put("ssid", device.getNetwork().getSsid());
+            }
+            if (StringUtils.hasText(device.getNetwork().getIp())) {
+                deviceMap.put("ip", device.getNetwork().getIp());
+            }
+            if (StringUtils.hasText(device.getNetwork().getPassword())) {
+                deviceMap.put("password", device.getNetwork().getPassword());
+            }
+        }
+
+        // 添加安装参数
+        if (device.getInstallParam() != null) {
+            if (StringUtils.hasText(device.getInstallParam().getMountPlain())) {
+                deviceMap.put("mountPlain", device.getInstallParam().getMountPlain());
+            }
+            if (device.getInstallParam().getIsCeiling() != null) {
+                deviceMap.put("isCeiling", device.getInstallParam().getIsCeiling());
+            }
+            if (device.getInstallParam().getHeight() != null) {
+                deviceMap.put("height", device.getInstallParam().getHeight());
+            }
+
+            // 添加跟踪区域
+            if (device.getInstallParam().getTrackingRegion() != null) {
+                if (device.getInstallParam().getTrackingRegion().getStartX() != null) {
+                    deviceMap.put("startX", device.getInstallParam().getTrackingRegion().getStartX());
+                }
+                if (device.getInstallParam().getTrackingRegion().getStartY() != null) {
+                    deviceMap.put("startY", device.getInstallParam().getTrackingRegion().getStartY());
+                }
+                if (device.getInstallParam().getTrackingRegion().getStartZ() != null) {
+                    deviceMap.put("startZ", device.getInstallParam().getTrackingRegion().getStartZ());
+                }
+                if (device.getInstallParam().getTrackingRegion().getStopX() != null) {
+                    deviceMap.put("stopX", device.getInstallParam().getTrackingRegion().getStopX());
+                }
+                if (device.getInstallParam().getTrackingRegion().getStopY() != null) {
+                    deviceMap.put("stopY", device.getInstallParam().getTrackingRegion().getStopY());
+                }
+                if (device.getInstallParam().getTrackingRegion().getStopZ() != null) {
+                    deviceMap.put("stopZ", device.getInstallParam().getTrackingRegion().getStopZ());
+                }
+            }
+        }
+
+        // 实时点位
+        // List<Float> targets = new ArrayList<>();
+        // String targetsStr = JsonUtil.toJson(targets);
+//        deviceMap.put("targets", targetsStr);
+
+        // 在线状态
+        if (device.getOnline() != null) {
+            deviceMap.put("online", device.getOnline());
+        }
+        // 最后心跳时间戳
+        if (device.getKeepaliveTime() != null) {
+            deviceMap.put("keepAliveTime", device.getKeepaliveTime());
+        }
+        // 超时时间 默认90秒
+        if (device.getExpireTime() != null) {
+            deviceMap.put("expireTime", device.getExpireTime());
+        }
+
+        // 跌倒信息
+        // 最后上报跌倒时间
+        if (device.getLastReportFallTime() != null) {
+            deviceMap.put("lastReportFallTime", device.getLastReportFallTime());
+        }
+        // 告警时间间隔(毫秒),默认30秒
+        if (device.getAlarmInterval() != null) {
+            deviceMap.put("alarmInterval", device.getAlarmInterval());
+        }
+        // 告警确认
+        if (device.getAlarmAck() != null) {
+            deviceMap.put("alarmAck", String.valueOf(device.getAlarmAck()));
+        }
+        // 最后告警确认时间
+        if (device.getLastAlarmAckTime() != null) {
+            deviceMap.put("lastAlarmAckTime", device.getLastAlarmAckTime());
+        }
+        // 告警确认时间间间隔(毫秒),默认5分钟
+        if (device.getAlarmAckInterval() != null) {
+            deviceMap.put("alarmAckInterval", device.getAlarmAckInterval());
+        }
+        // 最后上报跌倒信息 跌倒状态
+        if (device.getFalling() != null) {
+            deviceMap.put("falling", device.getFalling());
+        }
+        if (!CollectionUtils.isEmpty(device.getLastFallTimeByEvent())) {
+            Map<String, Long> fallTimeMap = device.getLastFallTimeByEvent();
+            if (fallTimeMap != null) {
+                // 没有检测到跌倒
+                if (fallTimeMap.containsKey("no_fall") && fallTimeMap.get("no_fall") != null) {
+                    deviceMap.put("no_fall", fallTimeMap.get("no_fall"));
+                }
+                // 检测到跌倒
+                if (fallTimeMap.containsKey("fall_detected") && fallTimeMap.get("fall_detected") != null) {
+                    deviceMap.put("fall_detected", fallTimeMap.get("fall_detected"));
+                }
+                // 跌倒确认
+                if (fallTimeMap.containsKey("fall_confirmed") && fallTimeMap.get("fall_confirmed") != null) {
+                    deviceMap.put("fall_confirmed", fallTimeMap.get("fall_confirmed"));
+                }
+                // 跌倒呼救
+                if (fallTimeMap.containsKey("fall_calling") && fallTimeMap.get("fall_calling") != null) {
+                    deviceMap.put("fall_calling", fallTimeMap.get("fall_calling"));
+                }
+            }
+        }
+
+        // 设备调试参数
+//        deviceMap.put(RedisCacheConstant.KEY_DEVICE_DEBUG_PARAM_PRE + "", device.getDebugParam(""));
+
+        redisService.hSetAll(RedisCacheConstant.KEY_DEVICE_pre + device.getDevId(), deviceMap);
+        log.debug("Device updated in cache: {}", device.getDevId());
+    }
+
+    @Override
+    public void updateDeviceKeepAliveInCache(String devId,  Long keepaliveTime) {
+//        deviceCache.put(device.getDevId(), device);
+        if (redisService.sIsMember(RedisCacheConstant.KEY_DEVICE_ID, devId)) {
+            redisService.hSet(RedisCacheConstant.KEY_DEVICE_pre + devId, "keepAliveTime", keepaliveTime);
+        }
+        log.debug("Device updated in cache: {}", devId);
+    }
+
+    @Override
+    public void updateDeviceAliveStatusInCache(String devId) {
+        Map<String, Object> updateDeviceMap = new HashMap<>();
+        updateDeviceMap.put("online", 1);
+        updateDeviceMap.put("keepAliveTime", System.currentTimeMillis());
+        redisService.hSetAll(RedisCacheConstant.KEY_DEVICE_pre + devId, updateDeviceMap);
+    }
+
+    public void updateDeviceMapInCache(String devId, Map<String, Object> map) {
+
+        if (CollectionUtils.isEmpty( map)) {
+            return;
+        }
+        redisService.hSetAll(RedisCacheConstant.KEY_DEVICE_pre + devId, map);
+        log.debug("Device updated in cache: {}", devId);
+    }
+
+    @Override
+    public void removeDeviceFromCache(String devId) {
+
+        if (redisService.sIsMember(RedisCacheConstant.KEY_DEVICE_ID, devId)) {
+
+            redisService.sRemove(RedisCacheConstant.KEY_DEVICE_ID, devId);
+            redisService.del(RedisCacheConstant.KEY_DEVICE_pre + devId);
+        }
+        log.info("Device removed from cache: {}", devId);
+    }
+
+    @Override
+    public void checkDeviceKeepAlive(long currentTimeMillis, long timeoutMillis) {
+
+        Set<Object> devIdSet = redisService.sMembers(RedisCacheConstant.KEY_DEVICE_ID);
+        if (CollectionUtils.isEmpty(devIdSet)) {
+            log.info("check device keepalive , no devices in cache");
+            return;
+        }
+
+        for (Object devIdObj : devIdSet) {
+            Object onlineObj = redisService.hGet(RedisCacheConstant.KEY_DEVICE_pre + devIdObj, "online");
+            if (onlineObj != null && Integer.parseInt(onlineObj.toString()) == 1) {
+                Long lastKeepAliveTime = (Long) redisService.hGet(RedisCacheConstant.KEY_DEVICE_pre + devIdObj, "keepAliveTime");
+                // 如果设备无保活时间或超时,则设置为离线
+                if (lastKeepAliveTime == null || (currentTimeMillis - lastKeepAliveTime) > timeoutMillis) {
+                    log.info("Device keepalive timeout: {}, last keepalive: {}", devIdObj, lastKeepAliveTime);
+                    redisService.hSet(RedisCacheConstant.KEY_DEVICE_pre + devIdObj, "online", 0);
+                    // 更新数据库 设备状态
+                    deviceGateway.updateDeviceOfflineStatus((String) devIdObj);
+                }
+            }
+        }
+    }
+
+    /**
+     * 检查设备告警确认状态
+     * 如果设备告警状态长时间未确认,可以执行特定的业务逻辑
+     * 
+     * @param currentTimeMillis 当前时间戳
+     * @param timeoutMillis 超时时间(毫秒)
+     */
+    @Override
+    public void checkDeviceAlarmAck(long currentTimeMillis, long timeoutMillis) {
+
+        Set<Object> devIdSet = redisService.sMembers(RedisCacheConstant.KEY_DEVICE_ID);
+        if (CollectionUtils.isEmpty(devIdSet)) {
+            log.info("No devices in cache");
+            return;
+        }
+
+        for (Object devId : devIdSet) {
+            Boolean alarmAck = Boolean.parseBoolean(String.valueOf(redisService.hGet(RedisCacheConstant.KEY_DEVICE_pre + devId, "alarmAck")));
+            Long lastAlarmAckTime = (Long) redisService.hGet(RedisCacheConstant.KEY_DEVICE_pre + devId, "lastAlarmAckTime");
+            if (Boolean.TRUE.equals(alarmAck) && lastAlarmAckTime != null) {
+                if (currentTimeMillis - lastAlarmAckTime > timeoutMillis) {
+                    log.info("告警确认超时,清除确认状态: deviceId={}, currentTime={}",
+                            devId, currentTimeMillis);
+                    redisService.hSet(RedisCacheConstant.KEY_DEVICE_pre + devId, "alarmAck", Boolean.FALSE.toString());
+                }
+            }
+
+        }
+//
+//        deviceCache.forEach((devId, device) -> {
+//            // 只检查未确认的告警
+//            if (device.getAlarmAck() != null && !device.getAlarmAck()) {
+//                Long lastAckTime = device.getLastAlarmAckTime();
+//
+//                // 如果有告警且超时未确认,则自动确认
+//                if (lastAckTime != null && (currentTimeMillis - lastAckTime) > timeoutMillis) {
+//                    log.info("Device alarm auto acknowledge: {}, last alarm: {}", devId, lastAckTime);
+//                    device.setAlarmAcknowledgement(true, currentTimeMillis);
+//                    updateDeviceInCache(device);
+//
+//                    // 更新数据库中的告警确认状态
+//                    // 这里应该调用相应的网关方法
+//                }
+//            }
+//        });
+    }
+
+    /**
+     * 检查所有设备的停留时间
+     * 根据设备报告的进入和离开时间计算停留时间
+     */
+    @Override
+    public void checkAllDeviceStayTime() {
+        deviceCache.forEach((devId, device) -> {
+            checkDeviceStayTime(device);
+        });
+    }
+
+    /**
+     * 检查单个设备的停留时间
+     * 
+     * @param device 设备信息
+     */
+    private void checkDeviceStayTime(Device device) {
+        try {
+            // 如果有进入时间和离开时间,计算停留时间
+            if (device.getEnterTs() != null && device.getLeaveTs() != null) {
+                device.updateStayTime();
+                // 这里可以增加业务逻辑,例如记录停留时间到数据库
+                log.debug("Device stay time updated: {}, stay time: {}", 
+                        device.getDevId(), device.getStayTime());
+            }
+        } catch (Exception e) {
+            log.error("Error checking device stay time: {}", device.getDevId(), e);
+        }
+    }
+
+    /**
+     * 检查所有设备的告警计划
+     * 可以根据设备的各种状态触发不同类型的告警
+     */
+    @Override
+    public void checkAllDeviceAlarmPlan() {
+        deviceCache.forEach((devId, device) -> {
+            checkDeviceRetention(device);
+        });
+    }
+
+    /**
+     * 检查设备的滞留状态
+     * 
+     * @param device 设备信息
+     */
+    private void checkDeviceRetention(Device device) {
+        try {
+            // 滞留检测逻辑
+            Long retentionTime = device.getRetentionTime();
+            if (retentionTime != null) {
+                long currentTime = System.currentTimeMillis();
+                long retentionKeepTime = device.getRetentionKeepTime() != null ? 
+                        device.getRetentionKeepTime() : 
+                        DeviceConstants.AlarmConfig.DEFAULT_RETENTION_KEEP_TIME * 1000L;
+                
+                if (currentTime - retentionTime > retentionKeepTime) {
+                    // 滞留时间超过阈值,触发告警
+                    log.warn("Device retention time exceeded threshold: {}", device.getDevId());
+                    // 这里可以增加告警逻辑
+                }
+            }
+        } catch (Exception e) {
+            log.error("Error checking device retention: {}", device.getDevId(), e);
+        }
+    }
+
+    @Override
+    public Collection<Device> getAllDevicesFromCache() {
+        return deviceCache.values();
+    }
+
+    @Override
+    public void checkDevicesTimeout() {
+        long currentTimeMillis = System.currentTimeMillis();
+        long timeoutMillis = 90000L; // 默认90秒超时
+        checkDeviceKeepAlive(currentTimeMillis, timeoutMillis);
+    }
+} 

+ 6 - 0
device-service-infrastructure/pom.xml

@@ -75,6 +75,12 @@
             <scope>test</scope>
         </dependency>
 
+        <dependency>
+            <groupId>com.github.phantomthief</groupId>
+            <artifactId>more-lambdas</artifactId>
+            <version>0.1.55</version>
+        </dependency>
+
     </dependencies>
 
     <build>

+ 44 - 0
device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/config/FastJson2JsonRedisSerializer.java

@@ -0,0 +1,44 @@
+package com.hfln.device.infrastructure.config;//package cn.hfln.framework.common.redis;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONReader;
+import com.alibaba.fastjson2.JSONWriter;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.serializer.SerializationException;
+
+import java.nio.charset.Charset;
+
+/**
+ * Redis使用FastJson序列化
+ *
+ * @author cw
+ */
+public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {
+    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
+
+    private Class<T> clazz;
+
+
+    public FastJson2JsonRedisSerializer(Class<T> clazz) {
+        super();
+        this.clazz = clazz;
+    }
+
+    @Override
+    public byte[] serialize(T t) throws SerializationException {
+        if (t == null) {
+            return new byte[0];
+        }
+        return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName).getBytes(DEFAULT_CHARSET);
+    }
+
+    @Override
+    public T deserialize(byte[] bytes) throws SerializationException {
+        if (bytes == null || bytes.length <= 0) {
+            return null;
+        }
+        String str = new String(bytes, DEFAULT_CHARSET);
+
+        return JSON.parseObject(str, clazz, JSONReader.Feature.SupportAutoType);
+    }
+}

+ 20 - 13
device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/config/MqttConfig.java

@@ -117,16 +117,23 @@ public class MqttConfig {
     @Bean
     public MessageProducer deviceInbound() {
         String[] topics = {
-            MqttTopics.DEV_LOGIN,
-            MqttTopics.DEV_KEEPALIVE,
-            MqttTopics.DEV_DSP_DATA,
-            MqttTopics.DEV_CLOUDPOINT,
-            MqttTopics.DEV_REP_DEV_INFO,
-            MqttTopics.DEV_REP_DEV_PARAM,
-            MqttTopics.DEV_REP_FALL_EVENT,
-            MqttTopics.DEV_REP_PRES_EVENT,
-            MqttTopics.DEV_SET_DEBUG,
-            MqttTopics.DEV_GET_DEBUG
+//            MqttTopics.DEV_LOGIN,
+//            MqttTopics.DEV_KEEPALIVE,
+//            MqttTopics.DEV_DSP_DATA,
+//            MqttTopics.DEV_REP_DEV_PARAM,
+//            MqttTopics.DEV_DISCONNECT,
+
+            MqttTopics.SHARE_DEV_LOGIN,
+            MqttTopics.SHARE_DEV_KEEPALIVE,
+            MqttTopics.SHARE_DEV_DSP_DATA,
+            MqttTopics.SHARE_DEV_REP_DEV_PARAM,
+            MqttTopics.SHARE_DEV_DISCONNECT,
+//            MqttTopics.DEV_CLOUDPOINT,
+//            MqttTopics.DEV_REP_DEV_INFO,
+//            MqttTopics.DEV_REP_FALL_EVENT,
+//            MqttTopics.DEV_REP_PRES_EVENT,
+//            MqttTopics.DEV_SET_DEBUG,
+//            MqttTopics.DEV_GET_DEBUG
         };
         
         MqttPahoMessageDrivenChannelAdapter adapter =
@@ -154,12 +161,12 @@ public class MqttConfig {
     // 应用消息通道和适配器
     // ===========================================
 
-    @Bean
+//    @Bean
     public MessageChannel appInputChannel() {
         return new DirectChannel();
     }
 
-    @Bean
+//    @Bean
     public MessageProducer appInbound() {
         String[] topics = {
             MqttTopics.APP_FALL_EVENT_ACK,
@@ -178,7 +185,7 @@ public class MqttConfig {
         return adapter;
     }
 
-    @Bean
+//    @Bean
     @ServiceActivator(inputChannel = "appInputChannel")
     public MessageHandler appMqttMessageHandler(AppMessageHandler handler) {
         return new MessageHandler() {

+ 32 - 0
device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/config/RedisConfig.java

@@ -0,0 +1,32 @@
+package com.hfln.device.infrastructure.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+/**
+ * Redis 配置类
+ * 手动注册 RedisTemplate,确保与自研 Redis Starter 兼容
+ */
+@Configuration
+public class RedisConfig {
+
+    @Bean
+    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, Object> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用 StringRedisSerializer 进行序列化
+        StringRedisSerializer stringSerializer = new StringRedisSerializer();
+        FastJson2JsonRedisSerializer jsonSerializer = new FastJson2JsonRedisSerializer<>(Object.class);
+        template.setKeySerializer(stringSerializer);
+        template.setValueSerializer(jsonSerializer);
+        template.setHashKeySerializer(stringSerializer);
+        template.setHashValueSerializer(jsonSerializer);
+
+        template.afterPropertiesSet();
+        return template;
+    }
+}

+ 35 - 0
device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/config/TopicDealExecutor.java

@@ -0,0 +1,35 @@
+package com.hfln.device.infrastructure.config;
+import com.github.phantomthief.pool.KeyAffinityExecutor;
+import com.github.phantomthief.util.ThrowableRunnable;
+import org.springframework.stereotype.Component;
+
+// 优化配置(适用于万级Key+10万QPS)
+// 处理设备实时点位数据
+@Component
+public class TopicDealExecutor {
+
+    // 核心配置参数
+    private static final int PARALLELISM = 6;   // 并行线程数(建议CPU核心数×4)
+    private static final int QUEUE_SIZE = 256;   // 每个线程队列容量 (建议: 线程数×500)
+    private static final int MAX_KEY_PER_THREAD = 100; // 单线程处理Key上限
+
+    private final KeyAffinityExecutor executor = KeyAffinityExecutor.newSerializingExecutor(
+            PARALLELISM,
+            QUEUE_SIZE,
+            "mqtt_sub-%d"
+    );
+
+    public void submitTask(Object key, ThrowableRunnable<Exception> task) {
+
+        executor.executeEx(key, task);
+    }
+
+    public void close() {
+        try {
+            executor.close();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+}

+ 6 - 4
device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/gateway/MqttGatewayImpl.java

@@ -163,6 +163,8 @@ public class MqttGatewayImpl implements MqttGateway {
     public void sendDeviceInfoUpdateNotification(Device device) {
         try {
             Map<String, Object> message = new HashMap<>();
+            message.put("message", "notify");
+            message.put("timestamp", System.currentTimeMillis());
             message.put("dev_id", device.getDevId());
             message.put("dev_type", device.getDevType());
             message.put("software", device.getSoftware());
@@ -193,10 +195,10 @@ public class MqttGatewayImpl implements MqttGateway {
                     installParam.put("tracking_region", trackingRegion);
                 }
 
-                message.put("install_param", installParam);
+                message.put("radar_param", installParam);
             }
 
-            String topic = "/mps/update_dev_info";
+            String topic = "/das/dev_status";
             publishJson(topic, message);
 
             log.info("Device info update notification sent: deviceId={}", device.getDevId());
@@ -775,9 +777,9 @@ public class MqttGatewayImpl implements MqttGateway {
 
             // 目标位置 (对应Python版本的targets)
             if (targets != null) {
-                message.put("targets", targets);
+                message.put("target_point", targets);
             } else {
-                message.put("targets", new ArrayList<>());
+                message.put("target_point", new ArrayList<>());
             }
 
             // 发送到实时位置主题 (对应Python版本的MQTT主题)

+ 44 - 1
device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/gateway/impl/DeviceGatewayImpl.java

@@ -541,6 +541,49 @@ public class DeviceGatewayImpl implements DeviceGateway {
     }
 
     @Override
+    public boolean updateDeviceOfflineStatus(String devId) {
+        try {
+            log.info("更新设备在线状态: 设备={}", devId);
+
+            // 参数校验
+            if (StringUtils.isBlank(devId)) {
+                log.warn("更新设备在线状态参数无效: 设备={}, 状态={}", devId);
+                return false;
+            }
+
+            // 更新设备在线状态
+            boolean updateResult = devInfoService.update(
+                    Wrappers.<DevInfo>lambdaUpdate()
+                            .set(DevInfo::getOnline, 0)
+                            .set(DevInfo::getOfflineTime, LocalDateTime.now())
+                            .eq(DevInfo::getClientId, devId));
+
+            if (!updateResult) {
+                log.warn("更新设备在线状态失败: 设备不存在或更新失败, ID={}", devId);
+                return false;
+            }
+
+            // 获取更新后的设备信息
+            DevInfo devInfo = devInfoService.getOne(
+                    Wrappers.<DevInfo>lambdaQuery()
+                            .eq(DevInfo::getClientId, devId));
+
+            if (devInfo != null) {
+                // 转换为领域对象
+                Device device = convertToDevice(devInfo);
+
+                // 发送设备状态更新消息
+                mqttHandler.sendDeviceStatusUpdate(device);
+            }
+
+            return true;
+        } catch (Exception e) {
+            log.error("更新设备在线状态失败: {}, {}", devId, e.getMessage(), e);
+            return false;
+        }
+    }
+
+    @Override
     public boolean updateDeviceKeepAliveTime(String devId, Long keepaliveTime) {
         try {
             log.info("更新设备保活时间: 设备={}, 时间={}", devId, keepaliveTime);
@@ -1379,7 +1422,7 @@ public class DeviceGatewayImpl implements DeviceGateway {
                 status.put("deviceId", device.getDevId());
                 status.put("online", device.getOnline());
                 status.put("devType", device.getDevType());
-                status.put("keepaliveTime", device.getKeepaliveTime());
+                status.put("keepAliveTime", device.getKeepaliveTime());
                 status.put("lastAlarmTime", device.getLastAlarmTime());
                 status.put("alarmAck", device.getAlarmAck());
                 status.put("realtimePose", device.getRealtimePose());

+ 469 - 469
device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/gateway/impl/DeviceGatewaySimpleImpl.java

@@ -1,469 +1,469 @@
-package com.hfln.device.infrastructure.gateway.impl;
-
-import com.hfln.device.common.dto.data.device.DeviceDTO;
-import com.hfln.device.common.dto.data.event.EventListDTO;
-import com.hfln.device.common.dto.data.home.HomeInfoDTO;
-import com.hfln.device.common.request.device.DeviceBandingParams;
-import com.hfln.device.common.request.device.DeviceListParams;
-import com.hfln.device.common.request.device.DeviceLocationParams;
-import com.hfln.device.common.request.event.EventListParams;
-import com.hfln.device.common.vo.PageRecord;
-import com.hfln.device.domain.entity.Device;
-import com.hfln.device.domain.entity.Region;
-import com.hfln.device.domain.gateway.DeviceGateway;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.HashMap;
-import java.util.ArrayList;
-import java.util.UUID;
-
-/**
- * 设备网关简单实现类
- * 用于提供基本功能实现
- */
-@Service("deviceGatewaySimple")
-@Slf4j
-public class DeviceGatewaySimpleImpl implements DeviceGateway {
-
-    @Override
-    public List<Device> findAllDevices() {
-        log.info("查询所有设备");
-        return Collections.emptyList();
-    }
-
-    @Override
-    public Optional<Device> findDeviceById(String devId) {
-        log.info("根据ID查询设备: {}", devId);
-        return Optional.empty();
-    }
-
-    @Override
-    public Device saveDevice(Device device) {
-        log.info("保存设备: {}", device.getDevId());
-        return device;
-    }
-
-    @Override
-    public boolean updateDeviceOnlineStatus(String devId, Integer online) {
-        log.info("更新设备在线状态: {}, 状态: {}", devId, online);
-        return true;
-    }
-
-    @Override
-    public boolean updateDeviceKeepAliveTime(String devId, Long keepaliveTime) {
-        log.info("更新设备保活时间: {}, 时间: {}", devId, keepaliveTime);
-        return true;
-    }
-
-    @Override
-    public boolean recordDeviceStayTime(String devId, Long enterTime, Long leaveTime, String stayTime) {
-        log.info("记录设备停留时间: {}", devId);
-        return true;
-    }
-
-    @Override
-    public boolean recordDeviceRetentionAlarm(String devId, Long alarmTime, String alarmType, String description) {
-        log.info("记录设备滞留告警: {}, 类型: {}", devId, alarmType);
-        return true;
-    }
-
-    @Override
-    public HomeInfoDTO queryHomeInfo(Long userId) {
-        log.info("查询用户首页信息: {}", userId);
-        return new HomeInfoDTO();
-    }
-
-    @Override
-    public List<DeviceDTO> queryDeviceList(DeviceListParams request) {
-        log.info("查询设备列表: {}", request);
-        return Collections.emptyList();
-    }
-
-    @Override
-    public Boolean deviceUnBind(Long userId, String deviceId) {
-        log.info("解绑设备: {}, 用户: {}", deviceId, userId);
-        return true;
-    }
-
-    @Override
-    public Boolean deviceBind(DeviceBandingParams request) {
-        log.info("绑定设备: {}", request);
-        return true;
-    }
-
-    @Override
-    public DeviceDTO queryDeviceById(String deviceId) {
-        log.info("查询设备详情: {}", deviceId);
-        return new DeviceDTO();
-    }
-
-    @Override
-    public PageRecord<EventListDTO> queryEventByPage(EventListParams request) {
-        log.info("分页查询事件: {}", request);
-        return new PageRecord<>();
-    }
-
-    @Override
-    public Boolean handleEvent(Long eventId) {
-        log.info("处理事件: {}", eventId);
-        return true;
-    }
-
-    @Override
-    public Boolean updateDevice(DeviceBandingParams request) {
-        log.info("更新设备: {}", request);
-        return true;
-    }
-
-    @Override
-    public Boolean updateDeviceLocation(DeviceLocationParams params) {
-        log.info("更新设备位置: {}", params);
-        return true;
-    }
-
-    @Override
-    public boolean updateDeviceNetwork(String deviceId, Device.NetworkInfo networkInfo) {
-        log.info("更新设备网络配置: {}", deviceId);
-        return true;
-    }
-
-    @Override
-    public boolean updateDeviceInstallParam(String deviceId, Device.InstallParam installParam) {
-        log.info("更新设备安装参数: {}", deviceId);
-        return true;
-    }
-
-    @Override
-    public boolean updateDeviceAlarmSchedule(String deviceId, Map<String, Object> alarmSchedule) {
-        log.info("更新设备告警计划: {}", deviceId);
-        return true;
-    }
-    
-    @Override
-    public boolean checkDeviceExists(String deviceId) {
-        log.info("检查设备是否存在: {}", deviceId);
-        return true;
-    }
-    
-    @Override
-    public boolean isDeviceBound(String deviceId) {
-        log.info("检查设备是否已绑定: {}", deviceId);
-        return false;
-    }
-    
-    @Override
-    public boolean isUserDevice(String deviceId, Long userId) {
-        log.info("检查设备是否属于指定用户: {}, 用户: {}", deviceId, userId);
-        return true;
-    }
-    
-    @Override
-    public boolean bindDevice(String deviceId, Long userId) {
-        log.info("绑定设备到用户: {}, 用户: {}", deviceId, userId);
-        return true;
-    }
-    
-    @Override
-    public boolean unbindDevice(String deviceId, Long userId) {
-        log.info("解绑用户设备: {}, 用户: {}", deviceId, userId);
-        return true;
-    }
-    
-    /**
-     * 保存告警配置
-     * 
-     * @param globalConfig 全局配置
-     * @return 是否保存成功
-     */
-    @Override
-    public boolean saveAlarmConfig(Map<String, Object> globalConfig) {
-        log.info("保存告警配置: {}", globalConfig);
-        return true;
-    }
-    
-    /**
-     * 创建设备
-     * 
-     * @param deviceId 设备ID
-     * @param deviceInfo 设备信息
-     * @return 创建的设备
-     */
-    @Override
-    public Device createDevice(String deviceId, Map<String, Object> deviceInfo) {
-        log.info("创建设备: {}, 信息: {}", deviceId, deviceInfo);
-        Device device = new Device();
-        device.setDevId(deviceId);
-        return device;
-    }
-    
-    /**
-     * 更新设备信息
-     * 
-     * @param deviceId 设备ID
-     * @param deviceInfo 设备信息
-     * @return 是否更新成功
-     */
-    @Override
-    public boolean updateDeviceInfo(String deviceId, Map<String, Object> deviceInfo) {
-        log.info("更新设备信息: {}, 信息: {}", deviceId, deviceInfo);
-        return true;
-    }
-    
-    /**
-     * 更新告警状态
-     * 
-     * @param deviceId 设备ID
-     * @param eventId 事件ID
-     * @param status 状态
-     * @return 是否更新成功
-     */
-    @Override
-    public boolean updateAlarmStatus(String deviceId, Long eventId, int status) {
-        log.info("更新告警状态: 设备={}, 事件={}, 状态={}", deviceId, eventId, status);
-        return true;
-    }
-    
-    /**
-     * 记录跌倒事件
-     * 
-     * @param deviceId 设备ID
-     * @param pose 姿态
-     * @param targetPoint 目标点
-     * @return 事件ID
-     */
-    @Override
-    public Long recordFallEvent(String deviceId, int pose, List<Float> targetPoint) {
-        log.info("记录跌倒事件: 设备={}, 姿态={}", deviceId, pose);
-        return 1L;
-    }
-    
-    /**
-     * 记录事件
-     * 
-     * @param deviceId 设备ID
-     * @param event 事件类型
-     * @param pose 姿态
-     * @param targetPoint 目标点
-     * @return 是否记录成功
-     */
-    @Override
-    public boolean recordEvent(String deviceId, String event, Integer pose, List<Float> targetPoint) {
-        return recordEvent(deviceId, event, pose, targetPoint, System.currentTimeMillis());
-    }
-    
-    /**
-     * 记录存在事件
-     * 
-     * @param deviceId 设备ID
-     * @param event 事件类型
-     * @return 是否记录成功
-     */
-    @Override
-    public boolean recordExistEvent(String deviceId, String event) {
-        return recordExistEvent(deviceId, event, System.currentTimeMillis());
-    }
-    
-    /**
-     * 记录告警事件
-     * 
-     * @param deviceId 设备ID
-     * @param desc 描述
-     * @param table 表名
-     * @param tableId 表ID
-     * @return 是否记录成功
-     */
-    @Override
-    public boolean recordAlarmEvent(String deviceId, String desc, String table, Integer tableId) {
-        log.info("记录告警事件: 设备={}, 描述={}, 表={}, 表ID={}", deviceId, desc, table, tableId);
-        return true;
-    }
-    
-    @Override
-    public Device updateDevice(Device device) {
-        log.info("更新设备: {}", device.getDevId());
-        return device;
-    }
-    
-    @Override
-    public List<Device> getAllDevices() {
-        log.info("获取所有设备信息");
-        return Collections.emptyList();
-    }
-    
-    @Override
-    public Device getDeviceById(String deviceId) {
-        log.info("根据ID获取设备: {}", deviceId);
-        return null;
-    }
-
-    @Override
-    public HomeInfoDTO getHomeInfo(String homeId) {
-        log.info("查询家庭信息: homeId={}", homeId);
-        return new HomeInfoDTO();
-    }
-
-    @Override
-    public EventListDTO queryDeviceEvents(EventListParams params) {
-        log.info("查询设备事件: {}", params);
-        return new EventListDTO();
-    }
-
-    @Override
-    public boolean deviceReset(String deviceId) {
-        log.info("重置设备: {}", deviceId);
-        return true;
-    }
-
-    @Override
-    public boolean deviceReboot(String deviceId) {
-        log.info("重启设备: {}", deviceId);
-        return true;
-    }
-
-    @Override
-    public boolean recordBehaviorData(String deviceId, String dataType, Map<String, Object> data) {
-        log.info("记录行为数据: deviceId={}, dataType={}", deviceId, dataType);
-        return true;
-    }
-
-    @Override
-    public boolean recordRestBehavior(String deviceId, Long duration, List<Float> location, Long timestamp) {
-        log.info("记录休息行为: deviceId={}, duration={}, timestamp={}", deviceId, duration, timestamp);
-        return true;
-    }
-    
-    @Override
-    public boolean recordAbnormalBehavior(String deviceId, String behaviorType, String description, Double confidence, Long timestamp) {
-        log.info("记录异常行为: deviceId={}, type={}, desc={}, timestamp={}", deviceId, behaviorType, description, timestamp);
-        return true;
-    }
-    
-    @Override
-    public boolean recordNormalBehavior(String deviceId, Double confidence, Long timestamp) {
-        log.info("记录正常行为: deviceId={}, confidence={}, timestamp={}", deviceId, confidence, timestamp);
-        return true;
-    }
-    
-    @Override
-    public boolean recordEvent(String deviceId, String event, Integer pose, List<Float> targetPoint, Long timestamp) {
-        log.info("记录事件: deviceId={}, event={}, pose={}, timestamp={}", deviceId, event, pose, timestamp);
-        return true;
-    }
-    
-    @Override
-    public boolean recordAlarmEvent(String deviceId, String desc, String table, Integer tableId, Long timestamp) {
-        log.info("记录告警事件: deviceId={}, desc={}, timestamp={}", deviceId, desc, timestamp);
-        return true;
-    }
-    
-    @Override
-    public boolean recordExistEvent(String deviceId, String event, Long timestamp) {
-        log.info("记录存在事件: deviceId={}, event={}, timestamp={}", deviceId, event, timestamp);
-        return true;
-    }
-    
-    @Override
-    public boolean recordPointCloud(String deviceId, List<List<Float>> pointCloud, Long timestamp) {
-        log.info("记录点云数据: deviceId={}, timestamp={}", deviceId, timestamp);
-        return true;
-    }
-    
-    @Override
-    public boolean recordRealtimePosition(String deviceId, Integer pose, List<List<Float>> positions, Long timestamp) {
-        log.info("记录实时位置: deviceId={}, pose={}, timestamp={}", deviceId, pose, timestamp);
-        return true;
-    }
-    
-    @Override
-    public Map<String, Object> getDeviceStatus(String deviceId) {
-        log.info("获取设备状态: deviceId={}", deviceId);
-        return new HashMap<>();
-    }
-    
-    @Override
-    public Map<String, Object> getDeviceParams(String deviceId) {
-        log.info("获取设备参数: deviceId={}", deviceId);
-        return new HashMap<>();
-    }
-    
-    @Override
-    public boolean updateDeviceParams(String deviceId, Map<String, Object> params) {
-        log.info("更新设备参数: deviceId={}", deviceId);
-        return true;
-    }
-
-    @Override
-    public boolean recordActivityBehavior(String deviceId, Integer activityLevel, Long duration, Long timestamp) {
-        log.info("记录活动行为: deviceId={}, activityLevel={}, duration={}, timestamp={}", deviceId, activityLevel, duration, timestamp);
-        return true;
-    }
-
-    @Override
-    public PageRecord<DeviceDTO> queryDevices(DeviceListParams params) {
-        log.info("查询设备列表: {}", params);
-        return new PageRecord<>();
-    }
-
-    @Override
-    public boolean updateAlarmAckStatus(Long alarmId, Long userId) {
-        log.info("更新告警确认状态: {}, 用户: {}", alarmId, userId);
-        return true;
-    }
-    
-    @Override
-    public List<Map<String, Object>> getUnacknowledgedAlarms(String deviceId) {
-        log.info("获取设备未确认的告警: {}", deviceId);
-        return Collections.emptyList();
-    }
-    
-    @Override
-    public Long recordAlarmEventWithSeverity(String deviceId, String desc, String table, Integer severity, Long timestamp) {
-        log.info("记录告警事件(带告警级别): {}, 描述: {}, 级别: {}", deviceId, desc, severity);
-        // 返回模拟的告警ID
-        return timestamp != null ? timestamp : System.currentTimeMillis();
-    }
-
-    @Override
-    public boolean saveRegion(Region region) {
-        log.info("保存区域信息: {}", region.getName());
-        return true;
-    }
-    
-    @Override
-    public boolean updateRegion(Region region) {
-        log.info("更新区域信息: {}", region.getId());
-        return true;
-    }
-    
-    @Override
-    public Region getRegionById(String regionId) {
-        log.info("根据ID获取区域: {}", regionId);
-        Region region = new Region();
-        region.setId(regionId);
-        region.setName("模拟区域");
-        return region;
-    }
-    
-    @Override
-    public List<Region> getRegionsByDeviceId(String deviceId) {
-        log.info("获取设备的区域列表: {}", deviceId);
-        return new ArrayList<>();
-    }
-    
-    @Override
-    public boolean deleteRegion(String regionId) {
-        log.info("删除区域: {}", regionId);
-        return true;
-    }
-    
-    @Override
-    public boolean deleteDevice(String deviceId) {
-        log.info("删除设备: {}", deviceId);
-        return true;
-    }
-} 
+//package com.hfln.device.infrastructure.gateway.impl;
+//
+//import com.hfln.device.common.dto.data.device.DeviceDTO;
+//import com.hfln.device.common.dto.data.event.EventListDTO;
+//import com.hfln.device.common.dto.data.home.HomeInfoDTO;
+//import com.hfln.device.common.request.device.DeviceBandingParams;
+//import com.hfln.device.common.request.device.DeviceListParams;
+//import com.hfln.device.common.request.device.DeviceLocationParams;
+//import com.hfln.device.common.request.event.EventListParams;
+//import com.hfln.device.common.vo.PageRecord;
+//import com.hfln.device.domain.entity.Device;
+//import com.hfln.device.domain.entity.Region;
+//import com.hfln.device.domain.gateway.DeviceGateway;
+//import lombok.extern.slf4j.Slf4j;
+//import org.springframework.stereotype.Service;
+//
+//import java.util.Collections;
+//import java.util.List;
+//import java.util.Map;
+//import java.util.Optional;
+//import java.util.HashMap;
+//import java.util.ArrayList;
+//import java.util.UUID;
+//
+///**
+// * 设备网关简单实现类
+// * 用于提供基本功能实现
+// */
+//@Service("deviceGatewaySimple")
+//@Slf4j
+//public class DeviceGatewaySimpleImpl implements DeviceGateway {
+//
+//    @Override
+//    public List<Device> findAllDevices() {
+//        log.info("查询所有设备");
+//        return Collections.emptyList();
+//    }
+//
+//    @Override
+//    public Optional<Device> findDeviceById(String devId) {
+//        log.info("根据ID查询设备: {}", devId);
+//        return Optional.empty();
+//    }
+//
+//    @Override
+//    public Device saveDevice(Device device) {
+//        log.info("保存设备: {}", device.getDevId());
+//        return device;
+//    }
+//
+//    @Override
+//    public boolean updateDeviceOnlineStatus(String devId, Integer online) {
+//        log.info("更新设备在线状态: {}, 状态: {}", devId, online);
+//        return true;
+//    }
+//
+//    @Override
+//    public boolean updateDeviceKeepAliveTime(String devId, Long keepaliveTime) {
+//        log.info("更新设备保活时间: {}, 时间: {}", devId, keepaliveTime);
+//        return true;
+//    }
+//
+//    @Override
+//    public boolean recordDeviceStayTime(String devId, Long enterTime, Long leaveTime, String stayTime) {
+//        log.info("记录设备停留时间: {}", devId);
+//        return true;
+//    }
+//
+//    @Override
+//    public boolean recordDeviceRetentionAlarm(String devId, Long alarmTime, String alarmType, String description) {
+//        log.info("记录设备滞留告警: {}, 类型: {}", devId, alarmType);
+//        return true;
+//    }
+//
+//    @Override
+//    public HomeInfoDTO queryHomeInfo(Long userId) {
+//        log.info("查询用户首页信息: {}", userId);
+//        return new HomeInfoDTO();
+//    }
+//
+//    @Override
+//    public List<DeviceDTO> queryDeviceList(DeviceListParams request) {
+//        log.info("查询设备列表: {}", request);
+//        return Collections.emptyList();
+//    }
+//
+//    @Override
+//    public Boolean deviceUnBind(Long userId, String deviceId) {
+//        log.info("解绑设备: {}, 用户: {}", deviceId, userId);
+//        return true;
+//    }
+//
+//    @Override
+//    public Boolean deviceBind(DeviceBandingParams request) {
+//        log.info("绑定设备: {}", request);
+//        return true;
+//    }
+//
+//    @Override
+//    public DeviceDTO queryDeviceById(String deviceId) {
+//        log.info("查询设备详情: {}", deviceId);
+//        return new DeviceDTO();
+//    }
+//
+//    @Override
+//    public PageRecord<EventListDTO> queryEventByPage(EventListParams request) {
+//        log.info("分页查询事件: {}", request);
+//        return new PageRecord<>();
+//    }
+//
+//    @Override
+//    public Boolean handleEvent(Long eventId) {
+//        log.info("处理事件: {}", eventId);
+//        return true;
+//    }
+//
+//    @Override
+//    public Boolean updateDevice(DeviceBandingParams request) {
+//        log.info("更新设备: {}", request);
+//        return true;
+//    }
+//
+//    @Override
+//    public Boolean updateDeviceLocation(DeviceLocationParams params) {
+//        log.info("更新设备位置: {}", params);
+//        return true;
+//    }
+//
+//    @Override
+//    public boolean updateDeviceNetwork(String deviceId, Device.NetworkInfo networkInfo) {
+//        log.info("更新设备网络配置: {}", deviceId);
+//        return true;
+//    }
+//
+//    @Override
+//    public boolean updateDeviceInstallParam(String deviceId, Device.InstallParam installParam) {
+//        log.info("更新设备安装参数: {}", deviceId);
+//        return true;
+//    }
+//
+//    @Override
+//    public boolean updateDeviceAlarmSchedule(String deviceId, Map<String, Object> alarmSchedule) {
+//        log.info("更新设备告警计划: {}", deviceId);
+//        return true;
+//    }
+//
+//    @Override
+//    public boolean checkDeviceExists(String deviceId) {
+//        log.info("检查设备是否存在: {}", deviceId);
+//        return true;
+//    }
+//
+//    @Override
+//    public boolean isDeviceBound(String deviceId) {
+//        log.info("检查设备是否已绑定: {}", deviceId);
+//        return false;
+//    }
+//
+//    @Override
+//    public boolean isUserDevice(String deviceId, Long userId) {
+//        log.info("检查设备是否属于指定用户: {}, 用户: {}", deviceId, userId);
+//        return true;
+//    }
+//
+//    @Override
+//    public boolean bindDevice(String deviceId, Long userId) {
+//        log.info("绑定设备到用户: {}, 用户: {}", deviceId, userId);
+//        return true;
+//    }
+//
+//    @Override
+//    public boolean unbindDevice(String deviceId, Long userId) {
+//        log.info("解绑用户设备: {}, 用户: {}", deviceId, userId);
+//        return true;
+//    }
+//
+//    /**
+//     * 保存告警配置
+//     *
+//     * @param globalConfig 全局配置
+//     * @return 是否保存成功
+//     */
+//    @Override
+//    public boolean saveAlarmConfig(Map<String, Object> globalConfig) {
+//        log.info("保存告警配置: {}", globalConfig);
+//        return true;
+//    }
+//
+//    /**
+//     * 创建设备
+//     *
+//     * @param deviceId 设备ID
+//     * @param deviceInfo 设备信息
+//     * @return 创建的设备
+//     */
+//    @Override
+//    public Device createDevice(String deviceId, Map<String, Object> deviceInfo) {
+//        log.info("创建设备: {}, 信息: {}", deviceId, deviceInfo);
+//        Device device = new Device();
+//        device.setDevId(deviceId);
+//        return device;
+//    }
+//
+//    /**
+//     * 更新设备信息
+//     *
+//     * @param deviceId 设备ID
+//     * @param deviceInfo 设备信息
+//     * @return 是否更新成功
+//     */
+//    @Override
+//    public boolean updateDeviceInfo(String deviceId, Map<String, Object> deviceInfo) {
+//        log.info("更新设备信息: {}, 信息: {}", deviceId, deviceInfo);
+//        return true;
+//    }
+//
+//    /**
+//     * 更新告警状态
+//     *
+//     * @param deviceId 设备ID
+//     * @param eventId 事件ID
+//     * @param status 状态
+//     * @return 是否更新成功
+//     */
+//    @Override
+//    public boolean updateAlarmStatus(String deviceId, Long eventId, int status) {
+//        log.info("更新告警状态: 设备={}, 事件={}, 状态={}", deviceId, eventId, status);
+//        return true;
+//    }
+//
+//    /**
+//     * 记录跌倒事件
+//     *
+//     * @param deviceId 设备ID
+//     * @param pose 姿态
+//     * @param targetPoint 目标点
+//     * @return 事件ID
+//     */
+//    @Override
+//    public Long recordFallEvent(String deviceId, int pose, List<Float> targetPoint) {
+//        log.info("记录跌倒事件: 设备={}, 姿态={}", deviceId, pose);
+//        return 1L;
+//    }
+//
+//    /**
+//     * 记录事件
+//     *
+//     * @param deviceId 设备ID
+//     * @param event 事件类型
+//     * @param pose 姿态
+//     * @param targetPoint 目标点
+//     * @return 是否记录成功
+//     */
+//    @Override
+//    public boolean recordEvent(String deviceId, String event, Integer pose, List<Float> targetPoint) {
+//        return recordEvent(deviceId, event, pose, targetPoint, System.currentTimeMillis());
+//    }
+//
+//    /**
+//     * 记录存在事件
+//     *
+//     * @param deviceId 设备ID
+//     * @param event 事件类型
+//     * @return 是否记录成功
+//     */
+//    @Override
+//    public boolean recordExistEvent(String deviceId, String event) {
+//        return recordExistEvent(deviceId, event, System.currentTimeMillis());
+//    }
+//
+//    /**
+//     * 记录告警事件
+//     *
+//     * @param deviceId 设备ID
+//     * @param desc 描述
+//     * @param table 表名
+//     * @param tableId 表ID
+//     * @return 是否记录成功
+//     */
+//    @Override
+//    public boolean recordAlarmEvent(String deviceId, String desc, String table, Integer tableId) {
+//        log.info("记录告警事件: 设备={}, 描述={}, 表={}, 表ID={}", deviceId, desc, table, tableId);
+//        return true;
+//    }
+//
+//    @Override
+//    public Device updateDevice(Device device) {
+//        log.info("更新设备: {}", device.getDevId());
+//        return device;
+//    }
+//
+//    @Override
+//    public List<Device> getAllDevices() {
+//        log.info("获取所有设备信息");
+//        return Collections.emptyList();
+//    }
+//
+//    @Override
+//    public Device getDeviceById(String deviceId) {
+//        log.info("根据ID获取设备: {}", deviceId);
+//        return null;
+//    }
+//
+//    @Override
+//    public HomeInfoDTO getHomeInfo(String homeId) {
+//        log.info("查询家庭信息: homeId={}", homeId);
+//        return new HomeInfoDTO();
+//    }
+//
+//    @Override
+//    public EventListDTO queryDeviceEvents(EventListParams params) {
+//        log.info("查询设备事件: {}", params);
+//        return new EventListDTO();
+//    }
+//
+//    @Override
+//    public boolean deviceReset(String deviceId) {
+//        log.info("重置设备: {}", deviceId);
+//        return true;
+//    }
+//
+//    @Override
+//    public boolean deviceReboot(String deviceId) {
+//        log.info("重启设备: {}", deviceId);
+//        return true;
+//    }
+//
+//    @Override
+//    public boolean recordBehaviorData(String deviceId, String dataType, Map<String, Object> data) {
+//        log.info("记录行为数据: deviceId={}, dataType={}", deviceId, dataType);
+//        return true;
+//    }
+//
+//    @Override
+//    public boolean recordRestBehavior(String deviceId, Long duration, List<Float> location, Long timestamp) {
+//        log.info("记录休息行为: deviceId={}, duration={}, timestamp={}", deviceId, duration, timestamp);
+//        return true;
+//    }
+//
+//    @Override
+//    public boolean recordAbnormalBehavior(String deviceId, String behaviorType, String description, Double confidence, Long timestamp) {
+//        log.info("记录异常行为: deviceId={}, type={}, desc={}, timestamp={}", deviceId, behaviorType, description, timestamp);
+//        return true;
+//    }
+//
+//    @Override
+//    public boolean recordNormalBehavior(String deviceId, Double confidence, Long timestamp) {
+//        log.info("记录正常行为: deviceId={}, confidence={}, timestamp={}", deviceId, confidence, timestamp);
+//        return true;
+//    }
+//
+//    @Override
+//    public boolean recordEvent(String deviceId, String event, Integer pose, List<Float> targetPoint, Long timestamp) {
+//        log.info("记录事件: deviceId={}, event={}, pose={}, timestamp={}", deviceId, event, pose, timestamp);
+//        return true;
+//    }
+//
+//    @Override
+//    public boolean recordAlarmEvent(String deviceId, String desc, String table, Integer tableId, Long timestamp) {
+//        log.info("记录告警事件: deviceId={}, desc={}, timestamp={}", deviceId, desc, timestamp);
+//        return true;
+//    }
+//
+//    @Override
+//    public boolean recordExistEvent(String deviceId, String event, Long timestamp) {
+//        log.info("记录存在事件: deviceId={}, event={}, timestamp={}", deviceId, event, timestamp);
+//        return true;
+//    }
+//
+//    @Override
+//    public boolean recordPointCloud(String deviceId, List<List<Float>> pointCloud, Long timestamp) {
+//        log.info("记录点云数据: deviceId={}, timestamp={}", deviceId, timestamp);
+//        return true;
+//    }
+//
+//    @Override
+//    public boolean recordRealtimePosition(String deviceId, Integer pose, List<List<Float>> positions, Long timestamp) {
+//        log.info("记录实时位置: deviceId={}, pose={}, timestamp={}", deviceId, pose, timestamp);
+//        return true;
+//    }
+//
+//    @Override
+//    public Map<String, Object> getDeviceStatus(String deviceId) {
+//        log.info("获取设备状态: deviceId={}", deviceId);
+//        return new HashMap<>();
+//    }
+//
+//    @Override
+//    public Map<String, Object> getDeviceParams(String deviceId) {
+//        log.info("获取设备参数: deviceId={}", deviceId);
+//        return new HashMap<>();
+//    }
+//
+//    @Override
+//    public boolean updateDeviceParams(String deviceId, Map<String, Object> params) {
+//        log.info("更新设备参数: deviceId={}", deviceId);
+//        return true;
+//    }
+//
+//    @Override
+//    public boolean recordActivityBehavior(String deviceId, Integer activityLevel, Long duration, Long timestamp) {
+//        log.info("记录活动行为: deviceId={}, activityLevel={}, duration={}, timestamp={}", deviceId, activityLevel, duration, timestamp);
+//        return true;
+//    }
+//
+//    @Override
+//    public PageRecord<DeviceDTO> queryDevices(DeviceListParams params) {
+//        log.info("查询设备列表: {}", params);
+//        return new PageRecord<>();
+//    }
+//
+//    @Override
+//    public boolean updateAlarmAckStatus(Long alarmId, Long userId) {
+//        log.info("更新告警确认状态: {}, 用户: {}", alarmId, userId);
+//        return true;
+//    }
+//
+//    @Override
+//    public List<Map<String, Object>> getUnacknowledgedAlarms(String deviceId) {
+//        log.info("获取设备未确认的告警: {}", deviceId);
+//        return Collections.emptyList();
+//    }
+//
+//    @Override
+//    public Long recordAlarmEventWithSeverity(String deviceId, String desc, String table, Integer severity, Long timestamp) {
+//        log.info("记录告警事件(带告警级别): {}, 描述: {}, 级别: {}", deviceId, desc, severity);
+//        // 返回模拟的告警ID
+//        return timestamp != null ? timestamp : System.currentTimeMillis();
+//    }
+//
+//    @Override
+//    public boolean saveRegion(Region region) {
+//        log.info("保存区域信息: {}", region.getName());
+//        return true;
+//    }
+//
+//    @Override
+//    public boolean updateRegion(Region region) {
+//        log.info("更新区域信息: {}", region.getId());
+//        return true;
+//    }
+//
+//    @Override
+//    public Region getRegionById(String regionId) {
+//        log.info("根据ID获取区域: {}", regionId);
+//        Region region = new Region();
+//        region.setId(regionId);
+//        region.setName("模拟区域");
+//        return region;
+//    }
+//
+//    @Override
+//    public List<Region> getRegionsByDeviceId(String deviceId) {
+//        log.info("获取设备的区域列表: {}", deviceId);
+//        return new ArrayList<>();
+//    }
+//
+//    @Override
+//    public boolean deleteRegion(String regionId) {
+//        log.info("删除区域: {}", regionId);
+//        return true;
+//    }
+//
+//    @Override
+//    public boolean deleteDevice(String deviceId) {
+//        log.info("删除设备: {}", deviceId);
+//        return true;
+//    }
+//}

+ 0 - 161
device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/gateway/impl/UserGatewayImpl.java

@@ -1,161 +0,0 @@
-package com.hfln.device.infrastructure.gateway.impl;
-
-import cn.hfln.framework.extension.BizException;
-import com.alibaba.fastjson2.JSONObject;
-import com.hfln.device.common.dto.data.user.UserDto;
-import com.hfln.device.common.request.user.LoginBySmsCodeParams;
-import com.hfln.device.common.request.user.UserLoginParams;
-import com.hfln.device.common.request.user.UserSignupParams;
-import com.hfln.device.common.request.user.UserUpdatePasswordParams;
-import com.hfln.device.domain.customer.util.PasswordUtil;
-import com.hfln.device.domain.exception.ErrorEnum;
-import com.hfln.device.domain.gateway.UserGateway;
-import com.hfln.device.infrastructure.mapper.UserInfoMapper;
-import com.hfln.device.infrastructure.po.UserInfo;
-import com.hfln.device.infrastructure.service.UserService;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.BeanUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-import org.springframework.stereotype.Service;
-import org.springframework.web.client.RestTemplate;
-
-import java.util.Objects;
-
-@Service
-@Slf4j
-public class UserGatewayImpl implements UserGateway {
-
-    @Autowired
-    private RestTemplate restTemplate;
-
-
-    @Autowired
-    private UserInfoMapper userInfoMapper;
-
-    @Autowired
-    private UserService userService;
-
-    @Value("${lnxx.wechat.appid}")
-    private String appid;
-
-    @Value("${lnxx.wechat.secret}")
-    private String secret;
-
-
-
-
-    public static String WXX_CX_ACCESS_TOKEN = "";
-
-    @Override
-    public String getOpenId(String code) {
-        if (StringUtils.isEmpty(code)) {
-            throw new BizException(ErrorEnum.WECHAT_CODE_ISNULL.getErrorCode(), ErrorEnum.WECHAT_CODE_ISNULL.getErrorMessage());
-        }
-        String url = String.format("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code", appid, secret, code);
-        try {
-            String res = restTemplate.getForObject(url, String.class);
-            JSONObject obj = JSONObject.parseObject(res);
-            return Objects.requireNonNull(obj).getString("openid");
-        } catch (Exception e) {
-            log.error("微信登录接口异常", e);
-            throw new BizException(ErrorEnum.WECHAT_INTERFACE_CALL_EXCEPTION.getErrorCode(), ErrorEnum.WECHAT_INTERFACE_CALL_EXCEPTION.getErrorMessage());
-        }
-    }
-
-    @Override
-    public Boolean signup(UserSignupParams request) {
-        //校验验证码
-
-        return true;
-    }
-
-
-    @Override
-    public Boolean checkOpenId(String openId) {
-        return userService.checkOpenId(openId);
-    }
-
-    @Override
-    public UserDto loginBySmsCode(LoginBySmsCodeParams request) {
-
-        return null;
-    }
-
-
-    @Override
-    public UserDto loginByPassword(UserLoginParams request) {
-        UserDto userDto = new UserDto();
-        UserInfo user = userService.checkUserByPassword(request.getUserName(), request.getPassword());
-        if (Objects.isNull(user)) {
-            throw new BizException(ErrorEnum.USERNAME_OR_PASSWORD_ERROR.getErrorCode(), ErrorEnum.USERNAME_OR_PASSWORD_ERROR.getErrorMessage());
-        }
-        BeanUtils.copyProperties(user, userDto);
-        userDto.setUserId(user.getUserInfoId());
-        return userDto;
-    }
-
-
-    @Override
-    public String getUserPhone(String code) {
-        if (StringUtils.isEmpty(code)) {
-            throw new BizException(ErrorEnum.WECHAT_CODE_ISNULL.getErrorCode(), ErrorEnum.WECHAT_CODE_ISNULL.getErrorMessage());
-        }
-        try {
-            String url = String.format("https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=%s", WXX_CX_ACCESS_TOKEN);
-
-            // 构建请求体
-            JSONObject param = new JSONObject();
-            param.put("code", code);
-
-            HttpHeaders headers = new HttpHeaders();
-            headers.setContentType(MediaType.APPLICATION_JSON);
-            HttpEntity<String> request = new HttpEntity<>(param.toJSONString(), headers);
-
-            // 发起请求
-            String response = restTemplate.postForObject(url, request, String.class);
-            JSONObject json = JSONObject.parseObject(response);
-
-            // 判断微信返回是否成功
-            if (Objects.requireNonNull(json).getIntValue("errcode") == 0) {
-                return json.getJSONObject("phone_info").getString("phoneNumber");
-            } else {
-                log.error("获取手机号失败,微信返回:{}", json.toJSONString());
-                throw new BizException(ErrorEnum.WECHAT_INTERFACE_CALL_EXCEPTION.getErrorCode(), ErrorEnum.WECHAT_INTERFACE_CALL_EXCEPTION.getErrorMessage());
-            }
-        } catch (Exception e) {
-            log.error("调用微信接口异常", e);
-            throw new BizException(ErrorEnum.WECHAT_INTERFACE_CALL_EXCEPTION.getErrorCode(), ErrorEnum.WECHAT_INTERFACE_CALL_EXCEPTION.getErrorMessage());
-        }
-    }
-
-    @Override
-    // @MqttSubscribes(value = {})
-    public void test() {
-//        mqttPublisher.send("test", "test1");
-    }
-
-
-    @Override
-    public void updatePassword(UserUpdatePasswordParams request) {
-        if (request.getNewPassword().equals(request.getOldPassword())) {
-            throw new BizException(ErrorEnum.PASSWORD_IS_REPEAT.getErrorCode(), ErrorEnum.PASSWORD_IS_REPEAT.getErrorMessage());
-        }
-
-        UserInfo userInfo = userService.getById(request.getUserId());
-        if (Objects.isNull(userInfo)) {
-            throw new BizException(ErrorEnum.USER_IS_NOT_EXIST.getErrorCode(), ErrorEnum.USER_IS_NOT_EXIST.getErrorMessage());
-        }
-        if (!PasswordUtil.matches(request.getOldPassword(), userInfo.getPassword())) {
-            throw new BizException(ErrorEnum.OLD_PASSWORD_ERROR.getErrorCode(), ErrorEnum.OLD_PASSWORD_ERROR.getErrorMessage());
-        }
-        UserInfo info = new UserInfo();
-        info.setUserInfoId(request.getUserId());
-        info.setPassword(request.getNewPassword());
-        userService.updateById(userInfo);
-    }
-}

+ 0 - 29
device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/gateway/impl/sms/SmsGatewayImpl.java

@@ -1,29 +0,0 @@
-package com.hfln.device.infrastructure.gateway.impl.sms;
-
-import com.hfln.device.domain.customer.util.MsgClient;
-import com.hfln.device.domain.gateway.sms.SmsGateway;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-
-@Service
-public class SmsGatewayImpl implements SmsGateway {
-
-
-    @Autowired
-    private MsgClient msgClient;
-
-
-    @Override
-    public Boolean sendLoginSmsCode(String phone) {
-        return true;
-    }
-
-    @Override
-    public Boolean sendSignupSmsCode(String phone) {
-
-        return false;
-    }
-
-
-}

+ 1 - 1
device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/mqtt/handler/AppMessageHandler.java

@@ -35,7 +35,7 @@ import java.util.Optional;
  * @author 设备接入服务
  * @version 1.0
  */
-@Component
+//@Component
 @Slf4j
 public class AppMessageHandler {
     

+ 94 - 58
device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/mqtt/handler/DeviceMessageHandler.java

@@ -3,6 +3,7 @@ package com.hfln.device.infrastructure.mqtt.handler;
 import com.hfln.device.common.util.JsonUtil;
 import com.hfln.device.domain.port.DeviceEventPort;
 import com.hfln.device.domain.service.DeviceManagerService;
+import com.hfln.device.infrastructure.config.TopicDealExecutor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
@@ -12,6 +13,7 @@ import org.springframework.stereotype.Component;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.RejectedExecutionException;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
@@ -51,6 +53,9 @@ public class DeviceMessageHandler {
     @Autowired
     private DeviceManagerService deviceManagerService;
 
+    @Autowired
+    private TopicDealExecutor topicDealExecutor;
+
     /**
      * MQTT消息统一入口处理方法
      * 
@@ -76,45 +81,23 @@ public class DeviceMessageHandler {
 
             // 根据主题路由到不同的处理方法
             // 提取主题的操作部分(最后一段)
-            String action = extractActionFromTopic(topic);
-            if (action != null) {
-                switch (action) {
-                    case "login":
-                        handleDeviceLogin(topic, payload);
-                        break;
-                    case "keepalive":
-                        handleDeviceKeepAlive(topic, payload);
-                        break;
-                    case "report_device_info":
-                        handleDeviceReportDeviceInfo(topic, payload);
-                        break;
-                    case "report_device_param":
-                        handleDeviceReportDeviceParam(topic, payload);
-                        break;
-                    case "dsp_data":
-                        handleDeviceDspData(topic, payload);
-                        break;
-                    case "cloudpoint":
-                        handleDeviceCloudPoint(topic, payload);
-                        break;
-                    case "report_falling_event":
-                        handleDeviceReportFallEvent(topic, payload);
-                        break;
-                    case "report_presence_event":
-                        handleDeviceReportPresenceEvent(topic, payload);
-                        break;
-                    case "set_debug_param":
-                        handleSetDebugParam(topic, payload);
-                        break;
-                    case "get_debug_param":
-                        handleGetDebugParam(topic, payload);
-                        break;
-                    default:
-                        log.debug("Unhandled device topic action: {} for topic: {}", action, topic);
-                        break;
+            String[] parts = topic.split("/");
+            String action = parts[parts.length - 1];
+            String devId = parts[parts.length - 2];
+
+            try {
+
+                topicDealExecutor.submitTask(devId, () -> this.handleMessage(action, topic, payload));
+            } catch (RejectedExecutionException e) {
+
+                log.error("Rejected execution message, devId:{}, topic:{}", devId, topic, e);
+                try {
+                    this.handleMessage(action, topic, payload);
+                } catch (Exception ex) {
+                    log.error("Error handling message", ex);
                 }
-            } else {
-                log.debug("Could not extract action from device topic: {}", topic);
+            } catch (Exception e) {
+                log.error("Error handling message, devId:{}, topic:{}", devId, topic, e);
             }
 
         } catch (Exception e) {
@@ -122,6 +105,59 @@ public class DeviceMessageHandler {
         }
     }
 
+    private void handleMessage(String action, String topic, String payload) {
+
+        if (action != null) {
+            switch (action) {
+                case "login":
+                    handleDeviceLogin(topic, payload);
+                    break;
+                case "keepalive":
+                    handleDeviceKeepAlive(topic, payload);
+                    break;
+                case "report_device_info":
+                    handleDeviceReportDeviceInfo(topic, payload);
+                    break;
+                case "report_device_param":
+                    handleDeviceReportDeviceParam(topic, payload);
+                    break;
+                case "dsp_data":
+                    handleDeviceDspData(topic, payload);
+                    break;
+
+                case "disconnect":
+                    handleDeviceDisconnect(topic, payload);
+                    break;
+                default:
+                    log.debug("Unhandled device topic action: {} for topic: {}", action, topic);
+                    break;
+            }
+        } else {
+            log.debug("Could not extract action from device topic: {}", topic);
+        }
+    }
+
+    private void handleDeviceDisconnect(String topic, String payload) {
+        try {
+            log.info("Processing device login message: {}", topic);
+
+            Map<String, Object> messageData = JsonUtil.parseMap(payload);
+            String deviceId = (String) messageData.get("dev_id");
+
+            if (deviceId == null) {
+                log.warn("Invalid device login message, missing device_info: {}", payload);
+                return;
+            }
+
+            // 委托给应用层服务处理
+            // 应用层将处理:设备认证、状态更新、缓存刷新、响应发送
+            deviceEventPort.handleDeviceDisconnect(deviceId, messageData);
+
+        } catch (Exception e) {
+            log.error("Error handling device login: {}", e.getMessage(), e);
+        }
+    }
+
     /**
      * 处理设备登录消息
      * Python对应方法:deal_dev_login
@@ -540,7 +576,7 @@ public class DeviceMessageHandler {
             
             // === 设备验证 (对应Python: with g_dev_map_lock: if dev_id not in g_dev_map) ===
             // 未注册的设备,不处理
-            if (!deviceManagerService.getDeviceFromCache(deviceId).isPresent()) {
+            if (!deviceManagerService.existInCache(deviceId)) {
                 log.debug("error, device not registed: {}", deviceId); // 对应Python: LOGDBG(f"error, device not registed: {dev_id}")
                 return;
             }
@@ -564,25 +600,25 @@ public class DeviceMessageHandler {
             log.info("Device {} presence event: type={}, event={}, time={}", 
                     deviceId, type, event, timestamp);
             
-            // 根据事件类型进行不同的处理
-            switch (event) {
-                case "presence_detected":
-                    log.info("Person entered monitoring area of device {}", deviceId);
-                    break;
-                case "presence_lost":
-                    log.info("Person left monitoring area of device {}", deviceId);
-                    break;
-                case "motion_detected":
-                    log.debug("Motion detected by device {}", deviceId);
-                    break;
-                case "motion_stopped":
-                    log.debug("Motion stopped at device {}", deviceId);
-                    break;
-                default:
-                    log.debug("Unknown presence event: {} from device {}", event, deviceId);
-                    break;
-            }
-            
+//            // 根据事件类型进行不同的处理
+//            switch (event) {
+//                case "presence_detected":
+//                    log.info("Person entered monitoring area of device {}", deviceId);
+//                    break;
+//                case "presence_lost":
+//                    log.info("Person left monitoring area of device {}", deviceId);
+//                    break;
+//                case "motion_detected":
+//                    log.debug("Motion detected by device {}", deviceId);
+//                    break;
+//                case "motion_stopped":
+//                    log.debug("Motion stopped at device {}", deviceId);
+//                    break;
+//                default:
+//                    log.debug("Unknown presence event: {} from device {}", event, deviceId);
+//                    break;
+//            }
+//
             // === 委托给应用层服务处理 (对应Python: mqtt_send.exist_msg(dev_id=dev_id, event=event)) ===
             // 应用层将进行设备验证,并处理:状态更新、活动统计、模式分析、异常检测,发送存在事件消息
             deviceEventPort.handleExistEvent(deviceId, timestamp, type, event);

+ 30 - 0
device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/mqtt/handler/ExecutorTest.java

@@ -0,0 +1,30 @@
+package com.hfln.device.infrastructure.mqtt.handler;
+
+
+import com.hfln.device.infrastructure.config.TopicDealExecutor;
+
+import java.time.LocalDateTime;
+
+public class ExecutorTest {
+
+    public static void main(String[] args) {
+
+        TopicDealExecutor executor = new TopicDealExecutor();
+
+        for (int i = 0; i < 100; i++) {
+
+            int key = (int) (10 * Math.random());
+            executor.submitTask(key, () -> {
+
+                Thread thread = Thread.currentThread();
+                System.out.println("key = " + key + " thread = " + thread.getName() + " time = " + LocalDateTime.now());
+                Thread.sleep(50000);
+            });
+        }
+
+        System.out.println("main thread end , time = " + LocalDateTime.now());
+        executor.close();
+        System.out.println("main thread executor end , time = " + LocalDateTime.now());
+
+    }
+}

+ 26 - 24
device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/mqtt/handler/MpsMessageHandler.java

@@ -94,6 +94,7 @@ public class MpsMessageHandler {
                 handleDeviceReboot(topic, payload);
             } else {
                 switch (topic) {
+                    // todo 待确定是否废弃
                     case MqttTopics.MPS_GET_DEV_INFO:
                         handleGetDeviceInfo(topic, payload);
                         break;
@@ -103,6 +104,7 @@ public class MpsMessageHandler {
                     case MqttTopics.MPS_SET_DEV_PARAM:
                         handleSetDeviceParam(topic, payload);
                         break;
+                        // todo 待确定 添加删除 逻辑
                     case MqttTopics.MPS_ADD_DEVICE:
                         handleAddDevice(topic, payload);
                         break;
@@ -289,12 +291,12 @@ public class MpsMessageHandler {
             log.info("Processing set device param request: {}, payload: {}", devId, payload);
             
             // 获取操作者信息用于审计
-            String operatorId = (String) messageData.get("operator_id");
-            String operatorType = (String) messageData.get("operator_type");
-            String operationReason = (String) messageData.get("reason");
-            
-            log.info("Device parameters being set by: {} ({}), target device: {}, reason: {}", 
-                    operatorId, operatorType, devId, operationReason);
+//            String operatorId = (String) messageData.get("operator_id");
+//            String operatorType = (String) messageData.get("operator_type");
+//            String operationReason = (String) messageData.get("reason");
+//
+//            log.info("Device parameters being set by: {} ({}), target device: {}, reason: {}",
+//                    operatorId, operatorType, devId, operationReason);
             
             // 参数合理性验证
             Float heightValue = height.floatValue();
@@ -341,7 +343,7 @@ public class MpsMessageHandler {
             // 应用层将处理:设备通信、配置下发、确认等待、数据库更新、审计记录
             deviceCommandService.handleSetDeviceParam(devId, mountingPlain, areaStr, heightValue);
             
-            log.info("Device parameter setting request submitted by operator {}: {}", operatorId, devId);
+//            log.info("Device parameter setting request submitted by operator {}: {}", operatorId, devId);
             
         } catch (Exception e) {
             log.error("Error handling set device param request: {}", e.getMessage(), e);
@@ -391,23 +393,23 @@ public class MpsMessageHandler {
             String devId = matcher.group(1);
             log.warn("CRITICAL: Processing device reboot request for: {}", devId);
             
-            // 解析重启请求信息
-            Map<String, Object> messageData = JsonUtil.parseMap(payload);
-            String operatorId = (String) messageData.get("operator_id");
-            String operatorType = (String) messageData.get("operator_type");
-            String rebootReason = (String) messageData.get("reason");
-            String emergencyLevel = (String) messageData.get("emergency_level");
-            
-            // 记录重要的重启操作
-            log.warn("DEVICE REBOOT INITIATED - Device: {}, Operator: {} ({}), Reason: {}, Emergency Level: {}", 
-                    devId, operatorId, operatorType, rebootReason, emergencyLevel);
-            
-            // 验证重启权限(高风险操作)
-            if (!"admin".equals(operatorType) && !"technician".equals(operatorType)) {
-                log.error("UNAUTHORIZED REBOOT ATTEMPT - Device: {}, Operator: {} ({})", 
-                         devId, operatorId, operatorType);
-                return;
-            }
+//            // 解析重启请求信息
+//            Map<String, Object> messageData = JsonUtil.parseMap(payload);
+//            String operatorId = (String) messageData.get("operator_id");
+//            String operatorType = (String) messageData.get("operator_type");
+//            String rebootReason = (String) messageData.get("reason");
+//            String emergencyLevel = (String) messageData.get("emergency_level");
+//
+//            // 记录重要的重启操作
+//            log.warn("DEVICE REBOOT INITIATED - Device: {}, Operator: {} ({}), Reason: {}, Emergency Level: {}",
+//                    devId, operatorId, operatorType, rebootReason, emergencyLevel);
+//
+//            // 验证重启权限(高风险操作)
+//            if (!"admin".equals(operatorType) && !"technician".equals(operatorType)) {
+//                log.error("UNAUTHORIZED REBOOT ATTEMPT - Device: {}, Operator: {} ({})",
+//                         devId, operatorId, operatorType);
+//                return;
+//            }
             
             // 记录重启前的设备状态用于审计
             log.info("Recording device state before reboot: {}", devId);

+ 7 - 22
device-service-infrastructure/src/main/java/com/hfln/device/infrastructure/po/DevInfo.java

@@ -47,9 +47,16 @@ public class DevInfo extends BasePO {
     /**
      * 在线状态:0-离线,1-在线
      */
+    @TableField("online")
     private Integer online;
 
     /**
+     * 设备离线时间
+     */
+    @TableField("offline_time")
+    private LocalDateTime offlineTime;
+
+    /**
      * 设备报警:0-正常,1-报警
      */
     @TableField("dev_warn")
@@ -146,18 +153,6 @@ public class DevInfo extends BasePO {
     private BigDecimal width;
 
     /**
-     * target数组
-     */
-    @TableField("target_points")
-    private Object targetPoints;
-
-    /**
-     * 接收target时间
-     */
-    @TableField("signal_time")
-    private LocalDateTime signalTime;
-
-    /**
      * 北向夹角
      */
     @TableField("north_angle")
@@ -180,12 +175,6 @@ public class DevInfo extends BasePO {
      */
     @TableField("status_light")
     private Integer statusLight;
-    
-    /**
-     * 设备保活时间戳(毫秒)
-     */
-//    @TableField("keepalive_time")
-//    private Long keepaliveTime;
 
     /**
      * 设备信息常量类
@@ -255,8 +244,6 @@ public class DevInfo extends BasePO {
     public java.math.BigDecimal getStopZ() { return this.stopZ; }
     public java.math.BigDecimal getLength() { return this.length; }
     public java.math.BigDecimal getWidth() { return this.width; }
-    public Object getTargetPoints() { return this.targetPoints; }
-    public java.time.LocalDateTime getSignalTime() { return this.signalTime; }
     public java.math.BigDecimal getNorthAngle() { return this.northAngle; }
     public Integer getStatusLight() { return this.statusLight; }
     public void setHeight(java.math.BigDecimal height) { this.height = height; }
@@ -270,8 +257,6 @@ public class DevInfo extends BasePO {
     public void setStopZ(java.math.BigDecimal stopZ) { this.stopZ = stopZ; }
     public void setLength(java.math.BigDecimal length) { this.length = length; }
     public void setWidth(java.math.BigDecimal width) { this.width = width; }
-    public void setTargetPoints(Object targetPoints) { this.targetPoints = targetPoints; }
-    public void setSignalTime(java.time.LocalDateTime signalTime) { this.signalTime = signalTime; }
     public void setNorthAngle(java.math.BigDecimal northAngle) { this.northAngle = northAngle; }
     public void setStatusLight(Integer statusLight) { this.statusLight = statusLight; }
 }

+ 0 - 16
device-service-server/src/main/resources/bootstrap-local.yml

@@ -1,6 +1,4 @@
 spring:
-  config:
-    import: "optional:nacos:"
   cloud:
     nacos:
       discovery:
@@ -43,20 +41,6 @@ lnxx:
       basePackage: com.hfln.device.application.controller
       title: DEVICE-SERVICE-SERVER
       description: 设备服务
-  # 微信小程序
-  wechat:
-    appid: wx60b2cd643b46d5eb
-    secret: 15ebd7bed7b73d806eba2944f4e07592
-  # 短信验证码相关
-  sms:
-    tencent:
-      secretId: AKID40jFYdUCqMqFUXO2SecOvKYYKsGRP9rT
-      secretKey: Y3RcbMtO0V0bI2gzFShpocHjy1qSq0xf
-      loginId: 2368397
-      registerId: 2368393
-      notifyId: 2368474
-      region: ap-guangzhou
-      sdkAppId: 1400966707
 
 
 mqtt:

+ 1 - 1
device-service-server/src/main/resources/bootstrap.yml

@@ -7,7 +7,7 @@ spring:
     pathmatch:
       matching-strategy: ant_path_matcher
   profiles:
-    active: test
+    active: local
   application:
     name: device-service-server
 

+ 5 - 0
pom.xml

@@ -68,6 +68,11 @@
             </dependency>
             <dependency>
                 <groupId>cn.hfln.framework</groupId>
+                <artifactId>redis-spring-boot-starter</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>cn.hfln.framework</groupId>
                 <artifactId>knife4j-doc-spring-boot-starter</artifactId>
                 <version>${project.version}</version>
             </dependency>