Jelajahi Sumber

OpenMeteo Connector, Fix of Metno, Update of Fofr

Lukas Cerny 8 bulan lalu
induk
melakukan
240381f6a2
18 mengubah file dengan 339 tambahan dan 125 penghapusan
  1. 1 0
      config/fofrToTelemetry.yaml
  2. 35 24
      config/openMeteoToSenslog.yaml
  3. 6 0
      connector-fetch-fofr/src/main/java/cz/senslog/connector/fetch/fofr/FofrConfig.java
  4. 46 21
      connector-fetch-fofr/src/main/java/cz/senslog/connector/fetch/fofr/FofrFetcher.java
  5. 13 1
      connector-fetch-fofr/src/main/java/cz/senslog/connector/fetch/fofr/ParcelInfo.java
  6. 10 4
      connector-fetch-fofr/src/test/java/cz/senslog/connector/fetch/fofr/FofrFetcherTest.java
  7. 1 1
      connector-fetch-metno/src/main/java/cz/senslog/connector/fetch/metno/MetnoFetcher.java
  8. 27 26
      connector-fetch-openmeteo/src/main/java/cz/senslog/connector/fetch/openmeteo/OpenMeteoConfig.java
  9. 57 15
      connector-fetch-openmeteo/src/main/java/cz/senslog/connector/fetch/openmeteo/OpenMeteoFetcher.java
  10. 19 0
      connector-fetch-openmeteo/src/main/java/cz/senslog/connector/fetch/openmeteo/Station.java
  11. 35 22
      connector-fetch-openmeteo/src/test/java/cz/senslog/connector/fetch/openmeteo/OpenMeteoFetcherTest.java
  12. 6 6
      connector-fetch-senslog-telemetry/src/test/java/cz/senslog/connector/fetch/senslog/telemetry/SensLogTelemetryFetcherTest.java
  13. 35 2
      connector-model/src/main/java/cz/senslog/connector/model/converter/FofrModelTelemetryModelConverter.java
  14. 1 1
      connector-model/src/main/java/cz/senslog/connector/model/converter/MetnoToSensLogConverter.java
  15. 28 0
      connector-model/src/main/java/cz/senslog/connector/model/fofr/LocationTrack.java
  16. 16 0
      connector-model/src/main/java/cz/senslog/connector/model/fofr/ParcelUpdate.java
  17. 2 1
      connector-push-senslog/src/main/java/cz/senslog/connector/push/senslog/SensLogPusher.java
  18. 1 1
      connector-tools/src/main/java/cz/senslog/connector/tools/http/HttpContentType.java

+ 1 - 0
config/fofrToTelemetry.yaml

@@ -3,6 +3,7 @@ settings:
       name: "Fofr Fetcher"
       provider: "cz.senslog.connector.fetch.fofr.FofrFetchProvider"
 
+      timeZone: "Europe/Prague"
       orderStatesUrl: "https://objednavky.fofrcz.cz/stavy/fofr/xml"
       warehouseLocationsUrl: "https://objednavky.fofrcz.cz/seznam-dep/json"
       parcelTrackingUrl: "https://objednavky.fofrcz.cz/procedure/track_and_trace_sledovani_zasilek.php"

+ 35 - 24
config/openMeteoToSenslog.yaml

@@ -3,39 +3,50 @@ settings:
       name: "Open Meteo"
       provider: "cz.senslog.connector.fetch.openmeteo.ConnectorFetchOpenMeteoProvider"
 
-      baseUrl: "https://previous-runs-api.open-meteo.com/v1/forecast"
+#      baseUrl: "https://previous-runs-api.open-meteo.com/v1/forecast"
+      baseUrl: "https://archive-api.open-meteo.com/v1/archive"
+
       timeZone: "Europe/Prague"
+      startDate: "2024-01-03"
+
+      allowedStationURL: "https://sensor.lesprojekt.cz/senslogOTS3/rest/forecast/era5land/plan"
+      allowedStationURLParams:
+          models: era5_land
+          hourly: [temperature_2m, relative_humidity_2m, dew_point_2m, precipitation, rain, snowfall, pressure_msl, surface_pressure,
+                    et0_fao_evapotranspiration, cloud_cover,wind_speed_10m, wind_direction_10m, wind_gusts_10m, 
+                    soil_temperature_0_to_7cm,soil_temperature_7_to_28cm,soil_temperature_28_to_100cm,soil_temperature_100_to_255cm,
+                    soil_moisture_0_to_7cm,soil_moisture_7_to_28cm,soil_moisture_28_to_100cm,soil_moisture_100_to_255cm]
 
-      allowedStations:
-        - latitude: 49.72680307543005
-          longitude: 13.351931666613327
-          timezone: GMT
-          past_days: 1
-          hourly: [temperature_2m,temperature_2m_previous_day1,temperature_2m_previous_day2,temperature_2m_previous_day3,temperature_2m_previous_day4,temperature_2m_previous_day5,
-                   relative_humidity_2m,relative_humidity_2m_previous_day1,relative_humidity_2m_previous_day2,relative_humidity_2m_previous_day3,relative_humidity_2m_previous_day4,relative_humidity_2m_previous_day5,
-                   dew_point_2m,dew_point_2m_previous_day1,dew_point_2m_previous_day2,dew_point_2m_previous_day3,dew_point_2m_previous_day4,dew_point_2m_previous_day5,
-                   apparent_temperature,apparent_temperature_previous_day1,apparent_temperature_previous_day2,apparent_temperature_previous_day3,apparent_temperature_previous_day4,apparent_temperature_previous_day5,
-                   precipitation,precipitation_previous_day1,precipitation_previous_day2,precipitation_previous_day3,precipitation_previous_day4,precipitation_previous_day5,
-                   rain,rain_previous_day1,rain_previous_day2,rain_previous_day3,rain_previous_day4,rain_previous_day5,
-                   showers,showers_previous_day1,showers_previous_day2,showers_previous_day3,showers_previous_day4,showers_previous_day5,
-                   snowfall,snowfall_previous_day1,snowfall_previous_day2,snowfall_previous_day3,snowfall_previous_day4,snowfall_previous_day5,
-                   weather_code,weather_code_previous_day1,weather_code_previous_day2,weather_code_previous_day3,weather_code_previous_day4,weather_code_previous_day5,
-                   pressure_msl,pressure_msl_previous_day1,pressure_msl_previous_day2,pressure_msl_previous_day3,pressure_msl_previous_day4,pressure_msl_previous_day5,
-                   surface_pressure,surface_pressure_previous_day1,surface_pressure_previous_day2,surface_pressure_previous_day3,surface_pressure_previous_day4,surface_pressure_previous_day5,
-                   cloud_cover,cloud_cover_previous_day1,cloud_cover_previous_day2,cloud_cover_previous_day3,cloud_cover_previous_day4,cloud_cover_previous_day5,
-                   wind_speed_10m,wind_speed_10m_previous_day1,wind_speed_10m_previous_day2,wind_speed_10m_previous_day3,wind_speed_10m_previous_day4,wind_speed_10m_previous_day5,
-                   wind_direction_10m,wind_direction_10m_previous_day1,wind_direction_10m_previous_day2,wind_direction_10m_previous_day3,wind_direction_10m_previous_day4,wind_direction_10m_previous_day5]
+#      allowedStations:
+#        - latitude: 49.72680307543005
+#          longitude: 13.351931666613327
+#          timezone: GMT
+#          past_days: 1
+#          hourly: [temperature_2m,temperature_2m_previous_day1,temperature_2m_previous_day2,temperature_2m_previous_day3,temperature_2m_previous_day4,temperature_2m_previous_day5,
+#                   relative_humidity_2m,relative_humidity_2m_previous_day1,relative_humidity_2m_previous_day2,relative_humidity_2m_previous_day3,relative_humidity_2m_previous_day4,relative_humidity_2m_previous_day5,
+#                   dew_point_2m,dew_point_2m_previous_day1,dew_point_2m_previous_day2,dew_point_2m_previous_day3,dew_point_2m_previous_day4,dew_point_2m_previous_day5,
+#                   apparent_temperature,apparent_temperature_previous_day1,apparent_temperature_previous_day2,apparent_temperature_previous_day3,apparent_temperature_previous_day4,apparent_temperature_previous_day5,
+#                   precipitation,precipitation_previous_day1,precipitation_previous_day2,precipitation_previous_day3,precipitation_previous_day4,precipitation_previous_day5,
+#                   rain,rain_previous_day1,rain_previous_day2,rain_previous_day3,rain_previous_day4,rain_previous_day5,
+#                   showers,showers_previous_day1,showers_previous_day2,showers_previous_day3,showers_previous_day4,showers_previous_day5,
+#                   snowfall,snowfall_previous_day1,snowfall_previous_day2,snowfall_previous_day3,snowfall_previous_day4,snowfall_previous_day5,
+#                   weather_code,weather_code_previous_day1,weather_code_previous_day2,weather_code_previous_day3,weather_code_previous_day4,weather_code_previous_day5,
+#                   pressure_msl,pressure_msl_previous_day1,pressure_msl_previous_day2,pressure_msl_previous_day3,pressure_msl_previous_day4,pressure_msl_previous_day5,
+#                   surface_pressure,surface_pressure_previous_day1,surface_pressure_previous_day2,surface_pressure_previous_day3,surface_pressure_previous_day4,surface_pressure_previous_day5,
+#                   cloud_cover,cloud_cover_previous_day1,cloud_cover_previous_day2,cloud_cover_previous_day3,cloud_cover_previous_day4,cloud_cover_previous_day5,
+#                   wind_speed_10m,wind_speed_10m_previous_day1,wind_speed_10m_previous_day2,wind_speed_10m_previous_day3,wind_speed_10m_previous_day4,wind_speed_10m_previous_day5,
+#                   wind_direction_10m,wind_direction_10m_previous_day1,wind_direction_10m_previous_day2,wind_direction_10m_previous_day3,wind_direction_10m_previous_day4,wind_direction_10m_previous_day5]
 
   - Senslog:
       name: "Senslog Pass Trough"
       provider: "cz.senslog.connector.push.senslog.ConnectorPushSensLogProvider"
 
-      baseUrl: "https://sensor.lesprojekt.cz"
+      baseUrl: "https://sensor.lesprojekt.cz/senslogOTS3/rest/forecast/era5land"
 
 connectors:
   - OpenMeteoSenslog:
       fetcher: "OpenMeteo"
       pusher: "Senslog"
-      period: 3_600          # seconds
-#      startAt: "02:30:00" # hh:mm:ss  # non-mandatory attribute
-      initDelay: 10        # non-mandatory attribute
+      period: 300          # 5 minutes
+      startAt: "00:10:00" # hh:mm:ss  # non-mandatory attribute
+#      initDelay: 10        # non-mandatory attribute

+ 6 - 0
connector-fetch-fofr/src/main/java/cz/senslog/connector/fetch/fofr/FofrConfig.java

@@ -6,6 +6,7 @@ import java.util.*;
 
 public class FofrConfig {
 
+    private final TimeZone timeZone;
     private final String orderStatesUrl;
     private final String warehouseLocationsUrl;
     private final String parcelTrackingUrl;
@@ -16,6 +17,7 @@ public class FofrConfig {
     private final Set<WarehouseInfo> missingWarehouses;
 
     public FofrConfig(DefaultConfig defaultConfig) {
+        this.timeZone = TimeZone.getTimeZone(defaultConfig.getStringProperty("timeZone"));
         this.orderStatesUrl = defaultConfig.getStringProperty("orderStatesUrl");
         this.warehouseLocationsUrl = defaultConfig.getStringProperty("warehouseLocationsUrl");
         this.parcelTrackingUrl = defaultConfig.getStringProperty("parcelTrackingUrl");
@@ -47,6 +49,10 @@ public class FofrConfig {
         }
     }
 
+    public TimeZone getTimeZone() {
+        return timeZone;
+    }
+
     public int getDeliveryStatus() {
         return deliveryStatus;
     }

+ 46 - 21
connector-fetch-fofr/src/main/java/cz/senslog/connector/fetch/fofr/FofrFetcher.java

@@ -5,6 +5,7 @@ import com.fasterxml.jackson.dataformat.xml.XmlMapper;
 import cz.senslog.connector.fetch.api.ConnectorFetcher;
 import cz.senslog.connector.model.api.VoidSession;
 import cz.senslog.connector.model.fofr.FofrModel;
+import cz.senslog.connector.model.fofr.LocationTrack;
 import cz.senslog.connector.model.fofr.ParcelUpdate;
 import cz.senslog.connector.tools.http.HttpClient;
 import cz.senslog.connector.tools.http.HttpRequest;
@@ -17,12 +18,12 @@ import org.apache.logging.log4j.Logger;
 
 import java.time.LocalDateTime;
 import java.time.OffsetDateTime;
+import java.time.ZonedDateTime;
 import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
 import static cz.senslog.connector.tools.json.BasicJson.jsonToObject;
-import static cz.senslog.connector.tools.json.BasicJson.objectToJson;
 import static java.lang.String.format;
 import static java.time.format.DateTimeFormatter.ofPattern;
 
@@ -128,7 +129,7 @@ public class FofrFetcher implements ConnectorFetcher<VoidSession, FofrModel> {
 //            }
 //        }
 
-        orderInfos = Arrays.asList(new OrderInfo(0, 2590166192L, 0));
+        orderInfos = Arrays.asList(new OrderInfo(202500034, 2590166192L, 1305167562660700L));
 
         List<ParcelUpdate> parcelsToUpdate = new ArrayList<>();
         for (OrderInfo orderInfo : orderInfos) {
@@ -214,29 +215,53 @@ public class FofrFetcher implements ConnectorFetcher<VoidSession, FofrModel> {
 
                 LocalDateTime exportDate = LocalDateTime.parse((String)parcelInfo.get("datum_exportu"), ofPattern("yyyy-MM-dd HH:mm:ss"));
 
-                ParcelInfo parcel = new ParcelInfo(parcelId, officeBranch, exportDate, trackingStatuses,
-                        new ParcelInfo.Address(
-                                (String) parcelInfo.get("odes_firma"),
-                                (String) parcelInfo.get("odes_stat"),
-                                (String) parcelInfo.get("odes_mesto"),
-                                (String) parcelInfo.get("odes_ulice"),
-                                (String) parcelInfo.get("odes_psc")
-                        ),
-                        new ParcelInfo.Address(
-                                (String) parcelInfo.get("prij_firma"),
-                                (String) parcelInfo.get("prij_stat"),
-                                (String) parcelInfo.get("prij_mesto"),
-                                (String) parcelInfo.get("prij_ulice"),
-                                (String) parcelInfo.get("prij_psc")
-                        )
+                ParcelInfo.Address dispatcherAddress = new ParcelInfo.Address(
+                        (String) parcelInfo.get("odes_firma"),
+                        (String) parcelInfo.get("odes_stat"),
+                        (String) parcelInfo.get("odes_mesto"),
+                        (String) parcelInfo.get("odes_ulice"),
+                        (String) parcelInfo.get("odes_psc"),
+                        49.2279778, 13.5292353  // TODO SUMAVAPRODUCT Addr
                 );
 
-                if (parcel.lastTrackingStatus().getId() == config.getDeliveryStatus()) {
-                    // TODO parcel is delivered
-                    // GET GPS coordination from delivery address
+                ParcelInfo.Address recipientAddress = new ParcelInfo.Address(
+                        (String) parcelInfo.get("prij_firma"),
+                        (String) parcelInfo.get("prij_stat"),
+                        (String) parcelInfo.get("prij_mesto"),
+                        (String) parcelInfo.get("prij_ulice"),
+                        (String) parcelInfo.get("prij_psc"),
+                        49.7700992, 13.5921767  // TODO MIKE
+                );
+
+                ParcelInfo parcel = new ParcelInfo(parcelId, officeBranch, exportDate, trackingStatuses, dispatcherAddress, recipientAddress);
+
+
+                boolean isDelivered = false;
+                int indexSinceDelivered = parcel.getTrackingStatuses().size() - 1;
+                for (; indexSinceDelivered >= 0; indexSinceDelivered--) {
+                    if (parcel.getTrackingStatuses().get(indexSinceDelivered).getId() == config.getDeliveryStatus()) {
+                        isDelivered = true;
+                        break;
+                    }
+                }
+
+                List<LocationTrack> locationTracks = new ArrayList<>(parcel.getTrackingStatuses().size());
+                if (isDelivered) {
+                    LocalDateTime deliveryStart = parcel.getTrackingStatuses().get(0).getTimestamp();
+                    OffsetDateTime deliveryStartTimestamp = ZonedDateTime.of(deliveryStart, config.getTimeZone().toZoneId()).toOffsetDateTime();
+                    locationTracks.add(new LocationTrack(deliveryStartTimestamp, parcel.getDispatcherAddress().getLatitude(), parcel.getDispatcherAddress().getLongitude()));
+                    for (int i = 1; i < indexSinceDelivered - 1; i++) {
+                        ParcelInfo.TrackingStatus status = parcel.getTrackingStatuses().get(i);
+                        WarehouseInfo wi = status.getWarehouseInfo();
+                        OffsetDateTime statusTimestamp = ZonedDateTime.of(status.getTimestamp(), config.getTimeZone().toZoneId()).toOffsetDateTime();
+                        locationTracks.add(new LocationTrack(statusTimestamp, wi.getLatitude(), wi.getLongitude()));
+                    }
+                    LocalDateTime deliveryEnd = parcel.getTrackingStatuses().get(indexSinceDelivered).getTimestamp();
+                    OffsetDateTime deliveryEndTimestamp = ZonedDateTime.of(deliveryEnd, config.getTimeZone().toZoneId()).toOffsetDateTime();
+                    locationTracks.add(new LocationTrack(deliveryEndTimestamp, parcel.getRecipientAddress().getLatitude(), parcel.getRecipientAddress().getLongitude()));
                 }
 
-                System.out.println(objectToJson(parcel));
+                parcelsToUpdate.add(new ParcelUpdate(orderInfo.getUnitId(), locationTracks));
 
             } catch (JsonProcessingException e) {
                 throw new RuntimeException(e);

+ 13 - 1
connector-fetch-fofr/src/main/java/cz/senslog/connector/fetch/fofr/ParcelInfo.java

@@ -12,13 +12,17 @@ public class ParcelInfo {
         private final String city;
         private final String street;
         private final String zip;
+        private final double latitude;
+        private final double longitude;
 
-        public Address(String name, String country, String city, String street, String zip) {
+        public Address(String name, String country, String city, String street, String zip, double latitude, double longitude) {
             this.name = name;
             this.country = country;
             this.city = city;
             this.street = street;
             this.zip = zip;
+            this.latitude = latitude;
+            this.longitude = longitude;
         }
 
         public String getName() {
@@ -40,6 +44,14 @@ public class ParcelInfo {
         public String getZip() {
             return zip;
         }
+
+        public double getLatitude() {
+            return latitude;
+        }
+
+        public double getLongitude() {
+            return longitude;
+        }
     }
 
     public static class TrackingStatus {

+ 10 - 4
connector-fetch-fofr/src/test/java/cz/senslog/connector/fetch/fofr/FofrFetcherTest.java

@@ -1,6 +1,8 @@
 package cz.senslog.connector.fetch.fofr;
 
 import cz.senslog.connector.model.config.DefaultConfig;
+import cz.senslog.connector.model.converter.FofrModelTelemetryModelConverter;
+import cz.senslog.connector.model.fofr.FofrModel;
 import cz.senslog.connector.tools.http.HttpClient;
 import cz.senslog.connector.tools.util.DateTrunc;
 import org.junit.jupiter.api.Test;
@@ -15,17 +17,18 @@ class FofrFetcherTest {
     void fetch() throws Exception {
 
         DefaultConfig defaultConfig = new DefaultConfig("fofr", null);
+        defaultConfig.setProperty("timeZone", "Europe/Prague");
         defaultConfig.setProperty("orderStatesUrl", "https://objednavky.fofrcz.cz/stavy/fofr/xml");
             defaultConfig.setProperty("warehouseLocationsUrl", "https://objednavky.fofrcz.cz/seznam-dep/json");
         defaultConfig.setProperty("parcelTrackingUrl", "https://objednavky.fofrcz.cz/procedure/track_and_trace_sledovani_zasilek.php");
         defaultConfig.setProperty("parcelInfoUrl", "https://objednavky.fofrcz.cz/zasilka-info/%d/%d/json");
         defaultConfig.setProperty("activeOrdersUrl", "http://172.17.0.1:8085/integration/tracking/all");
-        defaultConfig.setProperty("deliveryStatus", 6);
+        defaultConfig.setProperty("deliveryStatus", 72);
 
         defaultConfig.setProperty("missingWarehouses", Collections.singletonList(
                 new HashMap<String, Object>() {{
-                    put("code", "CB");
-                    put("location", Arrays.asList(49.4854338, 16.6436640));
+                    put("code", "CP");
+                    put("location", Arrays.asList(48.9763139, 14.5065361));
                 }}
         ));
 
@@ -34,6 +37,9 @@ class FofrFetcherTest {
         FofrFetcher fofrFetcher = new FofrFetcher(config, HttpClient.newHttpClient());
 
         fofrFetcher.init();
-        fofrFetcher.fetch(Optional.empty());
+        FofrModel fofrModel = fofrFetcher.fetch(Optional.empty());
+
+        String geoJSON = new FofrModelTelemetryModelConverter().convert(fofrModel).getBody();
+        System.out.println(geoJSON);
     }
 }

+ 1 - 1
connector-fetch-metno/src/main/java/cz/senslog/connector/fetch/metno/MetnoFetcher.java

@@ -64,7 +64,7 @@ public class MetnoFetcher implements ConnectorFetcher<VoidSession, MetnoModel> {
             }
         }
 
-        List<JsonObject> predictions = new ArrayList<>(config.getStations().size());
+        List<JsonObject> predictions = new ArrayList<>(stations.size());
 
         OffsetDateTime minPredictionDate = OffsetDateTime.MAX;
         OffsetDateTime maxPredictionDate = OffsetDateTime.MIN;

+ 27 - 26
connector-fetch-openmeteo/src/main/java/cz/senslog/connector/fetch/openmeteo/OpenMeteoConfig.java

@@ -3,39 +3,28 @@ package cz.senslog.connector.fetch.openmeteo;
 import cz.senslog.connector.model.config.DefaultConfig;
 import cz.senslog.connector.model.config.PropertyConfig;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-import java.util.TimeZone;
+import java.time.LocalDate;
+import java.util.*;
 
 public class OpenMeteoConfig {
 
-    public static class Station {
-        double latitude, longitude;
-        String timezone;
-        int past_days;
-        List<String> hourly;
-        public Station(PropertyConfig stationConfig) {
-            this.latitude = stationConfig.getDoubleProperty("latitude");
-            this.longitude = stationConfig.getDoubleProperty("longitude");
-            this.timezone = stationConfig.getStringProperty("timezone");
-            this.past_days = stationConfig.getIntegerProperty("past_days");
-            this.hourly = stationConfig.getListProperty("hourly", String.class);
-        }
-    }
-
     private final String url;
     private final TimeZone timeZone;
-    private final List<Station> stations;
+    private final LocalDate startDate;
+    private final String allowedStationURL;
+    private final List<String> hourly;
+    private final String models;
 
     OpenMeteoConfig(DefaultConfig defaultConfig) {
         this.url = defaultConfig.getStringProperty("baseUrl");
+        this.startDate = LocalDate.parse(defaultConfig.getStringProperty("startDate"));
         this.timeZone = TimeZone.getTimeZone(defaultConfig.getStringProperty("timeZone"));
-        Set<PropertyConfig> stations = defaultConfig.getSetProperty("allowedStations");
-        this.stations = new ArrayList<>(stations.size());
-        for (PropertyConfig station : stations) {
-            this.stations.add(new Station(station));
-        }
+        this.allowedStationURL = defaultConfig.containsProperty("allowedStationURL") ? defaultConfig.getStringProperty("allowedStationURL") : null;
+
+        PropertyConfig params = defaultConfig.getPropertyConfig("allowedStationURLParams");
+        this.hourly = params.getListProperty("hourly", String.class);
+        this.models = params.getStringProperty("models");
+
     }
 
     public String getUrl() {
@@ -46,7 +35,19 @@ public class OpenMeteoConfig {
         return timeZone;
     }
 
-    public List<Station> getStations() {
-        return stations;
+    public LocalDate getStartDate() {
+        return startDate;
+    }
+
+    public String getAllowedStationURL() {
+        return allowedStationURL;
+    }
+
+    public List<String> getHourly() {
+        return hourly;
+    }
+
+    public String getModels() {
+        return models;
     }
 }

+ 57 - 15
connector-fetch-openmeteo/src/main/java/cz/senslog/connector/fetch/openmeteo/OpenMeteoFetcher.java

@@ -1,5 +1,7 @@
 package cz.senslog.connector.fetch.openmeteo;
 
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import cz.senslog.connector.fetch.api.ConnectorFetcher;
 import cz.senslog.connector.model.api.VoidSession;
@@ -11,11 +13,11 @@ import cz.senslog.connector.tools.http.URLBuilder;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
+import java.time.*;
+import java.util.*;
 
 import static cz.senslog.connector.tools.json.BasicJson.jsonToObject;
+import static java.time.format.DateTimeFormatter.ofPattern;
 
 public class OpenMeteoFetcher implements ConnectorFetcher<VoidSession, OpenMeteoModel> {
 
@@ -24,36 +26,72 @@ public class OpenMeteoFetcher implements ConnectorFetcher<VoidSession, OpenMeteo
     private final HttpClient httpClient;
     private final OpenMeteoConfig config;
 
+    private final Set<Station> stations;
+    private LocalDate currentDate;
+
+
     public OpenMeteoFetcher(OpenMeteoConfig config, HttpClient httpClient) {
         this.httpClient = httpClient;
         this.config = config;
+        this.stations = new HashSet<>();
     }
 
     @Override
-    public void init() throws Exception {
-
+    public void init() {
+        this.currentDate = config.getStartDate();
     }
 
     @Override
     public OpenMeteoModel fetch(Optional<VoidSession> session) {
 
-        List<JsonObject> results = new ArrayList<>(config.getStations().size());
+        stations.clear();
+
+        if (currentDate.isAfter(LocalDate.now())) {
+            LocalDateTime futureExecution = LocalDateTime.of(currentDate, LocalTime.now());
+            logger.info("Waiting for current date. Execution in {} minutes", Duration.between(futureExecution, LocalDateTime.now()).toMinutes());
+            return new OpenMeteoModel(null, null, Collections.emptyList());
+        }
+
+        {
+            HttpRequest.Builder req = HttpRequest.newBuilder().GET()
+                    .url(URLBuilder.newBuilder(config.getAllowedStationURL()).build());
+
+            HttpResponse res = httpClient.send(req.build());
+
+            if (res.isError()) {
+                throw logger.throwing(new RuntimeException(String.format("Error while getting the metno stations from %s.", config.getAllowedStationURL())));
+            }
 
-        for (OpenMeteoConfig.Station station : config.getStations()) {
+            JsonArray listJSON = jsonToObject(res.getBody(), JsonArray.class);
+            for (JsonElement element : listJSON) {
+                JsonObject stationJSON = element.getAsJsonObject();
+                JsonObject geometryJSON = stationJSON.get("geometry").getAsJsonObject();
+                String geometryType = geometryJSON.get("type").getAsString();
+                if (geometryType.equals("Point")) {
+                    JsonArray coordinatesJSON = geometryJSON.get("coordinates").getAsJsonArray();
+                    stations.add(new Station(coordinatesJSON.get(0).getAsDouble(), coordinatesJSON.get(1).getAsDouble()));
+                }
+            }
+        }
 
+        List<JsonObject> results = new ArrayList<>(stations.size());
+        for (Station station : stations) {
             HttpRequest.Builder req = HttpRequest.newBuilder().GET()
                     .url(URLBuilder.newBuilder(config.getUrl())
-                            .addParam("latitude", Double.toString(station.latitude))
-                            .addParam("longitude", Double.toString(station.longitude))
-                            .addParam("timezone", station.timezone)
-                            .addParam("past_days", Integer.toString(station.past_days))
-                            .addParam("hourly", String.join(",", station.hourly))
+                            .addParam("latitude", Double.toString(station.getLatitude()))
+                            .addParam("longitude", Double.toString(station.getLongitude()))
+                            .addParam("start_date", currentDate.format(ofPattern("yyyy-MM-dd")))
+                            .addParam("end_date", currentDate.format(ofPattern("yyyy-MM-dd")))
+//                            .addParam("timezone", station.timezone)
+//                            .addParam("past_days", Integer.toString(station.past_days))
+                            .addParam("hourly", String.join(",", config.getHourly()))
+                            .addParam("models", config.getModels())
                             .build());
 
             HttpResponse res = httpClient.send(req.build());
 
             if (res.isError()) {
-                logger.warn("Open Meteo station lat: {}, lon: {} failed to fetch. Error: {}", station.latitude, station.longitude, res.getBody());
+                logger.warn("Open Meteo station lat: {}, lon: {} failed to fetch. Error: {}", station.getLatitude(), station.getLongitude(), res.getBody());
                 continue;
             }
 
@@ -61,6 +99,10 @@ public class OpenMeteoFetcher implements ConnectorFetcher<VoidSession, OpenMeteo
             results.add(geoJson);
         }
 
-        return new OpenMeteoModel(null, null, results);
+        OffsetDateTime currentDateTime = ZonedDateTime.of(currentDate, LocalTime.now(), config.getTimeZone().toZoneId()).toOffsetDateTime();
+
+        currentDate = currentDate.plusDays(1);
+
+        return new OpenMeteoModel(currentDateTime, currentDateTime, results);
     }
-}
+}

+ 19 - 0
connector-fetch-openmeteo/src/main/java/cz/senslog/connector/fetch/openmeteo/Station.java

@@ -0,0 +1,19 @@
+package cz.senslog.connector.fetch.openmeteo;
+
+public class Station {
+
+    private final double latitude, longitude;
+
+    public Station(double longitudeX, double latitudeY) {
+        this.latitude = latitudeY;
+        this.longitude = longitudeX;
+    }
+
+    public double getLatitude() {
+        return latitude;
+    }
+
+    public double getLongitude() {
+        return longitude;
+    }
+}

+ 35 - 22
connector-fetch-openmeteo/src/test/java/cz/senslog/connector/fetch/openmeteo/OpenMeteoFetcherTest.java

@@ -16,38 +16,51 @@ import static org.junit.jupiter.api.Assertions.*;
 class OpenMeteoFetcherTest {
 
     @Test
-    void fetch() {
+    void fetch() throws Exception {
         ConnectorFetchOpenMeteoProvider provider = new ConnectorFetchOpenMeteoProvider();
 
         DefaultConfig defaultConfig = new DefaultConfig("", null);
 
-        defaultConfig.setProperty("baseUrl", "https://previous-runs-api.open-meteo.com/v1/forecast");
+//        defaultConfig.setProperty("baseUrl", "https://previous-runs-api.open-meteo.com/v1/forecast");
+        defaultConfig.setProperty("baseUrl", "https://archive-api.open-meteo.com/v1/archive");
         defaultConfig.setProperty("timeZone", "Europe/Prague");
+        defaultConfig.setProperty("startDate", "2024-01-01");
 
-        Map<String, Object> st1 = new HashMap<String, Object>() {{
-            put("latitude", 49.72680307543005);
-            put("longitude", 13.351931666613327);
-            put("timezone", "GMT");
-            put("past_days", 1);
-            put("hourly", Arrays.asList("temperature_2m","temperature_2m_previous_day1","temperature_2m_previous_day2","temperature_2m_previous_day3","temperature_2m_previous_day4","temperature_2m_previous_day5",
-                    "relative_humidity_2m","relative_humidity_2m_previous_day1","relative_humidity_2m_previous_day2","relative_humidity_2m_previous_day3","relative_humidity_2m_previous_day4","relative_humidity_2m_previous_day5",
-                    "dew_point_2m","dew_point_2m_previous_day1","dew_point_2m_previous_day2","dew_point_2m_previous_day3","dew_point_2m_previous_day4","dew_point_2m_previous_day5",
-                    "apparent_temperature","apparent_temperature_previous_day1","apparent_temperature_previous_day2","apparent_temperature_previous_day3","apparent_temperature_previous_day4","apparent_temperature_previous_day5",
-                    "precipitation","precipitation_previous_day1","precipitation_previous_day2","precipitation_previous_day3","precipitation_previous_day4","precipitation_previous_day5",
-                    "rain","rain_previous_day1","rain_previous_day2","rain_previous_day3","rain_previous_day4","rain_previous_day5",
-                    "showers","showers_previous_day1","showers_previous_day2","showers_previous_day3","showers_previous_day4","showers_previous_day5",
-                    "snowfall","snowfall_previous_day1","snowfall_previous_day2","snowfall_previous_day3","snowfall_previous_day4","snowfall_previous_day5",
-                    "weather_code","weather_code_previous_day1","weather_code_previous_day2","weather_code_previous_day3","weather_code_previous_day4","weather_code_previous_day5",
-                    "pressure_msl","pressure_msl_previous_day1","pressure_msl_previous_day2","pressure_msl_previous_day3","pressure_msl_previous_day4","pressure_msl_previous_day5",
-                    "surface_pressure","surface_pressure_previous_day1","surface_pressure_previous_day2","surface_pressure_previous_day3","surface_pressure_previous_day4","surface_pressure_previous_day5",
-                    "cloud_cover","cloud_cover_previous_day1","cloud_cover_previous_day2","cloud_cover_previous_day3","cloud_cover_previous_day4","cloud_cover_previous_day5",
-                    "wind_speed_10m","wind_speed_10m_previous_day1","wind_speed_10m_previous_day2","wind_speed_10m_previous_day3","wind_speed_10m_previous_day4","wind_speed_10m_previous_day5",
-                    "wind_direction_10m","wind_direction_10m_previous_day1","wind_direction_10m_previous_day2","wind_direction_10m_previous_day3","wind_direction_10m_previous_day4","wind_direction_10m_previous_day5"));
+        defaultConfig.setProperty("allowedStationURL", "https://sensor.lesprojekt.cz/senslogOTS3/rest/forecast/era5land/plan");
+        Map<String, Object> params = new HashMap<String, Object>(){{
+            put("models", "era5_land");
+            put("hourly", Arrays.asList("temperature_2m", "relative_humidity_2m", "dew_point_2m", "precipitation", "rain", "snowfall", "pressure_msl", "surface_pressure",
+                    "et0_fao_evapotranspiration", "cloud_cover","wind_speed_10m", "wind_direction_10m", "wind_gusts_10m",
+                    "soil_temperature_0_to_7cm","soil_temperature_7_to_28cm","soil_temperature_28_to_100cm","soil_temperature_100_to_255cm",
+                    "soil_moisture_0_to_7cm","soil_moisture_7_to_28cm","soil_moisture_28_to_100cm","soil_moisture_100_to_255cm"));
         }};
+        defaultConfig.setProperty("allowedStationURLParams", params);
 
-        defaultConfig.setProperty("allowedStations", Collections.singletonList(st1));
+//        Map<String, Object> st1 = new HashMap<String, Object>() {{
+//            put("latitude", 49.72680307543005);
+//            put("longitude", 13.351931666613327);
+//            put("timezone", "GMT");
+//            put("past_days", 1);
+//            put("hourly", Arrays.asList("temperature_2m","temperature_2m_previous_day1","temperature_2m_previous_day2","temperature_2m_previous_day3","temperature_2m_previous_day4","temperature_2m_previous_day5",
+//                    "relative_humidity_2m","relative_humidity_2m_previous_day1","relative_humidity_2m_previous_day2","relative_humidity_2m_previous_day3","relative_humidity_2m_previous_day4","relative_humidity_2m_previous_day5",
+//                    "dew_point_2m","dew_point_2m_previous_day1","dew_point_2m_previous_day2","dew_point_2m_previous_day3","dew_point_2m_previous_day4","dew_point_2m_previous_day5",
+//                    "apparent_temperature","apparent_temperature_previous_day1","apparent_temperature_previous_day2","apparent_temperature_previous_day3","apparent_temperature_previous_day4","apparent_temperature_previous_day5",
+//                    "precipitation","precipitation_previous_day1","precipitation_previous_day2","precipitation_previous_day3","precipitation_previous_day4","precipitation_previous_day5",
+//                    "rain","rain_previous_day1","rain_previous_day2","rain_previous_day3","rain_previous_day4","rain_previous_day5",
+//                    "showers","showers_previous_day1","showers_previous_day2","showers_previous_day3","showers_previous_day4","showers_previous_day5",
+//                    "snowfall","snowfall_previous_day1","snowfall_previous_day2","snowfall_previous_day3","snowfall_previous_day4","snowfall_previous_day5",
+//                    "weather_code","weather_code_previous_day1","weather_code_previous_day2","weather_code_previous_day3","weather_code_previous_day4","weather_code_previous_day5",
+//                    "pressure_msl","pressure_msl_previous_day1","pressure_msl_previous_day2","pressure_msl_previous_day3","pressure_msl_previous_day4","pressure_msl_previous_day5",
+//                    "surface_pressure","surface_pressure_previous_day1","surface_pressure_previous_day2","surface_pressure_previous_day3","surface_pressure_previous_day4","surface_pressure_previous_day5",
+//                    "cloud_cover","cloud_cover_previous_day1","cloud_cover_previous_day2","cloud_cover_previous_day3","cloud_cover_previous_day4","cloud_cover_previous_day5",
+//                    "wind_speed_10m","wind_speed_10m_previous_day1","wind_speed_10m_previous_day2","wind_speed_10m_previous_day3","wind_speed_10m_previous_day4","wind_speed_10m_previous_day5",
+//                    "wind_direction_10m","wind_direction_10m_previous_day1","wind_direction_10m_previous_day2","wind_direction_10m_previous_day3","wind_direction_10m_previous_day4","wind_direction_10m_previous_day5"));
+//        }};
+
+//        defaultConfig.setProperty("allowedStations", Collections.singletonList(st1));
 
         ExecutableFetcher<OpenMeteoModel> fetcher = provider.createExecutableFetcher(defaultConfig);
+        fetcher.getRawFetcher().init();
         fetcher.execute();
 
     }

+ 6 - 6
connector-fetch-senslog-telemetry/src/test/java/cz/senslog/connector/fetch/senslog/telemetry/SensLogTelemetryFetcherTest.java

@@ -2,6 +2,7 @@ package cz.senslog.connector.fetch.senslog.telemetry;
 
 import cz.senslog.connector.fetch.api.ExecutableFetcher;
 import cz.senslog.connector.model.api.GeoJsonModel;
+import cz.senslog.connector.model.api.VoidSession;
 import cz.senslog.connector.model.config.DefaultConfig;
 import cz.senslog.connector.tools.http.HttpClient;
 import org.junit.jupiter.api.Test;
@@ -16,9 +17,9 @@ class SensLogTelemetryFetcherTest {
 
         DefaultConfig defaultConfig = new DefaultConfig("", null);
 //        defaultConfig.setProperty("startAt", "now");
-        defaultConfig.setProperty("startAt", "2024-12-01T10:09:00+00:00"); // 2024-12-01T10:09:34.589Z
+        defaultConfig.setProperty("startAt", "2025-02-20T00:00:00+00:00"); // 2024-12-01T10:09:34.589Z
         defaultConfig.setProperty("bearerToken", "#123");
-        defaultConfig.setProperty("limit", 100);
+        defaultConfig.setProperty("limit", 500);
         defaultConfig.setProperty("interval", 1);
 
 //        defaultConfig.setProperty("baseUrl", "http://127.0.0.1:8085");
@@ -32,7 +33,7 @@ class SensLogTelemetryFetcherTest {
         defaultConfig.setProperty("campaignId", 4);
         defaultConfig.setProperty("actionId", 1);
         defaultConfig.setProperty("entityId", 1);
-        defaultConfig.setProperty("allowedStations", Arrays.asList(1305167563014004L, 1305167563048283L));
+        defaultConfig.setProperty("allowedStations", Arrays.asList(1305167562660700L));
 
 
         SensLogTelemetryConfig config = new SensLogTelemetryConfig(defaultConfig);
@@ -40,8 +41,7 @@ class SensLogTelemetryFetcherTest {
         ExecutableFetcher<GeoJsonModel> executor = ExecutableFetcher.create(fetcher);
 
         fetcher.init();
-        for (int i = 0; i < 10; i++) {
-            executor.execute();
-        }
+        GeoJsonModel geoJsonModel = executor.execute();
+        System.out.println(geoJsonModel.getGeoJson());
     }
 }

+ 35 - 2
connector-model/src/main/java/cz/senslog/connector/model/converter/FofrModelTelemetryModelConverter.java

@@ -1,18 +1,51 @@
 package cz.senslog.connector.model.converter;
 
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
 import cz.senslog.connector.model.api.Converter;
 import cz.senslog.connector.model.fofr.FofrModel;
+import cz.senslog.connector.model.fofr.LocationTrack;
 import cz.senslog.connector.model.fofr.ParcelUpdate;
 import cz.senslog.connector.model.logger.LoggerModel;
 import cz.senslog.connector.model.telemetry.TelemetryModel;
+import org.json.JSONObject;
 
+import java.time.format.DateTimeFormatter;
 import java.util.Arrays;
 
 public class FofrModelTelemetryModelConverter implements Converter<FofrModel, TelemetryModel> {
 
     @Override
     public TelemetryModel convert(FofrModel model) {
-        String body = Arrays.toString(model.getUpdates().toArray(new ParcelUpdate[0]));
-        return new TelemetryModel(body, model.getFrom(), model.getTo());
+
+        JsonObject geoJSON = new JsonObject();
+        geoJSON.addProperty("type", "FeatureCollection");
+        JsonArray features = new JsonArray();
+        geoJSON.add("features", features);
+
+        for (ParcelUpdate update : model.getUpdates()) {
+            for (LocationTrack location : update.getLocations()) {
+                JsonObject feature = new JsonObject();
+                features.add(feature);
+                feature.addProperty("type", "Feature");
+
+                JsonObject properties = new JsonObject();
+                feature.add("properties", properties);
+                properties.addProperty("unitId", update.getUnitId());
+                properties.addProperty("timestamp", location.getTimestamp().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
+
+                JsonObject geometry = new JsonObject();
+                feature.add("geometry", geometry);
+                geometry.addProperty("type", "Point");
+                JsonArray coordinates = new JsonArray();
+                coordinates.add(location.getLongitude());
+                coordinates.add(location.getLatitude());
+                coordinates.add(0); // altitude
+                geometry.add("coordinates", coordinates);
+
+            }
+        }
+
+        return new TelemetryModel(geoJSON.toString(), model.getFrom(), model.getTo());
     }
 }

+ 1 - 1
connector-model/src/main/java/cz/senslog/connector/model/converter/MetnoToSensLogConverter.java

@@ -14,7 +14,7 @@ public class MetnoToSensLogConverter implements Converter<MetnoModel, SensLogMod
     @Override
     public SensLogModel convert(MetnoModel model) {
         if (model == null) {
-             return null;
+            return null;
         }
 
         if (model.getPredictions() == null || model.getPredictions().isEmpty()) {

+ 28 - 0
connector-model/src/main/java/cz/senslog/connector/model/fofr/LocationTrack.java

@@ -0,0 +1,28 @@
+package cz.senslog.connector.model.fofr;
+
+import java.time.OffsetDateTime;
+
+public class LocationTrack {
+
+    private final OffsetDateTime timestamp;
+    private final double latitude;
+    private final double longitude;
+
+    public LocationTrack(OffsetDateTime timestamp, double latitude, double longitude) {
+        this.timestamp = timestamp;
+        this.latitude = latitude;
+        this.longitude = longitude;
+    }
+
+    public OffsetDateTime getTimestamp() {
+        return timestamp;
+    }
+
+    public double getLatitude() {
+        return latitude;
+    }
+
+    public double getLongitude() {
+        return longitude;
+    }
+}

+ 16 - 0
connector-model/src/main/java/cz/senslog/connector/model/fofr/ParcelUpdate.java

@@ -1,6 +1,22 @@
 package cz.senslog.connector.model.fofr;
 
+import java.util.List;
+
 public class ParcelUpdate {
 
+    private final long unitId;
+    private final List<LocationTrack> locationTracks;
+
+    public ParcelUpdate(long unitId, List<LocationTrack> locationTracks) {
+        this.unitId = unitId;
+        this.locationTracks = locationTracks;
+    }
+
+    public long getUnitId() {
+        return unitId;
+    }
 
+    public List<LocationTrack> getLocations() {
+        return locationTracks;
+    }
 }

+ 2 - 1
connector-push-senslog/src/main/java/cz/senslog/connector/push/senslog/SensLogPusher.java

@@ -54,6 +54,7 @@ public class SensLogPusher implements ConnectorPusher<SensLogModel> {
 
         }
 
-        logger.info("Pushed {}/{} payloads.", successfullyPushed, model.getPassThroughData().size());
+        int totalSize = model.getPassThroughData().size();
+        logger.info("Pushed {}/{} payloads. For the time <{} - {}>", successfullyPushed, totalSize, model.getFrom(), model.getTo());
     }
 }

+ 1 - 1
connector-tools/src/main/java/cz/senslog/connector/tools/http/HttpContentType.java

@@ -4,7 +4,7 @@ public final class HttpContentType {
     public final static String APPLICATION_ATOM_XML         = "application/atom+xml";
     public final static String APPLICATION_FORM_URLENCODED  = "application/x-www-form-urlencoded";
     public final static String APPLICATION_JSON             = "application/json";
-    public final static String APPLICATION_GEO_JSON         = "application/geojson";
+    public final static String APPLICATION_GEO_JSON         = "application/geo+json";
     public final static String APPLICATION_OCTET_STREAM     = "application/octet-stream";
     public final static String APPLICATION_SVG_XML          = "application/svg+xml";
     public final static String APPLICATION_XHTML_XML        = "application/xhtml+xml";