Added GPS, Odometer History, and Safety Event
This commit is contained in:
parent
1a6ab4669d
commit
ce146cd41a
|
|
@ -44,7 +44,7 @@ public class SamsaraClient {
|
|||
* Vehicle live stats (engine + gps)
|
||||
* Raw JSON 반환
|
||||
*/
|
||||
public String getVehicleStatsFeed(List<String> vehicleExternalIds) {
|
||||
public String getVehicleGpsFeed(List<String> vehicleExternalIds) {
|
||||
|
||||
String vehicleIdsParam = String.join(",", vehicleExternalIds);
|
||||
|
||||
|
|
@ -58,4 +58,51 @@ public class SamsaraClient {
|
|||
.bodyToMono(String.class)
|
||||
.block();
|
||||
}
|
||||
|
||||
/**
|
||||
* Vehicle odometer history (OBD odometer meters)
|
||||
* Raw JSON 반환
|
||||
*/
|
||||
public String getVehicleOdometerHistory(
|
||||
List<String> vehicleExternalIds,
|
||||
Instant startTime,
|
||||
Instant endTime
|
||||
) {
|
||||
|
||||
String vehicleIdsParam = String.join(",", vehicleExternalIds);
|
||||
|
||||
return webClient.get()
|
||||
.uri(uriBuilder -> uriBuilder
|
||||
.path("/fleet/vehicles/stats/history")
|
||||
.queryParam("vehicleIds", vehicleIdsParam)
|
||||
.queryParam("startTime", startTime.toString())
|
||||
.queryParam("endTime", endTime.toString())
|
||||
.queryParam("types", "obdOdometerMeters")
|
||||
.build())
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.block();
|
||||
}
|
||||
|
||||
/**
|
||||
* Vehicle Safety Event
|
||||
* Raw JSON 반환
|
||||
*
|
||||
*/
|
||||
public String getVehicleSafetyEvents(Instant startTime, Instant endTime, List<String> vehicleExternalIds) {
|
||||
|
||||
String vehicleIdsParam = String.join(",", vehicleExternalIds);
|
||||
|
||||
return webClient.get()
|
||||
.uri(uriBuilder -> uriBuilder
|
||||
.path("/fleet/safety-events")
|
||||
.queryParam("startTime", startTime.toString())
|
||||
.queryParam("endTime", endTime.toString())
|
||||
.queryParam("vehicleIds", vehicleIdsParam)
|
||||
.build())
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.block();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,10 +1,13 @@
|
|||
package com.goi.integration.samsara.controller;
|
||||
|
||||
import com.goi.integration.samsara.dto.VehicleStatResponseDto;
|
||||
import com.goi.integration.samsara.service.VehicleStatService;
|
||||
import com.goi.integration.samsara.dto.VehicleOdometerHistoryResponseDto;
|
||||
import com.goi.integration.samsara.dto.VehicleGpsResponseDto;
|
||||
import com.goi.integration.samsara.service.VehicleOdometerHistoryService;
|
||||
import com.goi.integration.samsara.service.VehicleGpsService;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
|
@ -14,12 +17,36 @@ import org.springframework.web.bind.annotation.*;
|
|||
@RequiredArgsConstructor
|
||||
public class VehicleController {
|
||||
|
||||
private final VehicleStatService vehicleStatService;
|
||||
private final VehicleGpsService vehicleStatService;
|
||||
private final VehicleOdometerHistoryService vehicleOdometerHistoryService;
|
||||
|
||||
@GetMapping("/stat")
|
||||
public List<VehicleStatResponseDto> getStats(
|
||||
@GetMapping("/stat/gps")
|
||||
public List<VehicleGpsResponseDto> getGps(
|
||||
@RequestParam List<String> vehicleIds
|
||||
) {
|
||||
return vehicleStatService.getVehicleStats(vehicleIds);
|
||||
return vehicleStatService.getVehicleGps(vehicleIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vehicle odometer history summary (window-based)
|
||||
*/
|
||||
@GetMapping("/stat/odometer/history")
|
||||
public List<VehicleOdometerHistoryResponseDto> getOdometerHistory(
|
||||
@RequestParam List<String> vehicleIds,
|
||||
@RequestParam Instant startTime,
|
||||
@RequestParam Instant endTime
|
||||
) {
|
||||
return vehicleOdometerHistoryService.getOdometerHistory(
|
||||
vehicleIds, startTime, endTime
|
||||
);
|
||||
}
|
||||
|
||||
// @GetMapping("/safety/events")
|
||||
// public List<VehicleSafetyEventResponseDto> getSafetyEvents(
|
||||
// @RequestParam Instant startTime,
|
||||
// @RequestParam Instant endTime,
|
||||
// @RequestParam List<String> vehicleIds
|
||||
// ) {
|
||||
// return vehicleSafetyEventService.getSafetyEvents(vehicleIds, startTime, endTime);
|
||||
// }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@ import java.time.Instant;
|
|||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class VehicleStatResponseDto {
|
||||
String vesVehicleExternalId;
|
||||
Boolean vesEngineOn;
|
||||
BigDecimal vesLatitude;
|
||||
BigDecimal vesLongitude;
|
||||
Instant vesGpsTime; // UTC 기준 절대 시점
|
||||
public class VehicleGpsResponseDto {
|
||||
private String vesVehicleExternalId;
|
||||
private Boolean vesEngineOn;
|
||||
private BigDecimal vesLatitude;
|
||||
private BigDecimal vesLongitude;
|
||||
private Instant vesGpsTime; // UTC 기준 절대 시점
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.goi.integration.samsara.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class VehicleOdometerHistoryResponseDto {
|
||||
private String vohVehicleExternalId;
|
||||
private Instant vohFirstSampleTime;
|
||||
private Instant vohLastSampleTime;
|
||||
private Long vohFirstOdometerMeters;
|
||||
private Long vohLastOdometerMeters;
|
||||
private Integer vohSampleCount;
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.goi.integration.samsara.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class VehicleSafetyEventResponseDto {
|
||||
private String vesVehicleExternalId;
|
||||
private Boolean vesEngineOn;
|
||||
private BigDecimal vesLatitude;
|
||||
private BigDecimal vesLongitude;
|
||||
private Instant vesGpsTime; // UTC 기준 절대 시점
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ package com.goi.integration.samsara.service;
|
|||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.goi.integration.samsara.client.SamsaraClient;
|
||||
import com.goi.integration.samsara.dto.VehicleStatResponseDto;
|
||||
import com.goi.integration.samsara.dto.VehicleGpsResponseDto;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
|
@ -20,7 +20,7 @@ import java.util.Optional;
|
|||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class VehicleStatService {
|
||||
public class VehicleGpsService {
|
||||
|
||||
private final SamsaraClient samsaraClient;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
|
@ -28,14 +28,14 @@ public class VehicleStatService {
|
|||
/**
|
||||
* 차량들의 실시간 상태 (engine + gps)
|
||||
*/
|
||||
public List<VehicleStatResponseDto> getVehicleStats(List<String> vehicleExternalIds) {
|
||||
public List<VehicleGpsResponseDto> getVehicleGps(List<String> vehicleExternalIds) {
|
||||
|
||||
if (vehicleExternalIds == null || vehicleExternalIds.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
// call Samsara API
|
||||
String rawJson = samsaraClient.getVehicleStatsFeed(vehicleExternalIds);
|
||||
String rawJson = samsaraClient.getVehicleGpsFeed(vehicleExternalIds);
|
||||
if (rawJson == null || rawJson.isBlank()) {
|
||||
log.warn("Samsara stats feed returned empty response");
|
||||
return List.of();
|
||||
|
|
@ -52,7 +52,7 @@ public class VehicleStatService {
|
|||
}
|
||||
|
||||
// set response
|
||||
List<VehicleStatResponseDto> result = new ArrayList<>();
|
||||
List<VehicleGpsResponseDto> result = new ArrayList<>();
|
||||
for (JsonNode vehicleNode : dataArray) {
|
||||
parseVehicleNode(vehicleNode).ifPresent(result::add);
|
||||
}
|
||||
|
|
@ -69,7 +69,7 @@ public class VehicleStatService {
|
|||
Parsing 필요한 정보만
|
||||
=============================== */
|
||||
|
||||
private Optional<VehicleStatResponseDto> parseVehicleNode(JsonNode vehicleNode) {
|
||||
private Optional<VehicleGpsResponseDto> parseVehicleNode(JsonNode vehicleNode) {
|
||||
|
||||
// Samsara vehicle ID (external)
|
||||
String vehicleId = vehicleNode.path("id").asText(null);
|
||||
|
|
@ -81,7 +81,7 @@ public class VehicleStatService {
|
|||
GpsInfo gpsInfo = extractLatestGps(vehicleNode.path("gps"));
|
||||
|
||||
return Optional.of(
|
||||
VehicleStatResponseDto.builder()
|
||||
VehicleGpsResponseDto.builder()
|
||||
.vesVehicleExternalId(vehicleId)
|
||||
.vesEngineOn(engineOn)
|
||||
.vesLatitude(gpsInfo.latitude)
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
package com.goi.integration.samsara.service;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.goi.integration.samsara.client.SamsaraClient;
|
||||
import com.goi.integration.samsara.dto.VehicleOdometerHistoryResponseDto;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class VehicleOdometerHistoryService {
|
||||
|
||||
private final SamsaraClient samsaraClient;
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
public List<VehicleOdometerHistoryResponseDto> getOdometerHistory(
|
||||
List<String> vehicleExternalIds,
|
||||
Instant startTime,
|
||||
Instant endTime
|
||||
) {
|
||||
// api 호출
|
||||
String rawJson = samsaraClient.getVehicleOdometerHistory(vehicleExternalIds, startTime, endTime);
|
||||
|
||||
return parseOdometerHistory(rawJson);
|
||||
}
|
||||
|
||||
private List<VehicleOdometerHistoryResponseDto> parseOdometerHistory(String rawJson) {
|
||||
|
||||
List<VehicleOdometerHistoryResponseDto> results = new ArrayList<>();
|
||||
|
||||
try {
|
||||
JsonNode root = objectMapper.readTree(rawJson);
|
||||
JsonNode dataArray = root.path("data");
|
||||
|
||||
for (JsonNode vehicleNode : dataArray) {
|
||||
|
||||
String vehicleId = vehicleNode.path("id").asText();
|
||||
JsonNode odoArray = vehicleNode.path("obdOdometerMeters");
|
||||
|
||||
if (!odoArray.isArray() || odoArray.isEmpty()) {
|
||||
// 데이터 없음
|
||||
results.add(
|
||||
VehicleOdometerHistoryResponseDto.builder()
|
||||
.vohVehicleExternalId(vehicleId)
|
||||
.vohSampleCount(0)
|
||||
.build()
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
Iterator<JsonNode> it = odoArray.elements();
|
||||
|
||||
JsonNode first = it.next();
|
||||
JsonNode last = first;
|
||||
|
||||
int count = 1;
|
||||
|
||||
while (it.hasNext()) {
|
||||
last = it.next();
|
||||
count++;
|
||||
}
|
||||
|
||||
// 거리 계산은 opr 에서. 여기선 이전 누적치를 모름.
|
||||
long firstValue = first.path("value").asLong();
|
||||
long lastValue = last.path("value").asLong();
|
||||
|
||||
Instant firstTime = Instant.parse(first.path("time").asText());
|
||||
Instant lastTime = Instant.parse(last.path("time").asText());
|
||||
|
||||
results.add(
|
||||
VehicleOdometerHistoryResponseDto.builder()
|
||||
.vohVehicleExternalId(vehicleId)
|
||||
.vohFirstSampleTime(firstTime)
|
||||
.vohLastSampleTime(lastTime)
|
||||
.vohFirstOdometerMeters(firstValue)
|
||||
.vohLastOdometerMeters(lastValue)
|
||||
.vohSampleCount(count)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("[ODOMETER][PARSE_FAIL]", e);
|
||||
throw new RuntimeException("Failed to parse vehicle odometer history", e);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue