diff --git a/fastbee-admin/src/main/java/com/fastbee/web/controller/backend/BackendController.java b/fastbee-admin/src/main/java/com/fastbee/web/controller/backend/BackendController.java new file mode 100644 index 00000000..453c387a --- /dev/null +++ b/fastbee-admin/src/main/java/com/fastbee/web/controller/backend/BackendController.java @@ -0,0 +1,67 @@ +package com.fastbee.web.controller.backend; + +import com.fastbee.common.core.domain.AjaxResult; +import com.fastbee.common.utils.StringUtils; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.concurrent.TimeUnit; + +/** + * @description: 调试/后台接口 + * + * @author Sumuxi + * @date 2026/3/23 + */ +@Api(tags = "后台接口") +@RestController +@RequestMapping("/api/backend") +public class BackendController { + + @Resource + private RedisTemplate redisTemplate; + + @ApiOperation("设置缓存值(调试/运维)") + @PreAuthorize("@ss.hasPermi('monitor:cache:remove')") + @PostMapping("/set") + public AjaxResult setCacheValue(@RequestParam("key") String key, @RequestParam("value") String value, @RequestParam(required = false) Long expireSeconds) { + if (StringUtils.isEmpty(key)) { + return AjaxResult.error("key不能为空"); + } + if (value == null || value.isEmpty()) { + return AjaxResult.error("value不能为空"); + } + + if (expireSeconds == null) { + redisTemplate.opsForValue().set(key, value); + return AjaxResult.success("ok"); + } + + if (expireSeconds > 0) { + redisTemplate.opsForValue().set(key, value, expireSeconds, TimeUnit.SECONDS); + } else { + // expireSeconds <= 0 视为不设置过期时间 + redisTemplate.opsForValue().set(key, value); + } + return AjaxResult.success("ok"); + } + + // 删除缓存值 + @ApiOperation("删除缓存值(调试/运维)") + @PreAuthorize("@ss.hasPermi('monitor:cache:remove')") + @PostMapping("/remove") + public AjaxResult removeCacheValue(@RequestParam("key") String key) { + if (StringUtils.isEmpty(key)) { + return AjaxResult.error("key不能为空"); + } + redisTemplate.delete(key); + return AjaxResult.success("ok"); + } +} diff --git a/fastbee-iot-data/src/main/java/com/fastbee/iot/data/executor/PowerOnTriggerTaskExecutor.java b/fastbee-iot-data/src/main/java/com/fastbee/iot/data/executor/PowerOnTriggerTaskExecutor.java index 607389e5..7c8ec626 100644 --- a/fastbee-iot-data/src/main/java/com/fastbee/iot/data/executor/PowerOnTriggerTaskExecutor.java +++ b/fastbee-iot-data/src/main/java/com/fastbee/iot/data/executor/PowerOnTriggerTaskExecutor.java @@ -3,12 +3,17 @@ package com.fastbee.iot.data.executor; import com.fastbee.base.service.ISessionStore; import com.fastbee.base.session.Session; import com.fastbee.common.constant.FastBeeConstant; +import com.fastbee.common.core.mq.message.DeviceMessage; import com.fastbee.common.core.protocol.Message; import com.fastbee.common.core.redis.RedisKeyBuilder; import com.fastbee.common.utils.StringUtils; import com.fastbee.common.utils.gateway.protocol.ByteUtils; +import com.fastbee.iot.data.service.IDeviceMessageService; import com.fastbee.iot.data.service.impl.MessageManager; +import com.fastbee.iot.domain.Device; import com.fastbee.iot.domain.ModbusJob; +import com.fastbee.iot.enums.DeviceType; +import com.fastbee.iot.service.IDeviceService; import com.fastbee.iot.service.IModbusJobService; import io.netty.buffer.Unpooled; import lombok.extern.slf4j.Slf4j; @@ -57,22 +62,62 @@ public class PowerOnTriggerTaskExecutor { @Resource private RedisTemplate redisTemplate; + @Resource + private IDeviceMessageService deviceMessageService; + + @Resource + private IDeviceService deviceService; + /** * 每台设备同一时刻仅允许一个"上电触发轮询"流水线运行,避免重复触发/并发下发导致应答错配 */ private final ConcurrentHashMap running = new ConcurrentHashMap<>(); /** - * 设置上电触发标识(设备注册/上线成功后调用) + * 注册之后处理 + * 1、设置上电触发标识(设备注册/上线成功后调用) + * 2、下发IMEI/ICCID读取指令 * @param serialNumber 设备编号 */ - public void setPowerOnTriggerFlag(String serialNumber) { + @Async(FastBeeConstant.TASK.TRIGGER_POWER_ON_TASK_ASYNC) + public void registerAfterHandle(String serialNumber) { if (StringUtils.isEmpty(serialNumber)) { return; } + // 1、设置上电触发redis标识 String key = RedisKeyBuilder.buildPowerOnTriggerFlagKey(serialNumber); redisTemplate.opsForValue().set(key, "1", TRIGGER_FLAG_EXPIRE_SECONDS, TimeUnit.SECONDS); - log.debug("设置上电触发标识,设备:{}", serialNumber); + //log.debug("设置上电触发标识,设备:{}", serialNumber); + + // 2、下发IMEI/ICCID读取指令 + if (redisTemplate.opsForValue().get("get_imei_iccid") == null){ + log.warn("无缓存标识,无法下发IMEI/ICCID指令"); + return; + } + Device device = deviceService.selectDeviceInfoBySerialNumber(serialNumber); + if (device == null) { + log.warn("设备不存在,无法下发指令,设备编号:{}", serialNumber); + return; + } + if (!(device.getDeviceType() == DeviceType.DIRECT_DEVICE.getCode() || device.getDeviceType() == DeviceType.GATEWAY.getCode())) { + log.warn("设备类型不为直连或网关,无需下发指令,设备编号:{}", serialNumber); + return; + } + // 等设备上线 + try { Thread.sleep(1000); } catch (InterruptedException e) { log.error("Thread sleep interrupted", e); } + + DeviceMessage deviceMessage = new DeviceMessage(); + deviceMessage.setSerialNumber(serialNumber); + deviceMessage.setTopicName("/function/get"); + deviceMessage.setDataType("hex"); + if (StringUtils.isEmpty(device.getImei())) { + deviceMessage.setMessage("41542b494d45495c725c6e"); + deviceMessageService.messagePost(deviceMessage); + } + if (StringUtils.isEmpty(device.getIccid())) { + deviceMessage.setMessage("41542b49434349445c725c6e"); + deviceMessageService.messagePost(deviceMessage); + } } /** diff --git a/fastbee-iot-data/src/main/java/com/fastbee/iot/data/service/impl/DeviceMessageServiceImpl.java b/fastbee-iot-data/src/main/java/com/fastbee/iot/data/service/impl/DeviceMessageServiceImpl.java index 7d75dd59..6136bbd0 100644 --- a/fastbee-iot-data/src/main/java/com/fastbee/iot/data/service/impl/DeviceMessageServiceImpl.java +++ b/fastbee-iot-data/src/main/java/com/fastbee/iot/data/service/impl/DeviceMessageServiceImpl.java @@ -93,7 +93,7 @@ public class DeviceMessageServiceImpl implements IDeviceMessageService { if (transport.equals(ServerType.MQTT.getCode())) { mqttClient.publish(0, false, topicName, deviceMessage.getMessage().toString()); } else if (transport.equals(ServerType.TCP.getCode())) { - //处理TCP下发 + // 处理TCP下发 ModbusPollMsg modbusPollMsg = new ModbusPollMsg(); modbusPollMsg.setSerialNumber(serialNumber); modbusPollMsg.setProductId(deviceAndProtocol.getProductId()); diff --git a/fastbee-server/boot-strap/src/main/java/com/fastbee/bootstrap/tcp/config/TcpHandlerInterceptor.java b/fastbee-server/boot-strap/src/main/java/com/fastbee/bootstrap/tcp/config/TcpHandlerInterceptor.java index 361deb62..1fc45262 100644 --- a/fastbee-server/boot-strap/src/main/java/com/fastbee/bootstrap/tcp/config/TcpHandlerInterceptor.java +++ b/fastbee-server/boot-strap/src/main/java/com/fastbee/bootstrap/tcp/config/TcpHandlerInterceptor.java @@ -56,7 +56,7 @@ public class TcpHandlerInterceptor implements HandlerInterceptor { // 注册报文处理完成后,设置上电触发标识 int messageId = Integer.parseInt(request.getMessageId()); if (messageId == TcpDtu.注册报文 && session.isRegistered()) { - powerOnTriggerTaskExecutor.setPowerOnTriggerFlag(session.getClientId()); + powerOnTriggerTaskExecutor.registerAfterHandle(session.getClientId()); log.debug("设备注册成功,设置上电触发标识,设备:{}", session.getClientId()); } } diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/mapper/DeviceMapper.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/mapper/DeviceMapper.java index 8d1f1991..77f7c92f 100644 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/mapper/DeviceMapper.java +++ b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/mapper/DeviceMapper.java @@ -1,6 +1,5 @@ package com.fastbee.iot.mapper; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.fastbee.common.core.device.DeviceAndProtocol; import com.fastbee.common.core.thingsModel.ThingsModelValuesInput; import com.fastbee.framework.mybatis.mapper.BaseMapperX; @@ -10,7 +9,6 @@ import com.fastbee.iot.model.*; import com.fastbee.iot.model.ThingsModels.ThingsModelValuesOutput; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; -import org.springframework.stereotype.Repository; import java.util.List; import java.util.Set; @@ -38,6 +36,16 @@ public interface DeviceMapper extends BaseMapperX { */ public DeviceStatistic selectDeviceProductAlertCount(Long deptId); + /** + * 根据设备编号查询轻量信息:deviceType/imei/iccid + * + *

用于只需要判断/下发 IMEI/ICCID 的场景,避免查询 DeviceResult 中的大量无关字段。

+ * + * @param serialNumber 设备编号 + * @return 设备轻量对象(只保证 deviceType/imei/iccid 字段可用) + */ + Device selectDeviceInfoBySerialNumber(String serialNumber); + /** * 根据设备编号查询设备 * diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/IDeviceService.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/IDeviceService.java index 0f3c7ff3..8144ccd8 100644 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/IDeviceService.java +++ b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/IDeviceService.java @@ -266,6 +266,13 @@ public interface IDeviceService { */ public void batchChangeStatus(List serialNumbers, DeviceStatus status); + /** + * 根据设备编号查询轻量信息:deviceType/imei/iccid + * + * @param serialNumber 设备编号 + * @return 设备轻量对象(只保证 deviceType/imei/iccid 字段可用) + */ + Device selectDeviceInfoBySerialNumber(String serialNumber); /** * 根据设备编号查询设备信息 -不带缓存物模型值 diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/DeviceServiceImpl.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/DeviceServiceImpl.java index 13beda65..fa3a6e98 100644 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/DeviceServiceImpl.java +++ b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/DeviceServiceImpl.java @@ -1555,6 +1555,10 @@ public class DeviceServiceImpl implements IDeviceService { deviceCache.updateBatchDeviceStatusCache(serialNumbers, status); } + public Device selectDeviceInfoBySerialNumber(String serialNumber) { + return deviceMapper.selectDeviceInfoBySerialNumber(serialNumber); + } + /** * 根据设备编号查询设备信息 -不带缓存物模型值 * diff --git a/fastbee-service/fastbee-iot-service/src/main/resources/mapper/iot/DeviceMapper.xml b/fastbee-service/fastbee-iot-service/src/main/resources/mapper/iot/DeviceMapper.xml index 4f137fbc..f171f246 100644 --- a/fastbee-service/fastbee-iot-service/src/main/resources/mapper/iot/DeviceMapper.xml +++ b/fastbee-service/fastbee-iot-service/src/main/resources/mapper/iot/DeviceMapper.xml @@ -40,6 +40,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + + + + + + @@ -449,6 +459,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" where device_id = #{deviceId} + +