diff --git a/intc-admin/src/main/resources/application-dev.yml b/intc-admin/src/main/resources/application-dev.yml index 87669ca..3bce85a 100644 --- a/intc-admin/src/main/resources/application-dev.yml +++ b/intc-admin/src/main/resources/application-dev.yml @@ -209,6 +209,8 @@ device-type: water-quality-monitor: a15hA3oBPmB # TODO: 请替换为实际的水质检测仪 ProductKey # 2-控制一体机 ProductKey(请填写实际的 ProductKey) control-integrated: a1Xj9dagTIx # TODO: 请替换为实际的控制一体机 ProductKey + # 3-太阳能网控 ProductKey + solar-controller: a1ZLJkYlSjs --- # 阿里云生活物联网平台(飞燕平台)配置 aliyun: living-iot: diff --git a/intc-common/intc-common-core/src/main/java/com/intc/common/core/config/properties/DeviceTypeProperties.java b/intc-common/intc-common-core/src/main/java/com/intc/common/core/config/properties/DeviceTypeProperties.java index 8a0abc6..dac6855 100644 --- a/intc-common/intc-common-core/src/main/java/com/intc/common/core/config/properties/DeviceTypeProperties.java +++ b/intc-common/intc-common-core/src/main/java/com/intc/common/core/config/properties/DeviceTypeProperties.java @@ -24,10 +24,15 @@ public class DeviceTypeProperties { */ private String controlIntegrated; + /** + * 太阳能网控 ProductKey + */ + private String solarController; + /** * 根据 ProductKey 判断设备类型 * @param productKey ProductKey - * @return 设备类型: 1-水质检测仪, 2-控制一体机, null-未知类型 + * @return 设备类型: 1-水质检测仪, 2-控制一体机, 3-太阳能网控, null-未知类型 */ public Integer getDeviceTypeByProductKey(String productKey) { if (productKey == null) { @@ -37,13 +42,15 @@ public class DeviceTypeProperties { return 1; } else if (productKey.equals(controlIntegrated)) { return 2; + } else if (productKey.equals(solarController)) { + return 3; } return null; } /** * 根据设备类型获取 ProductKey - * @param deviceType 1-水质检测仪, 2-控制一体机 + * @param deviceType 1-水质检测仪, 2-控制一体机, 3-太阳能网控 * @return ProductKey */ public String getProductKeyByType(Integer deviceType) { @@ -55,6 +62,8 @@ public class DeviceTypeProperties { return waterQualityMonitor; case 2: return controlIntegrated; + case 3: + return solarController; default: return null; } diff --git a/intc-modules/intc-iot/src/main/java/com/intc/iot/controller/IotController.java b/intc-modules/intc-iot/src/main/java/com/intc/iot/controller/IotController.java index e22c799..31e66f8 100644 --- a/intc-modules/intc-iot/src/main/java/com/intc/iot/controller/IotController.java +++ b/intc-modules/intc-iot/src/main/java/com/intc/iot/controller/IotController.java @@ -328,7 +328,7 @@ public class IotController extends BaseController { @Operation(summary = "查询设备当前状态(从物联网平台)") @GetMapping("/device/status") public R queryDeviceStatus( - @Parameter(description = "设备类型(1-水质检测仪, 2-控制一体机)") @RequestParam Integer devicetype, + @Parameter(description = "设备类型(1-水质检测仪, 2-控制一体机, 3-太阳能网控)") @RequestParam Integer devicetype, @Parameter(description = "设备编号/设备名称") @RequestParam String serialnum) { try { if (iotDeviceService == null) { @@ -1540,6 +1540,201 @@ public class IotController extends BaseController { } } + @Operation(summary = "添加设备(太阳能网控)") + @PostMapping("/device/add_device_solar_detector") + public R addDeviceSolarController(@RequestBody com.intc.iot.domain.bo.AddDeviceSolarControllerBo bo, @RequestParam Long rootUserId) { + try { + if (iotDeviceService == null) { + return R.fail("飞燕平台配置未启用"); + } + if (deviceMapper == null) { + return R.fail("设备数据库服务未启用"); + } + + // 获取用户ID(从 URL 查询参数 rootUserId 获取) + if (rootUserId == null) { + return R.fail("根用户ID不能为空"); + } + + // 验证塘口是否存在且属于当前用户 + if (bo.getPondId() != null && bo.getPondId() > 0 && pondMapper != null) { + long count = pondMapper.selectCount( + new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper() + .eq(Pond::getUserId, rootUserId) + .eq(Pond::getId, bo.getPondId()) + ); + if (count == 0) { + return R.fail("塘口不存在或无权限访问"); + } + } + + // 检查设备是否已被绑定 + Device existDevice = deviceMapper.selectOne( + new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper() + .eq(Device::getDeviceType, 3) // 3-太阳能网控 + .eq(Device::getSerialNum, bo.getSerialNum()) + ); + if (existDevice != null && existDevice.getUserId() != null) { + return R.fail("该设备号已被绑定"); + } + + // 获取太阳能网控的 ProductKey + String productKey = deviceTypeProperties.getSolarController(); + if (productKey == null || productKey.isEmpty()) { + return R.fail("未配置太阳能网控的 ProductKey"); + } + + // 查询设备基础信息 + Map deviceInfo = iotDeviceService.findDeviceByProductKeyAndName(productKey, bo.getSerialNum()); + if (deviceInfo == null || !Boolean.TRUE.equals(deviceInfo.get("success"))) { + return R.fail("设备不存在"); + } + + // 提取设备数据 + Map data = (Map) 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("设备禁用"); + } + } + + // 获取设备属性 + Map deviceProperties = iotDeviceService.queryDeviceProperties(iotId); + + // 计算设备数量,用于生成设备名称 + long deviceCount = deviceMapper.selectCount( + new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper() + .eq(Device::getUserId, rootUserId) + .eq(Device::getDeviceType, 3) + ); + + // 创建或更新设备信息 + 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(3); // 3-太阳能网控 + device.setDeadTime(new Date(now.getTime() + 365L * 24 * 60 * 60 * 1000)); // 一年后到期 + } + + // 设置基本信息 + device.setUserId(rootUserId); + device.setDeviceName("太阳能网控" + (deviceCount + 1)); + device.setBindTime(now); + device.setPondId(bo.getPondId() != null && bo.getPondId() > 0 ? bo.getPondId() : null); + device.setBatteryWarnCallOpen(bo.getBatteryWarnCallOpen()); + device.setBatteryWarnCallNoDis(bo.getBatteryWarnCallNoDis()); + device.setBatteryWarnLower(bo.getBatteryWarnLower()); + + // 解析并设置设备属性(ICCID 等) + 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 "ICCID": // 物联网卡号 + device.setIccId(value.toString()); + break; + } + } + } catch (Exception ex) { + log.error("无法从 SDK 对象中获取属性: {}", ex.getMessage(), ex); + } + } + } + } + } catch (Exception ex) { + log.error("无法从 SDK 对象中获取属性列表: {}", ex.getMessage(), ex); + } + } + } + + // 初始化警告码 + int warnCode = 0; + + // 如果设备离线,添加离线警告 + if (status != null && "OFFLINE".equalsIgnoreCase(status)) { + warnCode |= 0x0080; // 设备离线 + } + + device.setWarnCode(warnCode); + + // 验证 ICCID 是否存在 + if (device.getIccId() == null || device.getIccId().isEmpty()) { + return R.fail("设备缺少物联网卡号(ICCID)"); + } + + // 添加绑定记录 + addNewDeviceBindRecord(device, true); + + // 保存到数据库 + if (isNew) { + deviceMapper.insert(device); + log.info("新设备添加成功: userId={}, iotId={}, serialNum={}", rootUserId, iotId, bo.getSerialNum()); + } else { + deviceMapper.updateById(device); + log.info("设备更新成功: userId={}, iotId={}, serialNum={}", rootUserId, iotId, bo.getSerialNum()); + } + + return R.ok(); + } catch (Exception e) { + log.error("添加太阳能网控失败: {}", e.getMessage(), e); + return R.fail("添加太阳能网控失败: " + e.getMessage()); + } + } + @Operation(summary = "设备校准") @PostMapping("/device/calibrate") public R setCalibrate(@RequestBody DeviceCalibrateBo request) { diff --git a/intc-modules/intc-iot/src/main/java/com/intc/iot/domain/bo/AddDeviceSolarControllerBo.java b/intc-modules/intc-iot/src/main/java/com/intc/iot/domain/bo/AddDeviceSolarControllerBo.java new file mode 100644 index 0000000..5e539bf --- /dev/null +++ b/intc-modules/intc-iot/src/main/java/com/intc/iot/domain/bo/AddDeviceSolarControllerBo.java @@ -0,0 +1,56 @@ +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; + +/** + * 添加太阳能网控业务对象 + * + * @author intc + */ +@Data +@Schema(description = "添加太阳能网控请求对象") +public class AddDeviceSolarControllerBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 设备编号/序列号 + */ + @Schema(description = "设备编号/序列号") + @NotBlank(message = "设备编号不能为空") + private String serialNum; + + /** + * 塘口ID + */ + @Schema(description = "塘口ID") + private Long pondId; + + /** + * 电量电话告警开关(0-关闭, 1-开启) + */ + @Schema(description = "电量电话告警开关(0-关闭, 1-开启)") + @NotNull(message = "电量电话告警开关不能为空") + private Long batteryWarnCallOpen; + + /** + * 电量告警免打扰(0-关闭, 1-开启) + */ + @Schema(description = "电量告警免打扰(0-关闭, 1-开启)") + @NotNull(message = "电量告警免打扰不能为空") + private Long batteryWarnCallNoDis; + + /** + * 电量电话告警下限(百分比) + */ + @Schema(description = "电量电话告警下限(百分比)") + @NotNull(message = "电量电话告警下限不能为空") + private Long batteryWarnLower; +}