LED屏管理
parent
35376801aa
commit
d9b6afdc80
File diff suppressed because one or more lines are too long
|
|
@ -45,9 +45,7 @@ public class SysLedscreen extends BaseEntity
|
||||||
@Excel(name = "高")
|
@Excel(name = "高")
|
||||||
private Long height;
|
private Long height;
|
||||||
|
|
||||||
/** 频率(秒) */
|
|
||||||
@Excel(name = "频率(秒)")
|
|
||||||
private Long frequency;
|
|
||||||
|
|
||||||
/** LED绘图模式 */
|
/** LED绘图模式 */
|
||||||
@Excel(name = "LED绘图模式")
|
@Excel(name = "LED绘图模式")
|
||||||
|
|
@ -151,15 +149,8 @@ public class SysLedscreen extends BaseEntity
|
||||||
{
|
{
|
||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
public void setFrequency(Long frequency)
|
|
||||||
{
|
|
||||||
this.frequency = frequency;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getFrequency()
|
|
||||||
{
|
|
||||||
return frequency;
|
|
||||||
}
|
|
||||||
public void setDrawType(Long drawType)
|
public void setDrawType(Long drawType)
|
||||||
{
|
{
|
||||||
this.drawType = drawType;
|
this.drawType = drawType;
|
||||||
|
|
@ -236,7 +227,6 @@ public class SysLedscreen extends BaseEntity
|
||||||
.append("deviceSn", getDeviceSn())
|
.append("deviceSn", getDeviceSn())
|
||||||
.append("width", getWidth())
|
.append("width", getWidth())
|
||||||
.append("height", getHeight())
|
.append("height", getHeight())
|
||||||
.append("frequency", getFrequency())
|
|
||||||
.append("drawType", getDrawType())
|
.append("drawType", getDrawType())
|
||||||
.append("title", getTitle())
|
.append("title", getTitle())
|
||||||
.append("enabled", getEnabled())
|
.append("enabled", getEnabled())
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
<result property="deviceSn" column="device_sn" />
|
<result property="deviceSn" column="device_sn" />
|
||||||
<result property="width" column="width" />
|
<result property="width" column="width" />
|
||||||
<result property="height" column="height" />
|
<result property="height" column="height" />
|
||||||
<result property="frequency" column="frequency" />
|
|
||||||
<result property="drawType" column="draw_type" />
|
<result property="drawType" column="draw_type" />
|
||||||
<result property="title" column="title" />
|
<result property="title" column="title" />
|
||||||
<result property="enabled" column="enabled" />
|
<result property="enabled" column="enabled" />
|
||||||
|
|
@ -29,7 +28,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<sql id="selectSysLedscreenVo">
|
<sql id="selectSysLedscreenVo">
|
||||||
select sl.id, sl.project_id, sl.workarea_id, sl.device_name, sl.device_sn, sl.width, sl.height, sl.frequency, sl.draw_type, sl.title, sl.enabled, sl.is_del, sl.state, sl.is_online, sl.remark, sl.create_by, sl.create_time, sl.update_by, sl.update_time, pi.project_name, wa.title as workarea_name
|
select sl.id, sl.project_id, sl.workarea_id, sl.device_name, sl.device_sn, sl.width, sl.height, sl.draw_type, sl.title, sl.enabled, sl.is_del, sl.state, sl.is_online, sl.remark, sl.create_by, sl.create_time, sl.update_by, sl.update_time, pi.project_name, wa.title as workarea_name
|
||||||
from sys_ledscreen sl
|
from sys_ledscreen sl
|
||||||
left join pro_project_info pi on sl.project_id = pi.id
|
left join pro_project_info pi on sl.project_id = pi.id
|
||||||
left join sys_work_area wa on sl.workarea_id = wa.id
|
left join sys_work_area wa on sl.workarea_id = wa.id
|
||||||
|
|
@ -44,7 +43,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
<if test="deviceSn != null and deviceSn != ''"> and sl.device_sn = #{deviceSn}</if>
|
<if test="deviceSn != null and deviceSn != ''"> and sl.device_sn = #{deviceSn}</if>
|
||||||
<if test="width != null "> and sl.width = #{width}</if>
|
<if test="width != null "> and sl.width = #{width}</if>
|
||||||
<if test="height != null "> and sl.height = #{height}</if>
|
<if test="height != null "> and sl.height = #{height}</if>
|
||||||
<if test="frequency != null "> and sl.frequency = #{frequency}</if>
|
|
||||||
<if test="drawType != null "> and sl.draw_type = #{drawType}</if>
|
<if test="drawType != null "> and sl.draw_type = #{drawType}</if>
|
||||||
<if test="title != null and title != ''"> and sl.title = #{title}</if>
|
<if test="title != null and title != ''"> and sl.title = #{title}</if>
|
||||||
<if test="enabled != null "> and sl.enabled = #{enabled}</if>
|
<if test="enabled != null "> and sl.enabled = #{enabled}</if>
|
||||||
|
|
@ -68,7 +66,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
<if test="deviceSn != null">device_sn,</if>
|
<if test="deviceSn != null">device_sn,</if>
|
||||||
<if test="width != null">width,</if>
|
<if test="width != null">width,</if>
|
||||||
<if test="height != null">height,</if>
|
<if test="height != null">height,</if>
|
||||||
<if test="frequency != null">frequency,</if>
|
|
||||||
<if test="drawType != null">draw_type,</if>
|
<if test="drawType != null">draw_type,</if>
|
||||||
<if test="title != null">title,</if>
|
<if test="title != null">title,</if>
|
||||||
<if test="enabled != null">enabled,</if>
|
<if test="enabled != null">enabled,</if>
|
||||||
|
|
@ -89,7 +86,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
<if test="deviceSn != null">#{deviceSn},</if>
|
<if test="deviceSn != null">#{deviceSn},</if>
|
||||||
<if test="width != null">#{width},</if>
|
<if test="width != null">#{width},</if>
|
||||||
<if test="height != null">#{height},</if>
|
<if test="height != null">#{height},</if>
|
||||||
<if test="frequency != null">#{frequency},</if>
|
|
||||||
<if test="drawType != null">#{drawType},</if>
|
<if test="drawType != null">#{drawType},</if>
|
||||||
<if test="title != null">#{title},</if>
|
<if test="title != null">#{title},</if>
|
||||||
<if test="enabled != null">#{enabled},</if>
|
<if test="enabled != null">#{enabled},</if>
|
||||||
|
|
@ -113,7 +109,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
<if test="deviceSn != null">device_sn = #{deviceSn},</if>
|
<if test="deviceSn != null">device_sn = #{deviceSn},</if>
|
||||||
<if test="width != null">width = #{width},</if>
|
<if test="width != null">width = #{width},</if>
|
||||||
<if test="height != null">height = #{height},</if>
|
<if test="height != null">height = #{height},</if>
|
||||||
<if test="frequency != null">frequency = #{frequency},</if>
|
|
||||||
<if test="drawType != null">draw_type = #{drawType},</if>
|
<if test="drawType != null">draw_type = #{drawType},</if>
|
||||||
<if test="title != null">title = #{title},</if>
|
<if test="title != null">title = #{title},</if>
|
||||||
<if test="enabled != null">enabled = #{enabled},</if>
|
<if test="enabled != null">enabled = #{enabled},</if>
|
||||||
|
|
@ -148,7 +143,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
<if test="deviceName != null">device_name = #{deviceName},</if>
|
<if test="deviceName != null">device_name = #{deviceName},</if>
|
||||||
<if test="width != null">width = #{width},</if>
|
<if test="width != null">width = #{width},</if>
|
||||||
<if test="height != null">height = #{height},</if>
|
<if test="height != null">height = #{height},</if>
|
||||||
<if test="frequency != null">frequency = #{frequency},</if>
|
|
||||||
<if test="drawType != null">draw_type = #{drawType},</if>
|
<if test="drawType != null">draw_type = #{drawType},</if>
|
||||||
<if test="title != null">title = #{title},</if>
|
<if test="title != null">title = #{title},</if>
|
||||||
<if test="enabled != null">enabled = #{enabled},</if>
|
<if test="enabled != null">enabled = #{enabled},</if>
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,29 @@
|
||||||
package com.yanzhu.led;
|
package com.yanzhu.led;
|
||||||
|
|
||||||
|
import com.yanzhu.api.domain.SysDictData;
|
||||||
import com.yanzhu.led.service.ILedScreenService;
|
import com.yanzhu.led.service.ILedScreenService;
|
||||||
import com.yanzhu.led.service.LedDrawService;
|
import com.yanzhu.led.service.LedDrawService;
|
||||||
import com.yanzhu.led.service.LedServerService;
|
import com.yanzhu.led.service.LedServerService;
|
||||||
import com.yanzhu.system.domain.SysLedscreen;
|
import com.yanzhu.system.domain.SysLedscreen;
|
||||||
import com.yanzhu.system.domain.SysWorkArea;
|
import com.yanzhu.system.domain.SysWorkArea;
|
||||||
|
import com.yanzhu.system.mapper.SysDictDataMapper;
|
||||||
import com.yanzhu.system.mapper.SysWorkAreaMapper;
|
import com.yanzhu.system.mapper.SysWorkAreaMapper;
|
||||||
|
import onbon.bx06.Bx6GScreen;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||||
|
import org.springframework.scheduling.support.CronTrigger;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.stream.Collectors;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import com.yanzhu.led.config.LedProperties;
|
import com.yanzhu.led.config.LedProperties;
|
||||||
|
|
||||||
|
|
@ -42,45 +47,60 @@ public class LedMainApplication {
|
||||||
@Autowired
|
@Autowired
|
||||||
private LedDrawService ledDrawService;
|
private LedDrawService ledDrawService;
|
||||||
|
|
||||||
// 用于管理各个LED屏的刷新任务
|
@Autowired
|
||||||
|
private SysDictDataMapper sysDictDataMapper;
|
||||||
|
|
||||||
|
private final ThreadPoolTaskScheduler cronScheduler = new ThreadPoolTaskScheduler();
|
||||||
|
|
||||||
|
private final ConcurrentHashMap<String, Map<String, ScheduledFuture<?>>> scheduledTasks = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private final ConcurrentHashMap<String, Runnable> refreshTasks = new ConcurrentHashMap<>();
|
private final ConcurrentHashMap<String, Runnable> refreshTasks = new ConcurrentHashMap<>();
|
||||||
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(10);
|
|
||||||
|
private List<SysDictData> cronExpressions = Collections.emptyList();
|
||||||
|
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void initialize() throws Exception {
|
public void initialize() throws Exception {
|
||||||
// 启动LED服务器守护功能
|
loadLedRefreshTimer();
|
||||||
|
cronScheduler.initialize();
|
||||||
|
|
||||||
ledServerService.initializeServer();
|
ledServerService.initializeServer();
|
||||||
|
|
||||||
// 加载所有LED屏配置
|
|
||||||
loadAllLedScreens();
|
loadAllLedScreens();
|
||||||
|
|
||||||
// 启动定时刷新任务
|
|
||||||
startPeriodicRefresh();
|
startPeriodicRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void loadLedRefreshTimer(){
|
||||||
* 加载所有LED屏配置
|
SysDictData dictWhere=new SysDictData();
|
||||||
*/
|
dictWhere.setDictType("led_refresh_timer");
|
||||||
|
dictWhere.setStatus("0");
|
||||||
|
cronExpressions=sysDictDataMapper.selectDictDataList(dictWhere);
|
||||||
|
}
|
||||||
|
|
||||||
private void loadAllLedScreens() {
|
private void loadAllLedScreens() {
|
||||||
List<SysLedscreen> ledScreens = ledScreenService.getAllLedScreens();
|
List<SysLedscreen> ledScreens = ledScreenService.getAllLedScreens();
|
||||||
logger.info("加载了 {} 个LED屏配置", ledScreens.size());
|
logger.info("加载了 {} 个LED屏配置", ledScreens.size());
|
||||||
|
|
||||||
for (SysLedscreen ledScreen : ledScreens) {
|
for (SysLedscreen ledScreen : ledScreens) {
|
||||||
// 为每个LED屏创建刷新任务
|
|
||||||
createRefreshTask(ledScreen);
|
createRefreshTask(ledScreen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public List<String> getProjectCronExpressions(long projectId) {
|
||||||
* 为LED屏创建刷新任务
|
String prjId=""+projectId;
|
||||||
*/
|
List<SysDictData> prjList=cronExpressions.stream().filter(d-> StringUtils.equals(prjId,d.getCssClass())).collect(Collectors.toList());
|
||||||
|
if(prjList.isEmpty()){
|
||||||
|
prjList=cronExpressions.stream().filter(d->StringUtils.isBlank(d.getCssClass())).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
return prjList.stream().map(d->d.getDictValue()).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
private void createRefreshTask(SysLedscreen ledScreen) {
|
private void createRefreshTask(SysLedscreen ledScreen) {
|
||||||
Runnable task = () -> {
|
Runnable task = () -> {
|
||||||
try {
|
try {
|
||||||
// 从服务中获取最新的LED屏信息,确保获取最新的在线状态
|
|
||||||
SysLedscreen currentScreen = ledScreenService.getLedScreenByNetId(ledScreen.getDeviceSn());
|
SysLedscreen currentScreen = ledScreenService.getLedScreenByNetId(ledScreen.getDeviceSn());
|
||||||
if (currentScreen != null && currentScreen.isOnline()) {
|
if (currentScreen != null && currentScreen.isOnline()) {
|
||||||
|
|
||||||
boolean success = ledDrawService.drawLedScreenContent(currentScreen);
|
boolean success = ledDrawService.drawLedScreenContent(currentScreen);
|
||||||
if (success) {
|
if (success) {
|
||||||
logger.info("成功刷新LED屏: {}", currentScreen.getDeviceSn());
|
logger.info("成功刷新LED屏: {}", currentScreen.getDeviceSn());
|
||||||
|
|
@ -95,11 +115,33 @@ public class LedMainApplication {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 存储任务引用
|
|
||||||
refreshTasks.put(ledScreen.getDeviceSn(), task);
|
refreshTasks.put(ledScreen.getDeviceSn(), task);
|
||||||
|
scheduleWithCron(ledScreen.getDeviceSn(), task, getProjectCronExpressions(ledScreen.getProjectId()));
|
||||||
|
}
|
||||||
|
|
||||||
// 调度任务
|
private void scheduleWithCron(String deviceSn, Runnable task, List<String> cronExpressions) {
|
||||||
scheduler.scheduleAtFixedRate(task, 0, ledScreen.getFrequency(), TimeUnit.SECONDS);
|
Map<String, ScheduledFuture<?>> existingTasks = scheduledTasks.get(deviceSn);
|
||||||
|
if (existingTasks != null) {
|
||||||
|
for (ScheduledFuture<?> existingTask : existingTasks.values()) {
|
||||||
|
existingTask.cancel(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, ScheduledFuture<?>> newTasks = new HashMap<>();
|
||||||
|
|
||||||
|
for (String cronExpression : cronExpressions) {
|
||||||
|
if (StringUtils.isNotBlank(cronExpression)) {
|
||||||
|
try {
|
||||||
|
ScheduledFuture<?> scheduledTask = cronScheduler.schedule(task, new CronTrigger(cronExpression));
|
||||||
|
newTasks.put(cronExpression, scheduledTask);
|
||||||
|
logger.info("为LED屏 {} 创建调度任务,Cron表达式: {}", deviceSn, cronExpression);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("为LED屏 {} 创建调度任务失败,Cron表达式: {}, 错误: {}", deviceSn, cronExpression, e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scheduledTasks.put(deviceSn, newTasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -112,64 +154,74 @@ public class LedMainApplication {
|
||||||
return new String[]{"image1.jpg", "image2.jpg", "image3.jpg"}; // 实际使用时应从配置或数据库获取
|
return new String[]{"image1.jpg", "image2.jpg", "image3.jpg"}; // 实际使用时应从配置或数据库获取
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主动检测设备在线状态,通过ping命令验证
|
||||||
|
*/
|
||||||
private boolean ledIsOnline(String deviceSn) {
|
private boolean ledIsOnline(String deviceSn) {
|
||||||
try {
|
try {
|
||||||
if(ledServerService.getServer()==null){
|
return ledDrawService.isConnected(deviceSn);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return ledServerService.getServer().getOnlineScreenByNetId(deviceSn) != null;
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error(e.getMessage(), e);
|
logger.error(e.getMessage(), e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
@Scheduled(fixedRate = 60000)
|
||||||
* 定期刷新所有LED屏
|
|
||||||
*/
|
|
||||||
@Scheduled(fixedRate = 60000) // 每分钟执行一次
|
|
||||||
public void startPeriodicRefresh() {
|
public void startPeriodicRefresh() {
|
||||||
try {
|
try {
|
||||||
List<SysLedscreen> ledScreens = ledScreenService.getAllLedScreens();
|
List<SysLedscreen> ledScreens = ledScreenService.getAllLedScreens();
|
||||||
|
|
||||||
for (SysLedscreen ledScreen : ledScreens) {
|
for (SysLedscreen ledScreen : ledScreens) {
|
||||||
// 检查设备的实际连接状态
|
|
||||||
boolean isActuallyOnline = ledIsOnline(ledScreen.getDeviceSn());
|
boolean isActuallyOnline = ledIsOnline(ledScreen.getDeviceSn());
|
||||||
boolean wasOnline = ledScreen.isOnline();
|
boolean wasOnline = ledScreen.isOnline();
|
||||||
|
|
||||||
// 如果在线状态改变,更新缓存和数据库
|
|
||||||
if (isActuallyOnline != wasOnline) {
|
if (isActuallyOnline != wasOnline) {
|
||||||
ledScreen.setOnline(isActuallyOnline);
|
ledScreen.setOnline(isActuallyOnline);
|
||||||
ledScreenService.updateLedScreen(ledScreen);
|
ledScreenService.updateLedScreen(ledScreen);
|
||||||
logger.info("LED屏 {} 在线状态已更新: {} -> {}",
|
logger.info("LED屏 {} 在线状态已更新: {} -> {}",
|
||||||
ledScreen.getDeviceSn(), wasOnline, isActuallyOnline);
|
ledScreen.getDeviceSn(), wasOnline, isActuallyOnline);
|
||||||
|
|
||||||
|
if (!isActuallyOnline) {
|
||||||
|
cancelScheduledTask(ledScreen.getDeviceSn());
|
||||||
|
} else {
|
||||||
|
createRefreshTask(ledScreen);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否已有对应的任务
|
// 主动检测设备状态,如果设备已连接但ping失败,则认为设备离线
|
||||||
if (!refreshTasks.containsKey(ledScreen.getDeviceSn())) {
|
if (ledDrawService.isConnected(ledScreen.getDeviceSn()) && !isActuallyOnline) {
|
||||||
// 如果没有对应的任务,则创建新任务
|
// 从连接管理器移除屏幕
|
||||||
createRefreshTask(ledScreen);
|
ledDrawService.removeConnectedScreen(ledScreen.getDeviceSn());
|
||||||
} else {
|
logger.info("从连接管理器移除离线设备: {}", ledScreen.getDeviceSn());
|
||||||
// 如果已有任务,检查LED屏配置是否有变化,如果有变化则更新任务
|
|
||||||
// 这样可以确保任务使用最新的配置,包括在线状态
|
|
||||||
SysLedscreen existingScreen = ledScreenService.getLedScreenByNetId(ledScreen.getDeviceSn());
|
|
||||||
if (existingScreen != null) {
|
|
||||||
// 检查频率是否变化,如果变化则重新创建任务
|
|
||||||
if (existingScreen.getFrequency() != ledScreen.getFrequency()) {
|
|
||||||
// 重新创建任务以使用新的频率设置
|
|
||||||
Runnable oldTask = refreshTasks.remove(ledScreen.getDeviceSn());
|
|
||||||
if (oldTask != null) {
|
|
||||||
logger.info("更新LED屏任务: {}", ledScreen.getDeviceSn());
|
|
||||||
}
|
|
||||||
createRefreshTask(ledScreen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("执行定期刷新时出错: {}", e.getMessage(), e);
|
logger.error("定期刷新LED屏状态时出错", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Scheduled(fixedRate = 600000)
|
||||||
|
public void refreshLedTimerData() {
|
||||||
|
try {
|
||||||
|
loadLedRefreshTimer();
|
||||||
|
logger.info("已刷新LED定时器数据");
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("刷新LED定时器数据时出错: {}", e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancelScheduledTask(String deviceSn) {
|
||||||
|
Map<String, ScheduledFuture<?>> cronTasks = scheduledTasks.remove(deviceSn);
|
||||||
|
if (cronTasks != null) {
|
||||||
|
for (ScheduledFuture<?> cronTask : cronTasks.values()) {
|
||||||
|
if (cronTask != null) {
|
||||||
|
cronTask.cancel(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.info("已取消LED屏 {} 的所有调度任务", deviceSn);
|
||||||
|
}
|
||||||
|
refreshTasks.remove(deviceSn);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据NetID获取LED屏信息
|
* 根据NetID获取LED屏信息
|
||||||
*/
|
*/
|
||||||
|
|
@ -177,24 +229,16 @@ public class LedMainApplication {
|
||||||
return ledScreenService.getLedScreenByNetId(netId);
|
return ledScreenService.getLedScreenByNetId(netId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新LED屏配置
|
|
||||||
*/
|
|
||||||
public void updateLedScreen(SysLedscreen ledScreen) {
|
public void updateLedScreen(SysLedscreen ledScreen) {
|
||||||
// 先取消旧的刷新任务
|
cancelScheduledTask(ledScreen.getDeviceSn());
|
||||||
Runnable oldTask = refreshTasks.remove(ledScreen.getDeviceSn());
|
|
||||||
if (oldTask != null) {
|
|
||||||
// 注意:这里无法直接取消已提交的任务,但会移除引用
|
|
||||||
logger.info("移除旧的刷新任务: {}", ledScreen.getDeviceSn());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新配置
|
|
||||||
ledScreenService.updateLedScreen(ledScreen);
|
ledScreenService.updateLedScreen(ledScreen);
|
||||||
|
|
||||||
// 创建新的刷新任务
|
|
||||||
createRefreshTask(ledScreen);
|
createRefreshTask(ledScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取服务器运行状态
|
* 获取服务器运行状态
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import onbon.bx06.area.page.TextBxPage;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
|
@ -81,7 +82,6 @@ public class LedDrawService {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 为Bx6M控制器创建节目
|
* 为Bx6M控制器创建节目
|
||||||
*/
|
*/
|
||||||
|
|
@ -93,7 +93,8 @@ public class LedDrawService {
|
||||||
16, profile);
|
16, profile);
|
||||||
|
|
||||||
// 如果没有图片,添加文本页
|
// 如果没有图片,添加文本页
|
||||||
String text ="研筑科技LED屏内容 - " + ledScreen.getTitle()+ DateUtil.now();
|
String text ="X研筑科技LED屏内容 - " + ledScreen.getTitle()+ DateUtil.now();
|
||||||
|
logger.info("LED-->{},sn={}",text,ledScreen.getDeviceSn());
|
||||||
TextBxPage textPage = new TextBxPage(text, new Font("宋体", Font.PLAIN, 12));//+当前时间
|
TextBxPage textPage = new TextBxPage(text, new Font("宋体", Font.PLAIN, 12));//+当前时间
|
||||||
|
|
||||||
textPage.setForeground(Color.WHITE);
|
textPage.setForeground(Color.WHITE);
|
||||||
|
|
@ -127,7 +128,6 @@ public class LedDrawService {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加已连接的屏幕到管理器
|
* 添加已连接的屏幕到管理器
|
||||||
*/
|
*/
|
||||||
|
|
@ -159,4 +159,47 @@ public class LedDrawService {
|
||||||
public boolean isConnected(String deviceSn) {
|
public boolean isConnected(String deviceSn) {
|
||||||
return connectedScreens.containsKey(deviceSn);
|
return connectedScreens.containsKey(deviceSn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定设备的连接屏幕对象
|
||||||
|
* @param deviceSn 设备序列号
|
||||||
|
* @return Bx6GScreen对象,如果未连接则返回null
|
||||||
|
*/
|
||||||
|
public Bx6GScreen getConnectedScreen(String deviceSn) {
|
||||||
|
return connectedScreens.get(deviceSn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定期检测已连接设备的在线状态,如果ping不通则认为设备已离线
|
||||||
|
*/
|
||||||
|
@Scheduled(fixedRate = 30000) // 每30秒检测一次
|
||||||
|
public void checkConnectedDevicesStatus() {
|
||||||
|
for (Map.Entry<String, Bx6GScreen> entry : connectedScreens.entrySet()) {
|
||||||
|
String deviceSn = entry.getKey();
|
||||||
|
Bx6GScreen screen = entry.getValue();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 尝试ping设备,检测其是否仍然在线
|
||||||
|
Bx6GScreen.Result<?> result = screen.ping();
|
||||||
|
if (result == null || !result.isOK()) {
|
||||||
|
logger.warn("设备 {} ping失败,认为已离线,将从连接管理器中移除", deviceSn);
|
||||||
|
// 设备离线,从连接管理器中移除
|
||||||
|
connectedScreens.remove(deviceSn);
|
||||||
|
logger.info("已从连接管理器移除离线设备: {}", deviceSn);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.warn("检测设备 {} 在线状态时出错: {}, 将从连接管理器中移除", deviceSn, e.getMessage());
|
||||||
|
// 发生异常,从连接管理器中移除设备
|
||||||
|
connectedScreens.remove(deviceSn);
|
||||||
|
logger.info("已从连接管理器移除异常设备: {}", deviceSn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有已连接的设备SN列表
|
||||||
|
*/
|
||||||
|
public java.util.Set<String> getAllConnectedDeviceSns() {
|
||||||
|
return new java.util.HashSet<>(connectedScreens.keySet());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
package com.yanzhu.led.service;
|
||||||
|
|
||||||
|
import com.yanzhu.system.domain.SysLedscreen;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LED屏离线检测服务
|
||||||
|
* 定期检测设备状态,当设备离线时更新数据库状态
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class LedOfflineDetectionService {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(LedOfflineDetectionService.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ILedScreenService ledScreenService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private LedDrawService ledDrawService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定期检查连接状态,检测离线设备
|
||||||
|
* 比较数据库中的在线设备与连接管理器中的设备,更新不一致的状态
|
||||||
|
*/
|
||||||
|
@Scheduled(fixedRate = 45000) // 每45秒检查一次
|
||||||
|
public void detectOfflineDevices() {
|
||||||
|
try {
|
||||||
|
// 获取数据库中所有标记为在线的设备
|
||||||
|
java.util.List<SysLedscreen> onlineScreens = ledScreenService.getAllLedScreens().stream()
|
||||||
|
.filter(SysLedscreen::isOnline)
|
||||||
|
.collect(Collectors.toList()) ;
|
||||||
|
|
||||||
|
// 获取连接管理器中的所有设备
|
||||||
|
Set<String> connectedDeviceSns = ledDrawService.getAllConnectedDeviceSns();
|
||||||
|
|
||||||
|
// 检查数据库中标记为在线但实际未连接的设备
|
||||||
|
for (SysLedscreen screen : onlineScreens) {
|
||||||
|
if (!connectedDeviceSns.contains(screen.getDeviceSn())) {
|
||||||
|
// 设备在数据库中标记为在线,但不在连接管理器中,说明已离线
|
||||||
|
logger.info("检测到设备 {} 已离线,更新数据库状态", screen.getDeviceSn());
|
||||||
|
|
||||||
|
// 更新数据库状态
|
||||||
|
screen.setOnline(false);
|
||||||
|
ledScreenService.updateLedScreen(screen);
|
||||||
|
logger.info("LED屏 {} 状态更新为离线", screen.getDeviceSn());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug("离线设备检测完成,当前在线设备数: {}", connectedDeviceSns.size());
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("检测离线设备时出错", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -142,7 +142,6 @@ public class UniLedDrawer extends BaseDrawer{
|
||||||
SysLedscreen led=new SysLedscreen();
|
SysLedscreen led=new SysLedscreen();
|
||||||
led.setWidth(230l);
|
led.setWidth(230l);
|
||||||
led.setHeight(128l);
|
led.setHeight(128l);
|
||||||
led.setFrequency(180l);
|
|
||||||
led.setDeviceSn("B06M3P2501160132");
|
led.setDeviceSn("B06M3P2501160132");
|
||||||
led.setTitle("abc");
|
led.setTitle("abc");
|
||||||
LedProperties ledProperties=new LedProperties();
|
LedProperties ledProperties=new LedProperties();
|
||||||
|
|
|
||||||
|
|
@ -49,14 +49,6 @@
|
||||||
@keyup.enter="handleQuery"
|
@keyup.enter="handleQuery"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="频率(秒)" prop="frequency">
|
|
||||||
<el-input
|
|
||||||
v-model="queryParams.frequency"
|
|
||||||
placeholder="请输入频率(秒)"
|
|
||||||
clearable
|
|
||||||
@keyup.enter="handleQuery"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="标题" prop="title">
|
<el-form-item label="标题" prop="title">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="queryParams.title"
|
v-model="queryParams.title"
|
||||||
|
|
@ -146,7 +138,6 @@
|
||||||
<el-table-column label="设备序列号" align="center" prop="deviceSn" />
|
<el-table-column label="设备序列号" align="center" prop="deviceSn" />
|
||||||
<el-table-column label="宽" align="center" prop="width" />
|
<el-table-column label="宽" align="center" prop="width" />
|
||||||
<el-table-column label="高" align="center" prop="height" />
|
<el-table-column label="高" align="center" prop="height" />
|
||||||
<el-table-column label="频率(秒)" align="center" prop="frequency" />
|
|
||||||
<el-table-column label="LED绘图模式" align="center" prop="drawType" />
|
<el-table-column label="LED绘图模式" align="center" prop="drawType" />
|
||||||
<el-table-column label="标题" align="center" prop="title" />
|
<el-table-column label="标题" align="center" prop="title" />
|
||||||
<el-table-column label="启停1-启用 0-停用" align="center" prop="enabled" />
|
<el-table-column label="启停1-启用 0-停用" align="center" prop="enabled" />
|
||||||
|
|
@ -190,9 +181,6 @@
|
||||||
<el-form-item label="高" prop="height">
|
<el-form-item label="高" prop="height">
|
||||||
<el-input v-model="form.height" placeholder="请输入高" />
|
<el-input v-model="form.height" placeholder="请输入高" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="频率(秒)" prop="frequency">
|
|
||||||
<el-input v-model="form.frequency" placeholder="请输入频率(秒)" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="标题" prop="title">
|
<el-form-item label="标题" prop="title">
|
||||||
<el-input v-model="form.title" placeholder="请输入标题" />
|
<el-input v-model="form.title" placeholder="请输入标题" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
@ -245,7 +233,6 @@ const data = reactive({
|
||||||
deviceSn: null,
|
deviceSn: null,
|
||||||
width: null,
|
width: null,
|
||||||
height: null,
|
height: null,
|
||||||
frequency: null,
|
|
||||||
drawType: null,
|
drawType: null,
|
||||||
title: null,
|
title: null,
|
||||||
enabled: null,
|
enabled: null,
|
||||||
|
|
@ -284,7 +271,6 @@ function reset() {
|
||||||
deviceSn: null,
|
deviceSn: null,
|
||||||
width: null,
|
width: null,
|
||||||
height: null,
|
height: null,
|
||||||
frequency: null,
|
|
||||||
drawType: null,
|
drawType: null,
|
||||||
title: null,
|
title: null,
|
||||||
enabled: null,
|
enabled: null,
|
||||||
|
|
|
||||||
|
|
@ -65,11 +65,6 @@
|
||||||
{{ row.width }} × {{ row.height }}
|
{{ row.width }} × {{ row.height }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="更新频率" align="center" prop="frequency" width="100">
|
|
||||||
<template #default="{ row }">
|
|
||||||
{{ row.frequency }}秒
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="状态" align="center" width="100">
|
<el-table-column label="状态" align="center" width="100">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-tag :type="row.online ? 'success' : 'warning'">
|
<el-tag :type="row.online ? 'success' : 'warning'">
|
||||||
|
|
@ -146,12 +141,6 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="更新频率" prop="frequency">
|
|
||||||
<el-input v-model="form.frequency" type="number" placeholder="请输入更新频率(秒)"
|
|
||||||
:disabled="dialogType === 'view'" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="绘制模式" prop="drawType">
|
<el-form-item label="绘制模式" prop="drawType">
|
||||||
<el-input v-model="form.drawType" type="number" placeholder="请输入绘制模式"
|
<el-input v-model="form.drawType" type="number" placeholder="请输入绘制模式"
|
||||||
|
|
@ -254,7 +243,6 @@ const form = ref({
|
||||||
deviceSn: undefined,
|
deviceSn: undefined,
|
||||||
width: undefined,
|
width: undefined,
|
||||||
height: undefined,
|
height: undefined,
|
||||||
frequency: undefined,
|
|
||||||
drawType: undefined,
|
drawType: undefined,
|
||||||
title: undefined,
|
title: undefined,
|
||||||
enabled: 1,
|
enabled: 1,
|
||||||
|
|
@ -275,9 +263,6 @@ const rules = ref({
|
||||||
],
|
],
|
||||||
height: [
|
height: [
|
||||||
{ required: true, message: "屏幕高度不能为空", trigger: "blur" }
|
{ required: true, message: "屏幕高度不能为空", trigger: "blur" }
|
||||||
],
|
|
||||||
frequency: [
|
|
||||||
{ required: true, message: "更新频率不能为空", trigger: "blur" }
|
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue