Browse Source

OpenMeteo Connector, Fix of Metno, Update of Fofr

Lukas Cerny 10 tháng trước cách đây
mục cha
commit
240381f6a2
18 tập tin đã thay đổi với 339 bổ sung125 xóa
  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";