package com.xiaopeng.vehicleConvoy.util; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson2.JSON; import com.xiaopeng.api.dto.vehicleConvoy.BaseImOpenDto; import com.xiaopeng.api.dto.vehicleConvoy.ImOpenQueryStateDto; import com.xiaopeng.api.dto.vehicleConvoy.VehicleTemperatureDto; import com.xiaopeng.api.feignClient.vehicleConvoy.VehicleControlClient; import com.xiaopeng.api.vo.vehicleConvoy.VehicleStateVo; import com.xiaopeng.api.vo.vehicleConvoy.VehiclesCommandVo; import com.xiaopeng.vehicleConvoy.service.AsyncVehicleStateService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; /** * 车辆控制工具类 */ @Slf4j @Component public class VehicleControlUtil { public static final String OPEN_ID_ROBOT_TAXI = "robot_taxi"; @Resource private VehicleControlClient vehicleControlClient; @Resource private AsyncVehicleStateService asyncVehicleStateService; // 车辆控制接口appid @Value("${vehicle.control.appId}") private String appid; // 车辆控制接口appSecret @Value("${vehicle.control.appSecret}") private String appSecret; /** * 查询车辆内温度 * * @param uid 用户id * @param vin 车辆vin * 测试车辆:L1NNSGHA5PB000204 * @return 车辆温度信息 */ public VehicleTemperatureDto queryVehicleTemperature(String uid, String vin) { String nonce = System.currentTimeMillis() + ""; Set stateList = new HashSet<>(); stateList.add("hvacInnerTemp"); stateList.add("trunkAjarCloseSt"); Map map = new HashMap<>(); map.put("nonce", nonce); map.put("openId", OPEN_ID_ROBOT_TAXI); map.put("accessToken", ""); map.put("body", ""); map.put("vin", vin); map.put("stateList", StrUtil.join(",", stateList)); String sign = SignatureUtils.getSignatureSHA1(appid, map, appSecret); log.info("查询车内温度 请求参数:uid={}, vin={}", uid, vin); ImOpenQueryStateDto baseImOpenDto = vehicleControlClient.queryVehicleTemperature(appid, nonce, "", sign, OPEN_ID_ROBOT_TAXI, vin, stateList, uid); log.info("查询车内温度 结果:{}", JSON.toJSONString(baseImOpenDto)); if (null == baseImOpenDto || null == baseImOpenDto.getData()) { throw new RuntimeException("查询车内温度失败"); } if (0 != baseImOpenDto.getCode()) { throw new RuntimeException("查询车内温度失败:" + baseImOpenDto.getMsg()); } VehicleTemperatureDto vehicleTemperatureDto = baseImOpenDto.getData(); vehicleTemperatureDto.setVin(vin); return vehicleTemperatureDto; } /** * 同步查询车辆后备箱状态 * 下发一次指令,等待回调结果(1秒超时) * * @param uid 用户ID * @param vin 车辆VIN码 * @return 查询后备箱开关状态(打开状态=true,关闭状态=false) * @throws RuntimeException 查询失败或1秒超时 */ public Boolean queryTrunkDoorStateSync(Long uid, String vin, boolean reportEnable) { log.info("开始同步查询车辆后备箱状态: uid={}, vin={} (1秒超时)", uid, vin); if (!reportEnable) { VehicleTemperatureDto vehicleTemperatureDto = queryVehicleTemperature(String.valueOf(uid), vin); VehicleStateVo vehicleStateVo = vehicleTemperatureDto.getStateMap().get("trunkAjarCloseSt"); return null != vehicleStateVo && vehicleStateVo.getValue().equals("1"); } try { // 使用异步服务查询状态,内部有1秒超时处理 CompletableFuture future = asyncVehicleStateService .queryVehicleStateAsync(String.valueOf(uid), vin); // 等待回调结果,由AsyncVehicleStateService内部处理超时 VehicleTemperatureDto result = future.get(); if (result == null) { throw new RuntimeException("查询车辆状态失败: 未获取到状态数据"); } log.info("同步查询车辆后备箱状态成功: uid={}, vin={}", uid, vin); VehicleStateVo vehicleStateVo = result.getStateMap().get("trunkAjarCloseSt"); log.info("同步查询车辆后备箱状态成功: uid={}, vin={}, vehicleStateVo={}", uid, vin, JSON.toJSONString(vehicleStateVo)); return null != vehicleStateVo && vehicleStateVo.getValue().equals("5"); } catch (java.util.concurrent.ExecutionException e) { Throwable cause = e.getCause(); if (cause instanceof RuntimeException && cause.getMessage().contains("查询超时")) { log.error("查询车辆后备箱状态超时: uid={}, vin={} (1秒超时)", uid, vin); throw new RuntimeException("查询车辆状态超时,请稍后重试"); } else { log.error("同步查询车辆后备箱状态失败: uid={}, vin={}", uid, vin, cause); throw new RuntimeException("查询车辆状态失败: " + (cause != null ? cause.getMessage() : e.getMessage())); } } catch (Exception e) { log.error("同步查询车辆后备箱状态失败: uid={}, vin={}", uid, vin, e); throw new RuntimeException("查询车辆状态失败: " + e.getMessage()); } } /** * 车辆控制操作 *

* 注意:签名计算由 VehicleControlSignatureInterceptor 拦截器处理 * 拦截器会在 Feign 序列化 body 后,使用真实的 body 重新计算签名 * * @param commandVo 车辆控制命令参数 * @return msgId 消息id,对比消息回调通知 * 测试车辆:L1NNSGHA5PB000204 */ public String vehiclesCommand(VehiclesCommandVo commandVo, Long uid) { String nonce = System.currentTimeMillis() + ""; BaseImOpenDto baseImOpenDto = vehicleControlClient.vehiclesCommand( appid, nonce, "", "", OPEN_ID_ROBOT_TAXI, commandVo, uid ); if (null == baseImOpenDto || null == baseImOpenDto.getData()) { throw new RuntimeException("车辆控制失败"); } if (0 != baseImOpenDto.getCode()) { throw new RuntimeException("车辆控制失败:" + baseImOpenDto.getMsg()); } return baseImOpenDto.getData().getMsgId(); } }