diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java index 1e783e86..7e1286c5 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java @@ -104,7 +104,21 @@ public class Device { * 心跳间隔 */ @Schema(description = "心跳间隔") - private int keepaliveIntervalTime; + private Integer heartBeatInterval; + + + /** + * 心跳超时次数 + */ + @Schema(description = "心跳超时次数") + private Integer heartBeatCount; + + + /** + * 定位功能支持情况 + */ + @Schema(description = "定位功能支持情况。取值:0-不支持;1-支持 GPS定位;2-支持北斗定位(可选,默认取值为0") + private Integer positionCapability; /** * 通道个数 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceConfig.java b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceConfig.java index f6e7ddcb..d3b40e81 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceConfig.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceConfig.java @@ -65,7 +65,7 @@ public class DeviceConfig { @Parameter(name = "heartBeatInterval", description = "心跳间隔") @Parameter(name = "heartBeatCount", description = "心跳计数") public DeferredResult homePositionApi(@PathVariable String deviceId, - String channelId, + @RequestParam(required = false) String channelId, @RequestParam(required = false) String name, @RequestParam(required = false) String expiration, @RequestParam(required = false) String heartBeatInterval, @@ -124,7 +124,7 @@ public class DeviceConfig { if (log.isDebugEnabled()) { log.debug("设备状态查询API调用"); } - String key = DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (ObjectUtils.isEmpty(channelId) ? deviceId : channelId); + String key = DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (ObjectUtils.isEmpty(channelId) ? deviceId : deviceId + channelId); String uuid = UUID.randomUUID().toString(); Device device = deviceService.getDeviceByDeviceId(deviceId); try { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/DeviceMapper.java b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/DeviceMapper.java index 3f50e435..145469b7 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/DeviceMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/DeviceMapper.java @@ -66,7 +66,9 @@ public interface DeviceMapper { "expires," + "register_time," + "keepalive_time," + - "keepalive_interval_time," + + "heart_beat_interval," + + "heart_beat_count," + + "position_capability," + "create_time," + "update_time," + "charset," + @@ -96,7 +98,9 @@ public interface DeviceMapper { "#{expires}," + "#{registerTime}," + "#{keepaliveTime}," + - "#{keepaliveIntervalTime}," + + "#{heartBeatInterval}," + + "#{heartBeatCount}," + + "#{positionCapability}," + "#{createTime}," + "#{updateTime}," + "#{charset}," + @@ -128,7 +132,9 @@ public interface DeviceMapper { ", on_line=#{onLine}" + ", register_time=#{registerTime}" + ", keepalive_time=#{keepaliveTime}" + - ", keepalive_interval_time=#{keepaliveIntervalTime}" + + ", heart_beat_interval=#{heartBeatInterval}" + + ", position_capability=#{positionCapability}" + + ", heart_beat_count=#{heartBeatCount}" + ", expires=#{expires}" + "WHERE device_id=#{deviceId}"+ " "}) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IDeviceService.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IDeviceService.java index 09a86179..33f5e524 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IDeviceService.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IDeviceService.java @@ -166,4 +166,5 @@ public interface IDeviceService { void subscribeMobilePosition(int id, int cycle, int interval); + void updateDeviceHeartInfo(Device device); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceServiceImpl.java index 17dadef1..43087b54 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceServiceImpl.java @@ -41,6 +41,7 @@ import javax.sip.SipException; import java.text.ParseException; import java.time.Instant; import java.util.List; +import java.util.Objects; import java.util.concurrent.TimeUnit; /** @@ -110,9 +111,12 @@ public class DeviceServiceImpl implements IDeviceService { } device.setUpdateTime(now); device.setKeepaliveTime(now); - if (device.getKeepaliveIntervalTime() == 0) { - // 默认心跳间隔60 - device.setKeepaliveIntervalTime(60); + if (device.getHeartBeatCount() == null) { + // 读取设备配置, 获取心跳间隔和心跳超时次数, 在次之前暂时设置为默认值 + device.setHeartBeatCount(3); + device.setHeartBeatInterval(60); + device.setPositionCapability(0); + } if (sipTransactionInfo != null) { device.setSipTransactionInfo(sipTransactionInfo); @@ -132,6 +136,7 @@ public class DeviceServiceImpl implements IDeviceService { redisCatchStorage.updateDevice(device); try { commander.deviceInfoQuery(device); + commander.deviceConfigQuery(device, null, "BasicParam", null); } catch (InvalidArgumentException | SipException | ParseException e) { log.error("[命令发送失败] 查询设备信息: {}", e.getMessage()); } @@ -178,18 +183,8 @@ public class DeviceServiceImpl implements IDeviceService { // 刷新过期任务 String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + device.getDeviceId(); // 如果第一次注册那么必须在60 * 3时间内收到一个心跳,否则设备离线 - dynamicTask.startDelay(registerExpireTaskKey, ()-> offline(device.getDeviceId(), "首次注册后未能收到心跳"), device.getKeepaliveIntervalTime() * 1000 * 3); - -// -// try { -// cmder.alarmSubscribe(device, 600, "0", "4", "0", "2023-7-27T00:00:00", "2023-7-28T00:00:00"); -// } catch (InvalidArgumentException e) { -// throw new RuntimeException(e); -// } catch (SipException e) { -// throw new RuntimeException(e); -// } catch (ParseException e) { -// throw new RuntimeException(e); -// } + dynamicTask.startDelay(registerExpireTaskKey, ()-> offline(device.getDeviceId(), "三次心跳超时"), + device.getHeartBeatInterval() * 1000 * device.getHeartBeatCount()); } @@ -202,7 +197,7 @@ public class DeviceServiceImpl implements IDeviceService { return; } log.info("[设备离线] device:{}, 当前心跳间隔: {}, 上次心跳时间:{}, 上次注册时间: {}", deviceId, - device.getKeepaliveIntervalTime(), device.getKeepaliveTime(), device.getRegisterTime()); + device.getHeartBeatInterval(), device.getKeepaliveTime(), device.getRegisterTime()); String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + deviceId; dynamicTask.stop(registerExpireTaskKey); if (device.isOnLine()) { @@ -588,4 +583,24 @@ public class DeviceServiceImpl implements IDeviceService { redisCatchStorage.updateDevice(device); } } + + @Override + public void updateDeviceHeartInfo(Device device) { + Device deviceInDb = deviceMapper.query(device.getId()); + if (deviceInDb == null) { + return; + } + if (!Objects.equals(deviceInDb.getHeartBeatCount(), device.getHeartBeatCount()) + || !Objects.equals(deviceInDb.getHeartBeatInterval(), device.getHeartBeatInterval())) { + // 刷新过期任务 + String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + device.getDeviceId(); + // 如果第一次注册那么必须在60 * 3时间内收到一个心跳,否则设备离线 + dynamicTask.startDelay(registerExpireTaskKey, ()-> offline(device.getDeviceId(), "三次心跳超时"), + device.getHeartBeatInterval() * 1000 * device.getHeartBeatCount()); + deviceInDb.setHeartBeatCount(device.getHeartBeatCount()); + deviceInDb.setHeartBeatInterval(device.getHeartBeatInterval()); + deviceInDb.setPositionCapability(device.getPositionCapability()); + updateDevice(deviceInDb); + } + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java index 3232cae2..04d6a0ca 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java @@ -3,16 +3,18 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.conf.DynamicTask; import com.genersoft.iot.vmp.conf.UserSetting; -import com.genersoft.iot.vmp.gb28181.bean.*; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.Platform; +import com.genersoft.iot.vmp.gb28181.bean.RemoteAddressInfo; +import com.genersoft.iot.vmp.gb28181.bean.SipMsgInfo; +import com.genersoft.iot.vmp.gb28181.service.IDeviceService; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler; import com.genersoft.iot.vmp.gb28181.utils.SipUtils; -import com.genersoft.iot.vmp.gb28181.service.IDeviceService; import com.genersoft.iot.vmp.utils.DateUtil; import gov.nist.javax.sip.message.SIPRequest; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.ObjectUtils; import org.dom4j.Element; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; @@ -95,10 +97,10 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp } Device device = sipMsgInfo.getDevice(); SIPRequest request = (SIPRequest) evt.getRequest(); - if (!ObjectUtils.isEmpty(device.getKeepaliveTime()) && DateUtil.getDifferenceForNow(device.getKeepaliveTime()) <= 3000L) { - log.info("[收到心跳] 心跳发送过于频繁,已忽略 device: {}, callId: {}", device.getDeviceId(), request.getCallIdHeader().getCallId()); - return; - } +// if (!ObjectUtils.isEmpty(device.getKeepaliveTime()) && DateUtil.getDifferenceForNow(device.getKeepaliveTime()) <= 3000L) { +// log.info("[收到心跳] 心跳发送过于频繁,已忽略 device: {}, callId: {}", device.getDeviceId(), request.getCallIdHeader().getCallId()); +// return; +// } RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request, userSetting.getSipUseSourceIpAsRemoteAddress()); if (!device.getIp().equalsIgnoreCase(remoteAddressInfo.getIp()) || device.getPort() != remoteAddressInfo.getPort()) { @@ -114,14 +116,6 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp }); } } - if (device.getKeepaliveTime() == null) { - device.setKeepaliveIntervalTime(60); - } else { - long lastTime = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(device.getKeepaliveTime()); - if (System.currentTimeMillis() / 1000 - lastTime > 10) { - device.setKeepaliveIntervalTime(Long.valueOf(System.currentTimeMillis() / 1000 - lastTime).intValue()); - } - } device.setKeepaliveTime(DateUtil.getNow()); @@ -138,7 +132,8 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp // 刷新过期任务 String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + device.getDeviceId(); // 如果三次心跳失败,则设置设备离线 - dynamicTask.startDelay(registerExpireTaskKey, () -> deviceService.offline(device.getDeviceId(), "三次心跳失败"), device.getKeepaliveIntervalTime() * 1000 * 3); + dynamicTask.startDelay(registerExpireTaskKey, () -> deviceService.offline(device.getDeviceId(), "三次心跳超时"), + device.getHeartBeatInterval() * 1000 * device.getHeartBeatCount()); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/ConfigDownloadResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/ConfigDownloadResponseMessageHandler.java index ed2c8b0a..d124f236 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/ConfigDownloadResponseMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/ConfigDownloadResponseMessageHandler.java @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.respon import com.alibaba.fastjson2.JSONObject; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Platform; +import com.genersoft.iot.vmp.gb28181.service.IDeviceService; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; @@ -36,6 +37,9 @@ public class ConfigDownloadResponseMessageHandler extends SIPRequestProcessorPar @Autowired private DeferredResultHolder deferredResultHolder; + @Autowired + private IDeviceService deviceService; + @Override public void afterPropertiesSet() throws Exception { responseMessageHandler.addHandler(cmdType, this); @@ -45,7 +49,12 @@ public class ConfigDownloadResponseMessageHandler extends SIPRequestProcessorPar @Override public void handForDevice(RequestEvent evt, Device device, Element element) { String channelId = getText(element, "DeviceID"); - String key = DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + device.getDeviceId() + channelId; + String key; + if (device.getDeviceId().equals(channelId)) { + key = DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + device.getDeviceId(); + }else { + key = DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + device.getDeviceId() + channelId; + } try { // 回复200 OK responseAck((SIPRequest) evt.getRequest(), Response.OK); @@ -58,6 +67,18 @@ public class ConfigDownloadResponseMessageHandler extends SIPRequestProcessorPar if (log.isDebugEnabled()) { log.debug(json.toJSONString()); } + JSONObject basicParam = json.getJSONObject("BasicParam"); + Integer heartBeatInterval = basicParam.getInteger("HeartBeatInterval"); + Integer heartBeatCount = basicParam.getInteger("HeartBeatCount"); + Integer positionCapability = basicParam.getInteger("PositionCapability"); + device.setHeartBeatInterval(heartBeatInterval); + device.setHeartBeatCount(heartBeatCount); + device.setPositionCapability(positionCapability); + + deviceService.updateDeviceHeartInfo(device); + + + RequestMessage msg = new RequestMessage(); msg.setKey(key); msg.setData(json); diff --git a/web_src/src/components/DeviceList.vue b/web_src/src/components/DeviceList.vue index f538b1ea..d3664d8b 100755 --- a/web_src/src/components/DeviceList.vue +++ b/web_src/src/components/DeviceList.vue @@ -95,6 +95,8 @@ 布防 撤防 + + 基础配置同步 @@ -355,6 +357,8 @@ export default { this.resetGuard(itemData) }else if (command === "delete") { this.deleteDevice(itemData) + }else if (command === "syncBasicParam") { + this.syncBasicParam(itemData) } }, setGuard: function (itemData) { @@ -462,6 +466,33 @@ export default { message: error.message }) }); + }, + syncBasicParam: function (data) { + console.log(data) + this.$axios({ + method: 'get', + url: `/api/device/config/query/${data.deviceId}/BasicParam`, + params: { + // channelId: data.deviceId + } + }).then( (res)=> { + if (res.data.code === 0) { + this.$message.success({ + showClose: true, + message: `配置已同步,当前心跳间隔: ${res.data.data.BasicParam.HeartBeatInterval} 心跳间隔:${res.data.data.BasicParam.HeartBeatCount}` + }) + }else { + this.$message.error({ + showClose: true, + message: res.data.msg + }) + } + }).catch( (error)=> { + this.$message.error({ + showClose: true, + message: error.message + }) + }); }, diff --git a/数据库/2.7.3/初始化-mysql-2.7.3.sql b/数据库/2.7.3/初始化-mysql-2.7.3.sql index c147fd9c..66b1006b 100644 --- a/数据库/2.7.3/初始化-mysql-2.7.3.sql +++ b/数据库/2.7.3/初始化-mysql-2.7.3.sql @@ -31,7 +31,9 @@ create table wvp_device local_ip character varying(50), password character varying(255), as_message_channel bool default false, - keepalive_interval_time integer, + heart_beat_interval integer, + heart_beat_count integer, + position_capability integer, broadcast_push_after_ack bool default false, constraint uk_device_device unique (device_id) ); diff --git a/数据库/2.7.3/初始化-postgresql-kingbase-2.7.3.sql b/数据库/2.7.3/初始化-postgresql-kingbase-2.7.3.sql index 0695e410..4bfcb4f0 100644 --- a/数据库/2.7.3/初始化-postgresql-kingbase-2.7.3.sql +++ b/数据库/2.7.3/初始化-postgresql-kingbase-2.7.3.sql @@ -31,7 +31,9 @@ create table wvp_device local_ip character varying(50), password character varying(255), as_message_channel bool default false, - keepalive_interval_time integer, + heart_beat_interval integer, + heart_beat_count integer, + position_capability integer, broadcast_push_after_ack bool default false, constraint uk_device_device unique (device_id) ); diff --git a/数据库/2.7.3/更新-mysql-2.7.3.sql b/数据库/2.7.3/更新-mysql-2.7.3.sql index 01f42da4..47bf4ca3 100644 --- a/数据库/2.7.3/更新-mysql-2.7.3.sql +++ b/数据库/2.7.3/更新-mysql-2.7.3.sql @@ -40,4 +40,11 @@ alter table wvp_stream_proxy add relates_media_server_id character varying(50); */ drop index uk_stream_push_app_stream_path on wvp_cloud_record; alter table wvp_cloud_record change folder folder varchar(500) null; -alter table wvp_cloud_record change file_path file_path varchar(500) null; \ No newline at end of file +alter table wvp_cloud_record change file_path file_path varchar(500) null; + +/* +* 20250211 +*/ +alter table wvp_device change keepalive_interval_time heart_beat_interval integer; +alter table wvp_device add heart_beat_count integer; +alter table wvp_device add position_capability integer; \ No newline at end of file diff --git a/数据库/2.7.3/更新-postgresql-kingbase-2.7.3.sql b/数据库/2.7.3/更新-postgresql-kingbase-2.7.3.sql index 8317bce7..0acf261b 100644 --- a/数据库/2.7.3/更新-postgresql-kingbase-2.7.3.sql +++ b/数据库/2.7.3/更新-postgresql-kingbase-2.7.3.sql @@ -39,4 +39,11 @@ alter table wvp_stream_proxy add relates_media_server_id character varying(50); */ drop index uk_stream_push_app_stream_path on wvp_cloud_record; alter table wvp_cloud_record change folder folder varchar(500) null; -alter table wvp_cloud_record change file_path file_path varchar(500) null; \ No newline at end of file +alter table wvp_cloud_record change file_path file_path varchar(500) null; + +/* +* 20250211 +*/ +alter table wvp_device change keepalive_interval_time heart_beat_interval integer; +alter table wvp_device add heart_beat_count integer; +alter table wvp_device add position_capability integer; \ No newline at end of file