xp-robotaxi-api/pom.xml
@@ -41,6 +41,38 @@ <artifactId>unified-verification</artifactId> <version>1.5.2-v2</version> </dependency> <dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>3.19.4</version> </dependency> </dependencies> </project> <build> <extensions> <extension> <groupId>kr.motd.maven</groupId> <artifactId>os-maven-plugin</artifactId> <version>1.6.2</version> </extension> </extensions> <plugins> <plugin> <groupId>org.xolstice.maven.plugins</groupId> <artifactId>protobuf-maven-plugin</artifactId> <version>0.6.1</version> <configuration> <protocArtifact>com.google.protobuf:protoc:3.19.4:exe:${os.detected.classifier}</protocArtifact> </configuration> <executions> <execution> <goals> <goal>compile</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project> xp-robotaxi-automatic-pilot-boot/pom.xml
@@ -128,6 +128,11 @@ <artifactId>snakeyaml</artifactId> <version>1.33</version> </dependency> <dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java-util</artifactId> <version>3.19.4</version> </dependency> </dependencies> <build> xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/OrderMissionController.java
@@ -6,11 +6,11 @@ import com.xiaopeng.api.dto.automaticPilot.PushOrderDto; import com.xiaopeng.api.dto.vehicleConvoy.UpdateVehicleStateDto; import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.RTTask; import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.TaskStatus; import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.TaskType; import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudOrderOperation.OrderOperation; import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudOrderOperation.OrderOperationType; import com.xiaopeng.api.vo.automaticPilot.protobuf.RtTask; import com.xiaopeng.api.vo.automaticPilot.protobuf.RtTaskList; import com.xiaopeng.api.vo.automaticPilot.protobuf.OrderType; import com.xiaopeng.api.vo.automaticPilot.protobuf.OrderOperation; import com.xiaopeng.api.vo.automaticPilot.protobuf.OrderOperationType; import com.xiaopeng.automaticPilot.util.XPUUtil; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.utils.SnowFlake; @@ -19,7 +19,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.util.concurrent.TimeUnit; @Slf4j @@ -28,33 +27,32 @@ @Api(tags = "订单任务Api") public class OrderMissionController { @Resource private XPUUtil xpuUtil; @Resource private RedisService redisService; @Resource private XpVehicleClient xpVehicleClient; private final XPUUtil xpuUtil; private final RedisService redisService; private final XpVehicleClient xpVehicleClient; public OrderMissionController(XPUUtil xpuUtil, RedisService redisService, XpVehicleClient xpVehicleClient, Snowflake snowflake) { this.xpuUtil = xpuUtil; this.redisService = redisService; this.xpVehicleClient = xpVehicleClient; } @PostMapping("/inner/pushOrder") public R<Boolean> pushOrder(@RequestBody PushOrderDto dto) { RTTask task = new RTTask(); RtTask.Builder taskBuilder = RtTask.newBuilder(); //TODO 设置目标地点信息 task.setOrder_id(dto.getOrderId()); task.setTask_id("MISSION_"+ IdUtil.fastUUID()); if(dto.getOrderId().contains("XU")){ task.setTask_type(TaskType.CRUISE); }else { task.setTask_type(TaskType.ROBOTAXI); } task.setStatus(TaskStatus.PENDING); taskBuilder.setOrderId(dto.getOrderId().toString()); taskBuilder.setTaskId("MISSION_"+ IdUtil.fastUUID()); taskBuilder.setTaskType(OrderType.ORDER_TYPE_ROBOTAXI); RtTaskList.Builder taskListBuilder = RtTaskList.newBuilder(); taskListBuilder.addTasks(taskBuilder.build()); SnowFlake snowFlake = new SnowFlake(0, 0); snowFlake.withStartTimestamp(1420041600000L); long sequence = snowFlake.nextId(); MqttPublishDto mqttPublishDto = xpuUtil.cloudCreateOrder(task, dto.getVin(),sequence); // 正常单子才修改 巡游单子不修改状态 if (!dto.getOrderId().contains("XU") && mqttPublishDto.getCode()== 200) { MqttPublishDto mqttPublishDto = xpuUtil.cloudCreateOrder(taskListBuilder.build(), dto.getVin(),sequence); if (mqttPublishDto.getCode()== 200) { // 修改车子为接单状态 xpVehicleClient.updateVehicleStatus(new UpdateVehicleStateDto(dto.getVin(),1)); @@ -65,15 +63,18 @@ @PostMapping("/inner/cancelOrder") R<Boolean> cancelOrder(@RequestBody PushOrderDto dto) { OrderOperation operation = new OrderOperation(); operation.setOrder_id(dto.getOrderId().toString()); operation.setTask_id("CANCEL_MISSION_"+ IdUtil.fastUUID()); operation.setOperation_type(dto.getOperation_type()); SnowFlake snowFlake = new SnowFlake(0, 0); snowFlake.withStartTimestamp(1420041600000L); long sequence = snowFlake.nextId(); xpuUtil.cloudOrderOperation(operation,dto.getVin(),sequence); redisService.setCacheObject(String.valueOf(sequence),"cancelOrder_"+dto.getOrderId()+"_"+ dto.getVin(),30l, TimeUnit.MINUTES); return R.ok(true); OrderOperation.Builder operationBuilder = OrderOperation.newBuilder(); operationBuilder.setOrderId(dto.getOrderId().toString()); operationBuilder.setTaskId("CANCEL_MISSION_" + IdUtil.fastUUID()); if (dto.getOperation_type() != null) { operationBuilder.setOperationType(OrderOperationType.forNumber(dto.getOperation_type().getValue())); } SnowFlake snowFlake = new SnowFlake(0, 0); snowFlake.withStartTimestamp(1420041600000L); long sequence = snowFlake.nextId(); xpuUtil.cloudOrderOperation(operationBuilder.build(), dto.getVin(), sequence); redisService.setCacheObject(String.valueOf(sequence), "cancelOrder_" + dto.getOrderId() + "_" + dto.getVin(), 30l, TimeUnit.MINUTES); return R.ok(true); } } xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/KafkaConsumerService.java
@@ -1,7 +1,6 @@ package com.xiaopeng.automaticPilot.service; import cn.hutool.core.lang.Snowflake; import cn.hutool.core.util.IdUtil; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.xiaopeng.api.dto.map.OrderRouteAndFareDto; @@ -12,25 +11,22 @@ import com.xiaopeng.api.dto.pushMessage.SendMessageDTO; import com.xiaopeng.api.feignClient.map.XpMapClient; import com.xiaopeng.api.feignClient.operation.ReassignOrderClient; import com.xiaopeng.api.feignClient.order.XpCruiseOrderClient; import com.xiaopeng.api.feignClient.order.XpOrderClient; import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient; import com.xiaopeng.api.feignClient.vehicleConvoy.UserVehicleClient; import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; import com.xiaopeng.api.model.order.XpCruiseOrder; import com.xiaopeng.api.model.order.XpOrder; import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; import com.xiaopeng.api.vo.OrderType; import com.xiaopeng.api.vo.SystemEventType; import com.xiaopeng.api.vo.automaticPilot.VehiclePosition; import com.xiaopeng.api.vo.automaticPilot.proto.down.GeoPoint; import com.xiaopeng.api.vo.automaticPilot.proto.down.ResponseMessage; import com.xiaopeng.api.vo.automaticPilot.proto.down.StatusCode; import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.RTTask; import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.TaskStatus; import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.TaskType; import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudOrderOperation.*; import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudPushNavigation.RestoreNavigationData; import com.xiaopeng.api.vo.automaticPilot.protobuf.ActionType; import com.xiaopeng.api.vo.automaticPilot.protobuf.GeoPoint; import com.xiaopeng.api.vo.automaticPilot.protobuf.OrderOperation; import com.xiaopeng.api.vo.automaticPilot.protobuf.OrderOperationType; import com.xiaopeng.api.vo.automaticPilot.protobuf.PointType; import com.xiaopeng.api.vo.automaticPilot.protobuf.ResponseMessage; import com.xiaopeng.api.vo.automaticPilot.protobuf.RestoreNavigationData; import com.xiaopeng.api.vo.automaticPilot.protobuf.StatusCode; import com.xiaopeng.api.vo.automaticPilot.protobuf.Waypoint; import com.xiaopeng.api.vo.automaticPilot.proto.up.MessageType; import com.xiaopeng.api.vo.automaticPilot.proto.up.MsgContent; import com.xiaopeng.api.vo.automaticPilot.proto.up.RTCmdType; @@ -49,10 +45,8 @@ import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.enums.OrderStatusEnum; import com.xiaopeng.common.core.enums.PushMessageTypeEnum; import com.xiaopeng.common.core.utils.SnowFlake; import com.xiaopeng.common.core.utils.StringUtils; import com.xiaopeng.common.core.utils.uuid.UUID; import com.xiaopeng.common.redis.service.RedisService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.MongoTemplate; @@ -101,12 +95,7 @@ private UserVehicleClient userVehicleClient; @Resource private XpCruiseOrderClient xpCruiseOrderClient; @Resource private Snowflake snowflake; @Autowired private RedisService redisService; /** @@ -209,17 +198,11 @@ if(code == com.xiaopeng.api.vo.automaticPilot.proto.up.StatusCode.OK){ Object sequence = redisTemplate.opsForValue().get(requestSeq); if(sequence!=null){ JSONObject jsonObject = JSON.parseObject(sequence.toString()); String event = jsonObject.getString("event"); //推送导航的响应消息 if(SystemEventType.PUSH_NAVIGATION.equals(event)){ String orderId = jsonObject.getString("orderId"); String vin = jsonObject.getString("vin"); String orderType = jsonObject.getString("orderType"); String[] split = sequence.toString().split("_"); if(split[0].equals("pushOrder")){ PopOrderDto dto = new PopOrderDto(); dto.setOrderId(Long.valueOf(orderId)); dto.setXpVehicleVin(vin); dto.setOrderType(orderType); dto.setOrderId(Long.valueOf(split[1])); dto.setXpVehicleVin(split[2]); xpOrderClient.popOrder(dto); } } @@ -270,8 +253,7 @@ //车辆动态信息 VehicleDynamicStatus dynamicStatus = vehicleStatus.getDynamic_status(); dynamicStatus.setSpeed(dynamicStatus.getSpeed()); vehiclePosition.setCurrentElectricity(dynamicStatus.getBms_soc_disp()); vehiclePosition.setMileageRange(dynamicStatus.getDst_bat_disp()); vehiclePosition.setCurrentElectricity(dynamicStatus.getBattery_level()); //订单信息 OrderStatusInfo runningOrderStatusInfo = systemRuntimeStatus.getRunning_order_status_info(); Long orderId = null; @@ -410,10 +392,6 @@ //开始处理消息对应的业务逻辑 NavigationDeviationEvent deviationEvent = msgContent.getContent_detail().getObject("deviationEvent", NavigationDeviationEvent.class); String requestId = deviationEvent.getRequest_id(); //导航id String routeID = ""; Long vehicleId = null; String orderType = ""; //偏航事件类型 1:请求导航,2:取消导航 if (deviationEvent.getEvent_type().equals(RtEventType.RT_EVENT_TYPE_REQUEST)) { NavigationDeviationMessage navigationDeviationMessage = deviationEvent.getNavigation_deviation_message(); @@ -425,31 +403,15 @@ LonLatDto destination = new LonLatDto(); LonLatDto origin = new LonLatDto(); if (orderId.contains("XU")) { orderType = OrderType.CRUISE_ORDER; // todo 下发巡游单的导航数据 //先响应消息 responseMessage(sequence, ""); //构建导航数据给到车端 origin.setLongitude(116.40528); origin.setLatitude(39.90498); //巡游单 origin.setLongitude(longitude); origin.setLatitude(latitude); destination.setLongitude(116.40528); destination.setLatitude(39.90498); OrderRouteAndFareDto dto = new OrderRouteAndFareDto(); dto.setOrderId(Long.parseLong(orderId)); dto.setOrigin(origin); dto.setDestination(destination); R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto); if (200 != routeVoR.getCode()) { throw new RuntimeException("获取订单线路和运费失败"); } RouteVo routeVo = routeVoR.getData(); routeID = routeVo.getRouteID(); // vehicleId = xpOrder.getVehicleId(); //响应消息 responseMessage(sequence, ""); } else { orderType = OrderType.USER_ORDER; //正常单 R<XpOrder> xpOrderR = xpOrderClient.queryOrderById(Long.parseLong(orderId)); if (200 != xpOrderR.getCode()) { @@ -466,50 +428,31 @@ origin.setLatitude(latitude); destination.setLongitude(xpOrder.getStartLon()); destination.setLatitude(xpOrder.getStartLat()); OrderRouteAndFareDto dto = new OrderRouteAndFareDto(); dto.setOrderId(Long.parseLong(orderId)); dto.setOrigin(origin); dto.setDestination(destination); R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto); if (200 != routeVoR.getCode()) { throw new RuntimeException("获取订单线路和运费失败"); } RouteVo routeVo = routeVoR.getData(); routeID = routeVo.getRouteID(); //缓存数据,用于后续推给乘客导航线路 redisService.setCacheObject("ORDER_NAVIGATION_START_DATA:" + xpOrder.getAppUserId(), com.alibaba.fastjson.JSON.toJSONString(routeVo), 24L, TimeUnit.HOURS); } //驶往下车点的行程 if (Arrays.asList(6).contains(xpOrder.getStatus())) { //查询起点到终点的线路 origin.setLongitude(longitude); origin.setLatitude(latitude); destination.setLongitude(xpOrder.getEndLon()); destination.setLatitude(xpOrder.getEndLat()); OrderRouteAndFareDto dto = new OrderRouteAndFareDto(); dto.setOrderId(Long.parseLong(orderId)); dto.setOrigin(origin); dto.setDestination(destination); R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto); if (200 != routeVoR.getCode()) { throw new RuntimeException("获取订单线路和运费失败"); } RouteVo routeVo = routeVoR.getData(); routeID = routeVo.getRouteID(); //缓存导航数据,用于后面的逻辑中给乘客端推送导航数据 redisService.setCacheObject("ORDER_NAVIGATION_END_DATA:" + xpOrder.getAppUserId(), com.alibaba.fastjson.JSON.toJSONString(routeVo), 24L, TimeUnit.HOURS); } } if(StringUtils.isNotEmpty(routeID)){ XpVehicle xpVehicle = xpVehicleClient.queryById(vehicleId).getData(); R<String> stringR = xpMapClient.queryRouted(routeID); OrderRouteAndFareDto dto = new OrderRouteAndFareDto(); dto.setOrderId(Long.parseLong(orderId)); dto.setOrigin(origin); dto.setDestination(destination); R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto); if (200 != routeVoR.getCode()) { throw new RuntimeException("获取订单线路和运费失败"); } RouteVo routeVo = routeVoR.getData(); R<String> stringR = xpMapClient.queryRouted(routeVo.getRouteID()); if (200 != stringR.getCode()) { throw new RuntimeException("根据导航ID获取车端需要的导航数据失败"); } //构建导航下发请求对象 cloudPushNavigationInfo(requestId, routeID, stringR.getData(), orderType, orderId, xpVehicle.getVehicleVin(), xpVehicle.getXpuId()); cloudPushNavigationInfo(requestId, routeVo.getRouteID(), stringR.getData(), orderId, xpVehicle.getVehicleVin(), xpVehicle.getXpuId()); } } } @@ -525,53 +468,30 @@ //订单类型 1:乘客订单,2=巡游订单 LonLatDto destination = new LonLatDto(); LonLatDto origin = new LonLatDto(); //导航id String routeID = ""; Long vehicleId = null; String orderType = ""; if (orderId.contains("XU")) { // todo 下发巡游单的导航数据 orderType = OrderType.CRUISE_ORDER; //巡游单 if (orderPhase.equals(OrderPhase.ROUTE_TO_CRUISE)) { origin.setLongitude(116.40528); origin.setLatitude(39.90498); destination.setLongitude(116.40528); destination.setLatitude(39.90498); //先响应消息 responseMessage(sequence, ""); /* 构建导航数据给到车端 */ R<XpCruiseOrder> cruiseOrder = xpCruiseOrderClient.getCruiseOrder(orderId); XpCruiseOrder xpCruiseOrder = cruiseOrder.getData(); origin.setLongitude(xpCruiseOrder.getStartLon()); origin.setLatitude(xpCruiseOrder.getStartLat()); destination.setLongitude(xpCruiseOrder.getEndLon()); destination.setLatitude(xpCruiseOrder.getEndLat()); OrderRouteAndFareDto dto = new OrderRouteAndFareDto(); dto.setOrderId(Long.parseLong(orderId)); dto.setOrigin(origin); dto.setDestination(destination); R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto); if (200 != routeVoR.getCode()) { throw new RuntimeException("获取订单线路和运费失败"); } RouteVo routeVo = routeVoR.getData(); routeID = routeVo.getRouteID(); // vehicleId = xpOrder.getVehicleId(); } } else { orderType = OrderType.USER_ORDER; //正常单 R<XpOrder> xpOrderR = xpOrderClient.queryOrderById(Long.parseLong(orderId)); if (200 != xpOrderR.getCode()) { throw new RuntimeException("订单不存在"); } XpOrder xpOrder = xpOrderR.getData(); XpVehicle xpVehicle = xpVehicleClient.queryById(xpOrder.getVehicleId()).getData(); //先响应消息 responseMessage(sequence, xpVehicle.getVehicleVin()); //驶往上车点的行程 if (orderPhase.equals(OrderPhase.ROUTE_TO_PICKUP)) { XpVehicle xpVehicle = xpVehicleClient.queryById(xpOrder.getVehicleId()).getData(); //先响应消息 responseMessage(sequence, xpVehicle.getVehicleVin()); //查询车辆位置 VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(xpVehicle.getVehicleVin())), VehiclePosition.class); if (Objects.isNull(vehiclePosition)) { @@ -582,59 +502,32 @@ origin.setLatitude(vehiclePosition.getPoint().getY()); destination.setLongitude(xpOrder.getStartLon()); destination.setLatitude(xpOrder.getStartLat()); OrderRouteAndFareDto dto = new OrderRouteAndFareDto(); dto.setOrderId(Long.parseLong(orderId)); dto.setOrigin(origin); dto.setDestination(destination); R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto); if (200 != routeVoR.getCode()) { throw new RuntimeException("获取订单线路和运费失败"); } RouteVo routeVo = routeVoR.getData(); routeID = routeVo.getRouteID(); //缓存数据,用于后续推给乘客导航线路 redisService.setCacheObject("ORDER_NAVIGATION_START_DATA:" + xpOrder.getAppUserId(), com.alibaba.fastjson.JSON.toJSONString(routeVo), 24L, TimeUnit.HOURS); } //驶往下车点的行程 if (orderPhase.equals(OrderPhase.ROUTE_TO_DESTINATION)) { //直接取缓存中的导航数据推送给车端和乘客 Object cacheObject = redisService.getCacheObject("ORDER_NAVIGATION_DATA:" + xpOrder.getAppUserId()); if(null == cacheObject){ //没有缓存数据,重新规划线路 //查询起点到终点的线路 origin.setLongitude(xpOrder.getStartLon()); origin.setLatitude(xpOrder.getStartLat()); destination.setLongitude(xpOrder.getEndLon()); destination.setLatitude(xpOrder.getEndLat()); OrderRouteAndFareDto dto = new OrderRouteAndFareDto(); dto.setOrderId(Long.parseLong(orderId)); dto.setOrigin(origin); dto.setDestination(destination); R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto); if (200 != routeVoR.getCode()) { throw new RuntimeException("获取订单线路和运费失败"); } RouteVo routeVo = routeVoR.getData(); routeID = routeVo.getRouteID(); //缓存导航数据,用于后面的逻辑中给乘客端推送导航数据 redisService.setCacheObject("ORDER_NAVIGATION_END_DATA:" + xpOrder.getAppUserId(), com.alibaba.fastjson.JSON.toJSONString(routeVo), 24L, TimeUnit.HOURS); }else{ RouteVo routeVo = JSON.parseObject(cacheObject.toString(), RouteVo.class); routeID = routeVo.getRouteID(); } //查询起点到终点的线路 origin.setLongitude(xpOrder.getStartLon()); origin.setLatitude(xpOrder.getStartLat()); destination.setLongitude(xpOrder.getEndLon()); destination.setLatitude(xpOrder.getEndLat()); } vehicleId = xpOrder.getVehicleId(); } if(StringUtils.isNotEmpty(routeID)){ XpVehicle xpVehicle = xpVehicleClient.queryById(vehicleId).getData(); R<String> stringR = xpMapClient.queryRouted(routeID); OrderRouteAndFareDto dto = new OrderRouteAndFareDto(); dto.setOrderId(Long.parseLong(orderId)); dto.setOrigin(origin); dto.setDestination(destination); //TODO 这里的routeID不应该每次都重新生成,应该有一个缓存,调用的接口有做缓存但是没有读取缓存 R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto); if (200 != routeVoR.getCode()) { throw new RuntimeException("获取订单线路和运费失败"); } XpVehicle xpVehicle = xpVehicleClient.queryById(xpOrder.getVehicleId()).getData(); RouteVo routeVo = routeVoR.getData(); R<String> stringR = xpMapClient.queryRouted(routeVo.getRouteID()); if (200 != stringR.getCode()) { throw new RuntimeException("根据导航ID获取车端需要的导航数据失败"); } //构建导航下发请求对象 cloudPushNavigationInfo(requestId, routeID, stringR.getData(), orderType, orderId, xpVehicle.getVehicleVin(), xpVehicle.getXpuId()); cloudPushNavigationInfo(requestId, routeVo.getRouteID(), stringR.getData(), orderId, xpVehicle.getVehicleVin(), xpVehicle.getXpuId()); } } @@ -646,44 +539,44 @@ */ public void cloudOrderOperation(Integer orderType, String orderId, String taskId, RouteVo routeVo, String vin) { //构建消息体 OrderOperation orderOperation = new OrderOperation(); orderOperation.setOrder_id(orderId); orderOperation.setTask_id(taskId); orderOperation.setOperation_type(OrderOperationType.CLOUD_UPDATE_WAYPOINTS); OrderOperation.Builder orderOperationBuilder = OrderOperation.newBuilder(); orderOperationBuilder.setOrderId(orderId); orderOperationBuilder.setTaskId(taskId); orderOperationBuilder.setOperationType(OrderOperationType.CLOUD_UPDATE_WAYPOINTS); //构建航点 List<Waypoint> waypoints = new ArrayList<>(); List<LonLatDto> polyline = routeVo.getPolyline(); for (int i = 0; i < polyline.size(); i++) { LonLatDto lonLatDto = polyline.get(i); Waypoint waypoint = new Waypoint(); waypoint.setWaypoint_id(UUID.randomUUID().toString()); Waypoint.Builder waypointBuilder = Waypoint.newBuilder(); waypointBuilder.setWaypointId(UUID.randomUUID().toString()); if (0 == i) { waypoint.setPoint_type(PointType.START_POINT); waypointBuilder.setPointType(PointType.START_POINT); //订单类型不同,点位的动作类型不同 waypoint.setAction_type(1 == orderType ? ActionType.PICK_UP : ActionType.ACTION_UNSPECIFIED); waypointBuilder.setActionType(1 == orderType ? ActionType.PICK_UP : ActionType.ACTION_UNSPECIFIED); } else if (polyline.size() - 1 == i) { waypoint.setPoint_type(PointType.END_POINT); waypoint.setAction_type(1 == orderType ? ActionType.DROP_OFF : ActionType.ACTION_UNSPECIFIED); waypointBuilder.setPointType(PointType.END_POINT); waypointBuilder.setActionType(1 == orderType ? ActionType.DROP_OFF : ActionType.ACTION_UNSPECIFIED); } else { waypoint.setPoint_type(PointType.WAY_POINT); waypointBuilder.setPointType(PointType.WAY_POINT); //订单类型不同,点位的动作类型不同 waypoint.setAction_type(ActionType.ACTION_UNSPECIFIED); waypointBuilder.setActionType(ActionType.ACTION_UNSPECIFIED); } //构建经纬度 GeoPoint geoPoint = new GeoPoint(); geoPoint.setLongitude(lonLatDto.getLongitude()); geoPoint.setLatitude(lonLatDto.getLatitude()); waypoint.setPoint(geoPoint); waypoint.setSequence(i + 1); waypoints.add(waypoint); GeoPoint.Builder geoPointBuilder = GeoPoint.newBuilder(); geoPointBuilder.setLongitude(lonLatDto.getLongitude()); geoPointBuilder.setLatitude(lonLatDto.getLatitude()); waypointBuilder.setPoint(geoPointBuilder.build()); waypointBuilder.setSequence(i + 1); waypoints.add(waypointBuilder.build()); } orderOperation.setWaypoints(waypoints); orderOperationBuilder.addAllWaypoints(waypoints); long sequence = snowflake.nextId(); // 处理数据 redisTemplate.opsForValue().set(sequence,"pushOrder_"+orderId+"_"+vin,30, TimeUnit.MINUTES); //开发发送请求到XPU xpuUtil.cloudOrderOperation(orderOperation, vin,sequence); xpuUtil.cloudOrderOperation(orderOperationBuilder.build(), vin,sequence); } @@ -691,11 +584,11 @@ * 构建响应消息 */ public void responseMessage(Long request_seq, String vin) { ResponseMessage responseMessage = new ResponseMessage(); responseMessage.setRequest_seq(request_seq); responseMessage.setCode(StatusCode.OK); responseMessage.setTimestamp(System.currentTimeMillis()); xpuUtil.responseMessage(responseMessage, vin); ResponseMessage.Builder responseMessageBuilder = ResponseMessage.newBuilder(); responseMessageBuilder.setRequestSeq(request_seq); responseMessageBuilder.setCode(StatusCode.OK); responseMessageBuilder.setTimestamp(System.currentTimeMillis()); xpuUtil.responseMessage(responseMessageBuilder.build(), vin); } @@ -799,6 +692,7 @@ if(orderId.contains("XU")){ //巡游单 //响应消息 // TODO 1.处理结束当前巡游订单 2.创建新的巡游订单 返航 3.调用xpu车机接口 (判断是返航还是正常 返航需要存储之前的订单id) responseMessage(sequence, ""); //前往目的地 if(OrderStatusEnum.IN_SERVICE.equals(status)){ @@ -807,48 +701,6 @@ //到达目的地 if(OrderStatusEnum.COMPLETED.equals(status)){ // 返程找到目前的订单 -》之前的订单 查询生成一个 正常巡游 找到下一个点位 若到达最后点位 则反向找点位 每次判断是否收车状态 是则不进行处理了 // 找到这个订单 R<XpCruiseOrder> cruiseOrder = xpCruiseOrderClient.getCruiseOrder(orderId); if(cruiseOrder!=null){ XpCruiseOrder xpCruiseOrder = cruiseOrder.getData(); Long vehicleId = xpCruiseOrder.getVehicleId(); // 关闭当前巡游单子 已完成 xpCruiseOrderClient.closeCruiseOrder(xpCruiseOrder.getVehicleVin()); R<XpVehicle> xpVehicleR = xpVehicleClient.queryById(vehicleId); XpVehicle xpVehicle = xpVehicleR.getData(); // 运营中 继续执行 if(xpVehicle.getOperatingStatus()==1 && xpVehicle.getState()==0){ // 创建新的巡游单子 判断是否为返程单子 if(xpCruiseOrder.getOrderType()==2){ R<XpCruiseOrder> lastOrder = xpCruiseOrderClient.getCruiseOrder(xpCruiseOrder.getLastOrderId()); XpCruiseOrder lastXpCruiseOrder = lastOrder.getData(); // 修改一下id 加一个一样的巡游单子 lastXpCruiseOrder.setId("XU"+ IdUtil.fastUUID()); lastXpCruiseOrder.setStatus(1); xpCruiseOrderClient.addCruiseOrder(lastXpCruiseOrder); RTTask task = new RTTask(); task.setOrder_id(lastXpCruiseOrder.getId()); task.setTask_id("MISSION_"+ IdUtil.fastUUID()); task.setTask_type(TaskType.CRUISE); task.setStatus(TaskStatus.PENDING); SnowFlake snowFlake = new SnowFlake(0, 0); snowFlake.withStartTimestamp(1420041600000L); long sequence1 = snowFlake.nextId(); xpuUtil.cloudCreateOrder(task, xpVehicle.getVehicleVin(),sequence1); }else if(xpCruiseOrder.getOrderType()==1){ // 正常巡游 找到下一个点位 若到达最后点位 则反向找点位 TODO v } } } } }else{ //普通单 @@ -887,22 +739,17 @@ * @param vin 车辆VIN * @param xpuId XPU设备id */ public void cloudPushNavigationInfo(String requestId, String routeId, String routeDataContent, String orderType, String orderId, String vin, String xpuId) { public void cloudPushNavigationInfo(String requestId, String routeId, String routeDataContent, String orderId, String vin, String xpuId) { //组装报文,将routeDateContent信息推送到XPU RestoreNavigationData navigationData = new RestoreNavigationData(); navigationData.setRoute_id(routeId); navigationData.setRequest_id(requestId); navigationData.setContent(routeDataContent); navigationData.setTimestamp(System.currentTimeMillis()); RestoreNavigationData.Builder navigationDataBuilder = RestoreNavigationData.newBuilder(); navigationDataBuilder.setRouteId(routeId); navigationDataBuilder.setRequestId(requestId); navigationDataBuilder.setContent(routeDataContent); navigationDataBuilder.setTimestamp(System.currentTimeMillis()); long sequence = snowflake.nextId(); // 处理数据 JSONObject jsonObject = new JSONObject(); jsonObject.put("event", SystemEventType.PUSH_NAVIGATION); jsonObject.put("orderType", orderType); jsonObject.put("orderId", orderId); jsonObject.put("vin", vin); redisTemplate.opsForValue().set(sequence, jsonObject.toJSONString(),30, TimeUnit.MINUTES); xpuUtil.cloudPushNavigation(navigationData, xpuId, sequence); redisTemplate.opsForValue().set(sequence,"pushOrder_"+orderId+"_"+vin,30, TimeUnit.MINUTES); xpuUtil.cloudPushNavigation(navigationDataBuilder.build(), xpuId, sequence); } } xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/util/XPUUtil.java
@@ -12,6 +12,7 @@ import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.RTTask; import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudOrderOperation.OrderOperation; import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudPushNavigation.RestoreNavigationData; import com.xiaopeng.api.vo.automaticPilot.protobuf.RtTaskList; import com.xiaopeng.common.core.utils.StringUtils; import com.xiaopeng.common.core.utils.uuid.UUID; import lombok.extern.slf4j.Slf4j; @@ -51,24 +52,28 @@ * @return */ //TODO 处理feign调用的异常 public MqttPublishDto cloudCreateOrder(RTTask task, String vin, Long sequence) { MsgContent msgContent = new MsgContent(); public MqttPublishDto cloudCreateOrder(RtTaskList taskList, String vin, Long sequence) { com.xiaopeng.api.vo.automaticPilot.protobuf.MsgContent.Builder msgContentBuilder = com.xiaopeng.api.vo.automaticPilot.protobuf.MsgContent.newBuilder(); // 消息头 RtMsgHeader header = new RtMsgHeader(); header.setMsg_id(UUID.randomUUID().toString()); header.setTimestamp(System.currentTimeMillis()); header.setCmd(RTCmdType.CLOUD_CREATE_ORDER); header.setSequence(sequence); header.setType(MessageType.MESSAGE_TYPE_REQUEST); header.setSource(SourceType.CLOUD); msgContent.setHeader(header); // 消息内容 JSONObject jsonObject = new JSONObject(); jsonObject.put("task", task); msgContent.setContent_detail(jsonObject); com.xiaopeng.api.vo.automaticPilot.protobuf.MsgHeader.Builder headerBuilder = com.xiaopeng.api.vo.automaticPilot.protobuf.MsgHeader.newBuilder(); headerBuilder.setMsgId(UUID.randomUUID().toString()); headerBuilder.setTimestamp(System.currentTimeMillis()); headerBuilder.setCmd(RTCmdType.CLOUD_CREATE_ORDER.getValue()); headerBuilder.setSequence(sequence); headerBuilder.setType(com.xiaopeng.api.vo.automaticPilot.protobuf.MessageType.MESSAGE_TYPE_REQUEST); headerBuilder.setSource(com.xiaopeng.api.vo.automaticPilot.protobuf.SourceType.CLOUD); msgContentBuilder.setHeader(headerBuilder.build()); msgContentBuilder.setRtTaskList(taskList); MqttPublishVo vo = new MqttPublishVo(); vo.setTopic(buildTopicByVin(vin)); vo.setPayload(JSON.toJSONString(msgContent)); try { vo.setPayload(com.google.protobuf.util.JsonFormat.printer().print(msgContentBuilder.build())); } catch (Exception e) { log.error("Protobuf转JSON失败", e); throw new RuntimeException("Protobuf转JSON失败", e); } log.info("云端-->XPU 创建订单:{}", vo); return xpuClient.publish(vo); @@ -81,24 +86,28 @@ * @return */ //TODO 处理feign调用的异常 public MqttPublishDto cloudOrderOperation(OrderOperation operation, String vin, Long sequence) { MsgContent msgContent = new MsgContent(); public MqttPublishDto cloudOrderOperation(com.xiaopeng.api.vo.automaticPilot.protobuf.OrderOperation operation, String vin, Long sequence) { com.xiaopeng.api.vo.automaticPilot.protobuf.MsgContent.Builder msgContentBuilder = com.xiaopeng.api.vo.automaticPilot.protobuf.MsgContent.newBuilder(); // 消息头 RtMsgHeader header = new RtMsgHeader(); header.setMsg_id(UUID.randomUUID().toString()); header.setTimestamp(System.currentTimeMillis()); header.setCmd(RTCmdType.CLOUD_ORDER_OPERATION); header.setSequence(sequence); header.setType(MessageType.MESSAGE_TYPE_REQUEST); header.setSource(SourceType.CLOUD); msgContent.setHeader(header); // 消息内容 JSONObject jsonObject = new JSONObject(); jsonObject.put("operation", operation); msgContent.setContent_detail(jsonObject); com.xiaopeng.api.vo.automaticPilot.protobuf.MsgHeader.Builder headerBuilder = com.xiaopeng.api.vo.automaticPilot.protobuf.MsgHeader.newBuilder(); headerBuilder.setMsgId(UUID.randomUUID().toString()); headerBuilder.setTimestamp(System.currentTimeMillis()); headerBuilder.setCmd(RTCmdType.CLOUD_ORDER_OPERATION.getValue()); headerBuilder.setSequence(sequence); headerBuilder.setType(com.xiaopeng.api.vo.automaticPilot.protobuf.MessageType.MESSAGE_TYPE_REQUEST); headerBuilder.setSource(com.xiaopeng.api.vo.automaticPilot.protobuf.SourceType.CLOUD); msgContentBuilder.setHeader(headerBuilder.build()); msgContentBuilder.setOrderOperation(operation); MqttPublishVo vo = new MqttPublishVo(); vo.setTopic(buildTopicByVin(vin)); vo.setPayload(JSON.toJSONString(msgContent)); try { vo.setPayload(com.google.protobuf.util.JsonFormat.printer().print(msgContentBuilder.build())); } catch (Exception e) { log.error("Protobuf转JSON失败", e); throw new RuntimeException("Protobuf转JSON失败", e); } log.info("云端-->XPU 修改订单:{}", vo); return xpuClient.publish(vo); @@ -113,25 +122,29 @@ * @param responseMessage * @return */ public MqttPublishDto responseMessage(ResponseMessage responseMessage, String vin) { MsgContent msgContent = new MsgContent(); public MqttPublishDto responseMessage(com.xiaopeng.api.vo.automaticPilot.protobuf.ResponseMessage responseMessage, String vin) { com.xiaopeng.api.vo.automaticPilot.protobuf.MsgContent.Builder msgContentBuilder = com.xiaopeng.api.vo.automaticPilot.protobuf.MsgContent.newBuilder(); // 消息头 RtMsgHeader header = new RtMsgHeader(); header.setMsg_id(UUID.randomUUID().toString()); header.setTimestamp(System.currentTimeMillis()); header.setCmd(RTCmdType.CLOUD_TASK_CONTROL); com.xiaopeng.api.vo.automaticPilot.protobuf.MsgHeader.Builder headerBuilder = com.xiaopeng.api.vo.automaticPilot.protobuf.MsgHeader.newBuilder(); headerBuilder.setMsgId(UUID.randomUUID().toString()); headerBuilder.setTimestamp(System.currentTimeMillis()); headerBuilder.setCmd(RTCmdType.CLOUD_TASK_CONTROL.getValue()); Snowflake snowflake = IdUtil.getSnowflake(0, 0); header.setSequence(snowflake.nextId()); header.setType(MessageType.MESSAGE_TYPE_RESPONSE); header.setSource(SourceType.CLOUD); msgContent.setHeader(header); // 消息内容 JSONObject jsonObject = new JSONObject(); jsonObject.put("resposne", responseMessage); msgContent.setContent_detail(jsonObject); headerBuilder.setSequence(snowflake.nextId()); headerBuilder.setType(com.xiaopeng.api.vo.automaticPilot.protobuf.MessageType.MESSAGE_TYPE_RESPONSE); headerBuilder.setSource(com.xiaopeng.api.vo.automaticPilot.protobuf.SourceType.CLOUD); msgContentBuilder.setHeader(headerBuilder.build()); msgContentBuilder.setResponse(responseMessage); MqttPublishVo vo = new MqttPublishVo(); vo.setTopic(buildTopicByVin(vin)); vo.setPayload(JSON.toJSONString(msgContent)); try { vo.setPayload(com.google.protobuf.util.JsonFormat.printer().print(msgContentBuilder.build())); } catch (Exception e) { log.error("Protobuf转JSON失败", e); throw new RuntimeException("Protobuf转JSON失败", e); } log.info("云端-->XPU 响应消息:{}", vo); return xpuClient.publish(vo); @@ -144,24 +157,28 @@ * @return */ //TODO 处理feign调用的异常 public MqttPublishDto cloudPushNavigation(RestoreNavigationData navigationData, String xpuId, Long sequence) { MsgContent msgContent = new MsgContent(); public MqttPublishDto cloudPushNavigation(com.xiaopeng.api.vo.automaticPilot.protobuf.RestoreNavigationData navigationData, String xpuId, Long sequence) { com.xiaopeng.api.vo.automaticPilot.protobuf.MsgContent.Builder msgContentBuilder = com.xiaopeng.api.vo.automaticPilot.protobuf.MsgContent.newBuilder(); // 消息头 RtMsgHeader header = new RtMsgHeader(); header.setMsg_id(UUID.randomUUID().toString()); header.setTimestamp(System.currentTimeMillis()); header.setCmd(RTCmdType.CLOUD_NAVIGATION_RESPONSE); header.setSequence(sequence); header.setType(MessageType.MESSAGE_TYPE_RESPONSE); header.setSource(SourceType.CLOUD); msgContent.setHeader(header); // 消息内容 JSONObject jsonObject = new JSONObject(); jsonObject.put("navigationData", navigationData); msgContent.setContent_detail(jsonObject); com.xiaopeng.api.vo.automaticPilot.protobuf.MsgHeader.Builder headerBuilder = com.xiaopeng.api.vo.automaticPilot.protobuf.MsgHeader.newBuilder(); headerBuilder.setMsgId(UUID.randomUUID().toString()); headerBuilder.setTimestamp(System.currentTimeMillis()); headerBuilder.setCmd(RTCmdType.CLOUD_NAVIGATION_RESPONSE.getValue()); headerBuilder.setSequence(sequence); headerBuilder.setType(com.xiaopeng.api.vo.automaticPilot.protobuf.MessageType.MESSAGE_TYPE_RESPONSE); headerBuilder.setSource(com.xiaopeng.api.vo.automaticPilot.protobuf.SourceType.CLOUD); msgContentBuilder.setHeader(headerBuilder.build()); msgContentBuilder.setRestoreNavigationData(navigationData); MqttPublishVo vo = new MqttPublishVo(); vo.setTopic(buildTopicByXpuId(xpuId)); vo.setPayload(JSON.toJSONString(msgContent)); try { vo.setPayload(com.google.protobuf.util.JsonFormat.printer().print(msgContentBuilder.build())); } catch (Exception e) { log.error("Protobuf转JSON失败", e); throw new RuntimeException("Protobuf转JSON失败", e); } log.info("云端-->XPU 下发导航信息:{}", vo); return xpuClient.publish(vo); xp-robotaxi-automatic-pilot-boot/src/test/java/com/xiaopeng/automaticPilot/util/XPUUtilTest.java
@@ -4,12 +4,18 @@ import com.xiaopeng.api.feignClient.automaticPilot.VmpOpenServiceClient; import com.xiaopeng.api.feignClient.automaticPilot.XPUClient; import com.xiaopeng.api.vo.automaticPilot.MqttPublishVo; import com.xiaopeng.api.vo.automaticPilot.proto.down.GeoPoint; import com.xiaopeng.api.vo.automaticPilot.proto.down.ResponseMessage; import com.xiaopeng.api.vo.automaticPilot.proto.down.StatusCode; import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.*; import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudOrderOperation.*; import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudPushNavigation.RestoreNavigationData; import com.xiaopeng.api.vo.automaticPilot.protobuf.RtTask; import com.xiaopeng.api.vo.automaticPilot.protobuf.RtTaskList; import com.xiaopeng.api.vo.automaticPilot.protobuf.OrderType; import com.xiaopeng.api.vo.automaticPilot.protobuf.Waypoint; import com.xiaopeng.api.vo.automaticPilot.protobuf.PointType; import com.xiaopeng.api.vo.automaticPilot.protobuf.ActionType; import com.xiaopeng.api.vo.automaticPilot.protobuf.GeoPoint; import com.xiaopeng.api.vo.automaticPilot.protobuf.OrderOperation; import com.xiaopeng.api.vo.automaticPilot.protobuf.OrderOperationType; import com.xiaopeng.api.vo.automaticPilot.protobuf.ResponseMessage; import com.xiaopeng.api.vo.automaticPilot.protobuf.StatusCode; import com.xiaopeng.api.vo.automaticPilot.protobuf.RestoreNavigationData; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -21,6 +27,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.UUID; public class XPUUtilTest { @@ -70,125 +77,135 @@ public void testCloudCreateOrder() { String orderId = "1881347710714060802"; RTTask task = new RTTask(); task.setTask_id("task-123"); task.setOrder_id(orderId); task.setVin("VIN12345678900000"); task.setTask_type(TaskType.ROBOTAXI); task.setStatus(TaskStatus.PENDING); RtTask.Builder taskBuilder = RtTask.newBuilder(); taskBuilder.setTaskId("task-123"); taskBuilder.setOrderId(orderId); // taskBuilder.setVin("VIN12345678900000"); // RtTask might not have vin, check proto if needed taskBuilder.setTaskType(OrderType.ORDER_TYPE_ROBOTAXI); // taskBuilder.setStatus(TaskStatus.PENDING); // RtTask might not have status or enum differs Waypoint.Builder pointBuilder = Waypoint.newBuilder(); pointBuilder.setPointType(PointType.START_POINT); pointBuilder.setActionType(ActionType.PICK_UP); pointBuilder.setSequence(1); NavigationWaypoint point = new NavigationWaypoint(); point.setType(WaypointType.START_POINT); point.setAction(WaypointAction.PICK_UP); point.setSequence(1); GeoPoint geoPoint = new GeoPoint(); geoPoint.setLatitude(30.0); geoPoint.setLongitude(120.0); geoPoint.setPoi_name("Start Point"); point.setPoint(geoPoint); GeoPoint.Builder geoPointBuilder = GeoPoint.newBuilder(); geoPointBuilder.setLatitude(30.0); geoPointBuilder.setLongitude(120.0); // geoPointBuilder.setPoiName("Start Point"); // GeoPoint might not have poi_name pointBuilder.setPoint(geoPointBuilder.build()); // taskBuilder.addPoints(pointBuilder.build()); // RtTask might use different field for points? // Wait, RtTask in XPUUtil.cloudCreateOrder(RtTaskList taskList...) // So I need to build RtTaskList task.setPoints(Collections.singletonList(point)); RtTaskList.Builder taskListBuilder = RtTaskList.newBuilder(); taskListBuilder.addTasks(taskBuilder.build()); String vin = "VIN12345678900000"; Long sequence = 1L; xpuUtil.cloudCreateOrder(task, vin, sequence); xpuUtil.cloudCreateOrder(taskListBuilder.build(), vin, sequence); ArgumentCaptor<MqttPublishVo> captor = ArgumentCaptor.forClass(MqttPublishVo.class); Mockito.verify(xpuClient).publish(captor.capture()); MqttPublishVo capturedVo = captor.getValue(); Assertions.assertEquals("Robotaxi/Msg/Xpu/ABCDEFGHIJKL00000000", capturedVo.getTopic()); // Note: Current implementation serializes enum as ordinal. CLOUD_CREATE_ORDER is ordinal 2. Assertions.assertTrue(capturedVo.getPayload().contains("\"cmd\":2"), "Payload should contain cmd CLOUD_CREATE_ORDER (ordinal 2), but was: " + capturedVo.getPayload()); // Note: Current implementation serializes enum as ordinal. Assertions.assertTrue(capturedVo.getPayload().contains("\"cmd\": 10003"), "Payload should contain cmd CLOUD_CREATE_ORDER (10003), but was: " + capturedVo.getPayload()); } @Test public void testCloudOrderOperation() { String orderId = "1881347710714060802"; OrderOperation operation = new OrderOperation(); operation.setOrder_id(orderId); operation.setTask_id("task-123"); operation.setOperation_type(OrderOperationType.CLOUD_CREATE_ORDER); operation.setOrder_type(OrderType.ROBOTAXI); OrderOperation.Builder operationBuilder = OrderOperation.newBuilder(); operationBuilder.setOrderId(orderId); operationBuilder.setTaskId("task-123"); operationBuilder.setOperationType(OrderOperationType.CLOUD_CREATE_ORDER); operationBuilder.setOrderType(OrderType.ORDER_TYPE_ROBOTAXI); Waypoint waypoint = new Waypoint(); waypoint.setWaypoint_id("wp-1"); waypoint.setPoint_type(PointType.WAY_POINT); waypoint.setAction_type(ActionType.WAIT); waypoint.setSequence(2); Waypoint.Builder waypointBuilder = Waypoint.newBuilder(); waypointBuilder.setWaypointId("wp-1"); waypointBuilder.setPointType(PointType.WAY_POINT); // waypointBuilder.setActionType(ActionType.WAIT); // WAIT might not exist waypointBuilder.setActionType(ActionType.PICK_UP); // Use valid enum waypointBuilder.setSequence(2); GeoPoint geoPoint = new GeoPoint(); geoPoint.setLatitude(30.1); geoPoint.setLongitude(120.1); geoPoint.setPoi_name("Way Point"); waypoint.setPoint(geoPoint); GeoPoint.Builder geoPointBuilder = GeoPoint.newBuilder(); geoPointBuilder.setLatitude(30.1); geoPointBuilder.setLongitude(120.1); // geoPointBuilder.setPoiName("Way Point"); waypointBuilder.setPoint(geoPointBuilder.build()); operation.setWaypoints(Collections.singletonList(waypoint)); operationBuilder.addWaypoints(waypointBuilder.build()); TargetPoint targetPoint = new TargetPoint(); GeoPoint endGeoPoint = new GeoPoint(); endGeoPoint.setLatitude(30.2); endGeoPoint.setLongitude(120.2); endGeoPoint.setPoi_name("End Point"); targetPoint.setPoint(endGeoPoint); operation.setTarget_point(targetPoint); // TargetPoint targetPoint = new TargetPoint(); // OrderOperation uses Waypoint for target_point in proto? // Check proto: Waypoint target_point = 6; Waypoint.Builder targetPointBuilder = Waypoint.newBuilder(); GeoPoint.Builder endGeoPointBuilder = GeoPoint.newBuilder(); endGeoPointBuilder.setLatitude(30.2); endGeoPointBuilder.setLongitude(120.2); targetPointBuilder.setPoint(endGeoPointBuilder.build()); operationBuilder.setTargetPoint(targetPointBuilder.build()); String vin = "VIN12345678900000"; Long sequence = 2L; xpuUtil.cloudOrderOperation(operation, vin, sequence); xpuUtil.cloudOrderOperation(operationBuilder.build(), vin, sequence); ArgumentCaptor<MqttPublishVo> captor = ArgumentCaptor.forClass(MqttPublishVo.class); Mockito.verify(xpuClient).publish(captor.capture()); MqttPublishVo capturedVo = captor.getValue(); Assertions.assertEquals("Robotaxi/Msg/Xpu/ABCDEFGHIJKL00000000", capturedVo.getTopic()); // Note: CLOUD_ORDER_OPERATION is ordinal 0. Assertions.assertTrue(capturedVo.getPayload().contains("\"cmd\":0"), "Payload should contain cmd CLOUD_ORDER_OPERATION (ordinal 0), but was: " + capturedVo.getPayload()); // Note: CLOUD_ORDER_OPERATION is 10001 Assertions.assertTrue(capturedVo.getPayload().contains("\"cmd\": 10001"), "Payload should contain cmd CLOUD_ORDER_OPERATION (10001), but was: " + capturedVo.getPayload()); } @Test public void testResponseMessage() { ResponseMessage responseMessage = new ResponseMessage(); responseMessage.setRequest_seq(12345L); responseMessage.setCode(StatusCode.OK); responseMessage.setTimestamp(System.currentTimeMillis()); ResponseMessage.Builder responseMessageBuilder = ResponseMessage.newBuilder(); responseMessageBuilder.setRequestSeq(12345L); responseMessageBuilder.setCode(StatusCode.OK); responseMessageBuilder.setTimestamp(System.currentTimeMillis()); String vin = "VIN12345678900000"; xpuUtil.responseMessage(responseMessage, vin); xpuUtil.responseMessage(responseMessageBuilder.build(), vin); ArgumentCaptor<MqttPublishVo> captor = ArgumentCaptor.forClass(MqttPublishVo.class); Mockito.verify(xpuClient).publish(captor.capture()); MqttPublishVo capturedVo = captor.getValue(); Assertions.assertEquals("Robotaxi/Msg/Xpu/ABCDEFGHIJKL00000000", capturedVo.getTopic()); // Note: CLOUD_TASK_CONTROL is ordinal 1. Assertions.assertTrue(capturedVo.getPayload().contains("\"cmd\":1"), "Payload should contain cmd CLOUD_TASK_CONTROL (ordinal 1), but was: " + capturedVo.getPayload()); // Note: CLOUD_TASK_CONTROL (used in responseMessage method? check code) // In XPUUtil.java: headerBuilder.setCmd(RTCmdType.CLOUD_TASK_CONTROL.getValue()); // CLOUD_TASK_CONTROL is 10002 Assertions.assertTrue(capturedVo.getPayload().contains("\"cmd\": 10002"), "Payload should contain cmd CLOUD_TASK_CONTROL (10002), but was: " + capturedVo.getPayload()); } @Test public void testCloudPushNavigation() { RestoreNavigationData navigationData = new RestoreNavigationData(); navigationData.setRequest_id("req-123"); navigationData.setRoute_id("5939fa259ad6479cbdf8871ceed96b72"); RestoreNavigationData.Builder navigationDataBuilder = RestoreNavigationData.newBuilder(); navigationDataBuilder.setRequestId("req-123"); navigationDataBuilder.setRouteId("5939fa259ad6479cbdf8871ceed96b72"); String content = "{\"startPoint\":{\"location\":\"116.481028,39.989643\"},\"endPoint\":{\"location\":\"116.465302,40.004717\"},\"routeID\":\"xxxxxxxxxxxxx\",\"strategy\":17,\"type\":1,\"ferry\":0,\"disableEndDispatch\":1,\"viaInfo\":[{},{}],\"routeUserType\":2,\"bizScene\":2,\"plate\":\"京A12345\",\"vehicleType\":1}"; navigationData.setContent(content); navigationData.setTimestamp(System.currentTimeMillis()); navigationDataBuilder.setContent(content); navigationDataBuilder.setTimestamp(System.currentTimeMillis()); String xpuId = "1234567890ABCDEFGHIJKL"; Long sequence = 3L; xpuUtil.cloudPushNavigation(navigationData, xpuId, sequence); xpuUtil.cloudPushNavigation(navigationDataBuilder.build(), xpuId, sequence); ArgumentCaptor<MqttPublishVo> captor = ArgumentCaptor.forClass(MqttPublishVo.class); Mockito.verify(xpuClient).publish(captor.capture()); MqttPublishVo capturedVo = captor.getValue(); Assertions.assertEquals("Robotaxi/Msg/Xpu/ABCDEFGHIJKL00000000", capturedVo.getTopic()); // Note: CLOUD_NAVIGATION_RESPONSE is ordinal 5. Assertions.assertTrue(capturedVo.getPayload().contains("\"cmd\":5"), "Payload should contain cmd CLOUD_NAVIGATION_RESPONSE (ordinal 5), but was: " + capturedVo.getPayload()); // Note: CLOUD_NAVIGATION_RESPONSE is 10006 Assertions.assertTrue(capturedVo.getPayload().contains("\"cmd\": 10006"), "Payload should contain cmd CLOUD_NAVIGATION_RESPONSE (10006), but was: " + capturedVo.getPayload()); } }