20260627:监测点可以任意指定子设备
This commit is contained in:
parent
d07288b64d
commit
1846f4e717
@ -8,12 +8,14 @@ TARGET_PORT = 8888 # 请根据实际情况修改
|
|||||||
|
|
||||||
# 元数组 modbus 指令
|
# 元数组 modbus 指令
|
||||||
MODBUS_DATA_HEX = (
|
MODBUS_DATA_HEX = (
|
||||||
"7e80D55746B29F687e",
|
"7e80D21F6C448E8D7e",
|
||||||
"010310c07ffffe45217c3d41dfe9964140686641f4"
|
"01031c41b6dcec418b0000402d2148000000004017e0b8400c19efc2ad8a8acb2b",
|
||||||
|
"02031c41babecc419d8000402be3560000000040137c30bfb2f4d0c2ae9bc1b582",
|
||||||
|
"03031c41bd1c1941810000402bb38600000000bf4501bdc027dfcac2ae8853eaef",
|
||||||
|
"04031c41babecc419d8000402be3560000000040137c30bfb2f4d0c2ae9bc1D581",
|
||||||
|
"05031c41bd1c1941810000402bb38600000000bf4501bdc027dfcac2ae88538AEC"
|
||||||
)
|
)
|
||||||
# "01031c4268442f41d30000418b6685000000004026f4cac00d1fd3c2ad2a9d6311",
|
|
||||||
# "02031c42488fd041c5800041865ab7000000003f364458c03f765ec2add9722da5",
|
|
||||||
# "03031c42ffdad541c78000421529b8000000003d5f38f94082080dc2abdf4f1f94"
|
|
||||||
# 01 03 1c 4268 442f 41d3 0000 418b 6685 0000 0000 4026 f4ca c00d 1fd3 c2ad 2a9d 6311
|
# 01 03 1c 4268 442f 41d3 0000 418b 6685 0000 0000 4026 f4ca c00d 1fd3 c2ad 2a9d 6311
|
||||||
# 从机地址 功能码 字节长度 2个字节 CRC校验
|
# 从机地址 功能码 字节长度 2个字节 CRC校验
|
||||||
|
|
||||||
@ -45,7 +47,7 @@ def main():
|
|||||||
|
|
||||||
# 2. 等待0.5秒
|
# 2. 等待0.5秒
|
||||||
print("等待 0.1 秒...")
|
print("等待 0.1 秒...")
|
||||||
time.sleep(0.5)
|
time.sleep(1)
|
||||||
|
|
||||||
# (可选)接收最终响应
|
# (可选)接收最终响应
|
||||||
try:
|
try:
|
||||||
|
|||||||
@ -133,7 +133,7 @@ public class CRC16Utils {
|
|||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
String hex = "0103028000";
|
String hex = "006000000000";
|
||||||
byte[] bytes = ByteUtils.hexToByte(hex);
|
byte[] bytes = ByteUtils.hexToByte(hex);
|
||||||
String crc = getCRC(bytes);
|
String crc = getCRC(bytes);
|
||||||
System.out.println(crc);
|
System.out.println(crc);
|
||||||
|
|||||||
@ -303,9 +303,9 @@ public class ByteUtils {
|
|||||||
return data.getBytes(charset);
|
return data.getBytes(charset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* 把16进制字符串转换成字节数组
|
* 把16进制字符串转换成字节数组
|
||||||
* @param hex
|
* @param hexStr 16进制字符
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static byte[] hexToByte(String hexStr) {
|
public static byte[] hexToByte(String hexStr) {
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import com.fastbee.iot.platform.flow.FlowContext;
|
|||||||
import com.fastbee.iot.platform.flow.PlatformFlowExecutor;
|
import com.fastbee.iot.platform.flow.PlatformFlowExecutor;
|
||||||
import com.fastbee.iot.platform.mapper.PlatformFlowMapper;
|
import com.fastbee.iot.platform.mapper.PlatformFlowMapper;
|
||||||
import com.fastbee.iot.platform.mapper.PlatformInterfaceMapper;
|
import com.fastbee.iot.platform.mapper.PlatformInterfaceMapper;
|
||||||
|
import com.fastbee.iot.platform.service.IPlatformDeviceSubMappingService;
|
||||||
import com.fastbee.iot.platform.service.IPlatformInstanceService;
|
import com.fastbee.iot.platform.service.IPlatformInstanceService;
|
||||||
import com.fastbee.iot.platform.service.IPlatformPushLogService;
|
import com.fastbee.iot.platform.service.IPlatformPushLogService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -34,6 +35,7 @@ import java.time.format.DateTimeFormatter;
|
|||||||
import java.time.format.DateTimeParseException;
|
import java.time.format.DateTimeParseException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -66,6 +68,8 @@ public class DcpPlatformAdapter {
|
|||||||
private StaticLevelBufferService bufferService;
|
private StaticLevelBufferService bufferService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private PlatformInterfaceMapper interfaceMapper;
|
private PlatformInterfaceMapper interfaceMapper;
|
||||||
|
@Autowired
|
||||||
|
private IPlatformDeviceSubMappingService subMappingService;
|
||||||
|
|
||||||
/** 传感器类型 → 推送接口路径 */
|
/** 传感器类型 → 推送接口路径 */
|
||||||
private static final Map<String, String> PUSH_PATH = new HashMap<>();
|
private static final Map<String, String> PUSH_PATH = new HashMap<>();
|
||||||
@ -184,10 +188,12 @@ public class DcpPlatformAdapter {
|
|||||||
JSONObject currentBodyFields = buildObjectBySchema(platform, mapping, requestSchema, reportData, fieldMappings);
|
JSONObject currentBodyFields = buildObjectBySchema(platform, mapping, requestSchema, reportData, fieldMappings);
|
||||||
|
|
||||||
if (subMapping.isReference()) {
|
if (subMapping.isReference()) {
|
||||||
// 基准点上报:仅缓存,不推送
|
// 基准点上报:缓存当前基准点,并补推此前已缓存的监测点
|
||||||
bufferService.saveReferenceData(
|
bufferService.saveReferenceData(
|
||||||
platform.getId(), fieldName, reportSerialNumber, currentItem, reportIntervalSec);
|
platform.getId(), fieldName, reportSerialNumber, currentItem, reportIntervalSec);
|
||||||
log.info("[DCP] 基准点 {} 已缓存,等待监测点上报", reportSerialNumber);
|
int replayCount = replayPendingMonitorData(platform, mapping, fieldName, currentItem,
|
||||||
|
reportIntervalSec, baseUrl, interfaceCode);
|
||||||
|
log.info("[DCP] 基准点 {} 已缓存,补推监测点 {} 条", reportSerialNumber, replayCount);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,7 +204,7 @@ public class DcpPlatformAdapter {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取基准点序列号(从 onboard_config 中取 refSensorId 对应的原始序列号)
|
// 获取基准点序列号,优先使用子映射中当前标记的 reference 行
|
||||||
String refSerialNumber = resolveRefSerialNumber(subMapping, mapping);
|
String refSerialNumber = resolveRefSerialNumber(subMapping, mapping);
|
||||||
|
|
||||||
JSONObject refData = bufferService.getReferenceDataIfFresh(
|
JSONObject refData = bufferService.getReferenceDataIfFresh(
|
||||||
@ -243,12 +249,18 @@ public class DcpPlatformAdapter {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** 解析基准点序列号 */
|
||||||
* 从子映射的 onboard_config 解析基准点序列号
|
|
||||||
*/
|
|
||||||
private String resolveRefSerialNumber(PlatformDeviceSubMapping subMapping, PlatformDeviceMapping mapping) {
|
private String resolveRefSerialNumber(PlatformDeviceSubMapping subMapping, PlatformDeviceMapping mapping) {
|
||||||
// 从 onboard_config 取 refSensorId 对应的子设备序列号
|
try {
|
||||||
// 通常基准点的 sensorId == 基准点的 serialNumber
|
PlatformDeviceSubMapping reference = subMappingService.findReference(mapping.getId());
|
||||||
|
if (reference != null && StringUtils.hasText(reference.getSubSerialNumber())) {
|
||||||
|
return reference.getSubSerialNumber();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("[DCP] 查询静力水准基准点失败 mappingId={}, error={}", mapping.getId(), e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 兼容历史配置:从 onboard_config 取基准点原始序列号
|
||||||
if (StringUtils.hasText(subMapping.getOnboardConfig())) {
|
if (StringUtils.hasText(subMapping.getOnboardConfig())) {
|
||||||
try {
|
try {
|
||||||
JSONObject config = JSON.parseObject(subMapping.getOnboardConfig());
|
JSONObject config = JSON.parseObject(subMapping.getOnboardConfig());
|
||||||
@ -262,6 +274,67 @@ public class DcpPlatformAdapter {
|
|||||||
return mapping.getSerialNumber();
|
return mapping.getSerialNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基准点后到时,补推此前缓存的监测点数据。
|
||||||
|
*/
|
||||||
|
private int replayPendingMonitorData(PlatformInstance platform, PlatformDeviceMapping mapping,
|
||||||
|
String fieldName, JSONObject referenceItem,
|
||||||
|
int reportIntervalSec, String baseUrl, String interfaceCode) {
|
||||||
|
List<PlatformDeviceSubMapping> subMappings = subMappingService.selectByParentId(mapping.getId());
|
||||||
|
if (subMappings == null || subMappings.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int replayCount = 0;
|
||||||
|
for (PlatformDeviceSubMapping monitor : subMappings) {
|
||||||
|
if (monitor == null || !monitor.isMonitor()
|
||||||
|
|| !StringUtils.hasText(monitor.getSubSerialNumber())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
JSONObject monitorData = bufferService.getMonitorDataIfFresh(
|
||||||
|
platform.getId(), fieldName, monitor.getSubSerialNumber(), reportIntervalSec);
|
||||||
|
if (monitorData == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!StringUtils.hasText(monitor.getPlatformDeviceId())) {
|
||||||
|
log.warn("[DCP] 监测点 {} 有缓存但未分配平台设备ID,暂不补推",
|
||||||
|
monitor.getSubSerialNumber());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject monitorItem = monitorData.getJSONObject("itemData");
|
||||||
|
if (monitorItem == null || monitorItem.isEmpty()) {
|
||||||
|
bufferService.removeMonitorData(platform.getId(), fieldName, monitor.getSubSerialNumber());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
JSONObject bodyFields = monitorData.getJSONObject("bodyFields");
|
||||||
|
if (bodyFields == null) {
|
||||||
|
bodyFields = new JSONObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONArray sensorData = new JSONArray();
|
||||||
|
sensorData.add(referenceItem);
|
||||||
|
sensorData.add(monitorItem);
|
||||||
|
JSONArray pushBody = buildArrayPushBody(mapping, bodyFields, fieldName,
|
||||||
|
sensorData, monitor.getPlatformDeviceId());
|
||||||
|
|
||||||
|
PlatformPushLog logEntry = createLogEntry(platform, mapping, interfaceCode,
|
||||||
|
monitor.getSubSerialNumber());
|
||||||
|
doHttpPost(platform, baseUrl, JSON.toJSONString(pushBody), logEntry);
|
||||||
|
pushLogService.asyncSave(logEntry);
|
||||||
|
if (logEntry.getStatus() != null && logEntry.getStatus() == 1) {
|
||||||
|
bufferService.removeMonitorData(platform.getId(), fieldName, monitor.getSubSerialNumber());
|
||||||
|
replayCount++;
|
||||||
|
log.info("[DCP] 基准点后到,已补推监测点 {} deviceId={}",
|
||||||
|
monitor.getSubSerialNumber(), monitor.getPlatformDeviceId());
|
||||||
|
} else {
|
||||||
|
log.warn("[DCP] 基准点后到,补推监测点 {} 失败,保留缓存等待下次基准点上报",
|
||||||
|
monitor.getSubSerialNumber());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return replayCount;
|
||||||
|
}
|
||||||
|
|
||||||
// ==================== 普通推送 ====================
|
// ==================== 普通推送 ====================
|
||||||
|
|
||||||
private void handleNormalPush(PlatformInstance platform, PlatformDeviceMapping mapping,
|
private void handleNormalPush(PlatformInstance platform, PlatformDeviceMapping mapping,
|
||||||
|
|||||||
@ -21,6 +21,10 @@ public class FlowContext {
|
|||||||
private String currentMonitorSerialNumber;
|
private String currentMonitorSerialNumber;
|
||||||
/** 网关子设备入网时,当前子映射行的 onboard_config JSON(平台相关参数) */
|
/** 网关子设备入网时,当前子映射行的 onboard_config JSON(平台相关参数) */
|
||||||
private String subMappingOnboardConfig;
|
private String subMappingOnboardConfig;
|
||||||
|
/** 网关子设备入网时,当前基准点序列号 */
|
||||||
|
private String currentReferenceSerialNumber;
|
||||||
|
/** 网关子设备入网时,基准点子映射行的 onboard_config JSON */
|
||||||
|
private String referenceSubMappingOnboardConfig;
|
||||||
|
|
||||||
public FlowContext(PlatformInstance platform, PlatformDeviceMapping deviceMapping, String payload) {
|
public FlowContext(PlatformInstance platform, PlatformDeviceMapping deviceMapping, String payload) {
|
||||||
this.platform = platform;
|
this.platform = platform;
|
||||||
@ -64,6 +68,22 @@ public class FlowContext {
|
|||||||
this.subMappingOnboardConfig = subMappingOnboardConfig;
|
this.subMappingOnboardConfig = subMappingOnboardConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getCurrentReferenceSerialNumber() {
|
||||||
|
return currentReferenceSerialNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentReferenceSerialNumber(String currentReferenceSerialNumber) {
|
||||||
|
this.currentReferenceSerialNumber = currentReferenceSerialNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReferenceSubMappingOnboardConfig() {
|
||||||
|
return referenceSubMappingOnboardConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReferenceSubMappingOnboardConfig(String referenceSubMappingOnboardConfig) {
|
||||||
|
this.referenceSubMappingOnboardConfig = referenceSubMappingOnboardConfig;
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public Object getFromContext(String contextKey) {
|
public Object getFromContext(String contextKey) {
|
||||||
// contextKey 格式: "step1.access_token" 或 "step1"
|
// contextKey 格式: "step1.access_token" 或 "step1"
|
||||||
|
|||||||
@ -429,6 +429,20 @@ public class PlatformFlowExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<String> collectSubDeviceSensorIds(FlowContext ctx) {
|
private List<String> collectSubDeviceSensorIds(FlowContext ctx) {
|
||||||
|
if (StringUtils.hasText(ctx.getCurrentMonitorSerialNumber())
|
||||||
|
&& StringUtils.hasText(ctx.getCurrentReferenceSerialNumber())) {
|
||||||
|
String refSensorId = resolveOnboardSensorId(
|
||||||
|
ctx.getReferenceSubMappingOnboardConfig(), ctx.getCurrentReferenceSerialNumber());
|
||||||
|
String monitorSensorId = resolveOnboardSensorId(
|
||||||
|
ctx.getSubMappingOnboardConfig(), ctx.getCurrentMonitorSerialNumber());
|
||||||
|
List<String> ids = new ArrayList<>();
|
||||||
|
if (StringUtils.hasText(refSensorId)) ids.add(refSensorId);
|
||||||
|
if (StringUtils.hasText(monitorSensorId)) ids.add(monitorSensorId);
|
||||||
|
if (!ids.isEmpty()) {
|
||||||
|
return ids.stream().distinct().collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 网关入网时,从子表 onboard_config 获取 sensorId
|
// 网关入网时,从子表 onboard_config 获取 sensorId
|
||||||
if (StringUtils.hasText(ctx.getSubMappingOnboardConfig())) {
|
if (StringUtils.hasText(ctx.getSubMappingOnboardConfig())) {
|
||||||
try {
|
try {
|
||||||
@ -450,10 +464,32 @@ public class PlatformFlowExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 网关入网时:从当前子映射的 onboard_config 取 [refSensorId, sensorId] 一对。
|
* 网关入网时:优先按子表中当前 reference 行取 [基准点sensorId, 监测点sensorId] 一对。
|
||||||
* 直连设备/旧逻辑:从 extra_mapping 解析所有配对。
|
* 直连设备/旧逻辑:从 extra_mapping 解析所有配对。
|
||||||
*/
|
*/
|
||||||
private List<List<String>> collectReferenceSubDeviceSensorIdPairs(FlowContext ctx) {
|
private List<List<String>> collectReferenceSubDeviceSensorIdPairs(FlowContext ctx) {
|
||||||
|
if (StringUtils.hasText(ctx.getCurrentMonitorSerialNumber())) {
|
||||||
|
String sensorId = resolveOnboardSensorId(
|
||||||
|
ctx.getSubMappingOnboardConfig(), ctx.getCurrentMonitorSerialNumber());
|
||||||
|
String refSensorId = resolveOnboardSensorId(
|
||||||
|
ctx.getReferenceSubMappingOnboardConfig(), ctx.getCurrentReferenceSerialNumber());
|
||||||
|
if (!StringUtils.hasText(refSensorId)) {
|
||||||
|
refSensorId = resolveOnboardConfigText(ctx.getSubMappingOnboardConfig(), "refSensorId");
|
||||||
|
}
|
||||||
|
if (StringUtils.hasText(sensorId) && StringUtils.hasText(refSensorId)) {
|
||||||
|
if (sameText(refSensorId, sensorId)) {
|
||||||
|
throw new RuntimeException("静力水准 sensorIds 配置无效:基准点和监测点 sensorId 相同");
|
||||||
|
}
|
||||||
|
List<List<String>> pairs = new ArrayList<>();
|
||||||
|
pairs.add(Arrays.asList(refSensorId, sensorId));
|
||||||
|
return pairs;
|
||||||
|
}
|
||||||
|
if (isStaticLevel(ctx.getDeviceMapping())) {
|
||||||
|
throw new RuntimeException("静力水准监测点 " + ctx.getCurrentMonitorSerialNumber()
|
||||||
|
+ " 缺少基准点或监测点 sensorId,请检查子设备映射");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 网关入网:onboardConfig 已指定当前监测点
|
// 网关入网:onboardConfig 已指定当前监测点
|
||||||
if (StringUtils.hasText(ctx.getSubMappingOnboardConfig())) {
|
if (StringUtils.hasText(ctx.getSubMappingOnboardConfig())) {
|
||||||
try {
|
try {
|
||||||
@ -494,6 +530,27 @@ public class PlatformFlowExecutor {
|
|||||||
return pairs;
|
return pairs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String resolveOnboardSensorId(String onboardConfig, String fallbackSerialNumber) {
|
||||||
|
String sensorId = resolveOnboardConfigText(onboardConfig, "sensorId");
|
||||||
|
return StringUtils.hasText(sensorId) ? sensorId : normalizeText(fallbackSerialNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveOnboardConfigText(String onboardConfig, String field) {
|
||||||
|
if (!StringUtils.hasText(onboardConfig) || !StringUtils.hasText(field)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
JSONObject config = JSON.parseObject(onboardConfig);
|
||||||
|
return normalizeText(config.getString(field));
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isStaticLevel(PlatformDeviceMapping mapping) {
|
||||||
|
return mapping != null && Objects.equals("static_level", mapping.getSensorType());
|
||||||
|
}
|
||||||
|
|
||||||
private List<SubDeviceSensorBinding> collectSubDeviceSensorBindings(PlatformDeviceMapping mapping) {
|
private List<SubDeviceSensorBinding> collectSubDeviceSensorBindings(PlatformDeviceMapping mapping) {
|
||||||
if (mapping == null) {
|
if (mapping == null) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
|
|||||||
@ -21,6 +21,7 @@ import org.springframework.util.StringUtils;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -105,6 +106,7 @@ public class PlatformDeviceMappingServiceImpl extends ServiceImpl<PlatformDevice
|
|||||||
*/
|
*/
|
||||||
private void onboardGateway(PlatformDeviceMapping mapping, PlatformInstance platform, PlatformFlow onboardFlow) {
|
private void onboardGateway(PlatformDeviceMapping mapping, PlatformInstance platform, PlatformFlow onboardFlow) {
|
||||||
List<PlatformDeviceSubMapping> subMappings = subMappingService.selectByParentId(mapping.getId());
|
List<PlatformDeviceSubMapping> subMappings = subMappingService.selectByParentId(mapping.getId());
|
||||||
|
PlatformDeviceSubMapping reference = resolveGatewayReference(mapping, subMappings);
|
||||||
List<PlatformDeviceSubMapping> monitors = subMappings.stream()
|
List<PlatformDeviceSubMapping> monitors = subMappings.stream()
|
||||||
.filter(s -> s.isMonitor() && (s.getNetStatus() == null || s.getNetStatus() == 0))
|
.filter(s -> s.isMonitor() && (s.getNetStatus() == null || s.getNetStatus() == 0))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
@ -120,6 +122,10 @@ public class PlatformDeviceMappingServiceImpl extends ServiceImpl<PlatformDevice
|
|||||||
FlowContext ctx = new FlowContext(platform, mapping, null);
|
FlowContext ctx = new FlowContext(platform, mapping, null);
|
||||||
ctx.setCurrentMonitorSerialNumber(monitor.getSubSerialNumber());
|
ctx.setCurrentMonitorSerialNumber(monitor.getSubSerialNumber());
|
||||||
ctx.setSubMappingOnboardConfig(monitor.getOnboardConfig());
|
ctx.setSubMappingOnboardConfig(monitor.getOnboardConfig());
|
||||||
|
if (reference != null) {
|
||||||
|
ctx.setCurrentReferenceSerialNumber(reference.getSubSerialNumber());
|
||||||
|
ctx.setReferenceSubMappingOnboardConfig(reference.getOnboardConfig());
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
flowExecutor.execute(onboardFlow, ctx);
|
flowExecutor.execute(onboardFlow, ctx);
|
||||||
@ -165,4 +171,22 @@ public class PlatformDeviceMappingServiceImpl extends ServiceImpl<PlatformDevice
|
|||||||
+ String.join("\n", failedMessages));
|
+ String.join("\n", failedMessages));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PlatformDeviceSubMapping resolveGatewayReference(PlatformDeviceMapping mapping,
|
||||||
|
List<PlatformDeviceSubMapping> subMappings) {
|
||||||
|
List<PlatformDeviceSubMapping> references = subMappings.stream()
|
||||||
|
.filter(PlatformDeviceSubMapping::isReference)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
boolean staticLevel = Objects.equals("static_level", mapping.getSensorType());
|
||||||
|
if (references.size() > 1) {
|
||||||
|
throw new RuntimeException("子表中只能指定一个基准点,请检查子设备映射");
|
||||||
|
}
|
||||||
|
if (references.isEmpty()) {
|
||||||
|
if (staticLevel) {
|
||||||
|
throw new RuntimeException("静力水准网关入网需在子设备映射中指定一个基准点");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return references.get(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
<select id="selectByParentId" resultType="com.fastbee.iot.platform.domain.PlatformDeviceSubMapping">
|
<select id="selectByParentId" resultType="com.fastbee.iot.platform.domain.PlatformDeviceSubMapping">
|
||||||
SELECT * FROM platform_device_sub_mapping
|
SELECT * FROM platform_device_sub_mapping
|
||||||
WHERE parent_mapping_id = #{parentMappingId}
|
WHERE parent_mapping_id = #{parentMappingId}
|
||||||
ORDER BY device_role DESC, id ASC
|
ORDER BY id ASC
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectByParentAndSerial" resultType="com.fastbee.iot.platform.domain.PlatformDeviceSubMapping">
|
<select id="selectByParentAndSerial" resultType="com.fastbee.iot.platform.domain.PlatformDeviceSubMapping">
|
||||||
|
|||||||
@ -170,7 +170,7 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="角色" width="120" align="center">
|
<el-table-column label="角色" width="120" align="center">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-select v-model="scope.row.deviceRole" size="mini" style="width:100%">
|
<el-select v-model="scope.row.deviceRole" size="mini" style="width:100%" @change="onSubRoleChange(scope.row)">
|
||||||
<el-option label="基准点" value="reference" />
|
<el-option label="基准点" value="reference" />
|
||||||
<el-option label="监测点" value="monitor" />
|
<el-option label="监测点" value="monitor" />
|
||||||
</el-select>
|
</el-select>
|
||||||
@ -178,7 +178,7 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="入网参数 (JSON)" min-width="220">
|
<el-table-column label="入网参数 (JSON)" min-width="220">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-input v-model="scope.row.onboardConfig" size="mini" :placeholder="scope.row.deviceRole === 'reference' ? '{\"sensorId\":\"...\"}' : '{\"sensorId\":\"...\",\"refSensorId\":\"...\",\"refSerialNumber\":\"...\"}'" />
|
<el-input v-model="scope.row.onboardConfig" size="mini" :placeholder="getOnboardConfigPlaceholder(scope.row)" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="平台设备ID" width="140" v-if="form.netStatus===1">
|
<el-table-column label="平台设备ID" width="140" v-if="form.netStatus===1">
|
||||||
@ -323,11 +323,14 @@ export default {
|
|||||||
listPlatformDeviceMapping(this.queryParams).then(res => {
|
listPlatformDeviceMapping(this.queryParams).then(res => {
|
||||||
this.list = res.rows; this.total = res.total; this.loading = false
|
this.list = res.rows; this.total = res.total; this.loading = false
|
||||||
// 加载设备名称映射
|
// 加载设备名称映射
|
||||||
const ids = [...new Set(res.rows.map(r => r.deviceId))]
|
const ids = [...new Set(res.rows.map(r => r.deviceId).filter(Boolean))]
|
||||||
if (ids.length) {
|
if (ids.length) {
|
||||||
listDevice({ pageNum: 1, pageSize: 200 }).then(dr => {
|
Promise.all(ids.map(id => getDevice(id).catch(() => null))).then(results => {
|
||||||
const map = {}
|
const map = {}
|
||||||
dr.rows.forEach(d => { map[d.deviceId] = d.deviceName })
|
results.forEach(res => {
|
||||||
|
const d = res && (res.data || res)
|
||||||
|
if (d && d.deviceId) map[d.deviceId] = d.deviceName
|
||||||
|
})
|
||||||
this.deviceMap = map
|
this.deviceMap = map
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -349,6 +352,11 @@ export default {
|
|||||||
getSubDevicePairs(row) {
|
getSubDevicePairs(row) {
|
||||||
return this.subMappingCache[row.id] || []
|
return this.subMappingCache[row.id] || []
|
||||||
},
|
},
|
||||||
|
getOnboardConfigPlaceholder(row) {
|
||||||
|
return row.deviceRole === 'reference'
|
||||||
|
? '{"sensorId":"..."}'
|
||||||
|
: '{"sensorId":"...","refSensorId":"...","refSerialNumber":"..."}'
|
||||||
|
},
|
||||||
handleQuery() { this.queryParams.pageNum = 1; this.getList() },
|
handleQuery() { this.queryParams.pageNum = 1; this.getList() },
|
||||||
resetQuery() { this.resetForm('queryForm'); this.handleQuery() },
|
resetQuery() { this.resetForm('queryForm'); this.handleQuery() },
|
||||||
handleAdd() {
|
handleAdd() {
|
||||||
@ -409,16 +417,11 @@ export default {
|
|||||||
onDeviceTypeChange(val) {
|
onDeviceTypeChange(val) {
|
||||||
if (val === 1 && this.subMappingRows.length === 0 && this.subDeviceOptions.length > 0) {
|
if (val === 1 && this.subMappingRows.length === 0 && this.subDeviceOptions.length > 0) {
|
||||||
// 切换为网关设备时,自动用已加载的子设备列表预填
|
// 切换为网关设备时,自动用已加载的子设备列表预填
|
||||||
const refSn = this.subDeviceOptions[0].serialNumber
|
this.subMappingRows = this.subDeviceOptions.map(device => {
|
||||||
this.subMappingRows = this.subDeviceOptions.map((device, idx) => {
|
|
||||||
const role = idx === 0 ? 'reference' : 'monitor'
|
|
||||||
const config = role === 'reference'
|
|
||||||
? JSON.stringify({ sensorId: device.serialNumber })
|
|
||||||
: JSON.stringify({ sensorId: device.serialNumber, refSensorId: refSn, refSerialNumber: refSn })
|
|
||||||
return {
|
return {
|
||||||
subSerialNumber: device.serialNumber,
|
subSerialNumber: device.serialNumber,
|
||||||
deviceRole: role,
|
deviceRole: 'monitor',
|
||||||
onboardConfig: config,
|
onboardConfig: JSON.stringify({ sensorId: device.serialNumber }),
|
||||||
platformDeviceId: '',
|
platformDeviceId: '',
|
||||||
platformPointId: ''
|
platformPointId: ''
|
||||||
}
|
}
|
||||||
@ -475,12 +478,20 @@ export default {
|
|||||||
this.loadThingsModel(deviceId)
|
this.loadThingsModel(deviceId)
|
||||||
},
|
},
|
||||||
searchDevice(query) {
|
searchDevice(query) {
|
||||||
if (!query) return
|
const keyword = (query || '').trim()
|
||||||
|
if (!keyword) return
|
||||||
this.deviceSearchLoading = true
|
this.deviceSearchLoading = true
|
||||||
listDevice({ pageNum: 1, pageSize: 50, deviceName: query }).then(res => {
|
listDevice({ pageNum: 1, pageSize: 50, ...this.buildDeviceSearchParams(keyword) }).then(res => {
|
||||||
this.deviceOptions = res.rows; this.deviceSearchLoading = false
|
this.deviceOptions = res.rows; this.deviceSearchLoading = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
buildDeviceSearchParams(query) {
|
||||||
|
const keyword = (query || '').trim()
|
||||||
|
if (keyword.length === 12) {
|
||||||
|
return { serialNumber: keyword }
|
||||||
|
}
|
||||||
|
return { deviceName: keyword }
|
||||||
|
},
|
||||||
loadDeviceContext(deviceId) {
|
loadDeviceContext(deviceId) {
|
||||||
if (!deviceId) return
|
if (!deviceId) return
|
||||||
getDevice(deviceId).then(res => {
|
getDevice(deviceId).then(res => {
|
||||||
@ -524,18 +535,13 @@ export default {
|
|||||||
if (!this.form.id) {
|
if (!this.form.id) {
|
||||||
this.form.deviceType = this.subDeviceOptions.length > 0 ? 1 : 0
|
this.form.deviceType = this.subDeviceOptions.length > 0 ? 1 : 0
|
||||||
}
|
}
|
||||||
// 网关设备且子映射为空时,自动预填所有子设备,第一个为基准点
|
// 网关设备且子映射为空时,自动预填所有子设备;基准点由用户明确指定
|
||||||
if (this.form.deviceType === 1 && this.subMappingRows.length === 0 && this.subDeviceOptions.length > 0) {
|
if (this.form.deviceType === 1 && this.subMappingRows.length === 0 && this.subDeviceOptions.length > 0) {
|
||||||
this.subMappingRows = this.subDeviceOptions.map((device, idx) => {
|
this.subMappingRows = this.subDeviceOptions.map(device => {
|
||||||
const role = idx === 0 ? 'reference' : 'monitor'
|
|
||||||
const refSn = this.subDeviceOptions[0].serialNumber
|
|
||||||
const config = role === 'reference'
|
|
||||||
? JSON.stringify({ sensorId: device.serialNumber })
|
|
||||||
: JSON.stringify({ sensorId: device.serialNumber, refSensorId: refSn, refSerialNumber: refSn })
|
|
||||||
return {
|
return {
|
||||||
subSerialNumber: device.serialNumber,
|
subSerialNumber: device.serialNumber,
|
||||||
deviceRole: role,
|
deviceRole: 'monitor',
|
||||||
onboardConfig: config,
|
onboardConfig: JSON.stringify({ sensorId: device.serialNumber }),
|
||||||
platformDeviceId: '',
|
platformDeviceId: '',
|
||||||
platformPointId: ''
|
platformPointId: ''
|
||||||
}
|
}
|
||||||
@ -553,18 +559,69 @@ export default {
|
|||||||
addSubMapping() {
|
addSubMapping() {
|
||||||
this.subMappingRows.push({ subSerialNumber: '', deviceRole: 'monitor', onboardConfig: '', platformDeviceId: '', platformPointId: '' })
|
this.subMappingRows.push({ subSerialNumber: '', deviceRole: 'monitor', onboardConfig: '', platformDeviceId: '', platformPointId: '' })
|
||||||
},
|
},
|
||||||
onSubSerialChange(row) {
|
onSubRoleChange(row) {
|
||||||
// 自动填充 onboardConfig 中的 sensorId
|
if (row.deviceRole === 'reference') {
|
||||||
if (!row.onboardConfig && row.subSerialNumber) {
|
this.subMappingRows.forEach(item => {
|
||||||
const refRow = this.subMappingRows.find(r => r.deviceRole === 'reference')
|
if (item !== row && item.deviceRole === 'reference') {
|
||||||
if (row.deviceRole === 'reference') {
|
item.deviceRole = 'monitor'
|
||||||
row.onboardConfig = JSON.stringify({ sensorId: row.subSerialNumber })
|
}
|
||||||
} else if (refRow) {
|
})
|
||||||
row.onboardConfig = JSON.stringify({ sensorId: row.subSerialNumber, refSensorId: refRow.subSerialNumber, refSerialNumber: refRow.subSerialNumber })
|
|
||||||
} else {
|
|
||||||
row.onboardConfig = JSON.stringify({ sensorId: row.subSerialNumber })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
this.refreshSubMappingOnboardConfigs()
|
||||||
|
},
|
||||||
|
onSubSerialChange(row) {
|
||||||
|
if (!row.subSerialNumber) return
|
||||||
|
row.onboardConfig = JSON.stringify({ sensorId: row.subSerialNumber })
|
||||||
|
this.refreshSubMappingOnboardConfigs()
|
||||||
|
},
|
||||||
|
findReferenceRow(rows = this.subMappingRows) {
|
||||||
|
return (rows || []).find(r => r.deviceRole === 'reference' && r.subSerialNumber)
|
||||||
|
},
|
||||||
|
buildOnboardConfig(row, refRow) {
|
||||||
|
const config = this.safeParseJson(row.onboardConfig, {})
|
||||||
|
const next = { ...config, sensorId: config.sensorId || row.subSerialNumber }
|
||||||
|
if (row.deviceRole === 'reference') {
|
||||||
|
delete next.refSensorId
|
||||||
|
delete next.refSerialNumber
|
||||||
|
} else if (refRow && refRow.subSerialNumber) {
|
||||||
|
const refConfig = this.safeParseJson(refRow.onboardConfig, {})
|
||||||
|
next.refSensorId = refConfig.sensorId || refRow.subSerialNumber
|
||||||
|
next.refSerialNumber = refRow.subSerialNumber
|
||||||
|
} else {
|
||||||
|
delete next.refSensorId
|
||||||
|
delete next.refSerialNumber
|
||||||
|
}
|
||||||
|
return JSON.stringify(next)
|
||||||
|
},
|
||||||
|
refreshSubMappingOnboardConfigs() {
|
||||||
|
const refRow = this.findReferenceRow()
|
||||||
|
if (refRow && refRow.subSerialNumber) {
|
||||||
|
refRow.onboardConfig = this.buildOnboardConfig(refRow, null)
|
||||||
|
}
|
||||||
|
this.subMappingRows.forEach(row => {
|
||||||
|
if (!row.subSerialNumber || row === refRow) return
|
||||||
|
row.onboardConfig = this.buildOnboardConfig(row, refRow)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
normalizeSubMappingsForSubmit() {
|
||||||
|
const rows = (this.subMappingRows || [])
|
||||||
|
.filter(r => r.subSerialNumber)
|
||||||
|
.map(r => ({ ...r, deviceRole: r.deviceRole || 'monitor' }))
|
||||||
|
const references = rows.filter(r => r.deviceRole === 'reference')
|
||||||
|
const monitors = rows.filter(r => r.deviceRole === 'monitor')
|
||||||
|
if (references.length > 1) {
|
||||||
|
this.$modal.msgError('只能指定一个基准点')
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
if (this.form.sensorType === 'static_level' && (references.length !== 1 || monitors.length === 0)) {
|
||||||
|
this.$modal.msgError('静力水准需配置 1 个基准点和至少 1 个监测点')
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const refRow = references[0] || null
|
||||||
|
return rows.map(row => ({
|
||||||
|
...row,
|
||||||
|
onboardConfig: this.buildOnboardConfig(row, refRow)
|
||||||
|
}))
|
||||||
},
|
},
|
||||||
safeParseJson(value, defaultValue) {
|
safeParseJson(value, defaultValue) {
|
||||||
if (!value) return defaultValue
|
if (!value) return defaultValue
|
||||||
@ -576,6 +633,13 @@ export default {
|
|||||||
if (!valid) return
|
if (!valid) return
|
||||||
this.form.fieldMapping = this.fieldMappingRows.length > 0
|
this.form.fieldMapping = this.fieldMappingRows.length > 0
|
||||||
? JSON.stringify(this.fieldMappingRows) : null
|
? JSON.stringify(this.fieldMappingRows) : null
|
||||||
|
const normalizedSubRows = this.form.deviceType === 1
|
||||||
|
? this.normalizeSubMappingsForSubmit()
|
||||||
|
: []
|
||||||
|
if (this.form.deviceType === 1 && normalizedSubRows === null) return
|
||||||
|
if (this.form.deviceType === 1) {
|
||||||
|
this.subMappingRows = normalizedSubRows
|
||||||
|
}
|
||||||
// 网关设备:extra_mapping 只存数据映射配置
|
// 网关设备:extra_mapping 只存数据映射配置
|
||||||
if (this.form.deviceType === 1) {
|
if (this.form.deviceType === 1) {
|
||||||
this.form.extraMapping = JSON.stringify({
|
this.form.extraMapping = JSON.stringify({
|
||||||
@ -591,8 +655,7 @@ export default {
|
|||||||
const mappingId = this.form.id || (res.data && res.data.id) || res.data
|
const mappingId = this.form.id || (res.data && res.data.id) || res.data
|
||||||
// 网关设备:保存后同步子映射
|
// 网关设备:保存后同步子映射
|
||||||
if (this.form.deviceType === 1 && mappingId) {
|
if (this.form.deviceType === 1 && mappingId) {
|
||||||
const subData = this.subMappingRows
|
const subData = normalizedSubRows
|
||||||
.filter(r => r.subSerialNumber)
|
|
||||||
.map(r => ({
|
.map(r => ({
|
||||||
subSerialNumber: r.subSerialNumber,
|
subSerialNumber: r.subSerialNumber,
|
||||||
deviceRole: r.deviceRole || 'monitor',
|
deviceRole: r.deviceRole || 'monitor',
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user