fix: 微信小程序接口对接修改,联调测试问题修复。

This commit is contained in:
tianyongbao
2026-01-15 11:35:13 +08:00
parent 54bcaf3c2c
commit 7efbad95aa
23 changed files with 1797 additions and 179 deletions

View File

@@ -47,13 +47,6 @@ public class AliyunIotProperties {
*/
private String categoryKey;
/**
* 设备类型到产品Key的映射
* 1: 水质检测仪
* 2: 控制一体机
*/
private DeviceTypeMapping deviceType = new DeviceTypeMapping();
/**
* MQTT 配置(可选,用于设备直连)
*/
@@ -165,47 +158,4 @@ public class AliyunIotProperties {
private Integer reconnectDelay = 30000;
}
/**
* 设备类型映射配置
*/
@Data
public static class DeviceTypeMapping {
/**
* 水质检测仪 ProductKey
*/
private String waterQualityMonitor;
/**
* 控制一体机 ProductKey
*/
private String controlIntegrated;
/**
* 控制器 ProductKey (别名,指向 controlIntegrated)
* @return ProductKey
*/
public String getController() {
return controlIntegrated;
}
/**
* 根据设备类型获取 ProductKey
* @param deviceType 1-水质检测仪, 2-控制一体机
* @return ProductKey
*/
public String getProductKeyByType(Integer deviceType) {
if (deviceType == null) {
return null;
}
switch (deviceType) {
case 1:
return waterQualityMonitor;
case 2:
return controlIntegrated;
default:
return null;
}
}
}
}

View File

@@ -0,0 +1,105 @@
package com.intc.iot.constant;
/**
* 物联网平台设备属性名称常量
*
* @author intc
* @date 2026-01-14
*/
public class IOTPropertyName {
private IOTPropertyName() {
}
// ========== 水质检测仪属性 ==========
/**
* 物联网卡号
*/
public static final String ICCID = "ICCID";
/**
* 溶解氧
*/
public static final String DISSOLVED_OXYGEN = "dissolvedOxygen";
/**
* PH值
*/
public static final String PH = "PH";
/**
* 水温
*/
public static final String CURRENT_TEMPERATURE = "currentTemperature";
/**
* 饱和度
*/
public static final String DOSAT = "dosat";
/**
* 故障码
*/
public static final String ERROR_CODE = "errorCode";
/**
* 校准检测
*/
public static final String T_CORRECT = "Tcorrect";
/**
* 盐度
*/
public static final String SALINITY = "salinity";
/**
* 盐度设置
*/
public static final String SALINITY_SET = "salinitySet";
/**
* 参比值
*/
public static final String T_REFERENCE = "Treference";
/**
* 荧光值
*/
public static final String T_FLUORESCENCE = "Tfluorescence";
/**
* 相位差
*/
public static final String PHASE_DIFFERENCE = "Phasedifference";
/**
* 设备校准
*/
public static final String CORRECT = "correct";
// ========== 控制器属性 ==========
/**
* 控制器额定电压
*/
public static final String RATED_VOLTAGE = "rated_voltage";
/**
* 控制器开关定时控制(前缀)
*/
public static final String LOCAL_TIMER_SWITCH = "localTimer_switch";
/**
* 控制器开关(前缀)
*/
public static final String SWITCH_INDEX = "Switch";
/**
* 控制器开关额定电流(前缀)
*/
public static final String RATING_SWITCH_INDEX = "rating_switch";
/**
* 控制器传感器故障码
*/
public static final String SENSOR_ERROR_CODE = "sensorErrorCode";
}

View File

@@ -5,10 +5,21 @@ import com.intc.common.mybatis.core.page.PageQuery;
import com.intc.common.mybatis.core.page.TableDataInfo;
import com.intc.common.satoken.utils.LoginHelper;
import com.intc.common.web.core.BaseController;
import com.intc.common.core.config.properties.DeviceTypeProperties;
import com.intc.fishery.domain.Device;
import com.intc.fishery.domain.DeviceSwitch;
import com.intc.fishery.domain.TimingCtrl;
import com.intc.fishery.domain.Pond;
import com.intc.fishery.domain.LinkedCtrl;
import com.intc.fishery.domain.DeviceCorrectRecord;
import com.intc.fishery.domain.AquUser;
import com.intc.fishery.domain.bo.*;
import com.intc.fishery.domain.vo.DeviceSwitchVo;
import com.intc.fishery.mapper.DeviceMapper;
import com.intc.fishery.mapper.PondMapper;
import com.intc.iot.config.AliyunIotProperties;
import com.intc.fishery.mapper.DeviceSwitchMapper;
import com.intc.fishery.mapper.DeviceCorrectRecordMapper;
import com.intc.fishery.mapper.TimingCtrlMapper;
import com.intc.iot.domain.bo.AddDeviceControllerBo;
import com.intc.iot.domain.bo.AddDeviceDetectorBo;
import com.intc.iot.domain.bo.DeviceCalibrateBo;
@@ -27,12 +38,15 @@ import com.intc.iot.service.WarnCallNoticeService;
import com.intc.iot.utils.AliyunAmqpSignUtil;
import com.intc.iot.utils.ControllerHelper;
import com.intc.iot.service.IotCloudService;
import com.intc.iot.constant.IOTPropertyName;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
@@ -50,7 +64,7 @@ import java.util.Map;
@Tag(name = "生活物联网平台管理", description = "阿里云飞燕平台对接接口")
public class IotController extends BaseController {
private final AliyunIotProperties aliyunIotProperties;
private final DeviceTypeProperties deviceTypeProperties;
@Autowired(required = false)
private IotDeviceService iotDeviceService;
@@ -86,13 +100,13 @@ public class IotController extends BaseController {
private PondMapper pondMapper;
@Autowired(required = false)
private com.intc.fishery.mapper.DeviceSwitchMapper deviceSwitchMapper;
private DeviceSwitchMapper deviceSwitchMapper;
@Autowired(required = false)
private com.intc.fishery.mapper.DeviceCorrectRecordMapper deviceCorrectRecordMapper;
private DeviceCorrectRecordMapper deviceCorrectRecordMapper;
@Autowired(required = false)
private com.intc.fishery.mapper.TimingCtrlMapper timingCtrlMapper;
private TimingCtrlMapper timingCtrlMapper;
@Autowired(required = false)
private IotCloudService iotCloudService;
@@ -305,7 +319,7 @@ public class IotController extends BaseController {
}
// 根据设备类型获取 ProductKey
String productKey = aliyunIotProperties.getDeviceType().getProductKeyByType(devicetype);
String productKey = deviceTypeProperties.getProductKeyByType(devicetype);
if (productKey == null || productKey.isEmpty()) {
return R.fail("未配置该设备类型的 ProductKey请检查配置文件deviceType: " + devicetype + "");
}
@@ -722,9 +736,9 @@ public class IotController extends BaseController {
// 验证塘口是否存在且属于当前用户
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())
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<Pond>()
.eq(Pond::getUserId, userId)
.eq(Pond::getId, bo.getPondId())
);
if (count == 0) {
return R.fail("塘口不存在或无权限访问");
@@ -742,7 +756,7 @@ public class IotController extends BaseController {
}
// 获取控制器的 ProductKey
String productKey = aliyunIotProperties.getDeviceType().getControlIntegrated();
String productKey = deviceTypeProperties.getControlIntegrated();
if (productKey == null || productKey.isEmpty()) {
return R.fail("未配置测控一体机的 ProductKey");
}
@@ -944,9 +958,9 @@ public class IotController extends BaseController {
device.setTempWarnCallNoDis(0);
// 创建开关列表
java.util.List<com.intc.fishery.domain.DeviceSwitch> switches = new java.util.ArrayList<>();
java.util.List<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 deviceSwitch = new DeviceSwitch();
deviceSwitch.setIndex(i);
deviceSwitch.setSwitchName(device.getDeviceName() + "_开关_" + i);
deviceSwitch.setConnectVoltageType(bo.getInputVoltage());
@@ -1089,7 +1103,7 @@ public class IotController extends BaseController {
}
// 保存开关信息
for (com.intc.fishery.domain.DeviceSwitch deviceSwitch : switches) {
for (DeviceSwitch deviceSwitch : switches) {
deviceSwitch.setDeviceId(device.getId());
deviceSwitchMapper.insert(deviceSwitch);
}
@@ -1119,7 +1133,7 @@ public class IotController extends BaseController {
/**
* 解析开关电压电流数据
*/
private void parseSwitchVoltCur(String json, com.intc.fishery.domain.DeviceSwitch deviceSwitch) {
private void parseSwitchVoltCur(String json, DeviceSwitch deviceSwitch) {
try {
// 清理JSON字符串
json = json.replace("\"{", "{").replace("}\"", "}").replace("\\", "");
@@ -1156,9 +1170,9 @@ public class IotController extends BaseController {
// 验证塘口是否存在且属于当前用户
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())
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<Pond>()
.eq(Pond::getUserId, userId)
.eq(Pond::getId, bo.getPondId())
);
if (count == 0) {
return R.fail("塘口不存在或无权限访问");
@@ -1176,7 +1190,7 @@ public class IotController extends BaseController {
}
// 获取水质检测仪的 ProductKey
String productKey = aliyunIotProperties.getDeviceType().getWaterQualityMonitor();
String productKey = deviceTypeProperties.getWaterQualityMonitor();
if (productKey == null || productKey.isEmpty()) {
return R.fail("未配置水质检测仪的 ProductKey");
}
@@ -1478,7 +1492,7 @@ public class IotController extends BaseController {
// 创建校准记录
if (deviceCorrectRecordMapper != null) {
com.intc.fishery.domain.DeviceCorrectRecord correctRecord = new com.intc.fishery.domain.DeviceCorrectRecord();
DeviceCorrectRecord correctRecord = new DeviceCorrectRecord();
correctRecord.setDeviceId(device.getId());
correctRecord.setUserId(userId);
correctRecord.setSerialNum(device.getSerialNum());
@@ -1669,9 +1683,9 @@ public class IotController extends BaseController {
// 更新关联开关的接线方式
deviceSwitchMapper.update(null,
new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<com.intc.fishery.domain.DeviceSwitch>()
.eq(com.intc.fishery.domain.DeviceSwitch::getDeviceId, request.getId())
.set(com.intc.fishery.domain.DeviceSwitch::getConnectVoltageType, request.getVoltageType())
new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<DeviceSwitch>()
.eq(DeviceSwitch::getDeviceId, request.getId())
.set(DeviceSwitch::getConnectVoltageType, request.getVoltageType())
);
String voltageDesc = ControllerHelper.getVoltageDescription(request.getVoltageType());
@@ -1693,7 +1707,7 @@ public class IotController extends BaseController {
*/
@Operation(summary = "开关开启/关闭控制")
@PutMapping("/switch/turn_switch")
public R<Void> turnSwitch(@RequestBody com.intc.fishery.domain.bo.ReqTurnOpen request) {
public R<Void> turnSwitch(@RequestBody ReqTurnOpen request) {
try {
if (deviceSwitchMapper == null || deviceMapper == null) {
return R.fail("系统配置未完成");
@@ -1704,7 +1718,7 @@ public class IotController extends BaseController {
Integer targetStatus = request.getIsOpen();
// 查询开关信息
com.intc.fishery.domain.DeviceSwitch deviceSwitch = deviceSwitchMapper.selectById(switchId);
DeviceSwitch deviceSwitch = deviceSwitchMapper.selectById(switchId);
if (deviceSwitch == null) {
return R.fail("开关不存在");
}
@@ -1751,7 +1765,7 @@ public class IotController extends BaseController {
// 构造IoT属性
Map<String, Object> properties = new java.util.HashMap<>();
properties.put("switchIndex" + deviceSwitch.getIndex(), targetStatus);
properties.put(IOTPropertyName.SWITCH_INDEX + deviceSwitch.getIndex(), targetStatus);
// 调用物联网服务设置属性
boolean success = iotCloudService.setProperty(device.getIotId(), properties, true, 2);
@@ -1761,15 +1775,15 @@ public class IotController extends BaseController {
// 更新数据库中的开关状态和最后操作时间
deviceSwitchMapper.update(null,
new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<com.intc.fishery.domain.DeviceSwitch>()
.eq(com.intc.fishery.domain.DeviceSwitch::getId, switchId)
.set(com.intc.fishery.domain.DeviceSwitch::getIsOpen, targetStatus)
.set(com.intc.fishery.domain.DeviceSwitch::getLastTurnTime, new Date())
new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<DeviceSwitch>()
.eq(DeviceSwitch::getId, switchId)
.set(DeviceSwitch::getIsOpen, targetStatus)
.set(DeviceSwitch::getLastTurnTime, new Date())
);
// 记录操作日志
String operation = targetStatus == 1 ? "开启" : "关闭";
log.info("开关操作:{}({})的开关{}{}",
log.info("开关操作:{}({})的开关{}{}",
device.getDeviceName(), device.getSerialNum(), deviceSwitch.getSwitchName(), operation);
return R.ok();
@@ -1787,7 +1801,7 @@ public class IotController extends BaseController {
*/
@Operation(summary = "设置塘口所有开关状态")
@PutMapping("/switch/turn_pond_switch")
public R<Void> turnPondSwitch(@RequestBody com.intc.fishery.domain.bo.ReqTurnOpen request) {
public R<Void> turnPondSwitch(@RequestBody ReqTurnOpen request) {
try {
if (deviceSwitchMapper == null || deviceMapper == null) {
return R.fail("系统配置未完成");
@@ -1798,30 +1812,30 @@ public class IotController extends BaseController {
Integer targetStatus = request.getIsOpen();
// 查询塘口下所有开关信息(包括关联的设备信息)
com.github.yulichang.wrapper.MPJLambdaWrapper<com.intc.fishery.domain.DeviceSwitch> wrapper =
new com.github.yulichang.wrapper.MPJLambdaWrapper<com.intc.fishery.domain.DeviceSwitch>()
.selectAll(com.intc.fishery.domain.DeviceSwitch.class)
com.github.yulichang.wrapper.MPJLambdaWrapper<DeviceSwitch> wrapper =
new com.github.yulichang.wrapper.MPJLambdaWrapper<DeviceSwitch>()
.selectAll(DeviceSwitch.class)
.selectAs(Device::getUserId, "userId")
.selectAs(Device::getIotId, "iotId")
.selectAs(Device::getSerialNum, "serialNum")
.selectAs(Device::getDeviceName, "deviceName")
.selectAs(Device::getWarnCode, "warnCode")
.selectAs(Device::getDeadTime, "deadTime")
.leftJoin(Device.class, Device::getId, com.intc.fishery.domain.DeviceSwitch::getDeviceId)
.eq(com.intc.fishery.domain.DeviceSwitch::getPondId, pondId);
.leftJoin(Device.class, Device::getId, DeviceSwitch::getDeviceId)
.eq(DeviceSwitch::getPondId, pondId);
java.util.List<com.intc.fishery.domain.vo.DeviceSwitchVo> listSwitch =
deviceSwitchMapper.selectJoinList(com.intc.fishery.domain.vo.DeviceSwitchVo.class, wrapper);
java.util.List<DeviceSwitchVo> listSwitch =
deviceSwitchMapper.selectJoinList(DeviceSwitchVo.class, wrapper);
if (listSwitch == null || listSwitch.isEmpty()) {
return R.fail("该塘口下没有开关");
}
// 按设备IotId分组并过滤不符合条件的开关
Map<String, java.util.List<com.intc.fishery.domain.vo.DeviceSwitchVo>> iotIdSwitchMap =
Map<String, java.util.List<DeviceSwitchVo>> iotIdSwitchMap =
new java.util.HashMap<>();
for (com.intc.fishery.domain.vo.DeviceSwitchVo switchVo : listSwitch) {
for (DeviceSwitchVo switchVo : listSwitch) {
// 权限验证
if (switchVo.getUserId() == null || !switchVo.getUserId().equals(userId)) {
return R.fail("开关不存在或无权限访问");
@@ -1866,23 +1880,23 @@ public class IotController extends BaseController {
// 按设备批量设置开关状态
java.util.Set<Long> successSwitchIds = new java.util.HashSet<>();
java.util.List<com.intc.fishery.domain.vo.DeviceSwitchVo> successSwitches = new java.util.ArrayList<>();
java.util.List<DeviceSwitchVo> successSwitches = new java.util.ArrayList<>();
for (Map.Entry<String, java.util.List<com.intc.fishery.domain.vo.DeviceSwitchVo>> entry : iotIdSwitchMap.entrySet()) {
for (Map.Entry<String, java.util.List<DeviceSwitchVo>> entry : iotIdSwitchMap.entrySet()) {
String iotId = entry.getKey();
java.util.List<com.intc.fishery.domain.vo.DeviceSwitchVo> switches = entry.getValue();
java.util.List<DeviceSwitchVo> switches = entry.getValue();
// 构造该设备的所有开关属性
Map<String, Object> properties = new java.util.HashMap<>();
for (com.intc.fishery.domain.vo.DeviceSwitchVo switchVo : switches) {
properties.put("switchIndex" + switchVo.getIndex(), targetStatus);
for (DeviceSwitchVo switchVo : switches) {
properties.put(IOTPropertyName.SWITCH_INDEX + switchVo.getIndex(), targetStatus);
}
// 调用物联网服务设置属性
boolean success = iotCloudService.setProperty(iotId, properties, false, 0);
if (success) {
// 记录成功的开关ID
for (com.intc.fishery.domain.vo.DeviceSwitchVo switchVo : switches) {
for (DeviceSwitchVo switchVo : switches) {
successSwitchIds.add(switchVo.getId());
successSwitches.add(switchVo);
}
@@ -1892,15 +1906,15 @@ public class IotController extends BaseController {
// 批量更新数据库中成功设置的开关状态
if (!successSwitchIds.isEmpty()) {
deviceSwitchMapper.update(null,
new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<com.intc.fishery.domain.DeviceSwitch>()
.in(com.intc.fishery.domain.DeviceSwitch::getId, successSwitchIds)
.set(com.intc.fishery.domain.DeviceSwitch::getIsOpen, targetStatus)
.set(com.intc.fishery.domain.DeviceSwitch::getLastTurnTime, new Date())
new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<DeviceSwitch>()
.in(DeviceSwitch::getId, successSwitchIds)
.set(DeviceSwitch::getIsOpen, targetStatus)
.set(DeviceSwitch::getLastTurnTime, new Date())
);
// 记录操作日志
String operation = targetStatus == 1 ? "开启" : "关闭";
for (com.intc.fishery.domain.vo.DeviceSwitchVo switchVo : successSwitches) {
for (DeviceSwitchVo switchVo : successSwitches) {
log.info("开关操作:{}({})的开关{}{}",
switchVo.getDeviceName(), switchVo.getSerialNum(), switchVo.getSwitchName(), operation);
}
@@ -1921,7 +1935,7 @@ public class IotController extends BaseController {
*/
@Operation(summary = "设置开关额定电流")
@PutMapping("/switch/electric_set")
public R<Void> updateElectricSet(@RequestBody com.intc.fishery.domain.bo.ReqSwitchElectricSet request) {
public R<Void> updateElectricSet(@RequestBody ReqSwitchElectricSet request) {
try {
if (deviceSwitchMapper == null || deviceMapper == null) {
return R.fail("系统配置未完成");
@@ -1932,7 +1946,7 @@ public class IotController extends BaseController {
Double electric = request.getElectric();
// 查询开关信息
com.intc.fishery.domain.DeviceSwitch deviceSwitch = deviceSwitchMapper.selectById(switchId);
DeviceSwitch deviceSwitch = deviceSwitchMapper.selectById(switchId);
if (deviceSwitch == null) {
return R.fail("开关不存在");
}
@@ -1956,7 +1970,7 @@ public class IotController extends BaseController {
}
// 检查额定电流值是否已改变精度0.001
if (deviceSwitch.getRateElectricValue() != null
if (deviceSwitch.getRateElectricValue() != null
&& Math.abs(deviceSwitch.getRateElectricValue() - electric) < 0.001) {
return R.ok();
}
@@ -1983,9 +1997,9 @@ public class IotController extends BaseController {
// 更新数据库中的额定电流值
deviceSwitchMapper.update(null,
new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<com.intc.fishery.domain.DeviceSwitch>()
.eq(com.intc.fishery.domain.DeviceSwitch::getId, switchId)
.set(com.intc.fishery.domain.DeviceSwitch::getRateElectricValue, electric)
new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<DeviceSwitch>()
.eq(DeviceSwitch::getId, switchId)
.set(DeviceSwitch::getRateElectricValue, electric)
);
// 记录操作日志
@@ -2007,7 +2021,7 @@ public class IotController extends BaseController {
*/
@Operation(summary = "修改开关输出电压类型")
@PutMapping("/switch/update_voltage_type")
public R<Void> updateConnectVoltageType(@RequestBody com.intc.fishery.domain.bo.ReqSetVoltageType request) {
public R<Void> updateConnectVoltageType(@RequestBody ReqSetVoltageType request) {
try {
if (deviceSwitchMapper == null || deviceMapper == null) {
return R.fail("系统配置未完成");
@@ -2018,9 +2032,9 @@ public class IotController extends BaseController {
Integer voltageType = request.getVoltageType();
// 查询开关信息(包括关联的设备信息)
com.github.yulichang.wrapper.MPJLambdaWrapper<com.intc.fishery.domain.DeviceSwitch> wrapper =
new com.github.yulichang.wrapper.MPJLambdaWrapper<com.intc.fishery.domain.DeviceSwitch>()
.selectAll(com.intc.fishery.domain.DeviceSwitch.class)
com.github.yulichang.wrapper.MPJLambdaWrapper<DeviceSwitch> wrapper =
new com.github.yulichang.wrapper.MPJLambdaWrapper<DeviceSwitch>()
.selectAll(DeviceSwitch.class)
.selectAs(Device::getUserId, "userId")
.selectAs(Device::getIotId, "iotId")
.selectAs(Device::getSerialNum, "serialNum")
@@ -2029,11 +2043,11 @@ public class IotController extends BaseController {
.selectAs(Device::getInputVoltage, "inputVoltage")
.selectAs(Device::getWarnCode, "warnCode")
.selectAs(Device::getDeadTime, "deadTime")
.leftJoin(Device.class, Device::getId, com.intc.fishery.domain.DeviceSwitch::getDeviceId)
.eq(com.intc.fishery.domain.DeviceSwitch::getId, switchId);
.leftJoin(Device.class, Device::getId, DeviceSwitch::getDeviceId)
.eq(DeviceSwitch::getId, switchId);
com.intc.fishery.domain.vo.DeviceSwitchVo switchVo =
deviceSwitchMapper.selectJoinOne(com.intc.fishery.domain.vo.DeviceSwitchVo.class, wrapper);
DeviceSwitchVo switchVo =
deviceSwitchMapper.selectJoinOne(DeviceSwitchVo.class, wrapper);
if (switchVo == null) {
return R.fail("开关不存在");
@@ -2092,9 +2106,9 @@ public class IotController extends BaseController {
// 更新数据库中的电压类型
deviceSwitchMapper.update(null,
new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<com.intc.fishery.domain.DeviceSwitch>()
.eq(com.intc.fishery.domain.DeviceSwitch::getId, switchId)
.set(com.intc.fishery.domain.DeviceSwitch::getConnectVoltageType, voltageType)
new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<DeviceSwitch>()
.eq(DeviceSwitch::getId, switchId)
.set(DeviceSwitch::getConnectVoltageType, voltageType)
);
// 记录操作日志
@@ -2141,7 +2155,7 @@ public class IotController extends BaseController {
*/
@Operation(summary = "修改开关所属塘口")
@PutMapping("/switch/update_pond")
public R<Void> updateSwitchPond(@RequestBody com.intc.fishery.domain.bo.ReqChangePond request) {
public R<Void> updateSwitchPond(@RequestBody ReqChangePond request) {
try {
if (deviceSwitchMapper == null || pondMapper == null || deviceMapper == null) {
return R.fail("系统配置未完成");
@@ -2152,21 +2166,21 @@ public class IotController extends BaseController {
Long pondId = request.getPondId();
// 查询开关信息,包括关联的设备和塘口信息
com.github.yulichang.wrapper.MPJLambdaWrapper<com.intc.fishery.domain.DeviceSwitch> wrapper =
new com.github.yulichang.wrapper.MPJLambdaWrapper<com.intc.fishery.domain.DeviceSwitch>()
.selectAll(com.intc.fishery.domain.DeviceSwitch.class)
com.github.yulichang.wrapper.MPJLambdaWrapper<DeviceSwitch> wrapper =
new com.github.yulichang.wrapper.MPJLambdaWrapper<DeviceSwitch>()
.selectAll(DeviceSwitch.class)
.selectAs(Device::getDeviceName, "deviceName")
.selectAs(Device::getSerialNum, "serialNum")
.selectAs(Device::getIotId, "iotId")
.selectAs(Device::getWarnCode, "warnCode")
.selectAs(com.intc.fishery.domain.Pond::getPondName, "pondName")
.leftJoin(Device.class, Device::getId, com.intc.fishery.domain.DeviceSwitch::getDeviceId)
.leftJoin(com.intc.fishery.domain.Pond.class, com.intc.fishery.domain.Pond::getId, com.intc.fishery.domain.DeviceSwitch::getPondId)
.eq(com.intc.fishery.domain.DeviceSwitch::getId, switchId);
.selectAs(Pond::getPondName, "pondName")
.leftJoin(Device.class, Device::getId, DeviceSwitch::getDeviceId)
.leftJoin(Pond.class, Pond::getId, DeviceSwitch::getPondId)
.eq(DeviceSwitch::getId, switchId);
DeviceSwitchVo vo = deviceSwitchMapper.selectJoinOne(
DeviceSwitchVo.class, wrapper);
com.intc.fishery.domain.vo.DeviceSwitchVo vo = deviceSwitchMapper.selectJoinOne(
com.intc.fishery.domain.vo.DeviceSwitchVo.class, wrapper);
if (vo == null) {
return R.fail("开关不存在");
}
@@ -2186,30 +2200,30 @@ public class IotController extends BaseController {
if (device != null && com.intc.common.core.utils.StringUtils.isNotBlank(device.getIotId())) {
// 检查设备是否在线通过判断warnCode判断设备状态
boolean isOnline = device.getWarnCode() != null && device.getWarnCode() != 99;
if (isOnline && iotCloudService != null) {
try {
// 构造清空定时控制的属性
Map<String, Object> properties = new java.util.HashMap<>();
// 清空定时器localTimer_switch{Index}
properties.put("localTimer_switch" + vo.getIndex(), java.util.Collections.emptyList());
// 如果开关是打开状态,需要关闭它
if (vo.getIsOpen() != null && vo.getIsOpen() == 1) {
// 关闭开关:switchIndex{Index} = 0
properties.put("switchIndex" + vo.getIndex(), 0);
// 关闭开关:Switch{Index} = 0
properties.put(IOTPropertyName.SWITCH_INDEX + vo.getIndex(), 0);
// 更新数据库中的开关状态
deviceSwitchMapper.update(null,
new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<com.intc.fishery.domain.DeviceSwitch>()
.eq(com.intc.fishery.domain.DeviceSwitch::getId, switchId)
.set(com.intc.fishery.domain.DeviceSwitch::getIsOpen, 0)
new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<DeviceSwitch>()
.eq(DeviceSwitch::getId, switchId)
.set(DeviceSwitch::getIsOpen, 0)
);
}
// 调用物联网服务设置属性
boolean success = iotCloudService.setProperty(device.getIotId(), properties, false, 0);
if (success) {
log.info("成功通过物联网服务清空开关定时控制和关闭开关, switchId={}", switchId);
} else {
@@ -2220,53 +2234,53 @@ public class IotController extends BaseController {
}
}
}
// 删除该开关的所有定时控制记录
if (timingCtrlMapper != null) {
timingCtrlMapper.delete(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.intc.fishery.domain.TimingCtrl>()
.eq(com.intc.fishery.domain.TimingCtrl::getSwitchId, switchId)
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<TimingCtrl>()
.eq(TimingCtrl::getSwitchId, switchId)
);
}
log.info("已清除开关ID={}的定时控制数据", switchId);
}
// 处理新塘口分配
if (pondId != null && pondId > 0) {
// 验证塘口是否存在
com.intc.fishery.domain.Pond pond = pondMapper.selectById(pondId);
Pond pond = pondMapper.selectById(pondId);
if (pond == null) {
return R.fail("塘口不存在");
}
// 更新开关的塘口ID并清空联动控制ID
deviceSwitchMapper.update(null,
new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<com.intc.fishery.domain.DeviceSwitch>()
.eq(com.intc.fishery.domain.DeviceSwitch::getId, switchId)
.set(com.intc.fishery.domain.DeviceSwitch::getPondId, pondId)
.set(com.intc.fishery.domain.DeviceSwitch::getLinkedCtrlId, null)
new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<DeviceSwitch>()
.eq(DeviceSwitch::getId, switchId)
.set(DeviceSwitch::getPondId, pondId)
.set(DeviceSwitch::getLinkedCtrlId, null)
);
// 记录操作日志
if (oldPondId != null) {
log.info("开关操作:{}({})的开关{},转移到塘口:{}",
log.info("开关操作:{}({})的开关{},转移到塘口:{}",
vo.getDeviceName(), vo.getSerialNum(), vo.getSwitchName(), pond.getPondName());
} else {
log.info("开关操作:{}({})的开关{},分配到塘口:{}",
log.info("开关操作:{}({})的开关{},分配到塘口:{}",
vo.getDeviceName(), vo.getSerialNum(), vo.getSwitchName(), pond.getPondName());
}
} else if (oldPondId != null) {
// 移除塘口分配
deviceSwitchMapper.update(null,
new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<com.intc.fishery.domain.DeviceSwitch>()
.eq(com.intc.fishery.domain.DeviceSwitch::getId, switchId)
.set(com.intc.fishery.domain.DeviceSwitch::getPondId, null)
.set(com.intc.fishery.domain.DeviceSwitch::getLinkedCtrlId, null)
new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<DeviceSwitch>()
.eq(DeviceSwitch::getId, switchId)
.set(DeviceSwitch::getPondId, null)
.set(DeviceSwitch::getLinkedCtrlId, null)
);
// 记录操作日志
log.info("开关操作:{}({})的开关{} 从 {} 移除",
log.info("开关操作:{}({})的开关{} 从 {} 移除",
vo.getDeviceName(), vo.getSerialNum(), vo.getSwitchName(), oldPondName);
}
@@ -2276,4 +2290,347 @@ public class IotController extends BaseController {
return R.fail("修改失败: " + e.getMessage());
}
}
/**
* 设置定时控制开关
*
* @param request 请求对象
* @return 操作结果
*/
@Operation(summary = "设置定时控制开关")
@PostMapping("/timingCtrl/update")
public R<Void> setTimeCtrlOpen(
@Validated @org.springframework.web.bind.annotation.RequestBody ReqTurnOpen request) {
try {
// 查询定时控制信息
TimingCtrl timingCtrl = timingCtrlMapper.selectOne(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<TimingCtrl>()
.eq(TimingCtrl::getId, request.getId())
.select(TimingCtrl::getId,
TimingCtrl::getIsOpen,
TimingCtrl::getLoopType,
TimingCtrl::getSwitchId,
TimingCtrl::getOpenTime,
TimingCtrl::getCloseTime)
);
if (timingCtrl == null) {
return R.fail("定时控制不存在");
}
// 如果状态相同,无需更新
if (timingCtrl.getIsOpen().intValue() == request.getIsOpen()) {
return R.ok();
}
// 如果是启用且循环类型为1每天循环验证当前时间不在定时范围内
if (request.getIsOpen() == 1 && timingCtrl.getLoopType() != null && timingCtrl.getLoopType() == 1) {
Date now = new Date();
java.util.Calendar calendar = java.util.Calendar.getInstance();
calendar.setTime(now);
int currentHour = calendar.get(java.util.Calendar.HOUR_OF_DAY);
int currentMinute = calendar.get(java.util.Calendar.MINUTE);
java.util.Calendar openCal = java.util.Calendar.getInstance();
openCal.setTime(timingCtrl.getOpenTime());
int openHour = openCal.get(java.util.Calendar.HOUR_OF_DAY);
int openMinute = openCal.get(java.util.Calendar.MINUTE);
java.util.Calendar closeCal = java.util.Calendar.getInstance();
closeCal.setTime(timingCtrl.getCloseTime());
int closeHour = closeCal.get(java.util.Calendar.HOUR_OF_DAY);
int closeMinute = closeCal.get(java.util.Calendar.MINUTE);
int currentTimeInMinutes = currentHour * 60 + currentMinute;
int openTimeInMinutes = openHour * 60 + openMinute;
int closeTimeInMinutes = closeHour * 60 + closeMinute;
if (currentTimeInMinutes >= openTimeInMinutes && currentTimeInMinutes <= closeTimeInMinutes) {
return R.fail("开启失败");
}
}
// 查询开关和设备信息
DeviceSwitch deviceSwitch = deviceSwitchMapper.selectOne(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<DeviceSwitch>()
.eq(DeviceSwitch::getId, timingCtrl.getSwitchId())
.select(DeviceSwitch::getId,
DeviceSwitch::getDeviceId,
DeviceSwitch::getIndex,
DeviceSwitch::getSwitchName)
);
if (deviceSwitch == null) {
return R.fail("定时控制不存在");
}
// 查询设备信息
Device device = deviceMapper.selectOne(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<Device>()
.eq(Device::getId, deviceSwitch.getDeviceId())
.select(Device::getId, Device::getUserId, Device::getDeviceName,
Device::getIotId, Device::getSerialNum, Device::getWarnCode, Device::getDeadTime)
);
if (device == null) {
return R.fail("定时控制不存在");
}
// 检查设备是否过期
if (device.getDeadTime() != null && device.getDeadTime().before(new Date())) {
return R.fail("设备服务已过期");
}
// // 检查设备是否离线warnCode & 0x0080
// if (device.getWarnCode() != null && (device.getWarnCode() & 0x0080) != 0) {
// return R.fail("设备离线或关机");
// }
// 查询该开关的所有定时控制
java.util.List<TimingCtrl> allTimingCtrls = timingCtrlMapper.selectList(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<TimingCtrl>()
.eq(TimingCtrl::getSwitchId, timingCtrl.getSwitchId())
);
// 更新当前定时控制的状态
for (TimingCtrl tc : allTimingCtrls) {
if (tc.getId().equals(request.getId())) {
tc.setIsOpen(request.getIsOpen().longValue());
break;
}
}
// 调用设置属性方法
boolean success = setPropertyTimeCtrl(deviceSwitch, device, allTimingCtrls, request.getId());
if (!success) {
return R.fail("设置定时控制失败");
}
// 更新数据库
timingCtrlMapper.update(null,
new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<TimingCtrl>()
.eq(TimingCtrl::getId, request.getId())
.set(TimingCtrl::getIsOpen, request.getIsOpen().longValue())
.set(TimingCtrl::getOpenTime, timingCtrl.getOpenTime())
.set(TimingCtrl::getCloseTime, timingCtrl.getCloseTime())
);
// TODO: 记录操作日志
String operation = request.getIsOpen() == 1 ? "启用" : "停用";
log.info("开关定时控制:{}({}){}d定时控制。",
device.getDeviceName(), deviceSwitch.getSwitchName(), operation);
return R.ok();
} catch (Exception e) {
log.error("设置定时控制开关失败: {}", e.getMessage(), e);
return R.fail("设置失败: " + e.getMessage());
}
}
/**
* 设置设备定时控制属性
*
* @param deviceSwitch 开关信息
* @param device 设备信息
* @param allTimingCtrls 该开关的所有定时控制
* @param timeCtrlId 当前操作的定时控制ID
* @return 是否成功
*/
private boolean setPropertyTimeCtrl(
DeviceSwitch deviceSwitch,
Device device,
java.util.List<TimingCtrl> allTimingCtrls,
Long timeCtrlId) {
try {
java.util.List<Object> listTimingCtrl = new java.util.ArrayList<>();
Map<String, Object> properties = new java.util.HashMap<>();
Date dateToday = new Date();
java.util.Calendar calendar = java.util.Calendar.getInstance();
calendar.setTime(dateToday);
calendar.set(java.util.Calendar.HOUR_OF_DAY, 0);
calendar.set(java.util.Calendar.MINUTE, 0);
calendar.set(java.util.Calendar.SECOND, 0);
calendar.set(java.util.Calendar.MILLISECOND, 0);
Date todayStart = calendar.getTime();
Date now = new Date();
for (TimingCtrl timingCtrl : allTimingCtrls) {
Date onTime = timingCtrl.getOpenTime();
Date offTime = timingCtrl.getCloseTime();
// 如果是当前启用的定时控制,重新计算时间
if (timeCtrlId.equals(timingCtrl.getId()) && timingCtrl.getIsOpen() != null && timingCtrl.getIsOpen() == 1) {
java.util.Calendar onCal = java.util.Calendar.getInstance();
onCal.setTime(todayStart);
java.util.Calendar tempCal = java.util.Calendar.getInstance();
tempCal.setTime(onTime);
onCal.set(java.util.Calendar.HOUR_OF_DAY, tempCal.get(java.util.Calendar.HOUR_OF_DAY));
onCal.set(java.util.Calendar.MINUTE, tempCal.get(java.util.Calendar.MINUTE));
onTime = onCal.getTime();
java.util.Calendar offCal = java.util.Calendar.getInstance();
offCal.setTime(todayStart);
tempCal.setTime(offTime);
offCal.set(java.util.Calendar.HOUR_OF_DAY, tempCal.get(java.util.Calendar.HOUR_OF_DAY));
offCal.set(java.util.Calendar.MINUTE, tempCal.get(java.util.Calendar.MINUTE));
offTime = offCal.getTime();
// 如果开启时间小于当前时间加1天
if (onTime.before(now)) {
onCal.add(java.util.Calendar.DAY_OF_MONTH, 1);
onTime = onCal.getTime();
}
// 如果关闭时间小于当前时间加1天
if (offTime.before(now)) {
offCal.add(java.util.Calendar.DAY_OF_MONTH, 1);
offTime = offCal.getTime();
}
// 如果开启时间大于关闭时间关闭时间加1天
if (onTime.after(offTime)) {
offCal.add(java.util.Calendar.DAY_OF_MONTH, 1);
offTime = offCal.getTime();
}
// 如果当前时间在定时范围内,返回失败
if (!now.before(onTime) && !now.after(offTime)) {
return false;
}
// 更新定时控制的时间
timingCtrl.setOpenTime(onTime);
timingCtrl.setCloseTime(offTime);
}
// 转换为UTC Unix时间戳
long onUnixStamp = onTime.getTime() / 1000;
long offUnixStamp = offTime.getTime() / 1000;
// 构建定时控制对象
Map<String, Object> timeCtrl = new java.util.HashMap<>();
timeCtrl.put("timerMode", timingCtrl.getLoopType() != null ? timingCtrl.getLoopType() - 1 : 0);
timeCtrl.put("isValid", timingCtrl.getIsOpen() != null && timingCtrl.getIsOpen() == 1 ? 1 : 0);
timeCtrl.put("onTime", String.valueOf(onUnixStamp));
timeCtrl.put("offTime", String.valueOf(offUnixStamp));
listTimingCtrl.add(timeCtrl);
}
// 设置属性
properties.put(IOTPropertyName.LOCAL_TIMER_SWITCH + deviceSwitch.getIndex(), listTimingCtrl);
// 调用IoT服务设置属性0
return iotCloudService.setProperty(device.getIotId(), properties, false, 0);
} catch (Exception e) {
log.error("设置定时控制属性失败: {}", e.getMessage(), e);
return false;
}
}
/**
* 删除定时控制
*
* @param request 请求对象包含定时控制ID
* @return 操作结果
*/
@Operation(summary = "删除定时控制")
@DeleteMapping("/timingCtrl/delete")
@Transactional(rollbackFor = Exception.class)
public R<Void> deleteTimeCtrl(
@Validated @RequestBody ReqId request) {
try {
Long userId = LoginHelper.getUserId();
// 查询定时控制基本信息
TimingCtrl dbTimeCtrl = timingCtrlMapper.selectOne(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<TimingCtrl>()
.eq(TimingCtrl::getId, request.getId())
.select(TimingCtrl::getId,
TimingCtrl::getIsOpen,
TimingCtrl::getSwitchId)
);
if (dbTimeCtrl == null) {
return R.fail("定时控制不存在");
}
// 查询开关信息及关联的设备信息
DeviceSwitch deviceSwitch = deviceSwitchMapper.selectOne(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<DeviceSwitch>()
.eq(DeviceSwitch::getId, dbTimeCtrl.getSwitchId())
.select(DeviceSwitch::getId,
DeviceSwitch::getDeviceId,
DeviceSwitch::getIndex,
DeviceSwitch::getSwitchName)
);
if (deviceSwitch == null) {
return R.fail("定时控制不存在");
}
// 查询设备信息
Device device = deviceMapper.selectOne(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<Device>()
.eq(Device::getId, deviceSwitch.getDeviceId())
.select(Device::getId, Device::getUserId, Device::getDeviceName,
Device::getIotId, Device::getSerialNum, Device::getWarnCode, Device::getDeadTime)
);
// 权限验证
if (device == null || device.getUserId() == null || !device.getUserId().equals(userId)) {
return R.fail("定时控制不存在");
}
// 检查设备是否过期
if (device.getDeadTime() != null && device.getDeadTime().before(new Date())) {
return R.fail("设备服务已过期");
}
// // 检查设备是否离线warnCode & 0x0080
// if (device.getWarnCode() != null && (device.getWarnCode() & 0x0080) != 0) {
// return R.fail("设备离线或关机");
// }
// 查询该开关的所有定时控制
java.util.List<TimingCtrl> allTimingCtrls = timingCtrlMapper.selectList(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<TimingCtrl>()
.eq(TimingCtrl::getSwitchId, dbTimeCtrl.getSwitchId())
);
// 从列表中移除要删除的定时控制,并将其 isOpen 设置为 0
for (TimingCtrl tc : allTimingCtrls) {
if (tc.getId().equals(request.getId())) {
tc.setIsOpen(0L);
break;
}
}
// 调用设置属性方法,将更新后的定时控制列表同步到设备
boolean success = setPropertyTimeCtrl(deviceSwitch, device, allTimingCtrls, request.getId());
if (!success) {
return R.fail("设置定时控制失败");
}
// 从数据库中删除定时控制记录
int deleteCount = timingCtrlMapper.deleteById(request.getId());
if (deleteCount == 0) {
return R.fail("删除失败");
}
// 记录操作日志
log.info("开关定时控制:{}({})删除定时控制。",
device.getDeviceName(), deviceSwitch.getSwitchName());
return R.ok();
} catch (Exception e) {
log.error("删除定时控制失败: {}", e.getMessage(), e);
return R.fail("删除失败: " + e.getMessage());
}
}
}