fix (farm): 设备中心

- 水肥机
This commit is contained in:
达富斌
2025-10-04 14:22:51 +08:00
parent 636da5a512
commit 8989ccf1ab
12 changed files with 85 additions and 58 deletions

View File

@@ -122,7 +122,7 @@ public class DeviceInfoController {
@Operation(summary = "获得设备信息")
@Parameter(name = "id", description = "编号", required = true)
@Parameter(name = "dateType", description = "日期类型", required = false)
public CommonResult<DeviceInfoDetailV2RespVO> getDeviceInfo(@RequestParam("id") String id,@RequestParam("dateType") String dateType) {
public CommonResult<DeviceInfoDetailV2RespVO> getDeviceInfo(@RequestParam("id") String id,@RequestParam("dateType") Integer dateType) {
DeviceInfoDetailV2RespVO res = deviceInfoService.getDeviceRealTimeInfo(id,dateType);
return success(res);
}

View File

@@ -85,6 +85,7 @@ public class DeviceInfoDetailV2RespVO {
@NoArgsConstructor
public static class WfInfo{
private String deviceUniqueId;
private RealTimeDataResponse realTimeData;
}
public DeviceInfoDetailV2RespVO(String deviceUniqueId, SoilInfo soilInfo, WfInfo wfInfo) {

View File

@@ -101,5 +101,5 @@ public class CommonConstants {
public final static Integer FARM_MODEL_FARMING_OPERATION_USABLE_TYPE_2 = 2; // 不可用
public final static String DEVICE_TYPE_SOIL = "soil";
public final static String DEVICE_TYPE__WF = "water_fertilizer";
public final static String DEVICE_TYPE_WF = "water_fertilizer";
}

View File

@@ -26,9 +26,9 @@ public class EquipmentProducerManager {
/**
* 统一登录方法
*/
public UnifiedLoginResponse login(String deviceType, Long tenantId, String deviceId, Object loginRequest) {
public UnifiedLoginResponse login(String deviceType, Long tenantId, String deviceId) {
DeviceService service = this.getDeviceService(deviceType);
return service.login(tenantId, deviceId, loginRequest);
return service.login(tenantId, deviceId);
}
/**

View File

@@ -13,8 +13,8 @@ import java.util.Map;
public abstract class AbstractDeviceService extends TokenCacheService implements DeviceService{
@Override
public UnifiedLoginResponse login(Long tenantId, String deviceId, Object loginRequest) {
String cacheKey = generateCacheKey(getDeviceType(), tenantId, deviceId);
public UnifiedLoginResponse login(Long tenantId, String plotId) {
String cacheKey = generateCacheKey(getDeviceType(), tenantId, plotId);
// 检查缓存中是否有有效token
TokenCacheService.TokenInfo cachedToken = getToken(cacheKey);
@@ -23,7 +23,7 @@ public abstract class AbstractDeviceService extends TokenCacheService implements
}
// 调用具体设备登录
UnifiedLoginResponse loginResponse = doLogin(loginRequest);
UnifiedLoginResponse loginResponse = doLogin();
if ("200".equals(loginResponse.getCode()) && loginResponse.getData() != null) {
// 缓存token信息
@@ -103,7 +103,7 @@ public abstract class AbstractDeviceService extends TokenCacheService implements
/**
* 具体设备登录逻辑(由子类实现)
*/
protected abstract UnifiedLoginResponse doLogin(Object loginRequest);
protected abstract UnifiedLoginResponse doLogin();
/**
* 具体设备获取列表逻辑(由子类实现)
@@ -151,7 +151,7 @@ public abstract class AbstractDeviceService extends TokenCacheService implements
for (Map.Entry<String, TokenCacheService.TokenInfo> entry : tokenCacheMap.entrySet()) {
if (entry.getKey().startsWith(getDeviceType() + ":" + tenantId + ":") &&
token.equals(entry.getValue().getToken())
// && isTokenValid(entry.getKey())
&& isTokenValid(entry.getKey())
) {
return true;
}

View File

@@ -14,7 +14,7 @@ public interface DeviceService {
/**
* 登录获取token
*/
UnifiedLoginResponse login(Long tenantId, String deviceId, Object loginRequest);
UnifiedLoginResponse login(Long tenantId, String deviceId);
/**
* 获取设备列表

View File

@@ -67,7 +67,8 @@ public abstract class TokenCacheService {
if (tokenInfo == null) {
return false;
}
return tokenInfo.getExpDate() > System.currentTimeMillis();
long cu = System.currentTimeMillis();
return tokenInfo.getExpDate() * 1000 > cu;
}
/**
@@ -93,7 +94,7 @@ public abstract class TokenCacheService {
/**
* 定期清除过期token
*/
@Scheduled(fixedRate = 300000) // 每5分钟执行一次
@Scheduled(fixedRate = 1000 * 60 * 60 ) // 每1小时执行一次
public void cleanupExpiredTokens() {
long currentTime = System.currentTimeMillis();
@@ -108,8 +109,6 @@ public abstract class TokenCacheService {
}
}
log.info("清理过期token缓存");
// 清理长时间未使用的设备缓存(可选)
}
/**

View File

@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.farm.manager.equipmentproducer.service.impl;
import cn.iocoder.yudao.module.farm.enums.CommonConstants;
import cn.iocoder.yudao.module.farm.manager.equipmentproducer.conf.DeviceConf;
import cn.iocoder.yudao.module.farm.manager.equipmentproducer.dto.DeviceListResponse;
import cn.iocoder.yudao.module.farm.manager.equipmentproducer.dto.HistoryDataResponse;
@@ -44,14 +45,17 @@ public class SoilService extends AbstractDeviceService {
@Override
public String getDeviceType() {
return "soil";
return CommonConstants.DEVICE_TYPE_SOIL;
}
@Override
protected UnifiedLoginResponse doLogin(Object loginRequest) {
protected UnifiedLoginResponse doLogin() {
try {
// 转换请求参数
UserLoginReqVO soilRequest = (UserLoginReqVO) loginRequest;
UserLoginReqVO soilRequest = new UserLoginReqVO(
deviceConf.getFourSituations().getUsername(),
deviceConf.getFourSituations().getPassword()
);
// 调用土壤设备厂商API POST 请求方式
UserLoginRespVO vendorResponse = callSoilVendorApi(soilRequest);
@@ -127,7 +131,6 @@ public class SoilService extends AbstractDeviceService {
log.info("请求参数: {}", request);
Map<String, String> headers = new HashMap<>();
// headers.put("User-Agent", "FarmDeviceManager/1.0");
headers.put("Content-Type", "application/json");
// 先尝试获取原始响应进行调试

View File

@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.farm.manager.equipmentproducer.service.impl;
import cn.iocoder.yudao.module.farm.enums.CommonConstants;
import cn.iocoder.yudao.module.farm.manager.equipmentproducer.conf.DeviceConf;
import cn.iocoder.yudao.module.farm.manager.equipmentproducer.dto.DeviceListResponse;
import cn.iocoder.yudao.module.farm.manager.equipmentproducer.dto.RealTimeDataResponse;
@@ -16,8 +17,10 @@ import cn.iocoder.yudao.module.farm.manager.equipmentproducer.dto.wf.updateparam
import cn.iocoder.yudao.module.farm.manager.equipmentproducer.service.AbstractDeviceService;
import cn.iocoder.yudao.module.farm.manager.equipmentproducer.service.TokenCacheService;
import cn.iocoder.yudao.module.farm.manager.equipmentproducer.utils.HttpClientUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Service;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -41,17 +44,19 @@ public class WaterFertilizerService extends AbstractDeviceService {
@Override
public String getDeviceType() {
return "water_fertilizer";
return CommonConstants.DEVICE_TYPE_WF;
}
@Override
protected UnifiedLoginResponse doLogin(Object loginRequest) {
protected UnifiedLoginResponse doLogin() {
try {
// 转换请求参数
LoginReqVO wfRequest = (LoginReqVO) loginRequest;
LoginReqVO wfRequest = new LoginReqVO(deviceConf.getWaterAndFertilizer().getUsername(), deviceConf.getWaterAndFertilizer().getPassword());
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(wfRequest);
// 调用水肥机设备厂商API POST 请求方式
LoginRespVO vendorResponse = callWFVendorApi(json);
// TODO: 2025/9/25 调用水肥机设备厂商API POST 请求方式
LoginRespVO vendorResponse = callWFVendorApi(wfRequest);
// 转换为统一响应格式
return convertToUnifiedResponse(vendorResponse);
@@ -65,9 +70,9 @@ public class WaterFertilizerService extends AbstractDeviceService {
protected DeviceListResponse doGetDeviceList(String token, Object listRequest) {
try {
// 转换请求参数
DevicePageReqVO wfRequest = (DevicePageReqVO) listRequest;
DevicePageReqVO wfRequest = new DevicePageReqVO(token, deviceConf.getWaterAndFertilizer().getUsername());
// TODO: 2025/9/25 调用水肥机设备厂商API获取设备列表 GET 请求方式
// 调用水肥机设备厂商API获取设备列表 GET 请求方式
DevicePageRespVO vendorResponse = callWFDeviceListApi(token, wfRequest);
// 转换为统一响应格式
@@ -84,7 +89,7 @@ public class WaterFertilizerService extends AbstractDeviceService {
// 转换请求参数
RealTimeDeviceDataReqVO wfRequest = (RealTimeDeviceDataReqVO) realTimeRequest;
// TODO: 2025/9/26 调用水肥机设备厂商API获取实时数据 GET 请求方式
// 调用水肥机设备厂商API获取实时数据 GET 请求方式
RealTimeDeviceDataRespVO vendorResponse = callWFRealTimeDataApi(token, wfRequest);
// 直接返回原始响应数据,不进行统一转换
@@ -101,7 +106,7 @@ public class WaterFertilizerService extends AbstractDeviceService {
// 转换请求参数
UpdateDeviceStatusReqVO wfRequest = (UpdateDeviceStatusReqVO) updateRequest;
// TODO: 2025/9/26 调用水肥机设备厂商API更新设备属性 POST 请求方式
// 调用水肥机设备厂商API更新设备属性 POST 请求方式
UpdateDeviceStatusRespVO vendorResponse = callWFUpdateDeviceApi(token, wfRequest);
// 转换为统一响应格式
@@ -112,7 +117,7 @@ public class WaterFertilizerService extends AbstractDeviceService {
}
}
private LoginRespVO callWFVendorApi(LoginReqVO request) {
private LoginRespVO callWFVendorApi(String request) {
String url = deviceConf.getWaterAndFertilizer().getHosts() + deviceConf.getWaterAndFertilizer().getUrl1();
return httpClientUtils.doPost(url, null, request, LoginRespVO.class);
}
@@ -177,14 +182,12 @@ public class WaterFertilizerService extends AbstractDeviceService {
private RealTimeDeviceDataRespVO callWFRealTimeDataApi(String token, RealTimeDeviceDataReqVO request) {
String url = deviceConf.getWaterAndFertilizer().getHosts() + deviceConf.getWaterAndFertilizer().getUrl3();
url = MessageFormat.format(url,request.getDeviceId());
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", "Bearer " + token);
Map<String, Object> params = new HashMap<>();
params.put("deviceId", request.getDeviceId());
return httpClientUtils.doGet(url, headers, params, RealTimeDeviceDataRespVO.class);
return httpClientUtils.doGet(url, headers, null, RealTimeDeviceDataRespVO.class);
}
private UpdateDeviceStatusRespVO callWFUpdateDeviceApi(String token, UpdateDeviceStatusReqVO request) {

View File

@@ -63,7 +63,7 @@ public interface DeviceInfoService {
* @param id
* @return
*/
DeviceInfoDetailV2RespVO getDeviceRealTimeInfo(String id,String dateType);
DeviceInfoDetailV2RespVO getDeviceRealTimeInfo(String id,Integer dateType);
/**
* 获得设备信息分页

View File

@@ -17,13 +17,14 @@ import cn.iocoder.yudao.module.farm.dal.mysql.plotinfo.PlotInfoMapper;
import cn.iocoder.yudao.module.farm.enums.CommonConstants;
import cn.iocoder.yudao.module.farm.manager.equipmentproducer.EquipmentProducerManager;
import cn.iocoder.yudao.module.farm.manager.equipmentproducer.conf.DeviceConf;
import cn.iocoder.yudao.module.farm.manager.equipmentproducer.dto.DeviceListResponse;
import cn.iocoder.yudao.module.farm.manager.equipmentproducer.dto.HistoryDataResponse;
import cn.iocoder.yudao.module.farm.manager.equipmentproducer.dto.RealTimeDataResponse;
import cn.iocoder.yudao.module.farm.manager.equipmentproducer.dto.UnifiedLoginResponse;
import cn.iocoder.yudao.module.farm.manager.equipmentproducer.dto.soil.history.HistoryDataListPageReqVO;
import cn.iocoder.yudao.module.farm.manager.equipmentproducer.dto.soil.login.UserLoginReqVO;
import cn.iocoder.yudao.module.farm.manager.equipmentproducer.dto.soil.realtime.RealTimeDataReqVO;
import org.apache.commons.lang3.StringUtils;
import cn.iocoder.yudao.module.farm.manager.equipmentproducer.dto.wf.realtime.RealTimeDeviceDataReqVO;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
@@ -44,7 +45,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
import static cn.iocoder.yudao.module.farm.enums.CommonConstants.DEVICE_TYPE_SOIL;
import static cn.iocoder.yudao.module.farm.enums.CommonConstants.*;
import static cn.iocoder.yudao.module.farm.enums.ErrorCodeConstants.DEVICE_CLASS_TYPE_ERROR;
import static cn.iocoder.yudao.module.farm.enums.ErrorCodeConstants.DEVICE_INFO_NOT_EXISTS;
@@ -136,7 +137,7 @@ public class DeviceInfoServiceImpl implements DeviceInfoService {
}
@Override
public DeviceInfoDetailV2RespVO getDeviceRealTimeInfo(String id,String dateType) {
public DeviceInfoDetailV2RespVO getDeviceRealTimeInfo(String id, Integer dateType) {
List<DeviceClassifyDO> deviceClassifyDOS = deviceClassifyMapper.selectList();
Map<String, String> typeNameMap = deviceClassifyDOS.stream().filter(device -> device.getParentId() != null && device.getParentId() == 0).collect(Collectors.toMap(e -> e.getId().toString(), DeviceClassifyDO::getName));
@@ -146,6 +147,7 @@ public class DeviceInfoServiceImpl implements DeviceInfoService {
DeviceInfoDetailV2RespVO target = BeanUtils.toBean(deviceInfo, DeviceInfoDetailV2RespVO.class);
String deviceUniqueId = deviceInfo.getDeviceUniqueId();
String deviceType = deviceInfo.getDeviceType();
String plotId = deviceInfo.getPlotId();
// 设备类型名称
target.setDeviceTypeName(typeNameMap.getOrDefault(target.getDeviceType(), ""));
@@ -154,43 +156,65 @@ public class DeviceInfoServiceImpl implements DeviceInfoService {
// 获取设备商数据
switch (typeCodeMap.getOrDefault(deviceType, "other")) {
case "soil" :
if (!StringUtils.isEmpty(dateType)) {
DeviceInfoDetailV2RespVO.SoilInfo soilInfo = getSoilInfo(deviceUniqueId,Integer.parseInt(dateType));
case DEVICE_TYPE_SOIL:
if (!ObjectUtils.isEmpty(dateType)) {
DeviceInfoDetailV2RespVO.SoilInfo soilInfo = getSoilInfo(deviceUniqueId,plotId, dateType);
target.setSoilInfo(soilInfo);
}
break;
case "water_fertilizer" :
DeviceInfoDetailV2RespVO.WfInfo wfInfo = getWfInfo(deviceUniqueId);
case DEVICE_TYPE_WF:
DeviceInfoDetailV2RespVO.WfInfo wfInfo = getWfInfo(deviceUniqueId,plotId);
target.setWfInfo(wfInfo);
break;
}
return target;
}
private DeviceInfoDetailV2RespVO.SoilInfo getSoilInfo(String deviceUniqueId,Integer dateType) {
// 登录 todo 这里需要优化 2025-09-30 16:42:47
UserLoginReqVO userLoginReqVO = new UserLoginReqVO(deviceConf.getFourSituations().getUsername(), deviceConf.getFourSituations().getPassword());
UnifiedLoginResponse login = equipmentProducerManager.login(DEVICE_TYPE_SOIL, getLoginUser().getTenantId(), deviceUniqueId, userLoginReqVO);
/**
* 土壤墒情传感器
* @param deviceUniqueId 设备地址(唯一编号)
* @param dateType
* @return
*/
private DeviceInfoDetailV2RespVO.SoilInfo getSoilInfo(String deviceUniqueId,String plotId, Integer dateType) {
Long tenantId = getLoginUser().getTenantId();
UnifiedLoginResponse login = equipmentProducerManager.login(DEVICE_TYPE_SOIL, tenantId, plotId);
String token = login.getData().getToken();
// 实时数据
RealTimeDataReqVO soilRequest = new RealTimeDataReqVO();
soilRequest.setDeviceAddrs(deviceUniqueId);
RealTimeDataResponse realTimeData = equipmentProducerManager.getRealTimeData(DEVICE_TYPE_SOIL, getLoginUser().getTenantId(), token, soilRequest);
RealTimeDataResponse realTimeData = equipmentProducerManager.getRealTimeData(DEVICE_TYPE_SOIL, tenantId, token, soilRequest);
// 历史数据
HistoryDataListPageReqVO req = HistoryDataListPageReqVO.buildHistoryData(deviceUniqueId, dateType);
HistoryDataResponse historyData = equipmentProducerManager.getHistoryData(DEVICE_TYPE_SOIL, getLoginUser().getTenantId(), token, req);
HistoryDataResponse historyData = equipmentProducerManager.getHistoryData(DEVICE_TYPE_SOIL, tenantId, token, req);
return new DeviceInfoDetailV2RespVO.SoilInfo(deviceUniqueId, realTimeData, historyData);
}
private DeviceInfoDetailV2RespVO.WfInfo getWfInfo(String deviceUniqueId) {
/**
* 水肥机
* @param deviceUniqueId 设备地址(唯一编号)
* @return
*/
private DeviceInfoDetailV2RespVO.WfInfo getWfInfo(String deviceUniqueId,String plotId) {
// 登录
Long tenantId = getLoginUser().getTenantId();
UnifiedLoginResponse login = equipmentProducerManager.login(DEVICE_TYPE_WF, tenantId, plotId);
String token = login.getData().getToken();
// 获取设备列表
DeviceListResponse response = equipmentProducerManager.getDeviceList(DEVICE_TYPE_WF, tenantId, token, null);
System.out.println("获取设备列表:"+response);
// 实时数据
RealTimeDeviceDataReqVO wfRequest = new RealTimeDeviceDataReqVO(deviceUniqueId);
RealTimeDataResponse realTimeData = equipmentProducerManager.getRealTimeData(DEVICE_TYPE_WF, tenantId, token, wfRequest);
return new DeviceInfoDetailV2RespVO.WfInfo(deviceUniqueId);
return new DeviceInfoDetailV2RespVO.WfInfo(deviceUniqueId,realTimeData);
}
@Override
@@ -243,14 +267,11 @@ public class DeviceInfoServiceImpl implements DeviceInfoService {
List<DeviceInfoDO> list = deviceInfoMapper.selectList(wrapperX);
DeviceInfoDO d = list.get(0);
String type = "soil";
UserLoginReqVO userLoginReqVO = new UserLoginReqVO(deviceConf.getFourSituations().getUsername(), deviceConf.getFourSituations().getPassword());
UnifiedLoginResponse login = equipmentProducerManager.login(type, Long.valueOf(req.getTenantId()), req.getTenantId(), userLoginReqVO);
UnifiedLoginResponse login = equipmentProducerManager.login(DEVICE_TYPE_SOIL, Long.valueOf(req.getTenantId()), req.getTenantId());
String token = login.getData().getToken();
RealTimeDataReqVO soilRequest = new RealTimeDataReqVO();
soilRequest.setDeviceAddrs("");
RealTimeDataResponse realTimeData = equipmentProducerManager.getRealTimeData(type, Long.valueOf(req.getTenantId()), token, soilRequest);
RealTimeDataReqVO soilRequest = new RealTimeDataReqVO("");
RealTimeDataResponse realTimeData = equipmentProducerManager.getRealTimeData(DEVICE_TYPE_SOIL, Long.valueOf(req.getTenantId()), token, soilRequest);
return success(realTimeData);
} catch (Exception e) {

View File

@@ -374,7 +374,7 @@ device-manager:
water-and-fertilizer:
hosts: https://ryy.mythiot.com
username: jishui
password: jishui@888@
password: jishui@888
url-1: /prod-api/login # 获取公钥 POST
url-2: /prod-api/agriculture/deviceMain/list # 获取设备列表 GET
url-3: /prod-api/agriculture/deviceMain/getDeviceAllPropertyAndDataSimple/{0} # 获取设备实时状态 GET {0}: deviceId