fix: 微信小程序接口对接,测试问题修复。
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
package com.intc.fishery.constant;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 设备故障码常量定义
|
||||
*
|
||||
* @author intc
|
||||
*/
|
||||
public class DefineDeviceErrorCode {
|
||||
/**
|
||||
* 电源关闭
|
||||
*/
|
||||
public static final int PowerOff = 1;
|
||||
|
||||
// 三相电压告警 (2-7)
|
||||
/**
|
||||
* 三相A相过压
|
||||
*/
|
||||
public static final int Three_PhaseA_OverVoltage = 2;
|
||||
/**
|
||||
* 三相B相过压
|
||||
*/
|
||||
public static final int Three_PhaseB_OverVoltage = 3;
|
||||
/**
|
||||
* 三相C相过压
|
||||
*/
|
||||
public static final int Three_PhaseC_OverVoltage = 4;
|
||||
/**
|
||||
* 三相A相欠压
|
||||
*/
|
||||
public static final int Three_PhaseA_UnderVoltage = 5;
|
||||
/**
|
||||
* 三相B相欠压
|
||||
*/
|
||||
public static final int Three_PhaseB_UnderVoltage = 6;
|
||||
/**
|
||||
* 三相C相欠压
|
||||
*/
|
||||
public static final int Three_PhaseC_UnderVoltage = 7;
|
||||
|
||||
// 三相电流告警 (8-23)
|
||||
/**
|
||||
* 三相开关1路A相过流
|
||||
*/
|
||||
public static final int Three_Switch1OverElectricA = 8;
|
||||
public static final int Three_Switch1OverElectricB = 9;
|
||||
public static final int Three_Switch1OverElectricC = 10;
|
||||
public static final int Three_Switch2OverElectricA = 11;
|
||||
public static final int Three_Switch2OverElectricB = 12;
|
||||
public static final int Three_Switch2OverElectricC = 13;
|
||||
public static final int Three_Switch3OverElectricA = 14;
|
||||
public static final int Three_Switch3OverElectricB = 15;
|
||||
public static final int Three_Switch3OverElectricC = 16;
|
||||
public static final int Three_Switch4OverElectricA = 17;
|
||||
public static final int Three_Switch4OverElectricB = 18;
|
||||
public static final int Three_Switch4OverElectricC = 19;
|
||||
/**
|
||||
* 三相开关1路缺相
|
||||
*/
|
||||
public static final int Three_Switch1ElectricEmpty = 20;
|
||||
public static final int Three_Switch2ElectricEmpty = 21;
|
||||
public static final int Three_Switch3ElectricEmpty = 22;
|
||||
public static final int Three_Switch4ElectricEmpty = 23;
|
||||
|
||||
// 单相电流告警 (24-31)
|
||||
/**
|
||||
* 单相开关1路过流
|
||||
*/
|
||||
public static final int One_Switch1OverElectric = 24;
|
||||
public static final int One_Switch2OverElectric = 25;
|
||||
public static final int One_Switch3OverElectric = 26;
|
||||
public static final int One_Switch4OverElectric = 27;
|
||||
/**
|
||||
* 单相开关1路缺相
|
||||
*/
|
||||
public static final int One_Switch1ElectricEmpty = 28;
|
||||
public static final int One_Switch2ElectricEmpty = 29;
|
||||
public static final int One_Switch3ElectricEmpty = 30;
|
||||
public static final int One_Switch4ElectricEmpty = 31;
|
||||
|
||||
private static final Map<Integer, String> ERROR_CODE_MESSAGES = new HashMap<>();
|
||||
|
||||
static {
|
||||
ERROR_CODE_MESSAGES.put(PowerOff, "电源关闭");
|
||||
ERROR_CODE_MESSAGES.put(Three_PhaseA_OverVoltage, "A相过压");
|
||||
ERROR_CODE_MESSAGES.put(Three_PhaseB_OverVoltage, "B相过压");
|
||||
ERROR_CODE_MESSAGES.put(Three_PhaseC_OverVoltage, "C相过压");
|
||||
ERROR_CODE_MESSAGES.put(Three_PhaseA_UnderVoltage, "A相欠压");
|
||||
ERROR_CODE_MESSAGES.put(Three_PhaseB_UnderVoltage, "B相欠压");
|
||||
ERROR_CODE_MESSAGES.put(Three_PhaseC_UnderVoltage, "C相欠压");
|
||||
ERROR_CODE_MESSAGES.put(Three_Switch1OverElectricA, "1路A相过流");
|
||||
ERROR_CODE_MESSAGES.put(Three_Switch1OverElectricB, "1路B相过流");
|
||||
ERROR_CODE_MESSAGES.put(Three_Switch1OverElectricC, "1路C相过流");
|
||||
ERROR_CODE_MESSAGES.put(Three_Switch2OverElectricA, "2路A相过流");
|
||||
ERROR_CODE_MESSAGES.put(Three_Switch2OverElectricB, "2路B相过流");
|
||||
ERROR_CODE_MESSAGES.put(Three_Switch2OverElectricC, "2路C相过流");
|
||||
ERROR_CODE_MESSAGES.put(Three_Switch3OverElectricA, "3路A相过流");
|
||||
ERROR_CODE_MESSAGES.put(Three_Switch3OverElectricB, "3路B相过流");
|
||||
ERROR_CODE_MESSAGES.put(Three_Switch3OverElectricC, "3路C相过流");
|
||||
ERROR_CODE_MESSAGES.put(Three_Switch4OverElectricA, "4路A相过流");
|
||||
ERROR_CODE_MESSAGES.put(Three_Switch4OverElectricB, "4路B相过流");
|
||||
ERROR_CODE_MESSAGES.put(Three_Switch4OverElectricC, "4路C相过流");
|
||||
ERROR_CODE_MESSAGES.put(Three_Switch1ElectricEmpty, "1路缺相");
|
||||
ERROR_CODE_MESSAGES.put(Three_Switch2ElectricEmpty, "2路缺相");
|
||||
ERROR_CODE_MESSAGES.put(Three_Switch3ElectricEmpty, "3路缺相");
|
||||
ERROR_CODE_MESSAGES.put(Three_Switch4ElectricEmpty, "4路缺相");
|
||||
ERROR_CODE_MESSAGES.put(One_Switch1OverElectric, "1路过流");
|
||||
ERROR_CODE_MESSAGES.put(One_Switch2OverElectric, "2路过流");
|
||||
ERROR_CODE_MESSAGES.put(One_Switch3OverElectric, "3路过流");
|
||||
ERROR_CODE_MESSAGES.put(One_Switch4OverElectric, "4路过流");
|
||||
ERROR_CODE_MESSAGES.put(One_Switch1ElectricEmpty, "1路缺相");
|
||||
ERROR_CODE_MESSAGES.put(One_Switch2ElectricEmpty, "2路缺相");
|
||||
ERROR_CODE_MESSAGES.put(One_Switch3ElectricEmpty, "3路缺相");
|
||||
ERROR_CODE_MESSAGES.put(One_Switch4ElectricEmpty, "4路缺相");
|
||||
}
|
||||
|
||||
private DefineDeviceErrorCode() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取故障码对应的错误信息
|
||||
*/
|
||||
public static String getErrorMessage(int errorCode) {
|
||||
return ERROR_CODE_MESSAGES.getOrDefault(errorCode, "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package com.intc.fishery.constant;
|
||||
|
||||
/**
|
||||
* 设备告警码常量定义
|
||||
*
|
||||
* @author intc
|
||||
*/
|
||||
public class DefineDeviceWarnCode {
|
||||
/**
|
||||
* 无告警
|
||||
*/
|
||||
public static final int None = 0;
|
||||
|
||||
/**
|
||||
* 用户自定义告警最大码
|
||||
*/
|
||||
public static final int UserMaxCode = 65536;
|
||||
|
||||
/**
|
||||
* 低溶氧告警
|
||||
*/
|
||||
public static final int LowOxygen = 1;
|
||||
|
||||
/**
|
||||
* 高温告警
|
||||
*/
|
||||
public static final int HighTemperature = 2;
|
||||
|
||||
/**
|
||||
* 低温告警
|
||||
*/
|
||||
public static final int LowTemperature = 4;
|
||||
|
||||
/**
|
||||
* PH值告警
|
||||
*/
|
||||
public static final int PHAlarm = 8;
|
||||
|
||||
/**
|
||||
* 盐度告警
|
||||
*/
|
||||
public static final int SalinityAlarm = 16;
|
||||
|
||||
/**
|
||||
* 设备离线
|
||||
*/
|
||||
public static final int DeviceOffline = 32;
|
||||
|
||||
/**
|
||||
* 设备失联
|
||||
*/
|
||||
public static final int DeviceDead = 64;
|
||||
|
||||
private DefineDeviceWarnCode() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换告警码为告警描述
|
||||
*/
|
||||
public static String toWarnDescription(int warnCode) {
|
||||
if (warnCode == None) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if ((warnCode & LowOxygen) != 0) {
|
||||
sb.append("低溶氧告警,");
|
||||
}
|
||||
if ((warnCode & HighTemperature) != 0) {
|
||||
sb.append("高温告警,");
|
||||
}
|
||||
if ((warnCode & LowTemperature) != 0) {
|
||||
sb.append("低温告警,");
|
||||
}
|
||||
if ((warnCode & PHAlarm) != 0) {
|
||||
sb.append("PH值告警,");
|
||||
}
|
||||
if ((warnCode & SalinityAlarm) != 0) {
|
||||
sb.append("盐度告警,");
|
||||
}
|
||||
if ((warnCode & DeviceOffline) != 0) {
|
||||
sb.append("设备离线,");
|
||||
}
|
||||
if ((warnCode & DeviceDead) != 0) {
|
||||
sb.append("设备失联,");
|
||||
}
|
||||
|
||||
// 移除最后的逗号
|
||||
if (sb.length() > 0) {
|
||||
sb.setLength(sb.length() - 1);
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,19 @@ import com.intc.fishery.domain.vo.DeviceVo;
|
||||
import com.intc.fishery.domain.bo.DeviceBo;
|
||||
import com.intc.fishery.service.IDeviceService;
|
||||
import com.intc.common.mybatis.core.page.TableDataInfo;
|
||||
import com.intc.fishery.domain.vo.PublicDeviceSimpleVo;
|
||||
import com.intc.fishery.domain.vo.PublicPondIdNameVo;
|
||||
import com.intc.fishery.domain.vo.PublicDeviceSwitchSimpleVo;
|
||||
import com.intc.fishery.domain.Device;
|
||||
import com.intc.fishery.domain.DeviceSwitch;
|
||||
import com.intc.fishery.domain.Pond;
|
||||
import com.intc.fishery.mapper.DeviceMapper;
|
||||
import com.intc.fishery.mapper.DeviceSwitchMapper;
|
||||
import com.intc.fishery.mapper.PondMapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 设备管理
|
||||
@@ -35,6 +48,9 @@ import com.intc.common.mybatis.core.page.TableDataInfo;
|
||||
public class DeviceController extends BaseController {
|
||||
|
||||
private final IDeviceService deviceService;
|
||||
private final DeviceMapper deviceMapper;
|
||||
private final DeviceSwitchMapper deviceSwitchMapper;
|
||||
private final PondMapper pondMapper;
|
||||
|
||||
/**
|
||||
* 查询设备管理列表
|
||||
@@ -102,4 +118,146 @@ public class DeviceController extends BaseController {
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(deviceService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户所有设备简化列表
|
||||
* type=1: 返回完整信息(包含塘口信息和开关列表)
|
||||
* type!=1: 只返回基本信息(id, deviceName, deviceType, deadTime)
|
||||
*
|
||||
* @param rootUserId 用户ID
|
||||
* @param type 查询类型(1-完整信息,其他-基本信息)
|
||||
*/
|
||||
@GetMapping("/list_all_device")
|
||||
public R<List<PublicDeviceSimpleVo>> getDeviceSimpleList(
|
||||
@RequestParam("rootUserId") Long rootUserId,
|
||||
@RequestParam("type") Integer type) {
|
||||
|
||||
// 查询用户的所有设备
|
||||
List<Device> devices = deviceMapper.selectList(
|
||||
new LambdaQueryWrapper<Device>()
|
||||
.eq(Device::getUserId, rootUserId)
|
||||
.orderByDesc(Device::getCreateTime)
|
||||
);
|
||||
|
||||
if (devices == null || devices.isEmpty()) {
|
||||
return R.ok(List.of());
|
||||
}
|
||||
|
||||
// type=1: 返回完整信息
|
||||
if (type == 1) {
|
||||
// 批量查询所有需要的塘口信息
|
||||
List<Long> pondIds = devices.stream()
|
||||
.map(Device::getPondId)
|
||||
.filter(id -> id != null && id > 0)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Map<Long, Pond> pondMap = Map.of();
|
||||
if (!pondIds.isEmpty()) {
|
||||
List<Pond> ponds = pondMapper.selectBatchIds(pondIds);
|
||||
pondMap = ponds.stream()
|
||||
.collect(Collectors.toMap(Pond::getId, Function.identity()));
|
||||
}
|
||||
|
||||
// 批量查询所有开关
|
||||
List<Long> deviceIds = devices.stream()
|
||||
.map(Device::getId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<DeviceSwitch> allSwitches = deviceSwitchMapper.selectList(
|
||||
new LambdaQueryWrapper<DeviceSwitch>()
|
||||
.in(DeviceSwitch::getDeviceId, deviceIds)
|
||||
.orderByAsc(DeviceSwitch::getIndex)
|
||||
);
|
||||
|
||||
// 按设备ID分组开关
|
||||
Map<Long, List<DeviceSwitch>> switchMap = allSwitches.stream()
|
||||
.collect(Collectors.groupingBy(DeviceSwitch::getDeviceId));
|
||||
|
||||
// 开关关联的塘口ID
|
||||
List<Long> switchPondIds = allSwitches.stream()
|
||||
.map(DeviceSwitch::getPondId)
|
||||
.filter(id -> id != null && id > 0)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 合并塘口查询
|
||||
if (!switchPondIds.isEmpty()) {
|
||||
List<Pond> switchPonds = pondMapper.selectBatchIds(switchPondIds);
|
||||
Map<Long, Pond> finalPondMap = pondMap;
|
||||
pondMap = switchPonds.stream()
|
||||
.collect(Collectors.toMap(Pond::getId, Function.identity(), (v1, v2) -> v1));
|
||||
pondMap.putAll(finalPondMap);
|
||||
}
|
||||
|
||||
Map<Long, Pond> finalPondMapForLambda = pondMap;
|
||||
|
||||
// 构建返回结果
|
||||
List<PublicDeviceSimpleVo> result = devices.stream()
|
||||
.map(device -> {
|
||||
PublicDeviceSimpleVo vo = new PublicDeviceSimpleVo();
|
||||
vo.setId(device.getId());
|
||||
vo.setDeviceName(device.getDeviceName());
|
||||
vo.setDeviceType(device.getDeviceType());
|
||||
vo.setDeadTime(device.getDeadTime());
|
||||
vo.setIsOxygenUsed(device.getIsOxygenUsed());
|
||||
|
||||
// 设置塘口信息
|
||||
if (device.getPondId() != null && device.getPondId() > 0) {
|
||||
Pond pond = finalPondMapForLambda.get(device.getPondId());
|
||||
if (pond != null) {
|
||||
PublicPondIdNameVo pondInfo = new PublicPondIdNameVo();
|
||||
pondInfo.setId(pond.getId());
|
||||
pondInfo.setPondName(pond.getPondName());
|
||||
vo.setPondInfo(pondInfo);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置开关列表
|
||||
List<DeviceSwitch> switches = switchMap.getOrDefault(device.getId(), List.of());
|
||||
List<PublicDeviceSwitchSimpleVo> switchVos = switches.stream()
|
||||
.map(s -> {
|
||||
PublicDeviceSwitchSimpleVo switchVo = new PublicDeviceSwitchSimpleVo();
|
||||
switchVo.setId(s.getId());
|
||||
switchVo.setIndex(s.getIndex());
|
||||
switchVo.setSwitchName(s.getSwitchName());
|
||||
|
||||
// 设置开关的塘口信息
|
||||
if (s.getPondId() != null && s.getPondId() > 0) {
|
||||
Pond pond = finalPondMapForLambda.get(s.getPondId());
|
||||
if (pond != null) {
|
||||
PublicPondIdNameVo pondInfo = new PublicPondIdNameVo();
|
||||
pondInfo.setId(pond.getId());
|
||||
pondInfo.setPondName(pond.getPondName());
|
||||
switchVo.setPondInfo(pondInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return switchVo;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
vo.setListSwitch(switchVos);
|
||||
|
||||
return vo;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return R.ok(result);
|
||||
}
|
||||
// type!=1: 只返回基本信息
|
||||
else {
|
||||
List<PublicDeviceSimpleVo> result = devices.stream()
|
||||
.map(device -> {
|
||||
PublicDeviceSimpleVo vo = new PublicDeviceSimpleVo();
|
||||
vo.setId(device.getId());
|
||||
vo.setDeviceName(device.getDeviceName());
|
||||
vo.setDeviceType(device.getDeviceType());
|
||||
vo.setDeadTime(device.getDeadTime());
|
||||
return vo;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return R.ok(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,36 @@ import com.intc.fishery.domain.vo.AquUserVo;
|
||||
import com.intc.fishery.domain.bo.AquUserBo;
|
||||
import com.intc.system.service.ISysUserService;
|
||||
import com.intc.system.domain.vo.SysUserVo;
|
||||
import com.intc.fishery.domain.vo.PondDeviceListVo;
|
||||
import com.intc.fishery.domain.vo.DeviceVo;
|
||||
import com.intc.fishery.domain.vo.DeviceWithSwitchVo;
|
||||
import com.intc.fishery.domain.vo.DeviceSwitchVo;
|
||||
import com.intc.fishery.mapper.DeviceMapper;
|
||||
import com.intc.fishery.mapper.DeviceSwitchMapper;
|
||||
import com.intc.fishery.domain.Device;
|
||||
import com.intc.fishery.domain.DeviceSwitch;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import java.util.stream.Collectors;
|
||||
import com.intc.common.core.utils.MapstructUtils;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.intc.fishery.domain.bo.PondSelectDeviceOrSwitchBo;
|
||||
import com.intc.fishery.domain.Pond;
|
||||
import com.intc.fishery.mapper.PondMapper;
|
||||
import com.intc.fishery.mapper.LinkedCtrlMapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.ArrayList;
|
||||
import com.intc.fishery.domain.LinkedCtrl;
|
||||
import com.intc.fishery.domain.vo.PublicPondMode1Vo;
|
||||
import com.intc.fishery.domain.vo.PondMode1WarnCodeInfo;
|
||||
import com.intc.fishery.mapper.DeviceErrorCodeMapper;
|
||||
import com.intc.fishery.domain.DeviceErrorCode;
|
||||
import com.intc.fishery.constant.DefineDeviceWarnCode;
|
||||
import com.intc.fishery.constant.DefineDeviceErrorCode;
|
||||
import com.intc.fishery.mapper.TimingCtrlMapper;
|
||||
import com.intc.fishery.domain.TimingCtrl;
|
||||
|
||||
/**
|
||||
* 塘口管理
|
||||
@@ -43,6 +73,12 @@ public class PondController extends BaseController {
|
||||
private final IPondService pondService;
|
||||
private final IAquUserService aquUserService;
|
||||
private final ISysUserService sysUserService;
|
||||
private final DeviceMapper deviceMapper;
|
||||
private final DeviceSwitchMapper deviceSwitchMapper;
|
||||
private final PondMapper pondMapper;
|
||||
private final LinkedCtrlMapper linkedCtrlMapper;
|
||||
private final DeviceErrorCodeMapper deviceErrorCodeMapper;
|
||||
private final TimingCtrlMapper timingCtrlMapper;
|
||||
|
||||
/**
|
||||
* 查询塘口管理列表
|
||||
@@ -140,4 +176,636 @@ public class PondController extends BaseController {
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(pondService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据塘口ID查询设备列表
|
||||
* 返回数据按设备类型分类:
|
||||
* - listDetector: 水质检测仪列表(deviceType=1)+ 开启溶氧检测的测控一体机(deviceType=2 && isOxygenUsed=1)
|
||||
* - listController: 测控一体机列表(deviceType=2),包含开关列表
|
||||
*
|
||||
* @param pondId 塘口ID
|
||||
*/
|
||||
@GetMapping("/devices/{pondId}")
|
||||
public R<PondDeviceListVo> getDevicesByPondId(@NotNull(message = "塘口ID不能为空")
|
||||
@PathVariable Long pondId) {
|
||||
PondDeviceListVo result = new PondDeviceListVo();
|
||||
|
||||
// 1. 查询塘口下的所有设备
|
||||
List<Device> devices = deviceMapper.selectList(
|
||||
new LambdaQueryWrapper<Device>()
|
||||
.eq(Device::getPondId, pondId)
|
||||
.orderByAsc(Device::getDeviceType)
|
||||
.orderByDesc(Device::getCreateTime)
|
||||
);
|
||||
|
||||
if (devices == null || devices.isEmpty()) {
|
||||
result.setListDetector(List.of());
|
||||
result.setListController(List.of());
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
// 2. 收集所有设备ID,用于查询联动控制和故障码
|
||||
List<Long> deviceIds = devices.stream()
|
||||
.map(Device::getId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 3. 批量查询所有设备的联动控制
|
||||
List<LinkedCtrl> allLinkedCtrls = linkedCtrlMapper.selectList(
|
||||
new LambdaQueryWrapper<LinkedCtrl>()
|
||||
.in(LinkedCtrl::getDeviceId, deviceIds)
|
||||
);
|
||||
java.util.Map<Long, List<LinkedCtrl>> linkedCtrlsByDevice = allLinkedCtrls.stream()
|
||||
.collect(Collectors.groupingBy(LinkedCtrl::getDeviceId));
|
||||
|
||||
// 4. 批量查询塘口的所有开关
|
||||
List<DeviceSwitch> allSwitches = deviceSwitchMapper.selectList(
|
||||
new LambdaQueryWrapper<DeviceSwitch>()
|
||||
.eq(DeviceSwitch::getPondId, pondId)
|
||||
.orderByAsc(DeviceSwitch::getIndex)
|
||||
);
|
||||
|
||||
// 5. 收集开关ID,查询定时控制
|
||||
List<Long> switchIds = allSwitches.stream()
|
||||
.map(DeviceSwitch::getId)
|
||||
.collect(Collectors.toList());
|
||||
java.util.Map<Long, List<TimingCtrl>> timingCtrlsBySwitch = new java.util.HashMap<>();
|
||||
if (!switchIds.isEmpty()) {
|
||||
List<TimingCtrl> allTimingCtrls = timingCtrlMapper.selectList(
|
||||
new LambdaQueryWrapper<TimingCtrl>()
|
||||
.in(TimingCtrl::getSwitchId, switchIds)
|
||||
);
|
||||
timingCtrlsBySwitch = allTimingCtrls.stream()
|
||||
.collect(Collectors.groupingBy(TimingCtrl::getSwitchId));
|
||||
}
|
||||
|
||||
// 6. 按设备ID分组开关
|
||||
java.util.Map<Long, List<DeviceSwitch>> switchesByDevice = allSwitches.stream()
|
||||
.collect(Collectors.groupingBy(DeviceSwitch::getDeviceId));
|
||||
|
||||
// 7. 批量查询故障码
|
||||
Set<Long> controllerIds = devices.stream()
|
||||
.filter(d -> d.getDeviceType() != null && d.getDeviceType() == 2)
|
||||
.map(Device::getId)
|
||||
.collect(Collectors.toSet());
|
||||
List<DeviceErrorCode> errorCodes = new ArrayList<>();
|
||||
if (!controllerIds.isEmpty()) {
|
||||
errorCodes = deviceErrorCodeMapper.selectList(
|
||||
new LambdaQueryWrapper<DeviceErrorCode>()
|
||||
.in(DeviceErrorCode::getDeviceId, controllerIds)
|
||||
);
|
||||
}
|
||||
|
||||
// 8. 处理探测器列表 (包含: deviceType=1 + deviceType=2且isOxygenUsed=1)
|
||||
List<DeviceVo> detectorList = new ArrayList<>();
|
||||
for (Device device : devices) {
|
||||
// 水质检测仪 或 开启溶氧检测的测控一体机
|
||||
if ((device.getDeviceType() != null && device.getDeviceType() == 1)
|
||||
|| (device.getDeviceType() != null && device.getDeviceType() == 2
|
||||
&& device.getIsOxygenUsed() != null && device.getIsOxygenUsed() == 1)) {
|
||||
|
||||
DeviceVo deviceVo = MapstructUtils.convert(device, DeviceVo.class);
|
||||
|
||||
// 设置告警码信息
|
||||
if (device.getWarnCode() != null && device.getWarnCode() < DefineDeviceWarnCode.UserMaxCode) {
|
||||
// 告警码信息已在DeviceVo中,无需额外处理
|
||||
} else {
|
||||
deviceVo.setWarnCode(DefineDeviceWarnCode.None);
|
||||
}
|
||||
|
||||
// 判断是否有联动控制
|
||||
deviceVo.setIsLinkCtrl(false);
|
||||
List<LinkedCtrl> linkedCtrls = linkedCtrlsByDevice.get(device.getId());
|
||||
if (linkedCtrls != null && !linkedCtrls.isEmpty()) {
|
||||
for (LinkedCtrl linkedCtrl : linkedCtrls) {
|
||||
if ((linkedCtrl.getOxyLowerOpen() != null && linkedCtrl.getOxyLowerOpen() == 1)
|
||||
|| (linkedCtrl.getOxyUpperOpen() != null && linkedCtrl.getOxyUpperOpen() == 1)) {
|
||||
deviceVo.setIsLinkCtrl(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
detectorList.add(deviceVo);
|
||||
}
|
||||
}
|
||||
|
||||
// 9. 处理控制器列表 (仅测控一体机 deviceType=2)
|
||||
List<DeviceWithSwitchVo> controllerList = new ArrayList<>();
|
||||
for (Device device : devices) {
|
||||
if (device.getDeviceType() != null && device.getDeviceType() == 2) {
|
||||
// 转换为DeviceVo再复制到DeviceWithSwitchVo
|
||||
DeviceVo baseDeviceVo = MapstructUtils.convert(device, DeviceVo.class);
|
||||
DeviceWithSwitchVo deviceVo = new DeviceWithSwitchVo();
|
||||
BeanUtil.copyProperties(baseDeviceVo, deviceVo);
|
||||
|
||||
// 初始化告警码信息
|
||||
PondMode1WarnCodeInfo warnCodeInfo = new PondMode1WarnCodeInfo();
|
||||
if (device.getWarnCode() != null && device.getWarnCode() < DefineDeviceWarnCode.UserMaxCode) {
|
||||
warnCodeInfo.setWarnCode(device.getWarnCode());
|
||||
warnCodeInfo.setWarnDescription(DefineDeviceWarnCode.toWarnDescription(device.getWarnCode()));
|
||||
} else {
|
||||
warnCodeInfo.setWarnCode(DefineDeviceWarnCode.None);
|
||||
warnCodeInfo.setWarnDescription("");
|
||||
}
|
||||
deviceVo.setWarnCodeInfo(warnCodeInfo);
|
||||
|
||||
// 处理设备级故障码 (switchIndex=0的故障)
|
||||
StringBuilder errorMessage = new StringBuilder();
|
||||
for (DeviceErrorCode errorCode : errorCodes) {
|
||||
if (!errorCode.getDeviceId().equals(device.getId())) {
|
||||
continue;
|
||||
}
|
||||
if (errorCode.getSwitchIndex() == null || errorCode.getSwitchIndex() != 0) {
|
||||
continue;
|
||||
}
|
||||
if (errorCode.getErrorCode() == null || errorCode.getErrorCode() > DefineDeviceErrorCode.PowerOff) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 电压告警需要开关打开
|
||||
boolean isVoltageError = errorCode.getErrorCode() >= DefineDeviceErrorCode.Three_PhaseA_OverVoltage
|
||||
&& errorCode.getErrorCode() <= DefineDeviceErrorCode.Three_PhaseC_UnderVoltage;
|
||||
|
||||
if (device.getVoltageWarnOpen() != null && device.getVoltageWarnOpen() == 1 && isVoltageError
|
||||
|| !isVoltageError) {
|
||||
String msg = DefineDeviceErrorCode.getErrorMessage(errorCode.getErrorCode());
|
||||
if (msg != null && !msg.isEmpty()) {
|
||||
if (errorMessage.length() > 0 && !errorMessage.toString().contains(msg)) {
|
||||
errorMessage.append(",");
|
||||
}
|
||||
if (!errorMessage.toString().contains(msg)) {
|
||||
errorMessage.append(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
deviceVo.setErrorMessage(errorMessage.toString());
|
||||
|
||||
// 查询该设备的开关列表
|
||||
List<DeviceSwitch> switches = switchesByDevice.getOrDefault(device.getId(), new ArrayList<>());
|
||||
List<DeviceSwitchVo> switchVoList = new ArrayList<>();
|
||||
|
||||
for (DeviceSwitch sw : switches) {
|
||||
DeviceSwitchVo switchVo = MapstructUtils.convert(sw, DeviceSwitchVo.class);
|
||||
|
||||
// 判断是否有联动控制
|
||||
switchVo.setIsLinkedCtrl(0);
|
||||
if (sw.getLinkedCtrlId() != null) {
|
||||
LinkedCtrl linkedCtrl = linkedCtrlMapper.selectById(sw.getLinkedCtrlId());
|
||||
if (linkedCtrl != null
|
||||
&& ((linkedCtrl.getOxyLowerOpen() != null && linkedCtrl.getOxyLowerOpen() == 1)
|
||||
|| (linkedCtrl.getOxyUpperOpen() != null && linkedCtrl.getOxyUpperOpen() == 1))) {
|
||||
switchVo.setIsLinkedCtrl(1);
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否有定时控制
|
||||
switchVo.setIsTimingCtrl(false);
|
||||
List<TimingCtrl> timingCtrls = timingCtrlsBySwitch.get(sw.getId());
|
||||
if (timingCtrls != null && !timingCtrls.isEmpty()) {
|
||||
for (TimingCtrl timingCtrl : timingCtrls) {
|
||||
if (timingCtrl.getIsOpen() != null && timingCtrl.getIsOpen() == 1) {
|
||||
switchVo.setIsTimingCtrl(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理开关的故障码
|
||||
switchVo.setHasErrorCode(false);
|
||||
for (DeviceErrorCode errorCode : errorCodes) {
|
||||
if (!errorCode.getDeviceId().equals(sw.getDeviceId())) {
|
||||
continue;
|
||||
}
|
||||
if (errorCode.getSwitchIndex() == null || !errorCode.getSwitchIndex().equals(sw.getIndex())) {
|
||||
continue;
|
||||
}
|
||||
if (errorCode.getErrorCode() == null || errorCode.getErrorCode() > DefineDeviceErrorCode.PowerOff) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 电流告警范围
|
||||
boolean hasElectricError = (errorCode.getErrorCode() >= DefineDeviceErrorCode.Three_Switch1OverElectricA
|
||||
&& errorCode.getErrorCode() <= DefineDeviceErrorCode.Three_Switch4ElectricEmpty)
|
||||
|| (errorCode.getErrorCode() >= DefineDeviceErrorCode.One_Switch1OverElectric
|
||||
&& errorCode.getErrorCode() <= DefineDeviceErrorCode.One_Switch4ElectricEmpty);
|
||||
|
||||
if (sw.getElectricWarnOpen() != null && sw.getElectricWarnOpen() == 1 && hasElectricError) {
|
||||
switchVo.setHasErrorCode(true);
|
||||
String msg = DefineDeviceErrorCode.getErrorMessage(errorCode.getErrorCode());
|
||||
if (msg != null && !msg.isEmpty()) {
|
||||
if (errorMessage.length() > 0 && !errorMessage.toString().contains(msg)) {
|
||||
errorMessage.append(",");
|
||||
}
|
||||
if (!errorMessage.toString().contains(msg)) {
|
||||
errorMessage.append(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switchVoList.add(switchVo);
|
||||
}
|
||||
|
||||
// 更新设备的错误信息(包含开关的错误)
|
||||
deviceVo.setErrorMessage(errorMessage.toString());
|
||||
deviceVo.setListSwitch(switchVoList);
|
||||
controllerList.add(deviceVo);
|
||||
}
|
||||
}
|
||||
|
||||
result.setListDetector(detectorList);
|
||||
result.setListController(controllerList);
|
||||
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 为塘口选择/移除设备或开关
|
||||
* 将指定的设备(探测器)和开关分配到塘口,或从塘口移除
|
||||
*
|
||||
* @param request 请求参数(包含塘口ID、设备ID列表、开关ID列表)
|
||||
*/
|
||||
@PutMapping("/bind/device")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R<Void> selectDeviceOrSwitch(
|
||||
@Validated @RequestBody PondSelectDeviceOrSwitchBo request) {
|
||||
|
||||
// 获取当前登录用户ID
|
||||
Long userId = LoginHelper.getUserId();
|
||||
|
||||
// 查询塘口信息并验证权限
|
||||
Pond pond = pondMapper.selectById(request.getPondId());
|
||||
if (pond == null || !pond.getUserId().equals(userId)) {
|
||||
return R.fail("塘口不存在或无权限访问");
|
||||
}
|
||||
|
||||
// 处理空列表
|
||||
List<Long> listDetectorId = request.getListDetectorId() != null ? request.getListDetectorId() : new ArrayList<>();
|
||||
List<Long> listSwitchId = request.getListSwitchId() != null ? request.getListSwitchId() : new ArrayList<>();
|
||||
|
||||
// 查询当前塘口已有的设备
|
||||
List<Device> currentDevices = deviceMapper.selectList(
|
||||
new LambdaQueryWrapper<Device>()
|
||||
.eq(Device::getPondId, request.getPondId())
|
||||
);
|
||||
|
||||
// 查询当前塘口已有的开关
|
||||
List<DeviceSwitch> currentSwitches = deviceSwitchMapper.selectList(
|
||||
new LambdaQueryWrapper<DeviceSwitch>()
|
||||
.eq(DeviceSwitch::getPondId, request.getPondId())
|
||||
);
|
||||
|
||||
// 查询要添加的设备详细信息
|
||||
List<Device> newDevices = new ArrayList<>();
|
||||
if (!listDetectorId.isEmpty()) {
|
||||
newDevices = deviceMapper.selectBatchIds(listDetectorId);
|
||||
}
|
||||
|
||||
// 查询要添加的开关详细信息(包含设备信息)
|
||||
List<DeviceSwitch> newSwitches = new ArrayList<>();
|
||||
if (!listSwitchId.isEmpty()) {
|
||||
newSwitches = deviceSwitchMapper.selectList(
|
||||
new LambdaQueryWrapper<DeviceSwitch>()
|
||||
.in(DeviceSwitch::getId, listSwitchId)
|
||||
);
|
||||
// 查询开关关联的设备信息
|
||||
if (!newSwitches.isEmpty()) {
|
||||
List<Long> deviceIds = newSwitches.stream()
|
||||
.map(DeviceSwitch::getDeviceId)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
List<Device> switchDevices = deviceMapper.selectBatchIds(deviceIds);
|
||||
java.util.Map<Long, Device> deviceMap = switchDevices.stream()
|
||||
.collect(Collectors.toMap(Device::getId, d -> d));
|
||||
// 这里可以用于后续操作记录
|
||||
}
|
||||
}
|
||||
|
||||
// 构建字典:要添加的设备
|
||||
java.util.Map<Long, Device> dictDeviceAdd = new java.util.HashMap<>();
|
||||
for (Device device : newDevices) {
|
||||
dictDeviceAdd.put(device.getId(), device);
|
||||
}
|
||||
|
||||
// 构建字典:要添加的开关
|
||||
java.util.Map<Long, DeviceSwitch> dictSwitchAdd = new java.util.HashMap<>();
|
||||
for (DeviceSwitch sw : newSwitches) {
|
||||
dictSwitchAdd.put(sw.getId(), sw);
|
||||
}
|
||||
|
||||
// 构建字典:要移除的设备
|
||||
java.util.Map<Long, Device> dictDeviceRemove = new java.util.HashMap<>();
|
||||
Set<Long> hashDeviceRemove = new HashSet<>();
|
||||
for (Device device : currentDevices) {
|
||||
dictDeviceRemove.put(device.getId(), device);
|
||||
hashDeviceRemove.add(device.getId());
|
||||
dictDeviceAdd.remove(device.getId()); // 已存在的不算新增
|
||||
}
|
||||
// 从要移除的列表中排除仍要保留的
|
||||
for (Long id : listDetectorId) {
|
||||
dictDeviceRemove.remove(id);
|
||||
hashDeviceRemove.remove(id);
|
||||
}
|
||||
|
||||
// 构建字典:要移除的开关
|
||||
java.util.Map<Long, DeviceSwitch> dictSwitchRemove = new java.util.HashMap<>();
|
||||
Set<Long> hashSwitchRemove = new HashSet<>();
|
||||
for (DeviceSwitch sw : currentSwitches) {
|
||||
dictSwitchRemove.put(sw.getId(), sw);
|
||||
hashSwitchRemove.add(sw.getId());
|
||||
dictSwitchAdd.remove(sw.getId()); // 已存在的不算新增
|
||||
}
|
||||
// 从要移除的列表中排除仍要保留的
|
||||
for (Long id : listSwitchId) {
|
||||
dictSwitchRemove.remove(id);
|
||||
hashSwitchRemove.remove(id);
|
||||
}
|
||||
|
||||
// 1. 添加/更新设备到塘口
|
||||
if (!listDetectorId.isEmpty()) {
|
||||
deviceMapper.update(null,
|
||||
new LambdaUpdateWrapper<Device>()
|
||||
.in(Device::getId, listDetectorId)
|
||||
.set(Device::getPondId, request.getPondId())
|
||||
);
|
||||
}
|
||||
|
||||
// 2. 从塘口移除设备
|
||||
if (!hashDeviceRemove.isEmpty()) {
|
||||
// 删除关联的联动控制
|
||||
linkedCtrlMapper.delete(
|
||||
new LambdaQueryWrapper<LinkedCtrl>()
|
||||
.in(LinkedCtrl::getDeviceId, hashDeviceRemove)
|
||||
);
|
||||
|
||||
// 移除设备的塘口关联,并清除告警状态
|
||||
deviceMapper.update(null,
|
||||
new LambdaUpdateWrapper<Device>()
|
||||
.in(Device::getId, hashDeviceRemove)
|
||||
.set(Device::getPondId, null)
|
||||
.set(Device::getIsTempWarnExist, 0)
|
||||
.set(Device::getIsOxygenWarnExist, 0)
|
||||
);
|
||||
}
|
||||
|
||||
// 3. 添加/更新开关到塘口
|
||||
if (!listSwitchId.isEmpty()) {
|
||||
deviceSwitchMapper.update(null,
|
||||
new LambdaUpdateWrapper<DeviceSwitch>()
|
||||
.in(DeviceSwitch::getId, listSwitchId)
|
||||
.set(DeviceSwitch::getPondId, request.getPondId())
|
||||
);
|
||||
}
|
||||
|
||||
// 4. 从塘口移除开关
|
||||
if (!hashSwitchRemove.isEmpty()) {
|
||||
deviceSwitchMapper.update(null,
|
||||
new LambdaUpdateWrapper<DeviceSwitch>()
|
||||
.in(DeviceSwitch::getId, hashSwitchRemove)
|
||||
.set(DeviceSwitch::getPondId, null)
|
||||
.set(DeviceSwitch::getLinkedCtrlId, null)
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: 清除设备报警数据(类似C#中的EventHelper.RemoveDeviceWarnWaitAndNotice)
|
||||
// for (Long deviceId : hashDeviceRemove) {
|
||||
// // 清除该设备的报警等待和通知数据
|
||||
// }
|
||||
|
||||
// TODO: 操作记录(类似C#中的CacheData.AddMessageOpRecordUser)
|
||||
// 可以集成到日志系统中记录以下操作:
|
||||
// 1. 设备添加到塘口: dictDeviceAdd
|
||||
// 2. 设备从塘口移除: dictDeviceRemove
|
||||
// 3. 开关添加到塘口: dictSwitchAdd
|
||||
// 4. 开关从塘口移除: dictSwitchRemove
|
||||
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户塘口列表 - 模式1(用于首页展示)
|
||||
* 返回塘口的设备和开关汇总信息,包括最大水质参数、告警状态、故障信息等
|
||||
*
|
||||
* @param rootUserId 用户ID
|
||||
* @return 塘口列表
|
||||
*/
|
||||
@GetMapping("/list_mode1")
|
||||
public R<List<PublicPondMode1Vo>> getPondListMode1(
|
||||
@RequestParam("rootUserId") Long rootUserId) {
|
||||
|
||||
// 1. 查询用户的所有塘口
|
||||
List<Pond> ponds = pondMapper.selectList(
|
||||
new LambdaQueryWrapper<Pond>()
|
||||
.eq(Pond::getUserId, rootUserId)
|
||||
.orderByDesc(Pond::getCreateTime)
|
||||
);
|
||||
|
||||
List<PublicPondMode1Vo> listData = new ArrayList<>();
|
||||
if (ponds == null || ponds.isEmpty()) {
|
||||
return R.ok(listData);
|
||||
}
|
||||
|
||||
// 提取塘口ID列表
|
||||
List<Long> pondIds = ponds.stream()
|
||||
.map(Pond::getId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 2. 批量查询所有塘口的设备
|
||||
List<Device> allDevices = deviceMapper.selectList(
|
||||
new LambdaQueryWrapper<Device>()
|
||||
.in(Device::getPondId, pondIds)
|
||||
);
|
||||
|
||||
// 按塘口ID分组
|
||||
java.util.Map<Long, List<Device>> devicesByPond = allDevices.stream()
|
||||
.collect(Collectors.groupingBy(Device::getPondId));
|
||||
|
||||
// 3. 批量查询所有塘口的开关
|
||||
List<DeviceSwitch> allSwitches = deviceSwitchMapper.selectList(
|
||||
new LambdaQueryWrapper<DeviceSwitch>()
|
||||
.in(DeviceSwitch::getPondId, pondIds)
|
||||
);
|
||||
|
||||
// 按塘口ID分组
|
||||
java.util.Map<Long, List<DeviceSwitch>> switchesByPond = allSwitches.stream()
|
||||
.collect(Collectors.groupingBy(DeviceSwitch::getPondId));
|
||||
|
||||
// 4. 收集所有控制器ID(用于查询故障码)
|
||||
Set<Long> hashSetControllerId = new HashSet<>();
|
||||
for (Device device : allDevices) {
|
||||
if (device.getDeviceType() != null && device.getDeviceType() == 2) {
|
||||
hashSetControllerId.add(device.getId());
|
||||
}
|
||||
}
|
||||
for (DeviceSwitch sw : allSwitches) {
|
||||
if (sw.getDeviceId() != null) {
|
||||
hashSetControllerId.add(sw.getDeviceId());
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 查询控制器的故障码
|
||||
List<DeviceErrorCode> listErrorCodes = new ArrayList<>();
|
||||
if (!hashSetControllerId.isEmpty()) {
|
||||
listErrorCodes = deviceErrorCodeMapper.selectList(
|
||||
new LambdaQueryWrapper<DeviceErrorCode>()
|
||||
.in(DeviceErrorCode::getDeviceId, hashSetControllerId)
|
||||
);
|
||||
}
|
||||
|
||||
// 6. 查询开关关联的设备(用于获取WarnCode)
|
||||
Set<Long> switchDeviceIds = allSwitches.stream()
|
||||
.map(DeviceSwitch::getDeviceId)
|
||||
.collect(Collectors.toSet());
|
||||
java.util.Map<Long, Device> switchDeviceMap = new java.util.HashMap<>();
|
||||
if (!switchDeviceIds.isEmpty()) {
|
||||
List<Device> switchDevices = deviceMapper.selectBatchIds(switchDeviceIds);
|
||||
switchDeviceMap = switchDevices.stream()
|
||||
.collect(Collectors.toMap(Device::getId, d -> d));
|
||||
}
|
||||
|
||||
// 7. 为每个塘口聚合数据
|
||||
for (Pond pond : ponds) {
|
||||
PublicPondMode1Vo data = new PublicPondMode1Vo();
|
||||
data.setId(pond.getId());
|
||||
data.setPondName(pond.getPondName());
|
||||
|
||||
Set<Long> hashSetDeviceId = new HashSet<>();
|
||||
int warnCode = DefineDeviceWarnCode.None;
|
||||
|
||||
// 获取该塘口的设备列表
|
||||
List<Device> pondDevices = devicesByPond.getOrDefault(pond.getId(), new ArrayList<>());
|
||||
|
||||
// 处理设备数据
|
||||
for (Device device : pondDevices) {
|
||||
hashSetDeviceId.add(device.getId());
|
||||
|
||||
// 聚合告警码
|
||||
if (device.getWarnCode() != null
|
||||
&& device.getWarnCode() != DefineDeviceWarnCode.None
|
||||
&& device.getWarnCode() < DefineDeviceWarnCode.UserMaxCode) {
|
||||
warnCode |= device.getWarnCode();
|
||||
}
|
||||
|
||||
// 判断设备是否在线(简化判断,实际应根据业务逻辑)
|
||||
if (device.getWarnCode() == null
|
||||
|| (device.getWarnCode() != DefineDeviceWarnCode.DeviceDead
|
||||
&& device.getWarnCode() != DefineDeviceWarnCode.DeviceOffline)) {
|
||||
data.setIsAllDead(false);
|
||||
}
|
||||
|
||||
// 聚合最大水质参数
|
||||
if (device.getValueDissolvedOxygen() != null
|
||||
&& data.getValueDissolvedOxygen() < device.getValueDissolvedOxygen()) {
|
||||
data.setValueDissolvedOxygen(device.getValueDissolvedOxygen());
|
||||
}
|
||||
if (device.getValueTemperature() != null
|
||||
&& data.getValueTemperature() < device.getValueTemperature()) {
|
||||
data.setValueTemperature(device.getValueTemperature());
|
||||
}
|
||||
if (device.getValueSaturability() != null
|
||||
&& data.getValueSaturability() < device.getValueSaturability()) {
|
||||
data.setValueSaturability(device.getValueSaturability());
|
||||
}
|
||||
if (device.getValuePh() != null
|
||||
&& data.getValuePH() < device.getValuePh()) {
|
||||
data.setValuePH(device.getValuePh());
|
||||
}
|
||||
if (device.getValueSalinity() != null
|
||||
&& data.getValueSalinity() < device.getValueSalinity()) {
|
||||
data.setValueSalinity(device.getValueSalinity());
|
||||
}
|
||||
|
||||
// 处理设备的故障码(电压告警)
|
||||
if (device.getVoltageWarnOpen() != null && device.getVoltageWarnOpen() == 1) {
|
||||
for (DeviceErrorCode errorCode : listErrorCodes) {
|
||||
if (!errorCode.getDeviceId().equals(device.getId())) {
|
||||
continue;
|
||||
}
|
||||
if (errorCode.getErrorCode() == null
|
||||
|| errorCode.getErrorCode() > DefineDeviceErrorCode.PowerOff) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 电压告警范围
|
||||
if (errorCode.getErrorCode() >= DefineDeviceErrorCode.Three_PhaseA_OverVoltage
|
||||
&& errorCode.getErrorCode() <= DefineDeviceErrorCode.Three_PhaseC_UnderVoltage) {
|
||||
String errorMessage = DefineDeviceErrorCode.getErrorMessage(errorCode.getErrorCode());
|
||||
if (errorMessage != null && !errorMessage.isEmpty()) {
|
||||
if (data.getErrorMessage() == null || data.getErrorMessage().isEmpty()) {
|
||||
data.setErrorMessage(errorMessage);
|
||||
} else if (!data.getErrorMessage().contains(errorMessage)) {
|
||||
data.setErrorMessage(data.getErrorMessage() + "," + errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取该塘口的开关列表
|
||||
List<DeviceSwitch> pondSwitches = switchesByPond.getOrDefault(pond.getId(), new ArrayList<>());
|
||||
|
||||
// 处理开关数据
|
||||
for (DeviceSwitch sw : pondSwitches) {
|
||||
if (sw.getDeviceId() != null) {
|
||||
hashSetDeviceId.add(sw.getDeviceId());
|
||||
}
|
||||
|
||||
// 聚合开关关联设备的告警码
|
||||
Device switchDevice = switchDeviceMap.get(sw.getDeviceId());
|
||||
if (switchDevice != null
|
||||
&& switchDevice.getWarnCode() != null
|
||||
&& switchDevice.getWarnCode() != DefineDeviceWarnCode.None
|
||||
&& switchDevice.getWarnCode() < DefineDeviceWarnCode.UserMaxCode) {
|
||||
warnCode |= switchDevice.getWarnCode();
|
||||
}
|
||||
|
||||
// 统计开启的开关数量
|
||||
if (sw.getIsOpen() != null && sw.getIsOpen() == 1) {
|
||||
data.setSwitchOpenCount(data.getSwitchOpenCount() + 1);
|
||||
}
|
||||
|
||||
// 处理开关的故障码(电流告警)
|
||||
if (sw.getElectricWarnOpen() != null && sw.getElectricWarnOpen() == 1) {
|
||||
for (DeviceErrorCode errorCode : listErrorCodes) {
|
||||
if (!errorCode.getDeviceId().equals(sw.getDeviceId())) {
|
||||
continue;
|
||||
}
|
||||
if (errorCode.getErrorCode() == null
|
||||
|| errorCode.getErrorCode() > DefineDeviceErrorCode.PowerOff) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 电流告警范围
|
||||
boolean hasElectricError = (errorCode.getErrorCode() >= DefineDeviceErrorCode.Three_Switch1OverElectricA
|
||||
&& errorCode.getErrorCode() <= DefineDeviceErrorCode.Three_Switch4ElectricEmpty)
|
||||
|| (errorCode.getErrorCode() >= DefineDeviceErrorCode.One_Switch1OverElectric
|
||||
&& errorCode.getErrorCode() <= DefineDeviceErrorCode.One_Switch4ElectricEmpty);
|
||||
|
||||
if (hasElectricError) {
|
||||
String errorMessage = DefineDeviceErrorCode.getErrorMessage(errorCode.getErrorCode());
|
||||
if (errorMessage != null && !errorMessage.isEmpty()) {
|
||||
if (data.getErrorMessage() == null || data.getErrorMessage().isEmpty()) {
|
||||
data.setErrorMessage(errorMessage);
|
||||
} else if (!data.getErrorMessage().contains(errorMessage)) {
|
||||
data.setErrorMessage(data.getErrorMessage() + "," + errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 设置汇总数据
|
||||
data.setDeviceCount(hashSetDeviceId.size());
|
||||
data.setSwitchCount(pondSwitches.size());
|
||||
data.getWarnCodeInfo().setWarnCode(warnCode);
|
||||
data.getWarnCodeInfo().setWarnDescription(DefineDeviceWarnCode.toWarnDescription(warnCode));
|
||||
|
||||
listData.add(data);
|
||||
}
|
||||
|
||||
return R.ok(listData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.intc.fishery.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 塘口选择设备或开关请求对象
|
||||
*
|
||||
* @author intc
|
||||
* @date 2026-01-12
|
||||
*/
|
||||
@Data
|
||||
public class PondSelectDeviceOrSwitchBo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 塘口ID
|
||||
*/
|
||||
private Long pondId;
|
||||
|
||||
/**
|
||||
* 探测器(水质检测仪)ID列表
|
||||
*/
|
||||
private List<Long> listDetectorId;
|
||||
|
||||
/**
|
||||
* 开关ID列表
|
||||
*/
|
||||
private List<Long> listSwitchId;
|
||||
}
|
||||
@@ -154,4 +154,14 @@ public class DeviceSwitchVo implements Serializable {
|
||||
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 是否有定时控制
|
||||
*/
|
||||
private Boolean isTimingCtrl;
|
||||
|
||||
/**
|
||||
* 是否有故障码
|
||||
*/
|
||||
private Boolean hasErrorCode;
|
||||
|
||||
}
|
||||
|
||||
@@ -341,4 +341,9 @@ public class DeviceVo implements Serializable {
|
||||
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 是否有联动控制
|
||||
*/
|
||||
private Boolean isLinkCtrl;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.intc.fishery.domain.vo;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.intc.common.json.handler.DoubleSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 带开关列表的设备视图对象
|
||||
*
|
||||
* @author intc
|
||||
* @date 2026-01-12
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class DeviceWithSwitchVo extends DeviceVo {
|
||||
|
||||
/**
|
||||
* 开关列表(仅测控一体机有)
|
||||
*/
|
||||
private List<DeviceSwitchVo> listSwitch;
|
||||
|
||||
/**
|
||||
* 故障信息
|
||||
*/
|
||||
private String errorMessage;
|
||||
|
||||
/**
|
||||
* 告警码信息
|
||||
*/
|
||||
private PondMode1WarnCodeInfo warnCodeInfo;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.intc.fishery.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 塘口设备列表视图对象
|
||||
*
|
||||
* @author intc
|
||||
* @date 2026-01-12
|
||||
*/
|
||||
@Data
|
||||
public class PondDeviceListVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 探测器列表(水质检测仪)
|
||||
*/
|
||||
private List<DeviceVo> listDetector;
|
||||
|
||||
/**
|
||||
* 控制器列表(测控一体机,包含开关列表)
|
||||
*/
|
||||
private List<DeviceWithSwitchVo> listController;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.intc.fishery.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 塘口告警码信息
|
||||
*
|
||||
* @author intc
|
||||
*/
|
||||
@Data
|
||||
public class PondMode1WarnCodeInfo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 告警码
|
||||
*/
|
||||
private Integer warnCode;
|
||||
|
||||
/**
|
||||
* 告警描述
|
||||
*/
|
||||
private String warnDescription;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.intc.fishery.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 设备简化视图对象
|
||||
*
|
||||
* @author intc
|
||||
* @date 2026-01-12
|
||||
*/
|
||||
@Data
|
||||
public class PublicDeviceSimpleVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 设备ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
private String deviceName;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
private Integer deviceType;
|
||||
|
||||
/**
|
||||
* 服务到期时间
|
||||
*/
|
||||
private Date deadTime;
|
||||
|
||||
/**
|
||||
* 溶解氧参数配置开关
|
||||
*/
|
||||
private Integer isOxygenUsed;
|
||||
|
||||
/**
|
||||
* 塘口信息
|
||||
*/
|
||||
private PublicPondIdNameVo pondInfo;
|
||||
|
||||
/**
|
||||
* 开关列表
|
||||
*/
|
||||
private List<PublicDeviceSwitchSimpleVo> listSwitch;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.intc.fishery.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 设备开关简化视图对象
|
||||
*
|
||||
* @author intc
|
||||
* @date 2026-01-12
|
||||
*/
|
||||
@Data
|
||||
public class PublicDeviceSwitchSimpleVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 开关ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 序号
|
||||
*/
|
||||
private Integer index;
|
||||
|
||||
/**
|
||||
* 开关名称
|
||||
*/
|
||||
private String switchName;
|
||||
|
||||
/**
|
||||
* 塘口信息
|
||||
*/
|
||||
private PublicPondIdNameVo pondInfo;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.intc.fishery.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 塘口ID和名称视图对象
|
||||
*
|
||||
* @author intc
|
||||
* @date 2026-01-12
|
||||
*/
|
||||
@Data
|
||||
public class PublicPondIdNameVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 塘口ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 塘口名称
|
||||
*/
|
||||
private String pondName;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.intc.fishery.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 塘口模式1视图对象 - 用于首页展示
|
||||
*
|
||||
* @author intc
|
||||
*/
|
||||
@Data
|
||||
public class PublicPondMode1Vo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 塘口ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 塘口名称
|
||||
*/
|
||||
private String pondName;
|
||||
|
||||
/**
|
||||
* 设备数量
|
||||
*/
|
||||
private Integer deviceCount;
|
||||
|
||||
/**
|
||||
* 开关数量
|
||||
*/
|
||||
private Integer switchCount;
|
||||
|
||||
/**
|
||||
* 开启的开关数量
|
||||
*/
|
||||
private Integer switchOpenCount;
|
||||
|
||||
/**
|
||||
* 是否全部设备离线/失联
|
||||
*/
|
||||
private Boolean isAllDead;
|
||||
|
||||
/**
|
||||
* 溶解氧(最大值)
|
||||
*/
|
||||
private Double valueDissolvedOxygen;
|
||||
|
||||
/**
|
||||
* 水温(最大值)
|
||||
*/
|
||||
private Double valueTemperature;
|
||||
|
||||
/**
|
||||
* 饱和度(最大值)
|
||||
*/
|
||||
private Double valueSaturability;
|
||||
|
||||
/**
|
||||
* PH值(最大值)
|
||||
*/
|
||||
private Double valuePH;
|
||||
|
||||
/**
|
||||
* 盐度(最大值)
|
||||
*/
|
||||
private Double valueSalinity;
|
||||
|
||||
/**
|
||||
* 故障信息
|
||||
*/
|
||||
private String errorMessage;
|
||||
|
||||
/**
|
||||
* 告警码信息
|
||||
*/
|
||||
private PondMode1WarnCodeInfo warnCodeInfo;
|
||||
|
||||
public PublicPondMode1Vo() {
|
||||
this.deviceCount = 0;
|
||||
this.switchCount = 0;
|
||||
this.switchOpenCount = 0;
|
||||
this.isAllDead = true;
|
||||
this.valueDissolvedOxygen = 0.0;
|
||||
this.valueTemperature = 0.0;
|
||||
this.valueSaturability = 0.0;
|
||||
this.valuePH = 0.0;
|
||||
this.valueSalinity = 0.0;
|
||||
this.errorMessage = "";
|
||||
this.warnCodeInfo = new PondMode1WarnCodeInfo();
|
||||
this.warnCodeInfo.setWarnCode(0);
|
||||
this.warnCodeInfo.setWarnDescription("");
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,12 @@ import com.github.yulichang.wrapper.MPJLambdaWrapper;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.intc.fishery.mapper.DeviceMapper;
|
||||
import com.intc.fishery.mapper.DeviceSwitchMapper;
|
||||
import com.intc.fishery.domain.Device;
|
||||
import com.intc.fishery.domain.DeviceSwitch;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
|
||||
/**
|
||||
* 塘口管理Service业务层处理
|
||||
@@ -41,6 +47,10 @@ public class PondServiceImpl implements IPondService {
|
||||
|
||||
private final FishMapper fishMapper;
|
||||
|
||||
private final DeviceMapper deviceMapper;
|
||||
|
||||
private final DeviceSwitchMapper deviceSwitchMapper;
|
||||
|
||||
/**
|
||||
* 查询塘口管理
|
||||
*
|
||||
@@ -206,6 +216,7 @@ public class PondServiceImpl implements IPondService {
|
||||
|
||||
/**
|
||||
* 校验并批量删除塘口管理信息
|
||||
* 删除时会级联删除关联的设备和开关
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
@@ -216,6 +227,23 @@ public class PondServiceImpl implements IPondService {
|
||||
if(isValid){
|
||||
//TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
|
||||
// 删除前先级联删除关联数据
|
||||
for (Long pondId : ids) {
|
||||
// 1. 删除关联的设备
|
||||
deviceMapper.delete(
|
||||
new LambdaQueryWrapper<Device>()
|
||||
.eq(Device::getPondId, pondId)
|
||||
);
|
||||
|
||||
// 2. 删除关联的开关
|
||||
deviceSwitchMapper.delete(
|
||||
new LambdaQueryWrapper<DeviceSwitch>()
|
||||
.eq(DeviceSwitch::getPondId, pondId)
|
||||
);
|
||||
}
|
||||
|
||||
// 删除塘口
|
||||
return baseMapper.deleteByIds(ids) > 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -180,6 +180,14 @@ public class AliyunIotProperties {
|
||||
*/
|
||||
private String controlIntegrated;
|
||||
|
||||
/**
|
||||
* 控制器 ProductKey (别名,指向 controlIntegrated)
|
||||
* @return ProductKey
|
||||
*/
|
||||
public String getController() {
|
||||
return controlIntegrated;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据设备类型获取 ProductKey
|
||||
* @param deviceType 1-水质检测仪, 2-控制一体机
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.intc.fishery.domain.Device;
|
||||
import com.intc.fishery.mapper.DeviceMapper;
|
||||
import com.intc.fishery.mapper.PondMapper;
|
||||
import com.intc.iot.config.AliyunIotProperties;
|
||||
import com.intc.iot.domain.bo.AddDeviceControllerBo;
|
||||
import com.intc.iot.domain.bo.AddDeviceDetectorBo;
|
||||
import com.intc.iot.domain.bo.DeviceRealtimeDataBo;
|
||||
import com.intc.iot.domain.vo.DeviceRealtimeDataVo;
|
||||
@@ -79,6 +80,9 @@ public class IotController extends BaseController {
|
||||
@Autowired(required = false)
|
||||
private PondMapper pondMapper;
|
||||
|
||||
@Autowired(required = false)
|
||||
private com.intc.fishery.mapper.DeviceSwitchMapper deviceSwitchMapper;
|
||||
|
||||
@Operation(summary = "测试接口")
|
||||
@GetMapping("/test")
|
||||
public R<String> test() {
|
||||
@@ -339,23 +343,30 @@ public class IotController extends BaseController {
|
||||
Object detailData = deviceDetail.get("data");
|
||||
Integer statusCode = 0; // 默认为设备未激活
|
||||
|
||||
if (detailData instanceof Map) {
|
||||
Map<?, ?> detailMap = (Map<?, ?>) detailData;
|
||||
Object statusObj = detailMap.get("status");
|
||||
|
||||
if (statusObj != null) {
|
||||
String statusStr = statusObj.toString();
|
||||
// 根据物联网平台返回的状态转换为前端状态码
|
||||
// 0-未激活, 1-在线, 3-离线, 8-禁用
|
||||
if ("ONLINE".equalsIgnoreCase(statusStr) || "online".equals(statusStr)) {
|
||||
statusCode = 1;
|
||||
} else if ("OFFLINE".equalsIgnoreCase(statusStr) || "offline".equals(statusStr)) {
|
||||
statusCode = 3;
|
||||
} else if ("UNACTIVE".equalsIgnoreCase(statusStr) || "unactive".equals(statusStr)) {
|
||||
statusCode = 0;
|
||||
} else if ("DISABLE".equalsIgnoreCase(statusStr) || "disable".equals(statusStr)) {
|
||||
statusCode = 8;
|
||||
if (detailData != null) {
|
||||
// 通过反射获取 status
|
||||
try {
|
||||
java.lang.reflect.Method getStatusMethod = detailData.getClass().getMethod("getStatus");
|
||||
Object statusObj = getStatusMethod.invoke(detailData);
|
||||
|
||||
if (statusObj != null) {
|
||||
String statusStr = statusObj.toString();
|
||||
log.info("从 SDK 对象获取到的状态: {}", statusStr);
|
||||
|
||||
// 根据物联网平台返回的状态转换为前端状态码
|
||||
// 0-未激活, 1-在线, 3-离线, 8-禁用
|
||||
if ("ONLINE".equalsIgnoreCase(statusStr) || "online".equals(statusStr)) {
|
||||
statusCode = 1;
|
||||
} else if ("OFFLINE".equalsIgnoreCase(statusStr) || "offline".equals(statusStr)) {
|
||||
statusCode = 3;
|
||||
} else if ("UNACTIVE".equalsIgnoreCase(statusStr) || "unactive".equals(statusStr)) {
|
||||
statusCode = 0;
|
||||
} else if ("DISABLE".equalsIgnoreCase(statusStr) || "disable".equals(statusStr)) {
|
||||
statusCode = 8;
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
log.error("无法从 SDK 对象中获取 status: {}", ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -674,6 +685,443 @@ public class IotController extends BaseController {
|
||||
|
||||
// ======================== 设备管理相关接口 ========================
|
||||
|
||||
@Operation(summary = "添加测控一体机")
|
||||
@PostMapping("/device/add_device_controller")
|
||||
public R<Void> addDeviceController(@RequestBody AddDeviceControllerBo bo) {
|
||||
try {
|
||||
if (iotDeviceService == null) {
|
||||
return R.fail("飞燕平台配置未启用");
|
||||
}
|
||||
if (deviceMapper == null) {
|
||||
return R.fail("设备数据库服务未启用");
|
||||
}
|
||||
if (deviceSwitchMapper == null) {
|
||||
return R.fail("开关数据库服务未启用");
|
||||
}
|
||||
|
||||
// 获取当前登录用户ID
|
||||
Long userId = LoginHelper.getUserId();
|
||||
if (userId == null) {
|
||||
return R.fail("未登录或登录已过期");
|
||||
}
|
||||
|
||||
// 验证塘口是否存在且属于当前用户
|
||||
if (bo.getPondId() != null && bo.getPondId() > 0 && pondMapper != null) {
|
||||
long count = pondMapper.selectCount(
|
||||
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.intc.fishery.domain.Pond>()
|
||||
.eq(com.intc.fishery.domain.Pond::getUserId, userId)
|
||||
.eq(com.intc.fishery.domain.Pond::getId, bo.getPondId())
|
||||
);
|
||||
if (count == 0) {
|
||||
return R.fail("塘口不存在或无权限访问");
|
||||
}
|
||||
}
|
||||
|
||||
// 检查设备是否已被绑定
|
||||
Device existDevice = deviceMapper.selectOne(
|
||||
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<Device>()
|
||||
.eq(Device::getDeviceType, 2) // 2-测控一体机
|
||||
.eq(Device::getSerialNum, bo.getSerialNum())
|
||||
);
|
||||
if (existDevice != null && existDevice.getUserId() != null) {
|
||||
return R.fail("该设备号已被绑定");
|
||||
}
|
||||
|
||||
// 获取控制器的 ProductKey
|
||||
String productKey = aliyunIotProperties.getDeviceType().getControlIntegrated();
|
||||
if (productKey == null || productKey.isEmpty()) {
|
||||
return R.fail("未配置测控一体机的 ProductKey");
|
||||
}
|
||||
|
||||
// 查询设备基础信息
|
||||
Map<String, Object> deviceInfo = iotDeviceService.findDeviceByProductKeyAndName(productKey, bo.getSerialNum());
|
||||
if (deviceInfo == null || !Boolean.TRUE.equals(deviceInfo.get("success"))) {
|
||||
return R.fail("设备不存在");
|
||||
}
|
||||
|
||||
// 提取设备数据
|
||||
Map<String, Object> data = (Map<String, Object>) deviceInfo.get("data");
|
||||
if (data == null || !data.containsKey("deviceList")) {
|
||||
return R.fail("设备信息格式异常");
|
||||
}
|
||||
|
||||
java.util.List<?> deviceList = (java.util.List<?>) data.get("deviceList");
|
||||
if (deviceList == null || deviceList.isEmpty()) {
|
||||
return R.fail("设备不存在");
|
||||
}
|
||||
|
||||
Object deviceObj = deviceList.get(0);
|
||||
String iotId = null;
|
||||
String status = null;
|
||||
|
||||
// 提取 iotId 和 status
|
||||
if (deviceObj instanceof Map) {
|
||||
Map<?, ?> deviceMap = (Map<?, ?>) deviceObj;
|
||||
iotId = (String) deviceMap.get("iotId");
|
||||
Object statusObj = deviceMap.get("status");
|
||||
status = statusObj != null ? statusObj.toString() : null;
|
||||
} else {
|
||||
try {
|
||||
iotId = (String) deviceObj.getClass().getMethod("getIotId").invoke(deviceObj);
|
||||
Object statusObj = deviceObj.getClass().getMethod("getStatus").invoke(deviceObj);
|
||||
status = statusObj != null ? statusObj.toString() : null;
|
||||
} catch (Exception ex) {
|
||||
log.error("无法从设备对象中获取信息: {}", ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (iotId == null || iotId.isEmpty()) {
|
||||
return R.fail("设备 iotId 为空");
|
||||
}
|
||||
|
||||
// 检查设备状态
|
||||
if (status != null) {
|
||||
if ("UNACTIVE".equalsIgnoreCase(status)) {
|
||||
return R.fail("设备未激活");
|
||||
}
|
||||
if ("DISABLE".equalsIgnoreCase(status)) {
|
||||
return R.fail("设备禁用");
|
||||
}
|
||||
}
|
||||
|
||||
// 查询物模型,确定 rated_voltage 的正确格式
|
||||
log.info("查询控制器物模型,ProductKey: {}", productKey);
|
||||
Map<String, Object> thingModel = iotDeviceService.queryThingModel(productKey);
|
||||
log.info("物模型查询结果: {}", thingModel);
|
||||
|
||||
// 先查询现有设备属性,了解 rated_voltage 的正确格式
|
||||
try {
|
||||
Map<String, Object> currentProps = iotDeviceService.queryDeviceProperties(iotId);
|
||||
log.info("当前设备属性: {}", currentProps);
|
||||
} catch (Exception e) {
|
||||
log.warn("查询当前设备属性失败: {}", e.getMessage());
|
||||
}
|
||||
|
||||
// 设置设备属性
|
||||
Map<String, Object> properties = new java.util.HashMap<>();
|
||||
|
||||
// 设置额定电压 - rated_voltage 是结构体类型
|
||||
// 根据C#代码,需要调用 ControllerHelper.GetInputVoltageProperty
|
||||
// 该方法返回一个特定结构的对象
|
||||
Integer voltValue = getVoltageValue(bo.getInputVoltage());
|
||||
if (voltValue == null) {
|
||||
return R.fail("电压参数错误");
|
||||
}
|
||||
|
||||
// 暂时跳过 rated_voltage 设置,先设置其他属性
|
||||
// properties.put("rated_voltage", ratedVoltageStruct);
|
||||
|
||||
// 如果是三相380V四线,设置输出电压
|
||||
if (bo.getInputVoltage() == 4) {
|
||||
for (int i = 1; i <= 4; i++) {
|
||||
properties.put("Switch" + i + "_volt", 380);
|
||||
}
|
||||
}
|
||||
|
||||
// 清空定时控制数据和设置额定电流
|
||||
java.util.List<Object> emptyTimerList = new java.util.ArrayList<>();
|
||||
Double defaultRatingSwitch = 10.0; // 默认额定电流10A
|
||||
for (int i = 1; i <= 4; i++) {
|
||||
properties.put("rating_switch" + i, defaultRatingSwitch);
|
||||
properties.put("localTimer_switch" + i, emptyTimerList);
|
||||
}
|
||||
|
||||
// 如果使用溶解氧功能,设置盐度
|
||||
if (bo.getIsOxygenUsed()) {
|
||||
properties.put("salinitySet", bo.getSalinityCompensation());
|
||||
}
|
||||
|
||||
String propertiesJson = cn.hutool.json.JSONUtil.toJsonStr(properties);
|
||||
log.info("准备设置设备属性,iotId: {}, properties: {}", iotId, propertiesJson);
|
||||
|
||||
Map<String, Object> setResult = iotDeviceService.setDeviceProperty(iotId, propertiesJson);
|
||||
log.info("设置设备属性返回结果: {}", setResult);
|
||||
|
||||
if (setResult == null) {
|
||||
log.error("设置设备属性返回null");
|
||||
return R.fail("设置设备属性失败:返回结果为空");
|
||||
}
|
||||
|
||||
if (!Boolean.TRUE.equals(setResult.get("success"))) {
|
||||
String errorMsg = setResult.get("errorMessage") != null ?
|
||||
setResult.get("errorMessage").toString() : "未知错误";
|
||||
log.error("设置设备属性失败,错误信息: {}", errorMsg);
|
||||
return R.fail("设置设备属性失败: " + errorMsg);
|
||||
}
|
||||
|
||||
// 获取设备属性
|
||||
Map<String, Object> deviceProperties = iotDeviceService.queryDeviceProperties(iotId);
|
||||
|
||||
// 初始化警告码:默认探头离线且未校准 (0x0081)
|
||||
int warnCode = 0x0081;
|
||||
|
||||
// 如果设备离线,添加设备离线警告
|
||||
if (status != null && "OFFLINE".equalsIgnoreCase(status)) {
|
||||
warnCode |= 0x0080; // 设备离线 (0x0080)
|
||||
}
|
||||
|
||||
// 计算设备数量,用于生成设备名称
|
||||
long deviceCount = deviceMapper.selectCount(
|
||||
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<Device>()
|
||||
.eq(Device::getUserId, userId)
|
||||
.eq(Device::getDeviceType, 2)
|
||||
);
|
||||
|
||||
// 创建或更新设备信息
|
||||
Date now = new Date();
|
||||
boolean isNew = (existDevice == null);
|
||||
Device device = isNew ? new Device() : existDevice;
|
||||
|
||||
if (isNew) {
|
||||
device.setIotId(iotId);
|
||||
device.setSerialNum(bo.getSerialNum());
|
||||
device.setDeviceType(2); // 2-测控一体机
|
||||
device.setDeadTime(new Date(now.getTime() + 365L * 24 * 60 * 60 * 1000)); // 一年后到期
|
||||
} else {
|
||||
// 检查是否已过期
|
||||
if (device.getDeadTime() != null && now.after(device.getDeadTime())) {
|
||||
warnCode |= 0x0040; // 设备时间到期 (0x0040)
|
||||
}
|
||||
}
|
||||
|
||||
// 设置基本信息
|
||||
device.setUserId(userId);
|
||||
device.setDeviceName("控制器" + (deviceCount + 1));
|
||||
device.setBindTime(now);
|
||||
device.setInputVoltage(bo.getInputVoltage());
|
||||
device.setVoltageWarnOpen(0);
|
||||
device.setIsOxygenUsed(bo.getIsOxygenUsed() ? 1 : 0);
|
||||
|
||||
// 设置必填字段默认值(数据库非空约束)
|
||||
if (device.getValuePh() == null) {
|
||||
device.setValuePh(0.0);
|
||||
}
|
||||
if (device.getIsOxygenWarnExist() == null) {
|
||||
device.setIsOxygenWarnExist(0);
|
||||
}
|
||||
if (device.getTfluorescence() == null) {
|
||||
device.setTfluorescence(0.0);
|
||||
}
|
||||
if (device.getTreference() == null) {
|
||||
device.setTreference(0.0);
|
||||
}
|
||||
if (device.getPhaseDifference() == null) {
|
||||
device.setPhaseDifference(0.0);
|
||||
}
|
||||
|
||||
if (bo.getIsOxygenUsed()) {
|
||||
device.setSalinityCompensation(bo.getSalinityCompensation());
|
||||
device.setOxyWarnLower(bo.getOxyWarnLower());
|
||||
device.setOxyWarnCallOpen(1);
|
||||
device.setOxyWarnCallNoDis(1);
|
||||
|
||||
// 如果有塘口且开关列表包含0(设备自身),则设置设备的塘口ID
|
||||
if (bo.getPondId() != null && bo.getPondId() > 0
|
||||
&& bo.getListPutPondPartId() != null && bo.getListPutPondPartId().contains(0)) {
|
||||
device.setPondId(bo.getPondId());
|
||||
} else {
|
||||
device.setPondId(null);
|
||||
}
|
||||
} else {
|
||||
device.setPondId(null);
|
||||
}
|
||||
|
||||
device.setTempWarnCallOpen(0);
|
||||
device.setTempWarnCallNoDis(0);
|
||||
|
||||
// 创建开关列表
|
||||
java.util.List<com.intc.fishery.domain.DeviceSwitch> switches = new java.util.ArrayList<>();
|
||||
for (int i = 1; i <= 4; i++) {
|
||||
com.intc.fishery.domain.DeviceSwitch deviceSwitch = new com.intc.fishery.domain.DeviceSwitch();
|
||||
deviceSwitch.setIndex(i);
|
||||
deviceSwitch.setSwitchName(device.getDeviceName() + "_开关_" + i);
|
||||
deviceSwitch.setConnectVoltageType(bo.getInputVoltage());
|
||||
deviceSwitch.setRateElectricValue(defaultRatingSwitch);
|
||||
deviceSwitch.setElectricWarnOpen(0);
|
||||
deviceSwitch.setIsOpen(0);
|
||||
// 初始化电流和电压默认值,避免数据库非空约束错误
|
||||
deviceSwitch.setDetectElectricValue(0.0);
|
||||
deviceSwitch.setDetectVoltageValue(0.0);
|
||||
|
||||
// 如果有塘口且开关列表包含当前索引,则设置开关的塘口ID
|
||||
if (bo.getPondId() != null && bo.getPondId() > 0
|
||||
&& bo.getListPutPondPartId() != null && bo.getListPutPondPartId().contains(i)) {
|
||||
deviceSwitch.setPondId(bo.getPondId());
|
||||
}
|
||||
|
||||
switches.add(deviceSwitch);
|
||||
}
|
||||
|
||||
// 解析并设置设备属性
|
||||
int errorCode = 0;
|
||||
if (deviceProperties != null && Boolean.TRUE.equals(deviceProperties.get("success"))) {
|
||||
Object propData = deviceProperties.get("data");
|
||||
|
||||
if (propData != null) {
|
||||
try {
|
||||
java.lang.reflect.Method getListMethod = propData.getClass().getMethod("getList");
|
||||
Object listObj = getListMethod.invoke(propData);
|
||||
|
||||
if (listObj instanceof java.util.List) {
|
||||
java.util.List<?> propList = (java.util.List<?>) listObj;
|
||||
|
||||
for (Object item : propList) {
|
||||
if (item != null) {
|
||||
try {
|
||||
java.lang.reflect.Method getIdentifierMethod = item.getClass().getMethod("getIdentifier");
|
||||
java.lang.reflect.Method getValueMethod = item.getClass().getMethod("getValue");
|
||||
String attribute = (String) getIdentifierMethod.invoke(item);
|
||||
Object value = getValueMethod.invoke(item);
|
||||
|
||||
if (attribute != null && value != null) {
|
||||
switch (attribute) {
|
||||
case "dissolvedOxygen": // 溶解氧
|
||||
device.setValueDissolvedOxygen(Double.parseDouble(value.toString()));
|
||||
break;
|
||||
case "currentTemperature": // 温度
|
||||
device.setValueTemperature(Double.parseDouble(value.toString()));
|
||||
break;
|
||||
case "dosat": // 饱和度
|
||||
device.setValueSaturability(Double.parseDouble(value.toString()));
|
||||
break;
|
||||
case "errorCode": // 故障码
|
||||
try {
|
||||
errorCode = Integer.parseInt(value.toString());
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("无法解析故障码: {}", value);
|
||||
}
|
||||
break;
|
||||
case "sensorErrorCode": // 传感器错误码
|
||||
try {
|
||||
int sensorErrorCode = Integer.parseInt(value.toString());
|
||||
warnCode |= sensorErrorCode;
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("无法解析传感器错误码: {}", value);
|
||||
}
|
||||
break;
|
||||
case "Tcorrect": // 设备校准状态
|
||||
try {
|
||||
int tcorrect = Integer.parseInt(value.toString());
|
||||
if (tcorrect == 1) {
|
||||
warnCode &= ~0x0001; // 清除未校准标记
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("无法解析校准状态: {}", value);
|
||||
}
|
||||
break;
|
||||
case "ICCID": // 物联网卡号
|
||||
device.setIccId(value.toString());
|
||||
break;
|
||||
case "Treference": // 参比值
|
||||
device.setTreference(Double.parseDouble(value.toString()));
|
||||
break;
|
||||
case "Tfluorescence": // 荧光值
|
||||
device.setTfluorescence(Double.parseDouble(value.toString()));
|
||||
break;
|
||||
// 开关状态
|
||||
case "switch1":
|
||||
switches.get(0).setIsOpen(Integer.parseInt(value.toString()));
|
||||
break;
|
||||
case "switch2":
|
||||
switches.get(1).setIsOpen(Integer.parseInt(value.toString()));
|
||||
break;
|
||||
case "switch3":
|
||||
switches.get(2).setIsOpen(Integer.parseInt(value.toString()));
|
||||
break;
|
||||
case "switch4":
|
||||
switches.get(3).setIsOpen(Integer.parseInt(value.toString()));
|
||||
break;
|
||||
// 开关电压电流
|
||||
case "switch1_VoltCur":
|
||||
parseSwitchVoltCur(value.toString(), switches.get(0));
|
||||
break;
|
||||
case "switch2_VoltCur":
|
||||
parseSwitchVoltCur(value.toString(), switches.get(1));
|
||||
break;
|
||||
case "switch3_VoltCur":
|
||||
parseSwitchVoltCur(value.toString(), switches.get(2));
|
||||
break;
|
||||
case "switch4_VoltCur":
|
||||
parseSwitchVoltCur(value.toString(), switches.get(3));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
log.error("无法从 SDK 对象中获取属性: {}", ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
log.error("无法从 SDK 对象中获取属性列表: {}", ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 验证 ICCID 是否存在
|
||||
if (device.getIccId() == null || device.getIccId().isEmpty()) {
|
||||
return R.fail("设备缺少物联网卡号(ICCID)");
|
||||
}
|
||||
|
||||
device.setWarnCode(warnCode);
|
||||
|
||||
// 保存到数据库
|
||||
if (isNew) {
|
||||
deviceMapper.insert(device);
|
||||
log.info("新测控一体机添加成功: userId={}, iotId={}, serialNum={}", userId, iotId, bo.getSerialNum());
|
||||
} else {
|
||||
deviceMapper.updateById(device);
|
||||
log.info("测控一体机更新成功: userId={}, iotId={}, serialNum={}", userId, iotId, bo.getSerialNum());
|
||||
}
|
||||
|
||||
// 保存开关信息
|
||||
for (com.intc.fishery.domain.DeviceSwitch deviceSwitch : switches) {
|
||||
deviceSwitch.setDeviceId(device.getId());
|
||||
deviceSwitchMapper.insert(deviceSwitch);
|
||||
}
|
||||
|
||||
// TODO: 记录绑定历史和故障码(如果需要的话)
|
||||
|
||||
return R.ok();
|
||||
} catch (Exception e) {
|
||||
log.error("添加测控一体机失败: {}", e.getMessage(), e);
|
||||
return R.fail("添加测控一体机失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据输入电压类型获取电压值
|
||||
*/
|
||||
private Integer getVoltageValue(Integer inputVoltage) {
|
||||
switch (inputVoltage) {
|
||||
case 1: return 220;
|
||||
case 2: return 380;
|
||||
case 3: return 380;
|
||||
case 4: return 380;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析开关电压电流数据
|
||||
*/
|
||||
private void parseSwitchVoltCur(String json, com.intc.fishery.domain.DeviceSwitch deviceSwitch) {
|
||||
try {
|
||||
// 清理JSON字符串
|
||||
json = json.replace("\"{", "{").replace("}\"", "}").replace("\\", "");
|
||||
Map<String, Object> content = cn.hutool.json.JSONUtil.toBean(json, Map.class);
|
||||
|
||||
if (content.containsKey("voltage")) {
|
||||
deviceSwitch.setDetectVoltageValue(Double.parseDouble(content.get("voltage").toString()));
|
||||
}
|
||||
if (content.containsKey("current")) {
|
||||
deviceSwitch.setDetectElectricValue(Double.parseDouble(content.get("current").toString()));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("解析开关电压电流数据失败: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Operation(summary = "添加设备探测器(水质检测仪)")
|
||||
@PostMapping("/device/add_device_detector")
|
||||
public R<Void> addDeviceDetector(@RequestBody AddDeviceDetectorBo bo) {
|
||||
@@ -825,65 +1273,79 @@ public class IotController extends BaseController {
|
||||
// 解析并设置设备属性
|
||||
if (deviceProperties != null && Boolean.TRUE.equals(deviceProperties.get("success"))) {
|
||||
Object propData = deviceProperties.get("data");
|
||||
if (propData instanceof Map) {
|
||||
Map<?, ?> propMap = (Map<?, ?>) propData;
|
||||
Object listObj = propMap.get("list");
|
||||
if (listObj instanceof java.util.List) {
|
||||
java.util.List<?> propList = (java.util.List<?>) listObj;
|
||||
for (Object item : propList) {
|
||||
if (item instanceof Map) {
|
||||
Map<?, ?> prop = (Map<?, ?>) item;
|
||||
String attribute = (String) prop.get("identifier");
|
||||
Object value = prop.get("value");
|
||||
|
||||
if (attribute != null && value != null) {
|
||||
switch (attribute) {
|
||||
case "dissolvedOxygen": // 溶解氧
|
||||
device.setValueDissolvedOxygen(Double.parseDouble(value.toString()));
|
||||
break;
|
||||
case "currentTemperature": // 温度
|
||||
device.setValueTemperature(Double.parseDouble(value.toString()));
|
||||
break;
|
||||
case "dosat": // 饱和度
|
||||
device.setValueSaturability(Double.parseDouble(value.toString()));
|
||||
break;
|
||||
case "PH":
|
||||
device.setValuePh(Double.parseDouble(value.toString()));
|
||||
break;
|
||||
case "salinity": // 盐度
|
||||
device.setValueSalinity(Double.parseDouble(value.toString()));
|
||||
break;
|
||||
case "sensorErrorCode": // 警告码
|
||||
try {
|
||||
int errorCode = Integer.parseInt(value.toString());
|
||||
warnCode |= errorCode;
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("无法解析警告码: {}", value);
|
||||
|
||||
if (propData != null) {
|
||||
// 通过反射获取属性列表
|
||||
try {
|
||||
java.lang.reflect.Method getListMethod = propData.getClass().getMethod("getList");
|
||||
Object listObj = getListMethod.invoke(propData);
|
||||
|
||||
if (listObj instanceof java.util.List) {
|
||||
java.util.List<?> propList = (java.util.List<?>) listObj;
|
||||
|
||||
for (Object item : propList) {
|
||||
if (item != null) {
|
||||
// 通过反射获取属性标识符和值
|
||||
try {
|
||||
java.lang.reflect.Method getIdentifierMethod = item.getClass().getMethod("getIdentifier");
|
||||
java.lang.reflect.Method getValueMethod = item.getClass().getMethod("getValue");
|
||||
String attribute = (String) getIdentifierMethod.invoke(item);
|
||||
Object value = getValueMethod.invoke(item);
|
||||
|
||||
if (attribute != null && value != null) {
|
||||
switch (attribute) {
|
||||
case "dissolvedOxygen": // 溶解氧
|
||||
device.setValueDissolvedOxygen(Double.parseDouble(value.toString()));
|
||||
break;
|
||||
case "currentTemperature": // 温度
|
||||
device.setValueTemperature(Double.parseDouble(value.toString()));
|
||||
break;
|
||||
case "dosat": // 饱和度
|
||||
device.setValueSaturability(Double.parseDouble(value.toString()));
|
||||
break;
|
||||
case "PH":
|
||||
device.setValuePh(Double.parseDouble(value.toString()));
|
||||
break;
|
||||
case "salinity": // 盐度
|
||||
device.setValueSalinity(Double.parseDouble(value.toString()));
|
||||
break;
|
||||
case "sensorErrorCode": // 警告码
|
||||
try {
|
||||
int errorCode = Integer.parseInt(value.toString());
|
||||
warnCode |= errorCode;
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("无法解析警告码: {}", value);
|
||||
}
|
||||
break;
|
||||
case "Tcorrect": // 设备校准状态
|
||||
try {
|
||||
int tcorrect = Integer.parseInt(value.toString());
|
||||
if (tcorrect == 1) {
|
||||
warnCode &= ~0x0001; // 清除未校准标记
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("无法解析校准状态: {}", value);
|
||||
}
|
||||
break;
|
||||
case "ICCID": // 物联网卡号
|
||||
device.setIccId(value.toString());
|
||||
break;
|
||||
case "Treference": // 参比值
|
||||
device.setTreference(Double.parseDouble(value.toString()));
|
||||
break;
|
||||
case "Tfluorescence": // 荧光值
|
||||
device.setTfluorescence(Double.parseDouble(value.toString()));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "Tcorrect": // 设备校准状态
|
||||
try {
|
||||
int tcorrect = Integer.parseInt(value.toString());
|
||||
if (tcorrect == 1) {
|
||||
warnCode &= ~0x0001; // 清除未校准标记
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("无法解析校准状态: {}", value);
|
||||
}
|
||||
break;
|
||||
case "ICCID": // 物联网卡号
|
||||
device.setIccId(value.toString());
|
||||
break;
|
||||
case "Treference": // 参比值
|
||||
device.setTreference(Double.parseDouble(value.toString()));
|
||||
break;
|
||||
case "Tfluorescence": // 荧光值
|
||||
device.setTfluorescence(Double.parseDouble(value.toString()));
|
||||
break;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
log.error("无法从 SDK 对象中获取属性: {}", ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
log.error("无法从 SDK 对象中获取属性列表: {}", ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.intc.iot.domain.bo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 添加测控一体机业务对象
|
||||
*
|
||||
* @author intc
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "添加测控一体机请求对象")
|
||||
public class AddDeviceControllerBo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 设备编号/序列号
|
||||
*/
|
||||
@Schema(description = "设备编号/序列号")
|
||||
@NotBlank(message = "设备编号不能为空")
|
||||
private String serialNum;
|
||||
|
||||
/**
|
||||
* 塘口ID
|
||||
*/
|
||||
@Schema(description = "塘口ID")
|
||||
private Long pondId;
|
||||
|
||||
/**
|
||||
* 盐度补偿值
|
||||
*/
|
||||
@Schema(description = "盐度补偿值")
|
||||
@NotNull(message = "盐度补偿值不能为空")
|
||||
private Double salinityCompensation;
|
||||
|
||||
/**
|
||||
* 溶解氧报警下限
|
||||
*/
|
||||
@Schema(description = "溶解氧报警下限")
|
||||
@NotNull(message = "溶解氧报警下限不能为空")
|
||||
private Double oxyWarnLower;
|
||||
|
||||
/**
|
||||
* 输入电压类型(1-单相220V, 2-单相380V, 3-三相380V, 4-三相380V四线)
|
||||
*/
|
||||
@Schema(description = "输入电压类型")
|
||||
@NotNull(message = "输入电压类型不能为空")
|
||||
private Integer inputVoltage;
|
||||
|
||||
/**
|
||||
* 是否使用溶解氧功能
|
||||
*/
|
||||
@Schema(description = "是否使用溶解氧功能")
|
||||
@NotNull(message = "是否使用溶解氧功能不能为空")
|
||||
private Boolean isOxygenUsed;
|
||||
|
||||
/**
|
||||
* 开关放置塘口分区ID列表(0表示设备自身,1-4表示开关1-4)
|
||||
*/
|
||||
@Schema(description = "开关放置塘口分区ID列表")
|
||||
private List<Integer> listPutPondPartId;
|
||||
}
|
||||
@@ -132,6 +132,13 @@ public class IotDeviceServiceImpl implements IotDeviceService {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("success", response.getSuccess());
|
||||
result.put("data", response.getData());
|
||||
result.put("errorMessage", response.getErrorMessage());
|
||||
result.put("code", response.getCode());
|
||||
|
||||
if (!response.getSuccess()) {
|
||||
log.error("设置设备属性失败,Code: {}, ErrorMessage: {}", response.getCode(), response.getErrorMessage());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
# 阿里云生活物联网平台(飞燕平台)配置
|
||||
# 使用说明:
|
||||
# 1. 替换下面的占位符为实际值
|
||||
# 2. AccessKey/Secret 建议使用环境变量或配置中心管理
|
||||
# 3. 推荐使用 AMQP 服务端订阅接收所有设备数据
|
||||
aliyun:
|
||||
living-iot:
|
||||
# ========== 基础配置 ==========
|
||||
# 阿里云 AccessKey ID(必填)- 从阿里云控制台获取
|
||||
# 安全提示:请通过环境变量配置,不要在代码中暴露真实密钥
|
||||
access-key-id: LTAI5tRnPowmTLjH181nSbsR
|
||||
# 阿里云 AccessKey Secret(必填)- 从阿里云控制台获取
|
||||
# 安全提示:请通过环境变量配置,不要在代码中暴露真实密钥
|
||||
access-key-secret: Vh2LoAM1t3XuMUVy2wTWSACJ97kOUW
|
||||
# 地域节点(必填,如:cn-shanghai)
|
||||
region-id: cn-shanghai
|
||||
# 飞燕平台项目ID(Project ID,必填)
|
||||
project-id: a123nMibvh0q4UnU
|
||||
# App Key(必填)
|
||||
app-key: 334224397
|
||||
# App Secret(必填)
|
||||
app-secret: 70de3018ec39423e9ca1e1b6a6a84ad6
|
||||
|
||||
# ========== AMQP 服务端订阅配置(推荐) ==========
|
||||
# 说明:AMQP 服务端订阅用于接收所有设备的数据,无需为每个设备配置 MQTT
|
||||
# 配置步骤:
|
||||
# 1. 在阿里云IoT控制台创建消费组
|
||||
# 路径:IoT控制台 -> 规则引擎 -> 服务端订阅 -> 消费组管理 -> 创建消费组
|
||||
# 2. 获取 AMQP 接入点信息
|
||||
# 路径:IoT控制台 -> 实例详情 -> 开发配置 -> 服务端订阅 -> 查看 AMQP 接入点
|
||||
# 3. 使用工具生成认证信息:
|
||||
# username: {accessKeyId}|authMode=aksign|
|
||||
# password: 使用 HMAC-SHA1 签名生成,可使用阿里云提供的在线工具
|
||||
amqp:
|
||||
# 是否启用 AMQP 订阅
|
||||
enabled: true
|
||||
# AMQP 接入点地址(格式:${uid}.iot-amqp.${region}.aliyuncs.com)
|
||||
# 示例:1234567890.iot-amqp.cn-shanghai.aliyuncs.com
|
||||
host: 1572610294777992.iot-amqp.cn-shanghai.aliyuncs.com
|
||||
# AMQP 端口(默认 5672)
|
||||
port: 5672
|
||||
# 虚拟主机(默认为 AccessKey 的前 8 位)
|
||||
virtual-host:
|
||||
# 用户名(格式:${accessKeyId}|authMode=aksign|)
|
||||
username:
|
||||
# 密码(使用 HMAC-SHA1 签名生成)
|
||||
password:
|
||||
# 消费组 ID(在阿里云 IoT 控制台创建)
|
||||
consumer-group-id: HPaJu3YgmDnUAP43Z7xd000100
|
||||
# 连接超时时间(毫秒)
|
||||
connection-timeout: 30000
|
||||
# 自动重连
|
||||
auto-reconnect: true
|
||||
# 预取数量(每次批量拉取的消息数)
|
||||
prefetch-count: 50
|
||||
|
||||
# ========== MQTT 配置(可选,用于设备直连) ==========
|
||||
# 说明:MQTT 适用于单个设备直连,不推荐用于大量设备场景
|
||||
# 如需启用,请确保以下配置正确
|
||||
# 注:大量设备请使用 AMQP 服务端订阅
|
||||
mqtt:
|
||||
# MQTT Broker 地址(格式:tcp://{ProductKey}.iot-as-mqtt.{RegionId}.aliyuncs.com:1883)
|
||||
# 示例:tcp://a1Xj9dagTIx.iot-as-mqtt.cn-shanghai.aliyuncs.com:1883
|
||||
broker-url:
|
||||
# 客户端ID
|
||||
client-id:
|
||||
# 用户名(格式:{DeviceName}&{ProductKey})
|
||||
username:
|
||||
# 密码(使用 AliyunIotSignUtil.generatePassword() 方法生成)
|
||||
password:
|
||||
# 连接超时时间(秒)
|
||||
connection-timeout: 30
|
||||
# 保活时间(秒)
|
||||
keep-alive-interval: 60
|
||||
# 自动重连
|
||||
auto-reconnect: true
|
||||
# 清除会话
|
||||
clean-session: true
|
||||
|
||||
# ========== 配置说明 ==========
|
||||
#
|
||||
# 1. AMQP 服务端订阅配置步骤:
|
||||
# a. 登录阿里云 IoT 控制台
|
||||
# b. 进入实例管理 -> 选择你的实例 -> 规则引擎 -> 服务端订阅
|
||||
# c. 创建消费组(记住消费组 ID)
|
||||
# d. 查看 AMQP 接入点信息,获取 host 和 virtualHost
|
||||
# e. 生成认证信息:
|
||||
# username: {accessKeyId}|authMode=aksign|
|
||||
# password: 使用 HMAC-SHA1("{accessKeySecret}", "{consumerGroupId}") 计算
|
||||
# 可使用阿里云提供的在线签名工具
|
||||
#
|
||||
# 2. AMQP vs MQTT 选择:
|
||||
# - AMQP:推荐,适用于服务端接收所有设备数据,无需为每个设备配置
|
||||
# - MQTT:适用于单个设备直连,需要设备三元组(ProductKey/DeviceName/DeviceSecret)
|
||||
#
|
||||
# 3. 关键信息获取路径:
|
||||
# - AMQP 接入点:IoT控制台 -> 实例详情 -> 开发配置 -> 服务端订阅
|
||||
# - 消费组 ID:IoT控制台 -> 规则引擎 -> 服务端订阅 -> 消费组管理
|
||||
# - AccessKey:阿里云控制台 -> AccessKey 管理
|
||||
Reference in New Issue
Block a user