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)
|
* Vehicle live stats (engine + gps)
|
||||||
* Raw JSON 반환
|
* Raw JSON 반환
|
||||||
*/
|
*/
|
||||||
public String getVehicleStatsFeed(List<String> vehicleExternalIds) {
|
public String getVehicleGpsFeed(List<String> vehicleExternalIds) {
|
||||||
|
|
||||||
String vehicleIdsParam = String.join(",", vehicleExternalIds);
|
String vehicleIdsParam = String.join(",", vehicleExternalIds);
|
||||||
|
|
||||||
|
|
@ -58,4 +58,51 @@ public class SamsaraClient {
|
||||||
.bodyToMono(String.class)
|
.bodyToMono(String.class)
|
||||||
.block();
|
.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;
|
package com.goi.integration.samsara.controller;
|
||||||
|
|
||||||
import com.goi.integration.samsara.dto.VehicleStatResponseDto;
|
import com.goi.integration.samsara.dto.VehicleOdometerHistoryResponseDto;
|
||||||
import com.goi.integration.samsara.service.VehicleStatService;
|
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 lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
@ -14,12 +17,36 @@ import org.springframework.web.bind.annotation.*;
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class VehicleController {
|
public class VehicleController {
|
||||||
|
|
||||||
private final VehicleStatService vehicleStatService;
|
private final VehicleGpsService vehicleStatService;
|
||||||
|
private final VehicleOdometerHistoryService vehicleOdometerHistoryService;
|
||||||
|
|
||||||
@GetMapping("/stat")
|
@GetMapping("/stat/gps")
|
||||||
public List<VehicleStatResponseDto> getStats(
|
public List<VehicleGpsResponseDto> getGps(
|
||||||
@RequestParam List<String> vehicleIds
|
@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
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@Builder
|
@Builder
|
||||||
public class VehicleStatResponseDto {
|
public class VehicleGpsResponseDto {
|
||||||
String vesVehicleExternalId;
|
private String vesVehicleExternalId;
|
||||||
Boolean vesEngineOn;
|
private Boolean vesEngineOn;
|
||||||
BigDecimal vesLatitude;
|
private BigDecimal vesLatitude;
|
||||||
BigDecimal vesLongitude;
|
private BigDecimal vesLongitude;
|
||||||
Instant vesGpsTime; // UTC 기준 절대 시점
|
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.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.goi.integration.samsara.client.SamsaraClient;
|
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.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
@ -20,7 +20,7 @@ import java.util.Optional;
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class VehicleStatService {
|
public class VehicleGpsService {
|
||||||
|
|
||||||
private final SamsaraClient samsaraClient;
|
private final SamsaraClient samsaraClient;
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
|
|
@ -28,14 +28,14 @@ public class VehicleStatService {
|
||||||
/**
|
/**
|
||||||
* 차량들의 실시간 상태 (engine + gps)
|
* 차량들의 실시간 상태 (engine + gps)
|
||||||
*/
|
*/
|
||||||
public List<VehicleStatResponseDto> getVehicleStats(List<String> vehicleExternalIds) {
|
public List<VehicleGpsResponseDto> getVehicleGps(List<String> vehicleExternalIds) {
|
||||||
|
|
||||||
if (vehicleExternalIds == null || vehicleExternalIds.isEmpty()) {
|
if (vehicleExternalIds == null || vehicleExternalIds.isEmpty()) {
|
||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
// call Samsara API
|
// call Samsara API
|
||||||
String rawJson = samsaraClient.getVehicleStatsFeed(vehicleExternalIds);
|
String rawJson = samsaraClient.getVehicleGpsFeed(vehicleExternalIds);
|
||||||
if (rawJson == null || rawJson.isBlank()) {
|
if (rawJson == null || rawJson.isBlank()) {
|
||||||
log.warn("Samsara stats feed returned empty response");
|
log.warn("Samsara stats feed returned empty response");
|
||||||
return List.of();
|
return List.of();
|
||||||
|
|
@ -52,7 +52,7 @@ public class VehicleStatService {
|
||||||
}
|
}
|
||||||
|
|
||||||
// set response
|
// set response
|
||||||
List<VehicleStatResponseDto> result = new ArrayList<>();
|
List<VehicleGpsResponseDto> result = new ArrayList<>();
|
||||||
for (JsonNode vehicleNode : dataArray) {
|
for (JsonNode vehicleNode : dataArray) {
|
||||||
parseVehicleNode(vehicleNode).ifPresent(result::add);
|
parseVehicleNode(vehicleNode).ifPresent(result::add);
|
||||||
}
|
}
|
||||||
|
|
@ -69,7 +69,7 @@ public class VehicleStatService {
|
||||||
Parsing 필요한 정보만
|
Parsing 필요한 정보만
|
||||||
=============================== */
|
=============================== */
|
||||||
|
|
||||||
private Optional<VehicleStatResponseDto> parseVehicleNode(JsonNode vehicleNode) {
|
private Optional<VehicleGpsResponseDto> parseVehicleNode(JsonNode vehicleNode) {
|
||||||
|
|
||||||
// Samsara vehicle ID (external)
|
// Samsara vehicle ID (external)
|
||||||
String vehicleId = vehicleNode.path("id").asText(null);
|
String vehicleId = vehicleNode.path("id").asText(null);
|
||||||
|
|
@ -81,7 +81,7 @@ public class VehicleStatService {
|
||||||
GpsInfo gpsInfo = extractLatestGps(vehicleNode.path("gps"));
|
GpsInfo gpsInfo = extractLatestGps(vehicleNode.path("gps"));
|
||||||
|
|
||||||
return Optional.of(
|
return Optional.of(
|
||||||
VehicleStatResponseDto.builder()
|
VehicleGpsResponseDto.builder()
|
||||||
.vesVehicleExternalId(vehicleId)
|
.vesVehicleExternalId(vehicleId)
|
||||||
.vesEngineOn(engineOn)
|
.vesEngineOn(engineOn)
|
||||||
.vesLatitude(gpsInfo.latitude)
|
.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