Sfoglia il codice sorgente

Local dump of changes

Lukas Cerny 2 mesi fa
parent
commit
18fe9bd567
24 ha cambiato i file con 579 aggiunte e 66 eliminazioni
  1. 4 4
      build.gradle
  2. 1 1
      config/lv.yaml
  3. 11 11
      config/release-config.test.yaml
  4. 12 12
      config/release-senslog-config.yaml
  5. 100 0
      config/release-telemetry-config.yaml
  6. 3 3
      config/super-test-foodie.yaml
  7. 27 2
      config/test-ei.yaml
  8. 12 12
      config/test-foodie.yaml
  9. 24 0
      docker-compose.yaml
  10. 1 1
      src/main/java/cz/senslog/watchdog/app/Application.java
  11. 21 1
      src/main/java/cz/senslog/watchdog/config/Configuration.java
  12. 3 2
      src/main/java/cz/senslog/watchdog/config/DataProviderType.java
  13. 39 0
      src/main/java/cz/senslog/watchdog/config/TelemetryServerConfig.java
  14. 1 1
      src/main/java/cz/senslog/watchdog/config/WSSensLogDataProviderConfig.java
  15. 27 0
      src/main/java/cz/senslog/watchdog/config/WSTelemetryDataProviderConfig.java
  16. 2 0
      src/main/java/cz/senslog/watchdog/core/Watcher.java
  17. 95 0
      src/main/java/cz/senslog/watchdog/core/connection/TelemetryWSConnection.java
  18. 20 9
      src/main/java/cz/senslog/watchdog/provider/DataProviderManager.java
  19. 3 3
      src/main/java/cz/senslog/watchdog/provider/ws/WSSensLogDataProvider.java
  20. 86 0
      src/main/java/cz/senslog/watchdog/provider/ws/WSTelemetryDataProvider.java
  21. 1 1
      src/main/java/cz/senslog/watchdog/util/schedule/PeriodicalTask.java
  22. 1 1
      src/main/java/cz/senslog/watchdog/util/schedule/ScheduleTask.java
  23. 8 2
      src/main/java/cz/senslog/watchdog/util/schedule/SchedulerImpl.java
  24. 77 0
      src/test/java/cz/senslog/watchdog/core/connection/TelemetryWSConnectionTest.java

+ 4 - 4
build.gradle

@@ -33,12 +33,12 @@ jar {
 }
 
 dependencies {
-    implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.18.0'
-    implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.18.0'
-    implementation group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.18.0'
+    implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.22.1'
+    implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.22.1'
+    implementation group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.22.1'
 
     implementation group: 'com.beust', name: 'jcommander', version: '1.78'
-    implementation group: 'org.yaml', name: 'snakeyaml', version: '1.33'
+    implementation group: 'org.yaml', name: 'snakeyaml', version: '2.2'
     implementation group: 'org.apache.httpcomponents.client5', name: 'httpclient5', version: '5.1.3'
     implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.9'
     implementation group: 'com.github.spullara.mustache.java', name: 'compiler', version: '0.9.10'

+ 1 - 1
config/lv.yaml

@@ -23,7 +23,7 @@ messageBrokers:
 
 dataProviders:
   wsVilcini:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       baseUrl: "http://51.15.45.95:8080/senslog1"
       userName: "vilcini"

+ 11 - 11
config/release-config.test.yaml

@@ -71,67 +71,67 @@ messageBrokers:
 
 dataProviders:
   wsSensLogKynsperk:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "kynsperk"
 
   wsSensLogRostenice:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "rostenice_pudni"
 
   wsSensLogZcu:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "zcu"
 
   wsSensLogOsek:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "osek"
 
   wsSensLogSmiltene:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "Smiltene"
 
   wsSensLogMengele:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "Mengele"
 
   wsSensLogZabcice:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "neudert"
 
   wsSensLogZelenec:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "zelenec"
 
   wsSensLogCepirohy:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "agriclima"
 
   wsSensLogSanJuan:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "sanjuan"
 
   wsSensLogSVSMP:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "svsmp"

+ 12 - 12
config/release-config.yaml → config/release-senslog-config.yaml

@@ -78,73 +78,73 @@ messageBrokers:
 
 dataProviders:
   wsSensLogKynsperk:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "kynsperk"
 
   wsSensLogRostenice:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "rostenice_pudni"
 
   wsSensLogZcu:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "zcu"
 
   wsSensLogOsek:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "osek"
 
   wsSensLogSmiltene:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "Smiltene"
 
   wsSensLogMengele:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "Mengele"
 
   wsSensLogZabcice:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "neudert"
 
   wsSensLogZelenec:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "zelenec"
 
   wsSensLogCepirohy:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "agriclima"
 
   wsSensLogSanJuan:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "sanjuan"
 
   wsSensLogSVSMP:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "svsmp"
 
   wsSensLogVitispector:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "vitispector"

+ 100 - 0
config/release-telemetry-config.yaml

@@ -0,0 +1,100 @@
+__variables:
+  &email_subject_format "[Watchdog] $group.name - $result - Report"
+
+general:
+  firstStartAt: "00:20:00" # hh:mm:ss
+
+emailServers:
+  lspEmail:
+    smtpHost: "10.0.0.100" # "mail.lesprojekt.cz"
+    smtpPort: 465
+    authUsername: "watchdog@senslog.org"
+    authPassword: "5jspdD"
+
+senslogServers:
+  # empty
+
+telemetryServers:
+  therosTelemetry:
+    baseUrl: "https://theros.wirelessinfo.cz"
+
+messageBrokers:
+  testServisEmail:
+    type: EMAIL
+    config:
+      server: lspEmail
+      messageTemplate: "default"
+      senderEmail: "watchdog@senslog.org"
+      recipientEmail:
+        - "dev@lukascerny.me"
+        - "kepka@ccss.cz"
+        - "tzeleny@zoo-veterina.cz"
+      subject: *email_subject_format
+
+dataProviders:
+  wsTherosPackages:
+    type: WEB_SERVICE_TELEMETRY
+    config:
+      server: therosTelemetry
+      campaignId: 4
+
+groups:
+  sumavaProductPackages:
+    name: "Sumava Product"
+    active: true
+    dataProvider: wsTherosPackages
+    messageBroker: testServisEmail
+    period: 86400
+
+superGroups:
+  # empty
+
+monitoredObjects:
+  1305167563014004:
+    groups: [ sumavaProductPackages ]
+    sensors: [330230000, 340610184, 410230184]
+  1305167562660700:
+    groups: [ sumavaProductPackages ]
+    sensors: [330230000, 340610184, 410230184]
+  1305167563017840:
+    groups: [ sumavaProductPackages ]
+    sensors: [330230000, 340610184, 410230184]
+  1305167563018282:
+    groups: [ sumavaProductPackages ]
+    sensors: [330230000, 340610184, 410230184]
+  1305167563024382:
+    groups: [ sumavaProductPackages ]
+    sensors: [330230000, 340610184, 410230184]
+  1305167563025415:
+    groups: [ sumavaProductPackages ]
+    sensors: [330230000, 340610184, 410230184]
+  1305167563035763:
+    groups: [ sumavaProductPackages ]
+    sensors: [330230000, 340610184, 410230184]
+  1305167563048283:
+    groups: [ sumavaProductPackages ]
+    sensors: [330230000, 340610184, 410230184]
+  1305167563055478:
+    groups: [ sumavaProductPackages ]
+    sensors: [330230000, 340610184, 410230184]
+  1305167563055820:
+    groups: [ sumavaProductPackages ]
+    sensors: [330230000, 340610184, 410230184]
+  1305167563056450:
+    groups: [ sumavaProductPackages ]
+    sensors: [330230000, 340610184, 410230184]
+  1305167563838292:
+    groups: [ sumavaProductPackages ]
+    sensors: [330230000, 340610184, 410230184]
+  1305167563838839:
+    groups: [ sumavaProductPackages ]
+    sensors: [330230000, 340610184, 410230184]
+  1305167563894311:
+    groups: [ sumavaProductPackages ]
+    sensors: [330230000, 340610184, 410230184]
+  865340050625338:
+    groups: [ sumavaProductPackages ]
+    sensors: [ 330230000, 340610184, 410230184 ]
+  865340050596307:
+    groups: [ sumavaProductPackages ]
+    sensors: [ 330230000, 340610184, 410230184 ]

+ 3 - 3
config/super-test-foodie.yaml

@@ -33,19 +33,19 @@ messageBrokers:
 
 dataProviders:
   wsSensLogKynsperk:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "kynsperk"
 
   wsSensLogRostenice:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "rostenice_pudni"
 
   wsSensLogZcu:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "zcu"

+ 27 - 2
config/test-ei.yaml

@@ -18,6 +18,10 @@ senslogServers:
       username: "watchdog"
       password: "HAFhaf"
 
+telemetryServers:
+  therosTelemetry:
+    baseUrl: "https://theros.wirelessinfo.cz"
+
 messageBrokers:
   testServisEmail:
     type: EMAIL
@@ -27,24 +31,45 @@ messageBrokers:
       senderEmail: "watchdog@senslog.org"
       recipientEmail:
         - "dev@lukascerny.me"
+#        - "kepka@ccss.cz"
       subject: *email_subject_format
 
 dataProviders:
   wsSensLogTest:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "vitispector"
 
+  wsTherosPackages:
+    type: WEB_SERVICE_TELEMETRY
+    config:
+      server: therosTelemetry
+      campaignId: 4
+
 groups:
   testGroup:
     name: "Vitispector"
-    active: true
+    active: false
     dataProvider: wsSensLogTest
     messageBroker: testServisEmail
     period: 86400
 
+  sumavaProductPackages:
+    name: "Sumava Product"
+    active: true
+    dataProvider: wsTherosPackages
+    messageBroker: testServisEmail
+    period: 86400
+
 superGroups:
 
 
 monitoredObjects:
+  1305167563014004:
+    groups: [ sumavaProductPackages ]
+    sensors: [330230000, 340610184, 410230184]
+
+  1305167562660700:
+    groups: [ sumavaProductPackages ]
+    sensors: [330230000, 340610184, 410230184]

+ 12 - 12
config/test-foodie.yaml

@@ -32,73 +32,73 @@ messageBrokers:
 
 dataProviders:
   wsSensLogKynsperk:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "kynsperk"
 
   wsSensLogRostenice:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "rostenice_pudni"
 
   wsSensLogZcu:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "zcu"
 
   wsSensLogOsek:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "osek"
 
   wsSensLogSmiltene:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "Smiltene"
 
   wsSensLogMengele:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "Mengele"
 
   wsSensLogZabcice:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "neudert"
 
   wsSensLogInnovar:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "Innovar"
 
   wsSensLogZelenec:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "zelenec"
 
   wsSensLogCepirohy:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "agriclima"
 
   wsSensLogSanJuan:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "sanjuan"
 
   wsSensLogSVSMP:
-    type: WEB_SERVICE
+    type: WEB_SERVICE_SENSLOG
     config:
       server: lspSenslog15
       groupName: "svsmp"

+ 24 - 0
docker-compose.yaml

@@ -0,0 +1,24 @@
+version: "3.9"
+
+services:
+  watchdog-senslog-prod:
+    container_name: watchdog_senslog
+    image: senslog/watchdog-senslog
+    environment:
+      TZ: "Europe/Prague"
+    build:
+      target: production
+      args:
+        config_file: ./config/release-senslog-config.yaml
+      context: .
+
+  watchdog-telemetry-prod:
+    container_name: watchdog_telemetry
+    image: senslog/watchdog-telemetry
+    environment:
+      TZ: "Europe/Prague"
+    build:
+      target: production
+      args:
+        config_file: ./config/release-telemetry-config.yaml
+      context: .

+ 1 - 1
src/main/java/cz/senslog/watchdog/app/Application.java

@@ -74,7 +74,7 @@ public class Application extends Thread {
         );
 
         DataProviderManager dataProviderManager = DataProviderManager.createInstance(
-                config.getSensLogServerConfigs(), config.getDataProviderConfigs()
+                config.getSensLogServerConfigs(), config.getTelemetryServerConfigs(), config.getDataProviderConfigs()
         );
 
         LocalDateTime now = LocalDateTime.now();

+ 21 - 1
src/main/java/cz/senslog/watchdog/config/Configuration.java

@@ -26,6 +26,7 @@ public class Configuration {
     private final Collection<MessageBrokerConfig> messageBrokerConfigs;
     private final Collection<EmailServerConfig> emailServerConfigs;
     private final Collection<SensLogServerConfig> sensLogServerConfigs;
+    private final Collection<TelemetryServerConfig> telemetryServerConfigs;
     private final Collection<DataProviderConfig> dataProviderConfigs;
 
     private Configuration(
@@ -35,6 +36,7 @@ public class Configuration {
             Collection<EmailServerConfig> emailServerConfigs,
             Collection<MessageBrokerConfig> messageBrokerConfigs,
             Collection<SensLogServerConfig> sensLogServerConfigs,
+            Collection<TelemetryServerConfig> telemetryServerConfigs,
             Collection<DataProviderConfig> dataProviderConfigs
     ){
         this.generalConfig = generalConfig;
@@ -43,6 +45,7 @@ public class Configuration {
         this.messageBrokerConfigs = messageBrokerConfigs;
         this.emailServerConfigs = emailServerConfigs;
         this.sensLogServerConfigs = sensLogServerConfigs;
+        this.telemetryServerConfigs = telemetryServerConfigs;
         this.dataProviderConfigs = dataProviderConfigs;
     }
 
@@ -52,6 +55,7 @@ public class Configuration {
             Map<String, EmailServerConfig> emailServers,
             Map<String, MessageBrokerConfig> messageBrokers,
             Map<String, SensLogServerConfig> sensLogServers,
+            Map<String, TelemetryServerConfig> telemetryServers,
             Map<String, DataProviderConfig> dataProviders,
             Map<String, GroupConfig> groups,
             Map<String, SuperGroupConfig> superGroups
@@ -150,12 +154,13 @@ public class Configuration {
         Collection<ExecutableSuperGroup> execSGroups = executableSGroupsMap.values();
         Collection<EmailServerConfig> emailServerConfigs = emailServers.values();
         Collection<SensLogServerConfig> sensLogServerConfigs = sensLogServers.values();
+        Collection<TelemetryServerConfig> telemetryServerConfigs = telemetryServers.values();
         Collection<DataProviderConfig> dataProviderConfigs = dataProviders.values();
         Collection<MessageBrokerConfig> messageBrokerConfigs = messageBrokers.values();
 
         return new Configuration(generalConfig, execGroups, execSGroups,
                 emailServerConfigs, messageBrokerConfigs,
-                sensLogServerConfigs, dataProviderConfigs
+                sensLogServerConfigs, telemetryServerConfigs, dataProviderConfigs
         );
     }
 
@@ -194,6 +199,7 @@ public class Configuration {
                     parseEmailServers(createPropertyConfig(properties, "emailServers")),
                     parseMessageBrokers(createPropertyConfig(properties, "messageBrokers")),
                     parseSensLogServers(createPropertyConfig(properties, "senslogServers")),
+                    parseTelemetryServers(createPropertyConfig(properties, "telemetryServers")),
                     parseDataProviders(createPropertyConfig(properties, "dataProviders")),
                     parseGroups(createPropertyConfig(properties, "groups")),
                     parseSuperGroups(createPropertyConfig(properties, "superGroups"))
@@ -241,6 +247,16 @@ public class Configuration {
         return serverConfigs;
     }
 
+    private static Map<String, TelemetryServerConfig> parseTelemetryServers(PropertyConfig config) {
+        Set<String> serverIds = config.getAttributes();
+        Map<String, TelemetryServerConfig> serverConfigs = new HashMap<>(serverIds.size());
+        for (String id : serverIds) {
+            PropertyConfig serverConfig = config.getPropertyConfig(id);
+            serverConfigs.put(id, TelemetryServerConfig.create(serverConfig));
+        }
+        return serverConfigs;
+    }
+
     private static Map<String, DataProviderConfig> parseDataProviders(PropertyConfig config) {
         Set<String> providerIds = config.getAttributes();
         Map<String, DataProviderConfig> dataProviders = new HashMap<>(providerIds.size());
@@ -343,6 +359,10 @@ public class Configuration {
         return sensLogServerConfigs;
     }
 
+    public Collection<TelemetryServerConfig> getTelemetryServerConfigs() {
+        return telemetryServerConfigs;
+    }
+
     public Collection<DataProviderConfig> getDataProviderConfigs() {
         return dataProviderConfigs;
     }

+ 3 - 2
src/main/java/cz/senslog/watchdog/config/DataProviderType.java

@@ -3,8 +3,9 @@ package cz.senslog.watchdog.config;
 import java.util.function.BiFunction;
 
 public enum DataProviderType {
-    DATABASE        (DatabaseDataProviderConfig::create),
-    WEB_SERVICE     (WSSensLogDataProviderConfig::create)
+    DATABASE                (DatabaseDataProviderConfig::create),
+    WEB_SERVICE_SENSLOG     (WSSensLogDataProviderConfig::create),
+    WEB_SERVICE_TELEMETRY   (WSTelemetryDataProviderConfig::create)
 
     ;
     private final BiFunction<String, PropertyConfig, DataProviderConfig> fnc;

+ 39 - 0
src/main/java/cz/senslog/watchdog/config/TelemetryServerConfig.java

@@ -0,0 +1,39 @@
+package cz.senslog.watchdog.config;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+public class TelemetryServerConfig {
+
+    private final String id;
+    private final String baseUrl;
+    private final URI baseUri;
+
+    public static TelemetryServerConfig create(PropertyConfig config) {
+        return new TelemetryServerConfig(config.getId(),
+                config.getStringProperty("baseUrl")
+        );
+    }
+
+    public TelemetryServerConfig(String id, String baseUrl) {
+        this.id = id;
+        this.baseUrl = baseUrl;
+        try {
+            this.baseUri = new URI(baseUrl);
+        } catch (URISyntaxException e) {
+            throw new RuntimeException("The config is in invalid format. " + e.getMessage());
+        }
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public String getBaseUrl() {
+        return baseUrl;
+    }
+
+    public URI getBaseURI() {
+        return baseUri;
+    }
+}

+ 1 - 1
src/main/java/cz/senslog/watchdog/config/WSSensLogDataProviderConfig.java

@@ -13,7 +13,7 @@ public class WSSensLogDataProviderConfig extends DataProviderConfig {
     }
 
     public WSSensLogDataProviderConfig(String id, String serverId, String groupName) {
-        super(id, DataProviderType.WEB_SERVICE);
+        super(id, DataProviderType.WEB_SERVICE_SENSLOG);
         this.serverId = serverId;
         this.groupName = groupName;
     }

+ 27 - 0
src/main/java/cz/senslog/watchdog/config/WSTelemetryDataProviderConfig.java

@@ -0,0 +1,27 @@
+package cz.senslog.watchdog.config;
+
+public class WSTelemetryDataProviderConfig extends DataProviderConfig {
+
+    private final String serverId;
+    private final int campaignId;
+
+    public static WSTelemetryDataProviderConfig create(String id, PropertyConfig config) {
+        return new WSTelemetryDataProviderConfig(id,
+                config.getStringProperty("server"),
+                config.getIntegerProperty("campaignId"));
+    }
+
+    public WSTelemetryDataProviderConfig(String id, String serverId, int campaignId) {
+        super(id, DataProviderType.WEB_SERVICE_TELEMETRY);
+        this.campaignId = campaignId;
+        this.serverId = serverId;
+    }
+
+    public String getServerId() {
+        return serverId;
+    }
+
+    public int getCampaignId() {
+        return campaignId;
+    }
+}

+ 2 - 0
src/main/java/cz/senslog/watchdog/core/Watcher.java

@@ -64,8 +64,10 @@ public final class Watcher {
 
         if (data.isErrorOccurred()) {
             reportedMessages.addAll(data.getErrorMessages());
+            overallStatus = FAIL;
         } else if (data.isEmpty()) {
             reportedMessages.add("No data to check.");
+            overallStatus = NO_DATA;
         } else  {
             for (String unitId : group.getKeys()) {
                 Node<String, MonitoredObject> mUnitNode = group.getNode(unitId);

+ 95 - 0
src/main/java/cz/senslog/watchdog/core/connection/TelemetryWSConnection.java

@@ -0,0 +1,95 @@
+package cz.senslog.watchdog.core.connection;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import cz.senslog.watchdog.config.TelemetryServerConfig;
+import cz.senslog.watchdog.util.http.HttpClient;
+import cz.senslog.watchdog.util.http.HttpRequest;
+import cz.senslog.watchdog.util.http.HttpResponse;
+import cz.senslog.watchdog.util.http.URLBuilder;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.*;
+
+import static cz.senslog.watchdog.util.json.BasicJson.jsonToObject;
+
+public class TelemetryWSConnection {
+
+    private static final Logger logger = LogManager.getLogger(TelemetryWSConnection.class);
+
+    private static final Map<String, TelemetryWSConnection> INSTANCES;
+
+    private final HttpClient httpClient;
+    private final TelemetryServerConfig config;
+
+    static {
+        INSTANCES = new HashMap<>();
+    }
+
+    public static TelemetryWSConnection getConnection(TelemetryServerConfig config) {
+        return INSTANCES.computeIfAbsent(config.getId(), id -> new TelemetryWSConnection(config));
+    }
+
+    private TelemetryWSConnection(TelemetryServerConfig config) {
+        this.config = config;
+        this.httpClient = HttpClient.newHttpClient();
+    }
+
+    private String callRequest(HttpRequest.Builder requestBuilder) {
+        HttpResponse response = httpClient.send(requestBuilder.build());
+
+        if (response.isError()) {
+            logger.error("code: {}, message: {}", response.getStatus(), response.getBody());
+            throw new IllegalStateException(response.getBody());
+        }
+        return response.getBody();
+    }
+
+    private JsonArray callJsonArray(HttpRequest.Builder requestBuilder) {
+        return jsonToObject(callRequest(requestBuilder), JsonArray.class);
+    }
+
+    private JsonObject callJsonObject(HttpRequest.Builder requestBuilder) {
+        return jsonToObject(callRequest(requestBuilder), JsonObject.class);
+    }
+
+    public String getHost() {
+        return config.getBaseUrl();
+    }
+
+    public JsonObject getInfo() {
+        return callJsonObject(HttpRequest.newBuilder().GET()
+                        .url(URLBuilder.newBuilder(config.getBaseUrl(), "/info").build()));
+
+    }
+
+    public JsonArray getUnits(int campaignId) {
+        final String reqPath = "/campaigns/"+campaignId+"/units";
+        return callJsonArray(HttpRequest.newBuilder().GET()
+                .url(URLBuilder.newBuilder(config.getBaseUrl(), reqPath)
+                            .addParam("navigationLinks", "false")
+                        .build()));
+    }
+
+    public JsonArray getSensorsByUnit(int campaignId, long unitId) {
+        final String reqPath = "/campaigns/"+campaignId+"/units/"+unitId+"/sensors";
+        return callJsonArray(HttpRequest.newBuilder().GET()
+                .url(URLBuilder.newBuilder(config.getBaseUrl(), reqPath)
+                            .addParam("navigationLinks", "false")
+                        .build()));
+    }
+
+    public JsonObject getLastTelemetryByUnit(int campaignId, long unitId) {
+        final String reqPath = "/campaigns/"+campaignId+"/units/"+unitId+"/observations";
+        return callJsonObject(HttpRequest.newBuilder().GET()
+                .url(URLBuilder.newBuilder(config.getBaseUrl(), reqPath)
+                            .addParam("zone", "Europe/Prague")
+                            .addParam("limit", "1")
+                            .addParam("sort", "desc")
+                            .addParam("observationformat", "ID")
+                            .addParam("navigationLinks", "false")
+                        .build()
+                ));
+    }
+}

+ 20 - 9
src/main/java/cz/senslog/watchdog/provider/DataProviderManager.java

@@ -1,12 +1,11 @@
 package cz.senslog.watchdog.provider;
 
-import cz.senslog.watchdog.config.DataProviderConfig;
-import cz.senslog.watchdog.config.DatabaseDataProviderConfig;
-import cz.senslog.watchdog.config.SensLogServerConfig;
-import cz.senslog.watchdog.config.WSSensLogDataProviderConfig;
+import cz.senslog.watchdog.config.*;
 import cz.senslog.watchdog.core.connection.SensLogWSConnection;
+import cz.senslog.watchdog.core.connection.TelemetryWSConnection;
 import cz.senslog.watchdog.provider.database.DBDataProvider;
 import cz.senslog.watchdog.provider.ws.WSSensLogDataProvider;
+import cz.senslog.watchdog.provider.ws.WSTelemetryDataProvider;
 
 import java.util.Collection;
 import java.util.HashMap;
@@ -17,22 +16,34 @@ public class DataProviderManager {
     private final Map<String, DataProvider> providerInstances;
 
     public static DataProviderManager createInstance(
-            Collection<SensLogServerConfig> sensLogServerConfigs, Collection<DataProviderConfig> providerConfigs
+            Collection<SensLogServerConfig> sensLogServerConfigs,
+            Collection<TelemetryServerConfig> telemetryServerConfigs,
+            Collection<DataProviderConfig> providerConfigs
     ) {
-        Map<String, SensLogWSConnection> connectionMap = new HashMap<>(sensLogServerConfigs.size());
+        Map<String, SensLogWSConnection> sensLogConnectionMap = new HashMap<>(sensLogServerConfigs.size());
         for (SensLogServerConfig config : sensLogServerConfigs) {
-            connectionMap.put(config.getId(), SensLogWSConnection.getConnection(config));
+            sensLogConnectionMap.put(config.getId(), SensLogWSConnection.getConnection(config));
+        }
+
+        Map<String, TelemetryWSConnection> telemetryConnectionMap = new HashMap<>(sensLogServerConfigs.size());
+        for (TelemetryServerConfig config : telemetryServerConfigs) {
+            telemetryConnectionMap.put(config.getId(), TelemetryWSConnection.getConnection(config));
         }
 
         Map<String, DataProvider> instances = new HashMap<>();
         for (DataProviderConfig config : providerConfigs) {
             String id = config.getId();
             switch (config.getType()) {
-                case WEB_SERVICE: {
+                case WEB_SERVICE_SENSLOG: {
                     WSSensLogDataProviderConfig wsConfig = (WSSensLogDataProviderConfig) config;
-                    SensLogWSConnection connection = connectionMap.get(wsConfig.getServerId());
+                    SensLogWSConnection connection = sensLogConnectionMap.get(wsConfig.getServerId());
                     instances.put(id, new WSSensLogDataProvider(connection, wsConfig));
                 } break;
+                case WEB_SERVICE_TELEMETRY: {
+                    WSTelemetryDataProviderConfig wsConfig = (WSTelemetryDataProviderConfig) config;
+                    TelemetryWSConnection connection = telemetryConnectionMap.get(wsConfig.getServerId());
+                    instances.put(id, new WSTelemetryDataProvider(connection, wsConfig));
+                } break;
                 case DATABASE: {
                     DatabaseDataProviderConfig dbConfig = (DatabaseDataProviderConfig) config;
                     instances.put(id, new DBDataProvider(dbConfig));

+ 3 - 3
src/main/java/cz/senslog/watchdog/provider/ws/WSSensLogDataProvider.java

@@ -10,7 +10,7 @@ import java.time.OffsetDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
 
-import static cz.senslog.watchdog.config.DataProviderType.WEB_SERVICE;
+import static cz.senslog.watchdog.config.DataProviderType.WEB_SERVICE_SENSLOG;
 import static java.time.format.DateTimeFormatter.ofPattern;
 import static java.util.Collections.emptyList;
 import static java.nio.charset.StandardCharsets.UTF_8;
@@ -39,13 +39,13 @@ public class WSSensLogDataProvider implements DataProvider {
         List<Map<String, Object>> lastObservations = emptyList();
         try {
             lastObservations = connection.loadLastObservation(config.getGroupName());
-        } catch (IllegalStateException e) {
+        } catch (Exception e) {
             errorMessages.add(e.getMessage());
             isServerAlive = false;
         }
 
         String source = String.format("%s: %s", config.getId(), connection.getHost());
-        ProvidedData providedData = new ProvidedData(new ProviderInfo(source, WEB_SERVICE, isServerAlive), errorMessages);
+        ProvidedData providedData = new ProvidedData(new ProviderInfo(source, WEB_SERVICE_SENSLOG, isServerAlive), errorMessages);
 
         if (isServerAlive) {
             for (Map<String, Object> obMap : lastObservations) {

+ 86 - 0
src/main/java/cz/senslog/watchdog/provider/ws/WSTelemetryDataProvider.java

@@ -0,0 +1,86 @@
+package cz.senslog.watchdog.provider.ws;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import cz.senslog.watchdog.config.WSTelemetryDataProviderConfig;
+import cz.senslog.watchdog.core.connection.TelemetryWSConnection;
+import cz.senslog.watchdog.provider.DataProvider;
+import cz.senslog.watchdog.provider.ProvidedData;
+import cz.senslog.watchdog.provider.ProvidedObject;
+import cz.senslog.watchdog.provider.ProviderInfo;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.time.OffsetDateTime;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static cz.senslog.watchdog.config.DataProviderType.WEB_SERVICE_TELEMETRY;
+
+public class WSTelemetryDataProvider implements DataProvider {
+
+    private static final Logger logger = LogManager.getLogger(WSTelemetryDataProvider.class);
+
+    private final TelemetryWSConnection connection;
+    private final WSTelemetryDataProviderConfig config;
+
+    public WSTelemetryDataProvider(TelemetryWSConnection connection, WSTelemetryDataProviderConfig config) {
+        this.connection = connection;
+        this.config = config;
+    }
+
+    @Override
+    public ProvidedData getData() {
+        final String source = String.format("%s: %s", config.getId(), connection.getHost());
+        final List<String> errorMessages = new ArrayList<>();
+
+        try {
+            JsonObject serverInfo = connection.getInfo();
+            String server = String.format("%s:%s", serverInfo.get("name").getAsString(), serverInfo.get("version").getAsString());
+            logger.info("Server Info: {}", server);
+
+            ProvidedData providedData = new ProvidedData(new ProviderInfo(source, WEB_SERVICE_TELEMETRY, true), errorMessages);
+
+            JsonArray units = connection.getUnits(config.getCampaignId());
+            for (JsonElement unitEl : units) {
+                JsonObject unit = unitEl.getAsJsonObject();
+
+                long unitId = unit.get("unitId").getAsLong();
+                String unitIdStr = String.format("%d", unitId);
+                String unitName = unit.get("name").getAsString();
+
+
+                JsonArray sensors = connection.getSensorsByUnit(config.getCampaignId(), unitId);
+                Map<String, String> sensorIdToName = new HashMap<>(sensors.size());
+                for (JsonElement sensorEl : sensors) {
+                    JsonObject sensor = sensorEl.getAsJsonObject();
+                    long sensorId = sensor.get("sensorId").getAsLong();
+                    sensorIdToName.put(Long.toString(sensorId), sensor.get("name").getAsString());
+                }
+
+                JsonObject lastTelemetry = connection.getLastTelemetryByUnit(config.getCampaignId(), unitId);
+                JsonArray data = lastTelemetry.get("data").getAsJsonArray();
+                if (data.size() == 1) {
+                    JsonObject tel = data.get(0).getAsJsonObject();
+                    String timestampStr = tel.get("timestamp").getAsString();
+                    OffsetDateTime timestamp = OffsetDateTime.parse(timestampStr);
+                    JsonObject observedValues = tel.get("observedValues").getAsJsonObject();
+                    for (String sensorIdStr : observedValues.keySet()) {
+                        String sensorName = sensorIdToName.get(sensorIdStr);
+
+                        providedData.computeIfAbsent(unitIdStr, k -> new ProvidedObject(k, unitName, null))
+                                .addNode(sensorIdStr, new ProvidedObject(sensorIdStr, sensorName, timestamp));
+                    }
+                }
+            }
+            return providedData;
+
+        } catch (Exception e) {
+            errorMessages.add(e.getMessage());
+            return new ProvidedData(new ProviderInfo(source, WEB_SERVICE_TELEMETRY, false), errorMessages);
+        }
+    }
+}

+ 1 - 1
src/main/java/cz/senslog/watchdog/util/schedule/PeriodicalTask.java

@@ -9,7 +9,7 @@ public class PeriodicalTask implements Task {
     private final Runnable task;
     private final int repeat;
 
-    private TaskDescription description;
+    private final TaskDescription description;
 
     public PeriodicalTask(String name, Runnable task, int repeat) {
         this.description = new TaskDescription(name, Status.STOPPED);

+ 1 - 1
src/main/java/cz/senslog/watchdog/util/schedule/ScheduleTask.java

@@ -85,7 +85,7 @@ public class ScheduleTask implements Task {
             try {
                 future.get();
             } catch (Exception e) {
-                e.printStackTrace();
+                logger.catching(e);
             } finally {
                 future.cancel(true);
                 latch.countDown();

+ 8 - 2
src/main/java/cz/senslog/watchdog/util/schedule/SchedulerImpl.java

@@ -1,5 +1,9 @@
 package cz.senslog.watchdog.util.schedule;
 
+import cz.senslog.watchdog.app.Application;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -11,6 +15,8 @@ import java.util.concurrent.TimeUnit;
 
 public class SchedulerImpl implements Scheduler {
 
+    private static final Logger logger = LogManager.getLogger(SchedulerImpl.class);
+
     private final Map<String, Task> tasks;
 
     private ScheduledExecutorService scheduler;
@@ -35,10 +41,10 @@ public class SchedulerImpl implements Scheduler {
             try {
                 latch.await();
             } catch (InterruptedException e) {
-                e.printStackTrace();
+                logger.catching(e);
             }
         } else {
-            // TODO no tasks
+            logger.warn("No tasks to run");
         }
     }
 

+ 77 - 0
src/test/java/cz/senslog/watchdog/core/connection/TelemetryWSConnectionTest.java

@@ -0,0 +1,77 @@
+package cz.senslog.watchdog.core.connection;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import cz.senslog.watchdog.config.TelemetryServerConfig;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class TelemetryWSConnectionTest {
+
+    private static final TelemetryServerConfig serverConfig;
+    private static final int testCampaignId;
+    private static final long testUnitId;
+
+    static {
+        serverConfig = new TelemetryServerConfig("theros", "https://theros.wirelessinfo.cz");
+        testCampaignId = 4;
+        testUnitId = 1305167562660700L;
+    }
+
+
+    @Test
+    void info() {
+        TelemetryWSConnection connection = TelemetryWSConnection.getConnection(serverConfig);
+        assertNotNull(connection);
+
+        JsonObject info = connection.getInfo();
+        assertNotNull(info);
+        assertTrue(info.has("name"));
+    }
+
+    @Test
+    void units() {
+        TelemetryWSConnection connection = TelemetryWSConnection.getConnection(serverConfig);
+        assertNotNull(connection);
+
+        JsonArray units = connection.getUnits(testCampaignId);
+        assertNotNull(units);
+        assertFalse(units.isEmpty());
+
+        JsonObject u1 = units.get(0).getAsJsonObject();
+        assertTrue(u1.has("unitId"));
+        assertTrue(u1.has("name"));
+    }
+
+    @Test
+    void sensors() {
+        TelemetryWSConnection connection = TelemetryWSConnection.getConnection(serverConfig);
+        assertNotNull(connection);
+
+        JsonArray sensors = connection.getSensorsByUnit(testCampaignId, testUnitId);
+        assertNotNull(sensors);
+        assertFalse(sensors.isEmpty());
+
+        JsonObject s1 = sensors.get(0).getAsJsonObject();
+        assertTrue(s1.has("sensorId"));
+        assertTrue(s1.has("name"));
+    }
+
+    @Test
+    void lastTelemetry() {
+        TelemetryWSConnection connection = TelemetryWSConnection.getConnection(serverConfig);
+        assertNotNull(connection);
+
+        JsonObject telemetry = connection.getLastTelemetryByUnit(testCampaignId, testUnitId);
+        assertNotNull(telemetry);
+
+        assertTrue(telemetry.has("data"));
+        JsonArray data = telemetry.getAsJsonArray("data");
+        assertEquals(1, data.size());
+
+        JsonObject d1 = data.get(0).getAsJsonObject();
+        assertTrue(d1.has("timestamp"));
+        assertTrue(d1.has("observedValues"));
+    }
+}