diff --git a/src/main/java/de/app/fivegla/api/Error.java b/src/main/java/de/app/fivegla/api/Error.java index e787a3e5..ca71a945 100644 --- a/src/main/java/de/app/fivegla/api/Error.java +++ b/src/main/java/de/app/fivegla/api/Error.java @@ -37,7 +37,8 @@ public enum Error { COULD_NOT_PARSE_GEO_JSON(errorOf(27)), COULD_NOT_PARSE_CSV(errorOf(28)), THIRD_PARTY_SERVICE_UNAVAILABLE(errorOf(29)), - MICASENSE_TX_NOT_FOUND(errorOf(30)); + MICASENSE_TX_NOT_FOUND(errorOf(30)), + AGRANIMO_COULD_NOT_FETCH_SOIL_MOISTURE(errorOf(31)); private static String errorOf(int i) { return ERR_ + String.format("%05d", i); diff --git a/src/main/java/de/app/fivegla/integration/agranimo/AgranimoFiwareIntegrationServiceWrapper.java b/src/main/java/de/app/fivegla/integration/agranimo/AgranimoFiwareIntegrationServiceWrapper.java index 10b198be..5037125d 100644 --- a/src/main/java/de/app/fivegla/integration/agranimo/AgranimoFiwareIntegrationServiceWrapper.java +++ b/src/main/java/de/app/fivegla/integration/agranimo/AgranimoFiwareIntegrationServiceWrapper.java @@ -1,9 +1,19 @@ package de.app.fivegla.integration.agranimo; +import de.app.fivegla.api.FiwareDevicMeasurementeId; +import de.app.fivegla.api.FiwareDeviceId; +import de.app.fivegla.api.Format; +import de.app.fivegla.config.ApplicationConfiguration; +import de.app.fivegla.config.manufacturer.CommonManufacturerConfiguration; import de.app.fivegla.fiware.DeviceIntegrationService; import de.app.fivegla.fiware.DeviceMeasurementIntegrationService; -import de.app.fivegla.integration.soilscout.model.SensorData; +import de.app.fivegla.fiware.model.Device; +import de.app.fivegla.fiware.model.DeviceCategory; +import de.app.fivegla.fiware.model.DeviceMeasurement; +import de.app.fivegla.fiware.model.Location; +import de.app.fivegla.integration.agranimo.model.SoilMoisture; +import de.app.fivegla.integration.agranimo.model.Zone; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -18,10 +28,68 @@ @RequiredArgsConstructor @SuppressWarnings({"FieldCanBeLocal", "unused"}) public class AgranimoFiwareIntegrationServiceWrapper { + private final ApplicationConfiguration applicationConfiguration; private final DeviceIntegrationService deviceIntegrationService; private final DeviceMeasurementIntegrationService deviceMeasurementIntegrationService; - public void persist(List measurements) { - log.error("Not implemented yet"); + /** + * Persists the soil moisture measurement for a given zone. + * + * @param zone the zone associated with the soil moisture measurement + * @param soilMoisture the soil moisture measurement to persist + */ + public void persist(Zone zone, SoilMoisture soilMoisture) { + persist(soilMoisture.getDeviceId(), zone.getData().getPoint().getCoordinates()[0], zone.getData().getPoint().getCoordinates()[1]); + var deviceMeasurement = createDeviceMeasurements(zone, soilMoisture); + log.info("Persisting measurement for device: {}", soilMoisture.getDeviceId()); + deviceMeasurementIntegrationService.persist(deviceMeasurement); + } + + private void persist(String deviceId, double latitude, double longitude) { + var device = Device.builder() + .id(FiwareDeviceId.create(getManufacturerConfiguration(), deviceId)) + .manufacturerSpecificId(deviceId) + .deviceCategory(DeviceCategory.builder() + .value(List.of(getManufacturerConfiguration().getKey())) + .build()) + .location(Location.builder() + .coordinates(List.of(latitude, longitude)) + .build()) + .build(); + deviceIntegrationService.persist(device); + } + + private DeviceMeasurement createDeviceMeasurements(Zone zone, SoilMoisture soilMoisture) { + log.debug("Persisting data for zone: {}", zone.getId()); + return DeviceMeasurement.builder() + .id(FiwareDevicMeasurementeId.create(getManufacturerConfiguration())) + .refDevice(FiwareDeviceId.create(getManufacturerConfiguration(), String.valueOf(soilMoisture.getDeviceId()))) + .dateObserved(Format.format(soilMoisture.getTms())) + .location(Location.builder() + .coordinates(List.of(zone.getData().getPoint().getCoordinates()[0], zone.getData().getPoint().getCoordinates()[1])) + .build()) + .controlledProperty("smo1") + .numValue(soilMoisture.getSmo1()) + .controlledProperty("smo2") + .numValue(soilMoisture.getSmo2()) + .controlledProperty("smo3") + .numValue(soilMoisture.getSmo3()) + .controlledProperty("smo4") + .numValue(soilMoisture.getSmo4()) + .build(); + } + + private CommonManufacturerConfiguration getManufacturerConfiguration() { + return applicationConfiguration.getSensors().agranimo(); + } + + /** + * Retrieves the unique device ID of the specified device. + * + * @param deviceId The unique identifier of the device. + * @return The device ID. + */ + public String deviceIdOf(String deviceId) { + return FiwareDeviceId.create(getManufacturerConfiguration(), deviceId); } } diff --git a/src/main/java/de/app/fivegla/integration/agranimo/LoginIntegrationService.java b/src/main/java/de/app/fivegla/integration/agranimo/AgranimoLoginIntegrationService.java similarity index 96% rename from src/main/java/de/app/fivegla/integration/agranimo/LoginIntegrationService.java rename to src/main/java/de/app/fivegla/integration/agranimo/AgranimoLoginIntegrationService.java index 9392f460..3844c4c9 100644 --- a/src/main/java/de/app/fivegla/integration/agranimo/LoginIntegrationService.java +++ b/src/main/java/de/app/fivegla/integration/agranimo/AgranimoLoginIntegrationService.java @@ -4,7 +4,7 @@ import de.app.fivegla.api.ErrorMessage; import de.app.fivegla.api.exceptions.BusinessException; import de.app.fivegla.integration.agranimo.cache.UserDataCache; -import de.app.fivegla.integration.agranimo.dto.Credentials; +import de.app.fivegla.integration.agranimo.model.Credentials; import de.app.fivegla.integration.agranimo.dto.request.LoginRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -19,7 +19,7 @@ @Slf4j @Service @RequiredArgsConstructor -public class LoginIntegrationService { +public class AgranimoLoginIntegrationService { @Value("${app.sensors.agranimo.url}") private String url; diff --git a/src/main/java/de/app/fivegla/integration/agranimo/AgranimoMeasurementImport.java b/src/main/java/de/app/fivegla/integration/agranimo/AgranimoMeasurementImport.java index eed69908..be0af31e 100644 --- a/src/main/java/de/app/fivegla/integration/agranimo/AgranimoMeasurementImport.java +++ b/src/main/java/de/app/fivegla/integration/agranimo/AgranimoMeasurementImport.java @@ -1,10 +1,13 @@ package de.app.fivegla.integration.agranimo; import de.app.fivegla.api.Manufacturer; +import de.app.fivegla.integration.agranimo.model.SoilMoisture; +import de.app.fivegla.integration.agranimo.model.Zone; import de.app.fivegla.monitoring.JobMonitor; import de.app.fivegla.persistence.ApplicationDataRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; @@ -20,18 +23,42 @@ public class AgranimoMeasurementImport { private final ApplicationDataRepository applicationDataRepository; - @SuppressWarnings({"FieldCanBeLocal", "unused"}) private final AgranimoFiwareIntegrationServiceWrapper fiwareIntegrationServiceWrapper; + private final AgranimoSoilMoistureIntegrationService agranimoSoilMoistureIntegrationService; + private final AgranimoZoneService agranimoZoneService; private final JobMonitor jobMonitor; + @Value("${app.scheduled.daysInThePastForInitialImport}") + private int daysInThePastForInitialImport; + @Async public void run() { var begin = Instant.now(); try { - if (applicationDataRepository.getLastRun(Manufacturer.AGRANIMO).isPresent()) { - jobMonitor.logNrOfEntitiesFetched(Manufacturer.AGRANIMO, 0); + var lastRun = applicationDataRepository.getLastRun(Manufacturer.AGRANIMO); + if (lastRun.isPresent()) { + log.info("Running scheduled data import from Agranimo API"); + agranimoZoneService.fetchZones().forEach(zone -> { + var waterContent = agranimoSoilMoistureIntegrationService.fetchWaterContent(zone, lastRun.get()); + jobMonitor.logNrOfEntitiesFetched(Manufacturer.AGRANIMO, waterContent.size()); + log.info("Found {} water content entries", waterContent.size()); + log.info("Persisting {} water content entries", waterContent.size()); + waterContent.forEach( + soilMoisture -> persistDataWithinFiware(zone, soilMoisture) + ); + }); + } else { - jobMonitor.logNrOfEntitiesFetched(Manufacturer.AGRANIMO, 0); + log.info("Running scheduled data import from Agranimo API"); + agranimoZoneService.fetchZones().forEach(zone -> { + var waterContent = agranimoSoilMoistureIntegrationService.fetchWaterContent(zone, Instant.now().minus(daysInThePastForInitialImport, ChronoUnit.DAYS)); + jobMonitor.logNrOfEntitiesFetched(Manufacturer.AGRANIMO, waterContent.size()); + log.info("Found {} water content entries", waterContent.size()); + log.info("Persisting {} water content entries", waterContent.size()); + waterContent.forEach( + soilMoisture -> persistDataWithinFiware(zone, soilMoisture) + ); + }); } applicationDataRepository.updateLastRun(Manufacturer.AGRANIMO); } catch (Exception e) { @@ -44,4 +71,13 @@ public void run() { } } + private void persistDataWithinFiware(Zone zone, SoilMoisture soilMoisture) { + try { + fiwareIntegrationServiceWrapper.persist(zone, soilMoisture); + } catch (Exception e) { + log.error("Error while running scheduled data import from Agranimo API", e); + jobMonitor.logErrorDuringExecution(Manufacturer.AGRANIMO); + } + } + } diff --git a/src/main/java/de/app/fivegla/integration/agranimo/AgranimoMonitoring.java b/src/main/java/de/app/fivegla/integration/agranimo/AgranimoMonitoring.java index c01165a7..3a19013b 100644 --- a/src/main/java/de/app/fivegla/integration/agranimo/AgranimoMonitoring.java +++ b/src/main/java/de/app/fivegla/integration/agranimo/AgranimoMonitoring.java @@ -23,7 +23,7 @@ public class AgranimoMonitoring { private final ApplicationConfiguration applicationConfiguration; - private final ZoneService zoneService; + private final AgranimoZoneService agranimoZoneService; @ReadOperation public Health read() { @@ -32,7 +32,7 @@ public Health read() { return null; } else { try { - var zones = zoneService.fetchZones(); + var zones = agranimoZoneService.fetchZones(); if (zones != null && !zones.isEmpty()) { return Health .up() diff --git a/src/main/java/de/app/fivegla/integration/agranimo/AgranimoSoilMoistureIntegrationService.java b/src/main/java/de/app/fivegla/integration/agranimo/AgranimoSoilMoistureIntegrationService.java index 35a30ad1..d474a656 100644 --- a/src/main/java/de/app/fivegla/integration/agranimo/AgranimoSoilMoistureIntegrationService.java +++ b/src/main/java/de/app/fivegla/integration/agranimo/AgranimoSoilMoistureIntegrationService.java @@ -1,6 +1,11 @@ package de.app.fivegla.integration.agranimo; +import de.app.fivegla.api.Error; +import de.app.fivegla.api.ErrorMessage; +import de.app.fivegla.api.exceptions.BusinessException; +import de.app.fivegla.integration.agranimo.model.SoilMoisture; import de.app.fivegla.integration.agranimo.model.SoilMoistureType; +import de.app.fivegla.integration.agranimo.model.Zone; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -11,6 +16,7 @@ import java.time.Instant; import java.util.Collections; +import java.util.List; import java.util.Map; /** @@ -24,80 +30,77 @@ public class AgranimoSoilMoistureIntegrationService { @Value("${app.sensors.agranimo.url}") private String url; - private final ZoneService zoneService; - private final LoginIntegrationService loginService; + private final AgranimoLoginIntegrationService loginService; private final RestTemplate restTemplate; /** * Fetch the water content from the API. * + * @param zone The zone to fetch the data for. * @param since The date since to fetch the data. - * @param until The date until to fetch the data. + * @return The water content. */ - public void fetchWaterContent(Instant since, Instant until) { - fetchAll(since, until, SoilMoistureType.WATER_CONTENT); - } - - /** - * Fetch the water height from the API. - * - * @param since The date since to fetch the data. - * @param until The date until to fetch the data. - */ - public void fetchWaterHeight(Instant since, Instant until) { - fetchAll(since, until, SoilMoistureType.WATER_HEIGHT); - } - - /** - * Fetch the water volume from the API. - * - * @param since The date since to fetch the data. - * @param until The date until to fetch the data. - */ - public void fetchWaterVolume(Instant since, Instant until) { - fetchAll(since, until, SoilMoistureType.WATER_VOLUMETRIC); + public List fetchWaterContent(Zone zone, Instant since) { + return fetchAll(zone, since); } /** * Fetch the soil moisture from the API. */ - private void fetchAll(Instant since, Instant until, SoilMoistureType soilMoistureType) { - zoneService.fetchZones().forEach(zone -> { - log.info("Fetching soil moisture data for zone {}.", zone.getName()); - log.debug("Fetching soil moisture data for zone {} from {} to {}.", zone.getId(), since, until); - try { - var headers = new HttpHeaders(); - headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); - headers.setBearerAuth(loginService.fetchAccessToken()); - var httpEntity = new HttpEntity<>(headers); - var uri = UriComponentsBuilder.fromHttpUrl(url + "/zone/{zoneId}/data/soilmoisture?dateStart={since}&dateEnd={until}&type={type}") - .encode() - .toUriString(); - var uriVariables = Map.of( - "zoneId", - zone.getId(), - "since", - since.getEpochSecond(), - "until", - until.getEpochSecond(), - "type", - soilMoistureType.getKey()); - log.debug("Calling API with URI {} and variables {}.", uri, uriVariables); - var response = restTemplate.exchange(uri, HttpMethod.GET, httpEntity, String.class, uriVariables); + private List fetchAll(Zone zone, Instant since) { + var until = Instant.now(); + log.info("Fetching soil moisture data for zone {}.", zone.getName()); + log.debug("Fetching soil moisture data for zone {} from {} to {}.", zone.getId(), since, until); + try { + var headers = new HttpHeaders(); + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + headers.setBearerAuth(loginService.fetchAccessToken()); + var httpEntity = new HttpEntity<>(headers); + var uri = UriComponentsBuilder.fromHttpUrl(url + "/zone/{zoneId}/data/soilmoisture?dateStart={since}&dateEnd={until}&type={type}") + .encode() + .toUriString(); + var uriVariables = Map.of( + "zoneId", + zone.getId(), + "since", + since.getEpochSecond(), + "until", + until.getEpochSecond(), + "type", + SoilMoistureType.WATER_CONTENT.getKey()); + log.debug("Calling API with URI {} and variables {}.", uri, uriVariables); + var response = restTemplate.exchange(uri, HttpMethod.GET, httpEntity, SoilMoisture[].class, uriVariables); - if (response.getStatusCode() != HttpStatus.OK) { - log.error("Error while fetching soil moisture from the API. Status code: {}", response.getStatusCode()); - log.info("Could not fetch soil moisture data for zone {}.", zone.getName()); + if (response.getStatusCode() != HttpStatus.OK) { + log.error("Error while fetching soil moisture from the API. Status code: {}", response.getStatusCode()); + log.info("Could not fetch soil moisture data for zone {}.", zone.getName()); + throw new BusinessException(ErrorMessage.builder() + .error(Error.AGRANIMO_COULD_NOT_FETCH_SOIL_MOISTURE_FOR_ZONE) + .message("Could not fetch soil moisture.") + .build()); + } else { + log.info("Successfully fetched soil moisture from the API."); + log.info("Successfully fetched soil moisture data for zone {}.", zone.getName()); + var soilMoistures = response.getBody(); + if (null != soilMoistures) { + log.info("Successfully fetched {} soil moisture data points for zone {}.", soilMoistures.length, zone.getName()); + return List.of(soilMoistures); } else { - log.info("Successfully fetched soil moisture from the API."); - log.debug("Response body: {}", response.getBody()); - log.info("Successfully fetched soil moisture data for zone {}.", zone.getName()); + log.info("Could not fetch soil moisture data for zone {}.", zone.getName()); + throw new BusinessException(ErrorMessage.builder() + .error(Error.AGRANIMO_COULD_NOT_FETCH_SOIL_MOISTURE_FOR_ZONE) + .message("Could not fetch soil moisture.") + .build()); } - } catch (Exception e) { - log.error("Error while fetching soil moisture from the API.", e); - log.info("Could not fetch soil moisture data for zone {}.", zone.getName()); } - }); + } catch (Exception e) { + log.error("Error while fetching soil moisture from the API.", e); + log.info("Could not fetch soil moisture data for zone {}.", zone.getName()); + throw new BusinessException(ErrorMessage.builder() + .error(Error.AGRANIMO_COULD_NOT_FETCH_SOIL_MOISTURE) + .message("Could not fetch soil moisture.") + .build()); + } } } diff --git a/src/main/java/de/app/fivegla/integration/agranimo/ZoneService.java b/src/main/java/de/app/fivegla/integration/agranimo/AgranimoZoneService.java similarity index 95% rename from src/main/java/de/app/fivegla/integration/agranimo/ZoneService.java rename to src/main/java/de/app/fivegla/integration/agranimo/AgranimoZoneService.java index d8ddac0b..b348e9d7 100644 --- a/src/main/java/de/app/fivegla/integration/agranimo/ZoneService.java +++ b/src/main/java/de/app/fivegla/integration/agranimo/AgranimoZoneService.java @@ -4,7 +4,7 @@ import de.app.fivegla.api.ErrorMessage; import de.app.fivegla.api.exceptions.BusinessException; import de.app.fivegla.integration.agranimo.cache.UserDataCache; -import de.app.fivegla.integration.agranimo.dto.Zone; +import de.app.fivegla.integration.agranimo.model.Zone; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -22,12 +22,12 @@ @Slf4j @Service @RequiredArgsConstructor -public class ZoneService { +public class AgranimoZoneService { @Value("${app.sensors.agranimo.url}") private String url; - private final LoginIntegrationService loginService; + private final AgranimoLoginIntegrationService loginService; private final UserDataCache userDataCache; private final RestTemplate restTemplate; diff --git a/src/main/java/de/app/fivegla/integration/agranimo/cache/UserDataCache.java b/src/main/java/de/app/fivegla/integration/agranimo/cache/UserDataCache.java index dc57ca8c..db526055 100644 --- a/src/main/java/de/app/fivegla/integration/agranimo/cache/UserDataCache.java +++ b/src/main/java/de/app/fivegla/integration/agranimo/cache/UserDataCache.java @@ -1,7 +1,7 @@ package de.app.fivegla.integration.agranimo.cache; -import de.app.fivegla.integration.agranimo.dto.Credentials; -import de.app.fivegla.integration.agranimo.dto.Zone; +import de.app.fivegla.integration.agranimo.model.Credentials; +import de.app.fivegla.integration.agranimo.model.Zone; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/src/main/java/de/app/fivegla/integration/agranimo/dto/Credentials.java b/src/main/java/de/app/fivegla/integration/agranimo/model/Credentials.java similarity index 83% rename from src/main/java/de/app/fivegla/integration/agranimo/dto/Credentials.java rename to src/main/java/de/app/fivegla/integration/agranimo/model/Credentials.java index 6d2ce4f9..f9e88dad 100644 --- a/src/main/java/de/app/fivegla/integration/agranimo/dto/Credentials.java +++ b/src/main/java/de/app/fivegla/integration/agranimo/model/Credentials.java @@ -1,4 +1,4 @@ -package de.app.fivegla.integration.agranimo.dto; +package de.app.fivegla.integration.agranimo.model; import lombok.Getter; import lombok.Setter; diff --git a/src/main/java/de/app/fivegla/integration/agranimo/dto/Features.java b/src/main/java/de/app/fivegla/integration/agranimo/model/Features.java similarity index 77% rename from src/main/java/de/app/fivegla/integration/agranimo/dto/Features.java rename to src/main/java/de/app/fivegla/integration/agranimo/model/Features.java index 3cade093..9454ac8d 100644 --- a/src/main/java/de/app/fivegla/integration/agranimo/dto/Features.java +++ b/src/main/java/de/app/fivegla/integration/agranimo/model/Features.java @@ -1,4 +1,4 @@ -package de.app.fivegla.integration.agranimo.dto; +package de.app.fivegla.integration.agranimo.model; import lombok.Getter; import lombok.Setter; diff --git a/src/main/java/de/app/fivegla/integration/agranimo/dto/Point.java b/src/main/java/de/app/fivegla/integration/agranimo/model/Point.java similarity index 73% rename from src/main/java/de/app/fivegla/integration/agranimo/dto/Point.java rename to src/main/java/de/app/fivegla/integration/agranimo/model/Point.java index 063eab69..6dcb9d23 100644 --- a/src/main/java/de/app/fivegla/integration/agranimo/dto/Point.java +++ b/src/main/java/de/app/fivegla/integration/agranimo/model/Point.java @@ -1,4 +1,4 @@ -package de.app.fivegla.integration.agranimo.dto; +package de.app.fivegla.integration.agranimo.model; import lombok.Getter; import lombok.Setter; diff --git a/src/main/java/de/app/fivegla/integration/agranimo/model/SoilMoisture.java b/src/main/java/de/app/fivegla/integration/agranimo/model/SoilMoisture.java new file mode 100644 index 00000000..becc1154 --- /dev/null +++ b/src/main/java/de/app/fivegla/integration/agranimo/model/SoilMoisture.java @@ -0,0 +1,82 @@ +package de.app.fivegla.integration.agranimo.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Getter; +import lombok.Setter; + +import java.time.Instant; + +/** + * The SoilMoisture class represents the soil moisture data obtained by a device. + * It holds information such as device ID, timestamp, creation timestamp, and soil moisture readings from four different sensors. + */ +@Getter +@Setter +public class SoilMoisture { + + /** + * The deviceId variable represents the unique identifier of a device. + * It is a string value used to uniquely identify a specific device. + * The device ID is typically assigned by the manufacturer or system administrator. + */ + private String deviceId; + + /** + * The tms variable represents the timestamp of the soil moisture data. + * It is an Instant object that stores an instant in time with nanosecond precision. + * The timestamp indicates when the soil moisture reading was recorded. + * + * @see SoilMoisture + */ + @JsonProperty("TMS") + private Instant tms; + + /** + * The createdAt variable represents the timestamp when the instance of SoilMoisture object was created. + * It is an Instant object that stores an instant in time with nanosecond precision. + * The createdAt timestamp indicates when the SoilMoisture object was instantiated. + * + * @see SoilMoisture + */ + private Instant createdAt; + + /** + * The smo1 variable represents the soil moisture reading from the first sensor. + * It is a double value that indicates the level of moisture in the soil. + * The value is obtained from the SoilMoisture object and can be accessed and modified using getter and setter methods. + */ + private double smo1; + + /** + * The smo2 variable represents the soil moisture reading from the second sensor. + * It is a double value that indicates the level of moisture in the soil + * as measured by the second sensor in the SoilMoisture object. + * This variable is accessible through getter and setter methods. + * + * @see SoilMoisture#getSmo2() + * @see SoilMoisture#setSmo2(double) + */ + private double smo2; + + /** + * The smo3 variable represents the soil moisture reading from the third sensor. + * It is a double value that indicates the level of moisture in the soil + * as measured by the third sensor in the SoilMoisture object. + * This variable is accessible through getter and setter methods. + * + * @see SoilMoisture#getSmo3() + * @see SoilMoisture#setSmo3(double) + */ + private double smo3; + + /** + * The `smo4` variable represents the soil moisture reading from the fourth sensor. + * It is a double value that indicates the level of moisture in the soil + * as measured by the fourth sensor in the SoilMoisture object. + * + * @see SoilMoisture#getSmo4() + * @see SoilMoisture#setSmo4(double) + */ + private double smo4; + +} diff --git a/src/main/java/de/app/fivegla/integration/agranimo/dto/Thresholds.java b/src/main/java/de/app/fivegla/integration/agranimo/model/Thresholds.java similarity index 76% rename from src/main/java/de/app/fivegla/integration/agranimo/dto/Thresholds.java rename to src/main/java/de/app/fivegla/integration/agranimo/model/Thresholds.java index 8f71343a..9d062875 100644 --- a/src/main/java/de/app/fivegla/integration/agranimo/dto/Thresholds.java +++ b/src/main/java/de/app/fivegla/integration/agranimo/model/Thresholds.java @@ -1,4 +1,4 @@ -package de.app.fivegla.integration.agranimo.dto; +package de.app.fivegla.integration.agranimo.model; import lombok.Getter; import lombok.Setter; diff --git a/src/main/java/de/app/fivegla/integration/agranimo/dto/Zone.java b/src/main/java/de/app/fivegla/integration/agranimo/model/Zone.java similarity index 92% rename from src/main/java/de/app/fivegla/integration/agranimo/dto/Zone.java rename to src/main/java/de/app/fivegla/integration/agranimo/model/Zone.java index dbba4193..2360cb22 100644 --- a/src/main/java/de/app/fivegla/integration/agranimo/dto/Zone.java +++ b/src/main/java/de/app/fivegla/integration/agranimo/model/Zone.java @@ -1,4 +1,4 @@ -package de.app.fivegla.integration.agranimo.dto; +package de.app.fivegla.integration.agranimo.model; import com.google.gson.annotations.SerializedName; import lombok.Getter; diff --git a/src/main/java/de/app/fivegla/integration/agranimo/dto/ZoneData.java b/src/main/java/de/app/fivegla/integration/agranimo/model/ZoneData.java similarity index 83% rename from src/main/java/de/app/fivegla/integration/agranimo/dto/ZoneData.java rename to src/main/java/de/app/fivegla/integration/agranimo/model/ZoneData.java index b9bfaa18..9fa5c117 100644 --- a/src/main/java/de/app/fivegla/integration/agranimo/dto/ZoneData.java +++ b/src/main/java/de/app/fivegla/integration/agranimo/model/ZoneData.java @@ -1,4 +1,4 @@ -package de.app.fivegla.integration.agranimo.dto; +package de.app.fivegla.integration.agranimo.model; import lombok.Getter; import lombok.Setter; diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 63903882..a80a6745 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -24,7 +24,7 @@ app: fiwareDeviceIdPrefix: "urn:5gla:dev:agr:" fiwareDeviceMeasurementIdPrefix: "urn:5gla:data:agr:" enabled: true - url: https://public-staging.agranimo.com + url: https://public.agranimo.com/ username: ${AGRANIMO_USERNAME} password: ${AGRANIMO_PASSWORD} agvolution: diff --git a/src/test/java/de/app/fivegla/integration/agranimo/AccessTokenIntegrationServiceIT.java b/src/test/java/de/app/fivegla/integration/agranimo/AccessTokenIntegrationServiceIT.java index 150215ae..5529a785 100644 --- a/src/test/java/de/app/fivegla/integration/agranimo/AccessTokenIntegrationServiceIT.java +++ b/src/test/java/de/app/fivegla/integration/agranimo/AccessTokenIntegrationServiceIT.java @@ -11,7 +11,7 @@ class AccessTokenIntegrationServiceIT extends SpringBootIntegrationTestBase { @Autowired - private LoginIntegrationService loginService; + private AgranimoLoginIntegrationService loginService; @Test void givenValidCredentialsWhenLoginThenTheRequestShouldBeAccepted() { diff --git a/src/test/java/de/app/fivegla/integration/agranimo/AgranimoSoilMoistureServiceIT.java b/src/test/java/de/app/fivegla/integration/agranimo/AgranimoSoilMoistureServiceIT.java index 0dc396e2..b9f69afb 100644 --- a/src/test/java/de/app/fivegla/integration/agranimo/AgranimoSoilMoistureServiceIT.java +++ b/src/test/java/de/app/fivegla/integration/agranimo/AgranimoSoilMoistureServiceIT.java @@ -1,38 +1,34 @@ package de.app.fivegla.integration.agranimo; import de.app.fivegla.SpringBootIntegrationTestBase; +import de.app.fivegla.integration.agranimo.model.Zone; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.time.Instant; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest class AgranimoSoilMoistureServiceIT extends SpringBootIntegrationTestBase { @Autowired private AgranimoSoilMoistureIntegrationService soilMoistureService; + @Autowired + private AgranimoZoneService agranimoZoneService; - private final Instant since = Instant.ofEpochSecond(1662087600); - private final Instant until = Instant.ofEpochSecond(1662617200); - - @Test - void givenInvalidTimePeriodWhenFetchingWaterVolumeShouldNotCauseAnError() { - soilMoistureService.fetchWaterVolume(until, since); - } - - @Test - void givenValidCredentialsWhenFetchingWaterVolumeThenThereShouldBeEntriesForTheZone() { - soilMoistureService.fetchWaterVolume(since, until); - } - - @Test - void givenValidCredentialsWhenFetchingWaterHeightThenThereShouldBeEntriesForTheZone() { - soilMoistureService.fetchWaterHeight(since, until); - } + private final Instant since = Instant.ofEpochSecond(1662617200); @Test void givenValidCredentialsWhenFetchingWaterContentThenThereShouldBeEntriesForTheZone() { - soilMoistureService.fetchWaterContent(since, until); + List zones = agranimoZoneService.fetchZones(); + zones.forEach(zone -> + { + var soilMoistures = soilMoistureService.fetchWaterContent(zone, since); + assertThat(soilMoistures).isNotEmpty(); + assertThat(soilMoistures.size()).isGreaterThan(0); + }); } } \ No newline at end of file diff --git a/src/test/java/de/app/fivegla/integration/agranimo/ZoneServiceIT.java b/src/test/java/de/app/fivegla/integration/agranimo/AgranimoZoneServiceIT.java similarity index 75% rename from src/test/java/de/app/fivegla/integration/agranimo/ZoneServiceIT.java rename to src/test/java/de/app/fivegla/integration/agranimo/AgranimoZoneServiceIT.java index 727fcc58..9ce3a910 100644 --- a/src/test/java/de/app/fivegla/integration/agranimo/ZoneServiceIT.java +++ b/src/test/java/de/app/fivegla/integration/agranimo/AgranimoZoneServiceIT.java @@ -8,14 +8,14 @@ import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest -class ZoneServiceIT extends SpringBootIntegrationTestBase { +class AgranimoZoneServiceIT extends SpringBootIntegrationTestBase { @Autowired - private ZoneService zoneService; + private AgranimoZoneService agranimoZoneService; @Test void givenValidCredentialsWhenFetchingTheZonesThenThereShouldBeAtLeast4Zones() { - var zones = zoneService.fetchZones(); + var zones = agranimoZoneService.fetchZones(); assertThat(zones).isNotEmpty(); assertThat(zones.size()).isEqualTo(4); } diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index 85d7be26..538e9a39 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -24,7 +24,7 @@ app: fiwareDeviceIdPrefix: "urn:5gla:iotdevice:agranimo:" fiwareDeviceMeasurementIdPrefix: "urn:5gla:sensordata:agranimo:" enabled: true - url: https://public-staging.agranimo.com + url: https://public.agranimo.com/ username: ${AGRANIMO_USERNAME} password: ${AGRANIMO_PASSWORD} agvolution: @@ -86,4 +86,8 @@ logging: one: microstream: storage-directory: .microstream-integration-test - channel-count: 2 \ No newline at end of file + channel-count: 2 +spring: + batch: + job: + enabled: false \ No newline at end of file