Browse Source

Added MET.NO to SensLog and OpenMeteo to SensLog

Lukas Cerny 11 tháng trước cách đây
mục cha
commit
355cd32e4e
29 tập tin đã thay đổi với 981 bổ sung18 xóa
  1. 26 0
      config/metnoToSenslog.yaml
  2. 41 0
      config/openMeteoToSenslog.yaml
  3. 32 0
      connector-fetch-metno/pom.xml
  4. 34 0
      connector-fetch-metno/src/main/java/cz/senslog/connector/fetch/metno/ConnectorFetchMetnoProvider.java
  5. 47 0
      connector-fetch-metno/src/main/java/cz/senslog/connector/fetch/metno/MetnoConfig.java
  6. 95 0
      connector-fetch-metno/src/main/java/cz/senslog/connector/fetch/metno/MetnoFetcher.java
  7. 29 0
      connector-fetch-metno/src/main/java/cz/senslog/connector/fetch/metno/Station.java
  8. 1 0
      connector-fetch-metno/src/main/resources/META-INF/services/cz.senslog.connector.fetch.api.ConnectorFetchProvider
  9. 35 0
      connector-fetch-metno/src/test/java/cz/senslog/connector/fetch/metno/MetnoFetcherTest.java
  10. 32 0
      connector-fetch-openmeteo/pom.xml
  11. 35 0
      connector-fetch-openmeteo/src/main/java/cz/senslog/connector/fetch/openmeteo/ConnectorFetchOpenMeteoProvider.java
  12. 52 0
      connector-fetch-openmeteo/src/main/java/cz/senslog/connector/fetch/openmeteo/OpenMeteoConfig.java
  13. 66 0
      connector-fetch-openmeteo/src/main/java/cz/senslog/connector/fetch/openmeteo/OpenMeteoFetcher.java
  14. 1 0
      connector-fetch-openmeteo/src/main/resources/META-INF/services/cz.senslog.connector.fetch.api.ConnectorFetchProvider
  15. 54 0
      connector-fetch-openmeteo/src/test/java/cz/senslog/connector/fetch/openmeteo/OpenMeteoFetcherTest.java
  16. 56 18
      connector-model/src/main/java/cz/senslog/connector/model/config/PropertyConfig.java
  17. 31 0
      connector-model/src/main/java/cz/senslog/connector/model/converter/MetnoToSensLogConverter.java
  18. 2 0
      connector-model/src/main/java/cz/senslog/connector/model/converter/ModelConverterProvider.java
  19. 31 0
      connector-model/src/main/java/cz/senslog/connector/model/converter/OpenMeteoToSensLogConverter.java
  20. 21 0
      connector-model/src/main/java/cz/senslog/connector/model/metno/MetnoModel.java
  21. 21 0
      connector-model/src/main/java/cz/senslog/connector/model/openmeteo/OpenMeteoModel.java
  22. 47 0
      connector-model/src/main/java/cz/senslog/connector/model/senslog/SensLogModel.java
  23. 39 0
      connector-push-senslog/pom.xml
  24. 29 0
      connector-push-senslog/src/main/java/cz/senslog/connector/push/senslog/ConnectorPushSensLogProvider.java
  25. 16 0
      connector-push-senslog/src/main/java/cz/senslog/connector/push/senslog/SensLogConfig.java
  26. 59 0
      connector-push-senslog/src/main/java/cz/senslog/connector/push/senslog/SensLogPusher.java
  27. 1 0
      connector-push-senslog/src/main/resources/META-INF/services/cz.senslog.connector.push.api.ConnectorPushProvider
  28. 26 0
      docker-compose.yaml
  29. 22 0
      pom.xml

+ 26 - 0
config/metnoToSenslog.yaml

@@ -0,0 +1,26 @@
+settings:
+  - Metno:
+      name: "Metno"
+      provider: "cz.senslog.connector.fetch.metno.ConnectorFetchMetnoProvider"
+
+      baseUrl: "https://api.met.no/weatherapi/locationforecast/2.0/complete"
+      timeZone: "Europe/Prague"
+
+#      allowedStations:
+#        - location: [13.351931666613327, 49.72680307543005] # [lon, lat]
+
+      allowedStationURL: "https://sensor.lesprojekt.cz/senslogOTS3/rest/forecast/locationforecast/plan"
+
+  - Senslog:
+      name: "Senslog Pass Trough"
+      provider: "cz.senslog.connector.push.senslog.ConnectorPushSensLogProvider"
+
+      baseUrl: "https://sensor.lesprojekt.cz/senslogOTS3/rest/forecast/locationforecast"
+
+connectors:
+  - MetnoSenslog:
+      fetcher: "Metno"
+      pusher: "Senslog"
+      period: 3_600          # seconds
+#      startAt: "02:30:00" # hh:mm:ss  # non-mandatory attribute
+      initDelay: 10        # non-mandatory attribute

+ 41 - 0
config/openMeteoToSenslog.yaml

@@ -0,0 +1,41 @@
+settings:
+  - OpenMeteo:
+      name: "Open Meteo"
+      provider: "cz.senslog.connector.fetch.openmeteo.ConnectorFetchOpenMeteoProvider"
+
+      baseUrl: "https://previous-runs-api.open-meteo.com/v1/forecast"
+      timeZone: "Europe/Prague"
+
+      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"
+
+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

+ 32 - 0
connector-fetch-metno/pom.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>cz.senslog</groupId>
+        <artifactId>connector-period</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>connector-fetch-metno</artifactId>
+    <name>fetch-metno</name>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>cz.senslog</groupId>
+            <artifactId>connector-fetch-api</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 34 - 0
connector-fetch-metno/src/main/java/cz/senslog/connector/fetch/metno/ConnectorFetchMetnoProvider.java

@@ -0,0 +1,34 @@
+package cz.senslog.connector.fetch.metno;
+
+import cz.senslog.connector.fetch.api.ConnectorFetchProvider;
+import cz.senslog.connector.fetch.api.ExecutableFetcher;
+import cz.senslog.connector.model.config.DefaultConfig;
+import cz.senslog.connector.model.metno.MetnoModel;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import static cz.senslog.connector.tools.http.HttpClient.newHttpClient;
+
+public class ConnectorFetchMetnoProvider implements ConnectorFetchProvider {
+
+    private static final Logger logger = LogManager.getLogger(ConnectorFetchMetnoProvider.class);
+
+    @Override
+    public ExecutableFetcher<MetnoModel> createExecutableFetcher(DefaultConfig defaultConfig) {
+        logger.info("Initialization a new fetch provider {}.", ConnectorFetchMetnoProvider.class);
+
+        logger.debug("Creating a new configuration.");
+        MetnoConfig config = new MetnoConfig(defaultConfig);
+        logger.info("Configuration for {} was created successfully.", MetnoFetcher.class);
+
+
+        logger.debug("Creating a new instance of {}.", MetnoFetcher.class);
+        MetnoFetcher fetcher = new MetnoFetcher(config, newHttpClient());
+        logger.info("Fetcher for {} was created successfully.", MetnoFetcher.class);
+
+        ExecutableFetcher<MetnoModel> executor = ExecutableFetcher.create(fetcher);
+        logger.info("Fetcher executor for {} was created successfully.", MetnoFetcher.class);
+
+        return executor;
+    }
+}

+ 47 - 0
connector-fetch-metno/src/main/java/cz/senslog/connector/fetch/metno/MetnoConfig.java

@@ -0,0 +1,47 @@
+package cz.senslog.connector.fetch.metno;
+
+import cz.senslog.connector.model.config.DefaultConfig;
+import cz.senslog.connector.model.config.PropertyConfig;
+
+import java.util.*;
+
+public class MetnoConfig {
+
+    private final String url;
+    private final TimeZone timeZone;
+    private final List<Station> stations;
+    private final String allowedStationURL;
+
+    MetnoConfig(DefaultConfig defaultConfig) {
+        this.url = defaultConfig.getStringProperty("baseUrl");
+        this.timeZone = TimeZone.getTimeZone(defaultConfig.getStringProperty("timeZone"));
+
+        this.allowedStationURL = defaultConfig.containsProperty("allowedStationURL") ? defaultConfig.getStringProperty("allowedStationURL") : null;
+        Set<PropertyConfig> stations = defaultConfig.containsProperty("allowedStations") ? defaultConfig.getSetProperty("allowedStations") : Collections.emptySet();
+        this.stations = new ArrayList<>(stations.size());
+        for (PropertyConfig station : stations) {
+            List<Double> locations = station.getListProperty("location", Double.class);
+            this.stations.add(new Station(locations.get(0), locations.get(1)));
+        }
+
+        if (allowedStationURL == null && this.stations.isEmpty()) {
+            throw new IllegalStateException("Metno config requires at least one station");
+        }
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public TimeZone getTimeZone() {
+        return timeZone;
+    }
+
+    public List<Station> getStations() {
+        return stations;
+    }
+
+    public String getAllowedStationURL() {
+        return allowedStationURL;
+    }
+}

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

@@ -0,0 +1,95 @@
+package cz.senslog.connector.fetch.metno;
+
+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;
+import cz.senslog.connector.model.metno.MetnoModel;
+import cz.senslog.connector.tools.http.HttpClient;
+import cz.senslog.connector.tools.http.HttpRequest;
+import cz.senslog.connector.tools.http.HttpResponse;
+import cz.senslog.connector.tools.http.URLBuilder;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.time.OffsetDateTime;
+import java.util.*;
+
+import static cz.senslog.connector.tools.json.BasicJson.jsonToObject;
+
+public class MetnoFetcher implements ConnectorFetcher<VoidSession, MetnoModel> {
+
+    private static final Logger logger = LogManager.getLogger(MetnoFetcher.class);
+
+    private final MetnoConfig config;
+    private final HttpClient httpClient;
+    private final Set<Station> stations;
+
+
+    public MetnoFetcher(MetnoConfig config, HttpClient httpClient) {
+        this.config = config;
+        this.httpClient = httpClient;
+        this.stations = new HashSet<>();
+    }
+
+    @Override
+    public void init() throws Exception {
+
+        stations.addAll(config.getStations());
+
+        if (config.getAllowedStationURL() != null) {
+            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())));
+            }
+
+            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()));
+                }
+            }
+        }
+
+    }
+
+    @Override
+    public MetnoModel fetch(Optional<VoidSession> session) {
+
+
+        List<JsonObject> predictions = new ArrayList<>(config.getStations().size());
+
+        OffsetDateTime minPredictionDate = OffsetDateTime.MAX;
+        OffsetDateTime maxPredictionDate = OffsetDateTime.MIN;
+
+        for (Station station : stations) {
+
+            HttpRequest.Builder req = HttpRequest.newBuilder().GET()
+                    .url(URLBuilder.newBuilder(config.getUrl())
+                            .addParam("lon", Double.toString(station.getLongitude()))
+                            .addParam("lat", Double.toString(station.getLatitude()))
+                            .build());
+
+            HttpResponse res = httpClient.send(req.build());
+
+            if (res.isError()) {
+                logger.warn("Metno station lat: {}, lon: {} failed to fetch. Error: {}", station.getLatitude(), station.getLongitude(), res.getBody());
+                continue;
+            }
+
+            JsonObject geoJson = jsonToObject(res.getBody(), JsonObject.class);
+            predictions.add(geoJson);
+        }
+
+        return new MetnoModel(minPredictionDate, maxPredictionDate, predictions);
+    }
+}

+ 29 - 0
connector-fetch-metno/src/main/java/cz/senslog/connector/fetch/metno/Station.java

@@ -0,0 +1,29 @@
+package cz.senslog.connector.fetch.metno;
+
+import cz.senslog.connector.model.config.PropertyConfig;
+
+import java.util.List;
+
+public class Station {
+
+    private double latitude, longitude;
+
+    Station(PropertyConfig stationConfig) {
+        List<Double> locations = stationConfig.getListProperty("location", Double.class);
+        this.longitude = locations.get(0);
+        this.latitude = locations.get(1);
+    }
+
+    Station(double latitude, double longitude) {
+        this.latitude = latitude;
+        this.longitude = longitude;
+    }
+
+    public double getLatitude() {
+        return latitude;
+    }
+
+    public double getLongitude() {
+        return longitude;
+    }
+}

+ 1 - 0
connector-fetch-metno/src/main/resources/META-INF/services/cz.senslog.connector.fetch.api.ConnectorFetchProvider

@@ -0,0 +1 @@
+cz.senslog.connector.fetch.metno.ConnectorFetchMetnoProvider

+ 35 - 0
connector-fetch-metno/src/test/java/cz/senslog/connector/fetch/metno/MetnoFetcherTest.java

@@ -0,0 +1,35 @@
+package cz.senslog.connector.fetch.metno;
+
+import cz.senslog.connector.fetch.api.ExecutableFetcher;
+import cz.senslog.connector.model.config.DefaultConfig;
+import cz.senslog.connector.model.converter.MetnoToSensLogConverter;
+import cz.senslog.connector.model.metno.MetnoModel;
+import org.junit.jupiter.api.Test;
+
+import java.util.*;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class MetnoFetcherTest {
+
+    @Test
+    void fetch() throws Exception {
+        ConnectorFetchMetnoProvider provider = new ConnectorFetchMetnoProvider();
+
+        DefaultConfig defaultConfig = new DefaultConfig("", null);
+
+        defaultConfig.setProperty("baseUrl", "https://api.met.no/weatherapi/locationforecast/2.0/complete");
+        defaultConfig.setProperty("timeZone", "Europe/Prague");
+
+        Map<String, Object> st1 = new HashMap<String, Object>() {{
+            put("location", Arrays.asList(13.351931666613327, 49.72680307543005));
+        }};
+
+//        defaultConfig.setProperty("allowedStations", Collections.singletonList(st1));
+        defaultConfig.setProperty("allowedStationURL", "https://sensor.lesprojekt.cz/senslogOTS3/rest/forecast/locationforecast/plan");
+
+        ExecutableFetcher<MetnoModel> fetcher = provider.createExecutableFetcher(defaultConfig);
+        fetcher.getRawFetcher().init();
+        fetcher.execute();
+    }
+}

+ 32 - 0
connector-fetch-openmeteo/pom.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>cz.senslog</groupId>
+        <artifactId>connector-period</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>connector-fetch-openmeteo</artifactId>
+    <name>fetch-openmeteo</name>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>cz.senslog</groupId>
+            <artifactId>connector-fetch-api</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 35 - 0
connector-fetch-openmeteo/src/main/java/cz/senslog/connector/fetch/openmeteo/ConnectorFetchOpenMeteoProvider.java

@@ -0,0 +1,35 @@
+package cz.senslog.connector.fetch.openmeteo;
+
+import cz.senslog.connector.fetch.api.ConnectorFetchProvider;
+import cz.senslog.connector.fetch.api.ExecutableFetcher;
+import cz.senslog.connector.model.config.DefaultConfig;
+import cz.senslog.connector.model.openmeteo.OpenMeteoModel;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import static cz.senslog.connector.tools.http.HttpClient.newHttpClient;
+
+public class ConnectorFetchOpenMeteoProvider implements ConnectorFetchProvider  {
+
+    private static final Logger logger = LogManager.getLogger(ConnectorFetchOpenMeteoProvider.class);
+
+
+    @Override
+    public ExecutableFetcher<OpenMeteoModel> createExecutableFetcher(DefaultConfig defaultConfig) {
+        logger.info("Initialization a new fetch provider {}.", ConnectorFetchOpenMeteoProvider.class);
+
+        logger.debug("Creating a new configuration.");
+        OpenMeteoConfig config = new OpenMeteoConfig(defaultConfig);
+        logger.info("Configuration for {} was created successfully.", OpenMeteoFetcher.class);
+
+
+        logger.debug("Creating a new instance of {}.", OpenMeteoFetcher.class);
+        OpenMeteoFetcher fetcher = new OpenMeteoFetcher(config, newHttpClient());
+        logger.info("Fetcher for {} was created successfully.", OpenMeteoFetcher.class);
+
+        ExecutableFetcher<OpenMeteoModel> executor = ExecutableFetcher.create(fetcher);
+        logger.info("Fetcher executor for {} was created successfully.", OpenMeteoFetcher.class);
+
+        return executor;
+    }
+}

+ 52 - 0
connector-fetch-openmeteo/src/main/java/cz/senslog/connector/fetch/openmeteo/OpenMeteoConfig.java

@@ -0,0 +1,52 @@
+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;
+
+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;
+
+    OpenMeteoConfig(DefaultConfig defaultConfig) {
+        this.url = defaultConfig.getStringProperty("baseUrl");
+        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));
+        }
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public TimeZone getTimeZone() {
+        return timeZone;
+    }
+
+    public List<Station> getStations() {
+        return stations;
+    }
+}

+ 66 - 0
connector-fetch-openmeteo/src/main/java/cz/senslog/connector/fetch/openmeteo/OpenMeteoFetcher.java

@@ -0,0 +1,66 @@
+package cz.senslog.connector.fetch.openmeteo;
+
+import com.google.gson.JsonObject;
+import cz.senslog.connector.fetch.api.ConnectorFetcher;
+import cz.senslog.connector.model.api.VoidSession;
+import cz.senslog.connector.model.openmeteo.OpenMeteoModel;
+import cz.senslog.connector.tools.http.HttpClient;
+import cz.senslog.connector.tools.http.HttpRequest;
+import cz.senslog.connector.tools.http.HttpResponse;
+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 static cz.senslog.connector.tools.json.BasicJson.jsonToObject;
+
+public class OpenMeteoFetcher implements ConnectorFetcher<VoidSession, OpenMeteoModel> {
+
+    private static final Logger logger = LogManager.getLogger(OpenMeteoFetcher.class);
+
+    private final HttpClient httpClient;
+    private final OpenMeteoConfig config;
+
+    public OpenMeteoFetcher(OpenMeteoConfig config, HttpClient httpClient) {
+        this.httpClient = httpClient;
+        this.config = config;
+    }
+
+    @Override
+    public void init() throws Exception {
+
+    }
+
+    @Override
+    public OpenMeteoModel fetch(Optional<VoidSession> session) {
+
+        List<JsonObject> results = new ArrayList<>(config.getStations().size());
+
+        for (OpenMeteoConfig.Station station : config.getStations()) {
+
+            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))
+                            .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());
+                continue;
+            }
+
+            JsonObject geoJson = jsonToObject(res.getBody(), JsonObject.class);
+            results.add(geoJson);
+        }
+
+        return new OpenMeteoModel(null, null, results);
+    }
+}

+ 1 - 0
connector-fetch-openmeteo/src/main/resources/META-INF/services/cz.senslog.connector.fetch.api.ConnectorFetchProvider

@@ -0,0 +1 @@
+cz.senslog.connector.fetch.openmeteo.ConnectorFetchOpenMeteoProvider

+ 54 - 0
connector-fetch-openmeteo/src/test/java/cz/senslog/connector/fetch/openmeteo/OpenMeteoFetcherTest.java

@@ -0,0 +1,54 @@
+package cz.senslog.connector.fetch.openmeteo;
+
+import cz.senslog.connector.fetch.api.ExecutableFetcher;
+import cz.senslog.connector.model.config.DefaultConfig;
+import cz.senslog.connector.model.metno.MetnoModel;
+import cz.senslog.connector.model.openmeteo.OpenMeteoModel;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class OpenMeteoFetcherTest {
+
+    @Test
+    void fetch() {
+        ConnectorFetchOpenMeteoProvider provider = new ConnectorFetchOpenMeteoProvider();
+
+        DefaultConfig defaultConfig = new DefaultConfig("", null);
+
+        defaultConfig.setProperty("baseUrl", "https://previous-runs-api.open-meteo.com/v1/forecast");
+        defaultConfig.setProperty("timeZone", "Europe/Prague");
+
+        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.execute();
+
+    }
+}

+ 56 - 18
connector-model/src/main/java/cz/senslog/connector/model/config/PropertyConfig.java

@@ -5,8 +5,8 @@ package cz.senslog.connector.model.config;
 
 import cz.senslog.connector.tools.exception.PropertyNotFoundException;
 import cz.senslog.connector.tools.util.ClassUtils;
-import cz.senslog.connector.tools.util.LocalDateTimeUtils;
 
+import java.lang.reflect.Array;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
@@ -15,6 +15,8 @@ import java.time.format.DateTimeFormatter;
 import java.util.*;
 
 import static java.lang.String.format;
+import static java.lang.String.valueOf;
+import static java.util.Collections.emptyList;
 import static java.util.Collections.emptySet;
 import static java.util.Optional.ofNullable;
 
@@ -116,6 +118,15 @@ public class PropertyConfig {
     }
 
     /**
+     * Returns property as a Double object.
+     * @param name - name of property.
+     * @return double value.
+     */
+    public Double getDoubleProperty(String name) {
+        return ClassUtils.cast(getProperty(name), Double.class);
+    }
+
+    /**
      * Returns property as a LocalDateTime.
      * @param name - name of property.
      * @return localDateTime value.
@@ -202,22 +213,54 @@ public class PropertyConfig {
      */
     public <T> Set<T> getSetProperty(String name, Class<T> type) {
         Object value = properties.get(name);
-
-        if (value instanceof  List) {
-            List<Object> list = (List<Object>) value;
+        if (value instanceof  Collection) {
+            Collection<?> list = (Collection<?>) value;
             Set<T> res = new HashSet<>(list.size());
             for (Object o : list) {
                 res.add(ClassUtils.cast(o, type));
             }
             return res;
-        } else if (value instanceof Set) {
-            Set<?> set = (Set<?>) value;
-            Set<T> res = new HashSet<>(set.size());
-            for (Object o : set) {
+        }
+
+        return emptySet();
+    }
+
+    public <T> List<T> getListProperty(String name, Class<T> type) {
+        Object object = getProperty(name);
+        if (object instanceof Collection) {
+            Collection<?> list = (Collection<?>) object;
+            List<T> res = new ArrayList<>(list.size());
+            for (Object o : list) {
                 res.add(ClassUtils.cast(o, type));
             }
             return res;
         }
+        return emptyList();
+    }
+
+    private static PropertyConfig mapMapObjectoToPropertyConfig(String id, Object mapObject) {
+        PropertyConfig config = new PropertyConfig(id);
+        if (mapObject instanceof Map) {
+            Map<?, ?> properties = (Map<?, ?>) mapObject;
+            for (Map.Entry<?, ?> propertyEntry : properties.entrySet()) {
+                config.setProperty(propertyEntry.getKey().toString(), propertyEntry.getValue());
+            }
+        }
+        return config;
+    }
+
+    public Set<PropertyConfig> getSetProperty(String name) {
+        Object value = properties.get(name);
+        if (value instanceof  Collection) {
+            Collection<?> collection = (Collection<?>) value;
+            Iterator<?> iter = collection.iterator();
+            Set<PropertyConfig> res = new HashSet<>(collection.size());
+            int index = 0;
+            while (iter.hasNext()) {
+                res.add(mapMapObjectoToPropertyConfig(getNewPropertyId(name, index++), iter.next()));
+            }
+            return res;
+        }
 
         return emptySet();
     }
@@ -229,16 +272,7 @@ public class PropertyConfig {
      */
     public PropertyConfig getPropertyConfig(String name) {
         Object property = getProperty(name);
-        PropertyConfig config = new PropertyConfig(getNewPropertyId(name));
-
-        if (property instanceof Map) {
-            Map<String, Object> properties = (Map<String, Object>) property;
-            for (Map.Entry<String, Object> propertyEntry : properties.entrySet()) {
-                config.setProperty(propertyEntry.getKey(), propertyEntry.getValue());
-            }
-        }
-
-        return config;
+        return mapMapObjectoToPropertyConfig(getNewPropertyId(name), property);
     }
 
     public Set<String> getAttributes() {
@@ -249,6 +283,10 @@ public class PropertyConfig {
         return id + PATH_DELIMITER + name;
     }
 
+    private String getNewPropertyId(String name, int index) {
+        return getNewPropertyId(name) + PATH_DELIMITER + index;
+    }
+
     public String getId() {
         return id;
     }

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

@@ -0,0 +1,31 @@
+package cz.senslog.connector.model.converter;
+
+import com.google.gson.JsonObject;
+import cz.senslog.connector.model.api.Converter;
+import cz.senslog.connector.model.metno.MetnoModel;
+import cz.senslog.connector.model.senslog.SensLogModel;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class MetnoToSensLogConverter implements Converter<MetnoModel, SensLogModel> {
+
+    @Override
+    public SensLogModel convert(MetnoModel model) {
+        if (model == null) {
+             return null;
+        }
+
+        if (model.getPredictions() == null || model.getPredictions().isEmpty()) {
+            return new SensLogModel(model.getFrom(), model.getTo(), Collections.emptyList());
+        }
+
+        List<SensLogModel.PassingData> data = new ArrayList<>(model.getPredictions().size());
+        for (JsonObject prediction : model.getPredictions()) {
+            data.add(new SensLogModel.PassingData(prediction.toString()));
+        }
+
+        return new SensLogModel(model.getFrom(), model.getTo(), data);
+    }
+}

+ 2 - 0
connector-model/src/main/java/cz/senslog/connector/model/converter/ModelConverterProvider.java

@@ -31,5 +31,7 @@ public class ModelConverterProvider extends ConverterProvider {
         register(DemoModelLoggerModelConverter.class);
         register(FofrModelTelemetryModelConverter.class);
         register(SoilscountSenslogV1Converter.class);
+        register(MetnoToSensLogConverter.class);
+        register(OpenMeteoToSensLogConverter.class);
     }
 }

+ 31 - 0
connector-model/src/main/java/cz/senslog/connector/model/converter/OpenMeteoToSensLogConverter.java

@@ -0,0 +1,31 @@
+package cz.senslog.connector.model.converter;
+
+import com.google.gson.JsonObject;
+import cz.senslog.connector.model.api.Converter;
+import cz.senslog.connector.model.openmeteo.OpenMeteoModel;
+import cz.senslog.connector.model.senslog.SensLogModel;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class OpenMeteoToSensLogConverter implements Converter<OpenMeteoModel, SensLogModel> {
+
+    @Override
+    public SensLogModel convert(OpenMeteoModel model) {
+        if (model == null) {
+            return null;
+        }
+
+        if (model.getData() == null || model.getData().isEmpty()) {
+            return new SensLogModel(model.getFrom(), model.getTo(), Collections.emptyList());
+        }
+
+        List<SensLogModel.PassingData> data = new ArrayList<>(model.getData().size());
+        for (JsonObject prediction : model.getData()) {
+            data.add(new SensLogModel.PassingData(prediction.toString()));
+        }
+
+        return new SensLogModel(model.getFrom(), model.getTo(), data);
+    }
+}

+ 21 - 0
connector-model/src/main/java/cz/senslog/connector/model/metno/MetnoModel.java

@@ -0,0 +1,21 @@
+package cz.senslog.connector.model.metno;
+
+import com.google.gson.JsonObject;
+import cz.senslog.connector.model.api.AbstractModel;
+
+import java.time.OffsetDateTime;
+import java.util.List;
+
+public class MetnoModel extends AbstractModel {
+
+    private final List<JsonObject> predictions;
+
+    public MetnoModel(OffsetDateTime from, OffsetDateTime to, List<JsonObject> predictions) {
+        super(from, to);
+        this.predictions = predictions;
+    }
+
+    public List<JsonObject> getPredictions() {
+        return predictions;
+    }
+}

+ 21 - 0
connector-model/src/main/java/cz/senslog/connector/model/openmeteo/OpenMeteoModel.java

@@ -0,0 +1,21 @@
+package cz.senslog.connector.model.openmeteo;
+
+import com.google.gson.JsonObject;
+import cz.senslog.connector.model.api.AbstractModel;
+
+import java.time.OffsetDateTime;
+import java.util.List;
+
+public class OpenMeteoModel extends AbstractModel {
+
+    private final List<JsonObject> data;
+
+    public OpenMeteoModel(OffsetDateTime from, OffsetDateTime to, List<JsonObject> data) {
+        super(from, to);
+        this.data = data;
+    }
+
+    public List<JsonObject> getData() {
+        return data;
+    }
+}

+ 47 - 0
connector-model/src/main/java/cz/senslog/connector/model/senslog/SensLogModel.java

@@ -0,0 +1,47 @@
+package cz.senslog.connector.model.senslog;
+
+import cz.senslog.connector.model.api.AbstractModel;
+
+import java.time.OffsetDateTime;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+public class SensLogModel extends AbstractModel {
+
+    public static final class PassingData {
+        private final Map<String, String> params;
+        private final String payload;
+
+        public PassingData(Map<String, String> params, String payload) {
+            Objects.requireNonNull(params);
+            Objects.requireNonNull(payload);
+            this.params = params;
+            this.payload = payload;
+        }
+
+        public PassingData(String payload) {
+            this(Collections.emptyMap(), payload);
+        }
+
+        public Map<String, String> getParams() {
+            return params;
+        }
+
+        public String getPayload() {
+            return payload;
+        }
+    }
+
+    private final List<PassingData> passThroughData;
+
+    public SensLogModel(OffsetDateTime from, OffsetDateTime to, List<PassingData> passThroughData) {
+        super(from, to);
+        this.passThroughData = passThroughData;
+    }
+
+    public List<PassingData> getPassThroughData() {
+        return passThroughData;
+    }
+}

+ 39 - 0
connector-push-senslog/pom.xml

@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>cz.senslog</groupId>
+        <artifactId>connector-period</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>connector-push-senslog</artifactId>
+    <name>push-senslog</name>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>cz.senslog</groupId>
+            <artifactId>connector-push-api</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>cz.senslog</groupId>
+            <artifactId>connector-model</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 29 - 0
connector-push-senslog/src/main/java/cz/senslog/connector/push/senslog/ConnectorPushSensLogProvider.java

@@ -0,0 +1,29 @@
+package cz.senslog.connector.push.senslog;
+
+import cz.senslog.connector.model.config.DefaultConfig;
+import cz.senslog.connector.push.api.ConnectorPushProvider;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import static cz.senslog.connector.tools.http.HttpClient.newHttpClient;
+
+public class ConnectorPushSensLogProvider implements ConnectorPushProvider {
+
+    private static final Logger logger = LogManager.getLogger(ConnectorPushSensLogProvider.class);
+
+
+    @Override
+    public SensLogPusher createPusher(DefaultConfig config) {
+        logger.info("Initialization a new push provider {}.", ConnectorPushSensLogProvider.class);
+
+        logger.debug("Creating a new configuration.");
+        SensLogConfig defaultConfig = new SensLogConfig(config);
+        logger.info("Configuration for {} was created successfully.", SensLogPusher.class);
+
+        logger.debug("Creating a new instance of {}.", SensLogPusher.class);
+        SensLogPusher pusher = new SensLogPusher(defaultConfig, newHttpClient());
+        logger.info("Pusher for {} was created successfully.", SensLogPusher.class);
+
+        return pusher;
+    }
+}

+ 16 - 0
connector-push-senslog/src/main/java/cz/senslog/connector/push/senslog/SensLogConfig.java

@@ -0,0 +1,16 @@
+package cz.senslog.connector.push.senslog;
+
+import cz.senslog.connector.model.config.DefaultConfig;
+
+public class SensLogConfig {
+
+    private final String baseUrl;
+
+    SensLogConfig(DefaultConfig defaultConfig) {
+        this.baseUrl = defaultConfig.getStringProperty("baseUrl");
+    }
+
+    public String getBaseUrl() {
+        return baseUrl;
+    }
+}

+ 59 - 0
connector-push-senslog/src/main/java/cz/senslog/connector/push/senslog/SensLogPusher.java

@@ -0,0 +1,59 @@
+package cz.senslog.connector.push.senslog;
+
+import cz.senslog.connector.model.senslog.SensLogModel;
+import cz.senslog.connector.push.api.ConnectorPusher;
+import cz.senslog.connector.tools.http.*;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import static cz.senslog.connector.tools.http.HttpContentType.APPLICATION_JSON;
+
+public class SensLogPusher implements ConnectorPusher<SensLogModel> {
+
+    private static final Logger logger = LogManager.getLogger(SensLogPusher.class);
+
+    private final SensLogConfig config;
+    private final HttpClient httpClient;
+
+    public SensLogPusher(SensLogConfig config, HttpClient httpClient) {
+        this.config = config;
+        this.httpClient = httpClient;
+    }
+
+    @Override
+    public void init() {}
+
+    @Override
+    public void push(SensLogModel model) {
+        if (model == null || model.getPassThroughData() == null || model.getPassThroughData().isEmpty()) {
+            logger.warn("Model has no observations."); return;
+        }
+
+        int successfullyPushed = 0;
+        for (SensLogModel.PassingData data : model.getPassThroughData()) {
+
+            URLBuilder urlBuilder = URLBuilder.newBuilder(config.getBaseUrl());
+            data.getParams().forEach(urlBuilder::addParam);
+
+            HttpRequest.Builder req = HttpRequest.newBuilder().POST()
+                    .url(urlBuilder.build())
+                    .contentType(APPLICATION_JSON)
+                    .body(data.getPayload());
+
+            HttpResponse res = httpClient.send(req.build());
+
+            if (res.isError()) {
+                logger.error("Request error <{}> with reason: {}", res.getStatus(), res.getBody());
+                continue;
+            }
+
+            if (res.isOk()) {
+                logger.info("Pushed <{}> successfully: {}", res.getStatus(), res.getBody());
+                successfullyPushed++;
+            }
+
+        }
+
+        logger.info("Pushed {}/{} payloads.", successfullyPushed, model.getPassThroughData().size());
+    }
+}

+ 1 - 0
connector-push-senslog/src/main/resources/META-INF/services/cz.senslog.connector.push.api.ConnectorPushProvider

@@ -0,0 +1 @@
+cz.senslog.connector.push.senslog.ConnectorPushSensLogProvider

+ 26 - 0
docker-compose.yaml

@@ -132,3 +132,29 @@ services:
       APP_PARAMS: -cf config/soilscountToSenslog.yaml
       DEBUG: "true"
 
+  metno2senslog:
+    container_name: metnosenslog
+    build:
+      dockerfile: docker/Dockerfile
+      context: .
+      args:
+        MAVEN_PROFILE: MetnoSenslog
+    ports:
+      - "5005:5005"
+    environment:
+      APP_PARAMS: -cf config/metnoToSenslog.yaml
+      DEBUG: "true"
+
+  openmeteo2senslog:
+    container_name: openmeteosenslog
+    build:
+      dockerfile: docker/Dockerfile
+      context: .
+      args:
+        MAVEN_PROFILE: OpenMeteoSenslog
+    ports:
+      - "5005:5005"
+    environment:
+      APP_PARAMS: -cf config/openMeteoToSenslog.yaml
+      DEBUG: "true"
+

+ 22 - 0
pom.xml

@@ -101,6 +101,22 @@
         </profile>
 
         <profile>
+            <id>MetnoSenslog</id>
+            <modules>
+                <module>connector-fetch-metno</module>
+                <module>connector-push-senslog</module>
+            </modules>
+        </profile>
+
+        <profile>
+            <id>OpenMeteoSenslog</id>
+            <modules>
+                <module>connector-fetch-openmeteo</module>
+                <module>connector-push-senslog</module>
+            </modules>
+        </profile>
+
+        <profile>
             <id>all</id>
             <activation>
                 <activeByDefault>true</activeByDefault>
@@ -121,6 +137,9 @@
                 <module>connector-fetch-fofr</module>
                 <module>connector-fetch-soilscount</module>
                 <module>connector-push-telemetry</module>
+                <module>connector-fetch-metno</module>
+                <module>connector-fetch-openmeteo</module>
+                <module>connector-push-senslog</module>
             </modules>
         </profile>
     </profiles>
@@ -142,6 +161,9 @@
         <module>connector-fetch-fofr</module>
         <module>connector-fetch-soilscount</module>
         <module>connector-push-telemetry</module>
+        <module>connector-fetch-metno</module>
+        <module>connector-fetch-openmeteo</module>
+        <module>connector-push-senslog</module>
     </modules>
 
     <properties>