Merge branch 'dyf-device' into 6170

This commit is contained in:
2025-09-03 15:57:21 +08:00
22 changed files with 699 additions and 61 deletions

View File

@ -47,4 +47,9 @@ public class DeviceRedisKeyConstants {
* 告警
*/
public static final String DEVICE_ALARM_KEY_PREFIX = ":alarm";
/**
* 告警信息
*/
public static final String DEVICE_ALARM_MESSAGE_KEY_PREFIX = ":alarmMessage";
}

View File

@ -114,13 +114,24 @@ public class XinghanBootLogoRule implements MqttMessageRule {
private static final int CHUNK_SIZE = 256;
/**
* 计算数据的CRC32校验值并将结果转换为整数列表
*
* @param data 需要计算CRC32校验值的字节数组
* @return 包含CRC32校验值的整数列表每个字节对应一个无符号整数
*/
private static ArrayList<Integer> crc32AsList(byte[] data) {
// 计算CRC32校验值
CRC32 crc = new CRC32();
crc.update(data);
// 将CRC32值转换为字节数组
byte[] crcBytes = ByteBuffer.allocate(4)
.order(ByteOrder.BIG_ENDIAN)
.putInt((int) crc.getValue())
.array();
// 将字节数组转换为无符号整数列表
ArrayList<Integer> list = new ArrayList<>(4);
for (byte b : crcBytes) {
list.add(Byte.toUnsignedInt(b));
@ -128,6 +139,7 @@ public class XinghanBootLogoRule implements MqttMessageRule {
return list;
}
/* ---------- DTO ---------- */
@Data

View File

@ -14,11 +14,13 @@ import com.fuyuanshen.global.mqtt.base.MqttXinghanJson;
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
import com.fuyuanshen.global.mqtt.constants.LightingCommandTypeConstants;
import com.fuyuanshen.global.mqtt.constants.XingHanCommandTypeConstants;
import com.fuyuanshen.global.mqtt.listener.domain.FunctionAccessStatus;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
@ -58,6 +60,7 @@ public class XinghanDeviceDataRule implements MqttMessageRule {
@Override
public void execute(MqttRuleContext context) {
String functionAccess = FUNCTION_ACCESS_KEY + context.getDeviceImei();
try {
// Latitude, longitude
//主灯档位,激光灯档位,电量百分比,充电状态,电池剩余续航时间
@ -65,8 +68,10 @@ public class XinghanDeviceDataRule implements MqttMessageRule {
// 发送设备状态和位置信息到Redis
asyncSendDeviceDataToRedisWithFuture(context.getDeviceImei(),deviceStatus);
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20));
} catch (Exception e) {
log.error("处理上报数据命令时出错", e);
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.FAILED.getCode(), Duration.ofSeconds(20));
}
}

View File

@ -0,0 +1,118 @@
package com.fuyuanshen.global.mqtt.rule.xinghan;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fuyuanshen.common.json.utils.JsonUtils;
import com.fuyuanshen.common.redis.utils.RedisUtils;
import com.fuyuanshen.global.mqtt.base.MqttMessageRule;
import com.fuyuanshen.global.mqtt.base.MqttRuleContext;
import com.fuyuanshen.global.mqtt.config.MqttGateway;
import com.fuyuanshen.global.mqtt.constants.MqttConstants;
import com.fuyuanshen.global.mqtt.constants.XingHanCommandTypeConstants;
import com.fuyuanshen.global.mqtt.listener.domain.FunctionAccessStatus;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.nio.charset.Charset;
import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY;
import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY;
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_ALARM_MESSAGE_KEY_PREFIX;
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
/**
* 星汉设备发送紧急通知 下发规则:
* <p>
* 1. 设备上行 sta_BreakNews=cover! => 仅标记成功<br>
* 2. 设备上行 sta_BreakNews=数字 => GBK编码每行文字为一包一共4包第一字节为包序号
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class XinghanSendAlarmMessageRule implements MqttMessageRule {
private final MqttGateway mqttGateway;
private final ObjectMapper objectMapper;
@Override
public String getCommandType() {
return XingHanCommandTypeConstants.XingHan_BREAK_NEWS;
}
@Override
public void execute(MqttRuleContext ctx) {
String functionAccess = FUNCTION_ACCESS_KEY + ctx.getDeviceImei();
try {
XinghanSendAlarmMessageRule.MqttXinghanAlarmMsgJson payload = objectMapper.convertValue(
ctx.getPayloadDict(), XinghanSendAlarmMessageRule.MqttXinghanAlarmMsgJson.class);
String respText = payload.getStaBreakNews();
log.info("设备上报紧急通知握手: {} ", respText);
// 1. cover! —— 成功标记
if ("cover!".equalsIgnoreCase(respText)) {
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20));
log.info("设备 {} 发送紧急通知完成", ctx.getDeviceImei());
return;
}
// 2. 数字 —— 下发数据块
int blockIndex;
try {
blockIndex = Integer.parseInt(respText);
} catch (NumberFormatException ex) {
log.warn("设备 {} 紧急通知上报非法块号:{}", ctx.getDeviceImei(), respText);
return;
}
// 将发送的信息原文本以List<String>形式存储在Redis中
String data = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + ctx.getDeviceImei() + DEVICE_ALARM_MESSAGE_KEY_PREFIX);
if (data == null || data.isEmpty()) {
return;
}
//
ArrayList<Integer> intData = new ArrayList<>();
intData.add(blockIndex);
// 获取块原内容 转成GBK 再转成无符号十进制整数
String blockTxt = data.split("\\|")[blockIndex-1];
// 再按 GBK 编码把字符串转成字节数组,并逐个转为无符号十进制整数
for (byte b : blockTxt.getBytes(GBK)) {
intData.add(b & 0xFF); // b & 0xFF 得到 0~255 的整数
}
Map<String, Object> map = new HashMap<>();
map.put("ins_BreakNews", intData);
String topic = MqttConstants.GLOBAL_PUB_KEY + ctx.getDeviceImei();
String json = JsonUtils.toJsonString(map);
mqttGateway.sendMsgToMqtt(topic, 1, json);
log.info("发送设备紧急通知=>topic:{},payload:{}",
MqttConstants.GLOBAL_PUB_KEY + ctx.getDeviceImei(),
JsonUtils.toJsonString(map));
} catch (Exception e) {
log.error("处理发送设备紧急通知时出错", e);
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.FAILED.getCode(), Duration.ofSeconds(20));
}
}
private static final Charset GBK = Charset.forName("GBK");
/* ---------- DTO ---------- */
@Data
private static class MqttXinghanAlarmMsgJson {
/**
* 设备上行:
* 数字 -> 请求对应块号
* cover! -> 写入成功
*/
@JsonProperty("sta_BreakNews")
private String staBreakNews;
}
}

View File

@ -57,7 +57,7 @@ public class XinghanSendMsgRule implements MqttMessageRule {
// 1. genius! —— 成功标记
if ("genius!".equalsIgnoreCase(respText)) {
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.FAILED.getCode(), Duration.ofSeconds(20));
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20));
log.info("设备 {} 发送消息完成", ctx.getDeviceImei());
return;
}
@ -79,6 +79,7 @@ public class XinghanSendMsgRule implements MqttMessageRule {
intData.add(blockIndex);
// 获取块原内容 转成GBK 再转成无符号十进制整数
String blockTxt = data.get(blockIndex-1);
log.warn("设备上报人员登记信息:{}", blockTxt);
// 再按 GBK 编码把字符串转成字节数组,并逐个转为无符号十进制整数
for (byte b : blockTxt.getBytes(GBK)) {
intData.add(b & 0xFF); // b & 0xFF 得到 0~255 的整数