]> git.basschouten.com Git - openhab-addons.git/commitdiff
[generacmobilelink| Initial Contribution (#9322)
authorDan Cunningham <dan@digitaldan.com>
Mon, 28 Dec 2020 05:49:30 +0000 (21:49 -0800)
committerGitHub <noreply@github.com>
Mon, 28 Dec 2020 05:49:30 +0000 (21:49 -0800)
* This is the initial contribution of the Generac MobileLink binding.  This allows the  Generac line of generators using their MobileLink cloud service to be monitored as things in openHAB.
* bump to 3.1

Signed-off-by: Dan Cunningham <dan@digitaldan.com>
21 files changed:
CODEOWNERS
bom/openhab-addons/pom.xml
bundles/org.openhab.binding.generacmobilelink/NOTICE [new file with mode: 0644]
bundles/org.openhab.binding.generacmobilelink/README.md [new file with mode: 0644]
bundles/org.openhab.binding.generacmobilelink/pom.xml [new file with mode: 0644]
bundles/org.openhab.binding.generacmobilelink/src/main/feature/feature.xml [new file with mode: 0644]
bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/GeneracMobileLinkBindingConstants.java [new file with mode: 0644]
bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/config/GeneracMobileLinkAccountConfiguration.java [new file with mode: 0644]
bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/discovery/GeneracMobileLinkDiscoveryService.java [new file with mode: 0644]
bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/dto/ErrorResponseDTO.java [new file with mode: 0644]
bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/dto/GeneratorStatusDTO.java [new file with mode: 0644]
bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/dto/GeneratorStatusResponseDTO.java [new file with mode: 0644]
bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/dto/LoginRequestDTO.java [new file with mode: 0644]
bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/dto/LoginResponseDTO.java [new file with mode: 0644]
bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/factory/GeneracMobileLinkHandlerFactory.java [new file with mode: 0644]
bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/handler/GeneracMobileLinkAccountHandler.java [new file with mode: 0644]
bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/handler/GeneracMobileLinkGeneratorHandler.java [new file with mode: 0644]
bundles/org.openhab.binding.generacmobilelink/src/main/resources/OH-INF/binding/binding.xml [new file with mode: 0644]
bundles/org.openhab.binding.generacmobilelink/src/main/resources/OH-INF/config/config.xml [new file with mode: 0644]
bundles/org.openhab.binding.generacmobilelink/src/main/resources/OH-INF/thing/thing-types.xml [new file with mode: 0644]
bundles/pom.xml

index 96f873cd0c5c0b55f36d3fe4ce68155d02b40d69..4f4cbc4e7a4a48bb398eb01e0aca4f1cb048b4cb 100644 (file)
@@ -80,6 +80,7 @@
 /bundles/org.openhab.binding.ftpupload/ @paulianttila
 /bundles/org.openhab.binding.gardena/ @gerrieg
 /bundles/org.openhab.binding.gce/ @clinique
+/bundles/org.openhab.binding.generacmobilelink/ @digitaldan
 /bundles/org.openhab.binding.globalcache/ @mhilbush
 /bundles/org.openhab.binding.goecharger/ @SamuelBrucksch
 /bundles/org.openhab.binding.gpstracker/ @gbicskei
index 63d1f4424fe2cfcb3b93c75e5e5ff309979e667c..33a19ae51f5772e3949a185543cfb2622d31dbb3 100644 (file)
       <artifactId>org.openhab.binding.gce</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.openhab.addons.bundles</groupId>
+      <artifactId>org.openhab.binding.generacmobilelink</artifactId>
+      <version>${project.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.openhab.addons.bundles</groupId>
       <artifactId>org.openhab.binding.globalcache</artifactId>
diff --git a/bundles/org.openhab.binding.generacmobilelink/NOTICE b/bundles/org.openhab.binding.generacmobilelink/NOTICE
new file mode 100644 (file)
index 0000000..38d625e
--- /dev/null
@@ -0,0 +1,13 @@
+This content is produced and maintained by the openHAB project.
+
+* Project home: https://www.openhab.org
+
+== Declared Project Licenses
+
+This program and the accompanying materials are made available under the terms
+of the Eclipse Public License 2.0 which is available at
+https://www.eclipse.org/legal/epl-2.0/.
+
+== Source Code
+
+https://github.com/openhab/openhab-addons
diff --git a/bundles/org.openhab.binding.generacmobilelink/README.md b/bundles/org.openhab.binding.generacmobilelink/README.md
new file mode 100644 (file)
index 0000000..adb7ccd
--- /dev/null
@@ -0,0 +1,95 @@
+# Generac MobileLink Binding
+
+This binding communicates with the Generac MobileLink API and reports on the status of Generac manufactured generators, including versions resold under the brands Eaton, Honeywell and Siemens.
+
+## Supported Things
+
+
+### MobileLink Account
+
+A MobileLink account bridge thing represents a user's MobileLink account and is responsible for authentication and polling for updates.
+
+ThingTypeUID: `account`
+
+### Generator
+
+A Generator thing represents a individual generator linked to an account bridge. Multiple generators are supported.  
+
+ThingTypeUID: `generator`
+
+## Discovery
+
+The MobileLink account bridge must be added manually. Once added, generator things will automatically be added to the inbox.  
+
+## Thing Configuration
+
+### MobileLink Account
+
+| Parameter       | Description                                                                        |
+|-----------------|------------------------------------------------------------------------------------|
+| username        | The user name, typically an email address, used to login to the MobileLink service |
+| password        | The password used to login to the MobileLink service                               |
+| refreshInterval | The frequency to poll for generator updates, minimum duration is 30 seconds        |
+
+
+## Channels
+
+### Generator Channels
+
+All channels are read-only. 
+
+| channel                 | type                 | description                               |
+|-------------------------|----------------------|-------------------------------------------|
+| connected               | Switch               | Connected status                          |
+| greenLight              | Switch               | Green light state (typically auto mode)   |
+| yellowLight             | Switch               | Yellow light state                        |
+| redLight                | Switch               | Red light state (typically off mode)      |
+| blueLight               | Switch               | Blue light state (typically running mode) |
+| statusDate              | DateTime             | Status date (start of day)                |
+| status                  | String               | General status                            |
+| currentAlarmDescription | String               | Current alarm description                 |
+| runHours                | Number:Time          | Number of run hours                       |
+| exerciseHours           | Number:Time          | Number of exercise hours                  |
+| fuelType                | Number               | Fuel type                                 |
+| fuelLevel               | Number:Dimensionless | Fuel level                                |
+| batteryVoltage          | String               | Battery voltage status                    |
+| serviceStatus           | Switch               | Service status                            |
+
+
+## Full Example
+
+### Things
+
+```xtend
+Bridge generacmobilelink:account:main "MobileLink Account" [ userName="foo@bar.com", password="secret",refreshInterval=60 ] {
+    Thing generator 123456 "MobileLink Generator" [ generatorId="123456" ]
+}
+```
+
+### Items
+
+```xtend
+Switch GeneratorConnected "Connected [%s]" {channel="generacmobilelink:generator:main:123456:connected"}
+Switch GeneratorGreenLight "Green Light [%s]" {channel="generacmobilelink:generator:main:123456:greenLight"}
+Switch GeneratorYellowLight "Yellow Light [%s]" {channel="generacmobilelink:generator:main:123456:yellowLight"}
+Switch GeneratorBlueLight "Blue Light [%s]" {channel="generacmobilelink:generator:main:123456:blueLight"}
+Switch GeneratorRedLight "Red Light [%s]" {channel="generacmobilelink:generator:main:123456:redLight"}
+String GeneratorStatus "Status [%s]" {channel="generacmobilelink:generator:main:123456:status"}
+String GeneratorAlarm "Alarm [%s]" {channel="generacmobilelink:generator:main:123456:currentAlarmDescription"}
+```
+
+### Sitemap
+
+```xtend
+sitemap MobileLink label="Demo Sitemap" {
+  Frame label="Generator" {
+    Switch item=GeneratorConnected
+    Switch item=GeneratorGreenLight
+    Switch item=GeneratorYellowLight
+    Switch item=GeneratorBlueLight
+    Switch item=GeneratorRedLight
+    Text   item=GeneratorStatus
+    Text   item=GeneratorAlarm
+  }                
+}
+```
diff --git a/bundles/org.openhab.binding.generacmobilelink/pom.xml b/bundles/org.openhab.binding.generacmobilelink/pom.xml
new file mode 100644 (file)
index 0000000..ca299fd
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+  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>org.openhab.addons.bundles</groupId>
+    <artifactId>org.openhab.addons.reactor.bundles</artifactId>
+    <version>3.1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>org.openhab.binding.generacmobilelink</artifactId>
+
+  <name>openHAB Add-ons :: Bundles :: GeneracMobileLink Binding</name>
+
+</project>
diff --git a/bundles/org.openhab.binding.generacmobilelink/src/main/feature/feature.xml b/bundles/org.openhab.binding.generacmobilelink/src/main/feature/feature.xml
new file mode 100644 (file)
index 0000000..71ed25e
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+       Copyright (c) 2010-2020 Contributors to the openHAB project
+
+       See the NOTICE file(s) distributed with this work for additional
+       information.
+
+       This program and the accompanying materials are made available under the
+       terms of the Eclipse Public License 2.0 which is available at
+       http://www.eclipse.org/legal/epl-2.0
+
+       SPDX-License-Identifier: EPL-2.0
+
+-->
+<features name="org.openhab.binding.generacmobilelink-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
+       <repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
+
+       <feature name="openhab-binding-generacmobilelink" description="Generac MobileLink Binding" version="${project.version}">
+               <feature>openhab-runtime-base</feature>
+               <bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.generacmobilelink/${project.version}</bundle>
+       </feature>
+</features>
diff --git a/bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/GeneracMobileLinkBindingConstants.java b/bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/GeneracMobileLinkBindingConstants.java
new file mode 100644 (file)
index 0000000..e27e02b
--- /dev/null
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.generacmobilelink.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.thing.ThingTypeUID;
+
+/**
+ * The {@link GeneracMobileLinkBindingConstants} class defines common constants, which are
+ * used across the whole binding.
+ *
+ * @author Dan Cunningham - Initial contribution
+ */
+@NonNullByDefault
+public class GeneracMobileLinkBindingConstants {
+    private static final String BINDING_ID = "generacmobilelink";
+    public static final ThingTypeUID THING_TYPE_ACCOUNT = new ThingTypeUID(BINDING_ID, "account");
+    public static final ThingTypeUID THING_TYPE_GENERATOR = new ThingTypeUID(BINDING_ID, "generator");
+}
diff --git a/bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/config/GeneracMobileLinkAccountConfiguration.java b/bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/config/GeneracMobileLinkAccountConfiguration.java
new file mode 100644 (file)
index 0000000..def1179
--- /dev/null
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.generacmobilelink.internal.config;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link GeneracMobileLinkAccountConfiguration} class contains fields mapping thing configuration parameters.
+ *
+ * @author Dan Cunningham - Initial contribution
+ */
+@NonNullByDefault
+public class GeneracMobileLinkAccountConfiguration {
+    public String username = "";
+    public String password = "";
+    public Integer refreshInterval = 60;
+}
diff --git a/bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/discovery/GeneracMobileLinkDiscoveryService.java b/bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/discovery/GeneracMobileLinkDiscoveryService.java
new file mode 100644 (file)
index 0000000..c0de87f
--- /dev/null
@@ -0,0 +1,64 @@
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.generacmobilelink.internal.discovery;
+
+import static org.openhab.binding.generacmobilelink.internal.GeneracMobileLinkBindingConstants.THING_TYPE_GENERATOR;
+
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.generacmobilelink.internal.GeneracMobileLinkBindingConstants;
+import org.openhab.binding.generacmobilelink.internal.dto.GeneratorStatusDTO;
+import org.openhab.core.config.discovery.AbstractDiscoveryService;
+import org.openhab.core.config.discovery.DiscoveryResult;
+import org.openhab.core.config.discovery.DiscoveryResultBuilder;
+import org.openhab.core.thing.ThingTypeUID;
+import org.openhab.core.thing.ThingUID;
+
+/**
+ * The {@link GeneracMobileLinkDiscoveryService} is responsible for discovering generator things
+ *
+ * @author Dan Cunningham - Initial contribution
+ */
+@NonNullByDefault
+public class GeneracMobileLinkDiscoveryService extends AbstractDiscoveryService {
+    private static final Set<ThingTypeUID> SUPPORTED_DISCOVERY_THING_TYPES_UIDS = Set.of(THING_TYPE_GENERATOR);
+
+    public GeneracMobileLinkDiscoveryService() {
+        super(SUPPORTED_DISCOVERY_THING_TYPES_UIDS, 0);
+    }
+
+    @Override
+    public Set<ThingTypeUID> getSupportedThingTypes() {
+        return SUPPORTED_DISCOVERY_THING_TYPES_UIDS;
+    }
+
+    @Override
+    public void startScan() {
+    }
+
+    @Override
+    public boolean isBackgroundDiscoveryEnabled() {
+        return false;
+    }
+
+    public void generatorDiscovered(GeneratorStatusDTO generator, ThingUID bridgeUID) {
+        DiscoveryResult result = DiscoveryResultBuilder
+                .create(new ThingUID(GeneracMobileLinkBindingConstants.THING_TYPE_GENERATOR, bridgeUID,
+                        String.valueOf(generator.gensetID)))
+                .withLabel("MobileLink Generator " + generator.generatorName)
+                .withProperty("generatorId", String.valueOf(generator.gensetID))
+                .withRepresentationProperty("generatorId").withBridge(bridgeUID).build();
+        thingDiscovered(result);
+    }
+}
diff --git a/bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/dto/ErrorResponseDTO.java b/bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/dto/ErrorResponseDTO.java
new file mode 100644 (file)
index 0000000..ee8abfe
--- /dev/null
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.generacmobilelink.internal.dto;
+
+/**
+ * {@link ErrorResponseDTO} object from the MobileLink API
+ *
+ * @author Dan Cunningham - Initial contribution
+ */
+public class ErrorResponseDTO {
+    public Integer errorCode;
+    public String errorMessage;
+}
diff --git a/bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/dto/GeneratorStatusDTO.java b/bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/dto/GeneratorStatusDTO.java
new file mode 100644 (file)
index 0000000..299954d
--- /dev/null
@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.generacmobilelink.internal.dto;
+
+/**
+ * {@link GeneratorStatusDTO} object from the MobileLink API
+ *
+ * @author Dan Cunningham - Initial contribution
+ */
+public class GeneratorStatusDTO {
+    public Integer gensetID;
+    public String generatorDate;
+    public String generatorName;
+    public String generatorSerialNumber;
+    public String generatorModel;
+    public String generatorDescription;
+    public String generatorMDN;
+    public String generatorImei;
+    public String generatorIccid;
+    public String generatorTetherSerial;
+    public Boolean connected;
+    public Boolean greenLightLit;
+    public Boolean yellowLightLit;
+    public Boolean redLightLit;
+    public Boolean blueLightLit;
+    public String generatorStatus;
+    public String generatorStatusDate;
+    public String currentAlarmDescription;
+    public Integer runHours;
+    public Integer exerciseHours;
+    public String batteryVoltage;
+    public Integer fuelType;
+    public Integer fuelLevel;
+    public String generatorBrandImageURL;
+    public Boolean generatorServiceStatus;
+    public String signalStrength;
+    public String deviceId;
+    public Integer deviceTypeId;
+    public String firmwareVersion;
+    public String timezone;
+    public String mACAddress;
+    public String iPAddress;
+    public String sSID;
+}
diff --git a/bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/dto/GeneratorStatusResponseDTO.java b/bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/dto/GeneratorStatusResponseDTO.java
new file mode 100644 (file)
index 0000000..645517d
--- /dev/null
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.generacmobilelink.internal.dto;
+
+import java.util.ArrayList;
+
+/**
+ * {@link GeneratorStatusResponseDTO} response from the MobileLink API
+ *
+ * @author Dan Cunningham - Initial contribution
+ */
+@SuppressWarnings("serial")
+public class GeneratorStatusResponseDTO extends ArrayList<GeneratorStatusDTO> {
+
+}
diff --git a/bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/dto/LoginRequestDTO.java b/bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/dto/LoginRequestDTO.java
new file mode 100644 (file)
index 0000000..a47decc
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.generacmobilelink.internal.dto;
+
+/**
+ * {@link LoginRequestDTO} request for the MobileLink API
+ *
+ * @author Dan Cunningham - Initial contribution
+ */
+public class LoginRequestDTO {
+    public LoginRequestDTO(String sharedKey, String userLogin, String userPassword) {
+        super();
+        this.sharedKey = sharedKey;
+        this.userLogin = userLogin;
+        this.userPassword = userPassword;
+    }
+
+    public String sharedKey;
+    public String userLogin;
+    public String userPassword;
+}
diff --git a/bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/dto/LoginResponseDTO.java b/bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/dto/LoginResponseDTO.java
new file mode 100644 (file)
index 0000000..b8382c8
--- /dev/null
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.generacmobilelink.internal.dto;
+
+/**
+ * {@link LoginResponseDTO} response from the MobileLink API
+ *
+ * @author Dan Cunningham - Initial contribution
+ */
+public class LoginResponseDTO {
+    public String authToken;
+    public String pushChannelName;
+}
diff --git a/bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/factory/GeneracMobileLinkHandlerFactory.java b/bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/factory/GeneracMobileLinkHandlerFactory.java
new file mode 100644 (file)
index 0000000..292e192
--- /dev/null
@@ -0,0 +1,95 @@
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.generacmobilelink.internal.factory;
+
+import static org.openhab.binding.generacmobilelink.internal.GeneracMobileLinkBindingConstants.*;
+
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.client.HttpClient;
+import org.openhab.binding.generacmobilelink.internal.discovery.GeneracMobileLinkDiscoveryService;
+import org.openhab.binding.generacmobilelink.internal.handler.GeneracMobileLinkAccountHandler;
+import org.openhab.binding.generacmobilelink.internal.handler.GeneracMobileLinkGeneratorHandler;
+import org.openhab.core.config.discovery.DiscoveryService;
+import org.openhab.core.io.net.http.HttpClientFactory;
+import org.openhab.core.thing.Bridge;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingTypeUID;
+import org.openhab.core.thing.ThingUID;
+import org.openhab.core.thing.binding.BaseThingHandlerFactory;
+import org.openhab.core.thing.binding.ThingHandler;
+import org.openhab.core.thing.binding.ThingHandlerFactory;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+
+/**
+ * The {@link GeneracMobileLinkHandlerFactory} is responsible for creating things and thing
+ * handlers.
+ *
+ * @author Dan Cunningham - Initial contribution
+ */
+@NonNullByDefault
+@Component(configurationPid = "binding.generacmobilelink", service = ThingHandlerFactory.class)
+public class GeneracMobileLinkHandlerFactory extends BaseThingHandlerFactory {
+    private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_ACCOUNT,
+            THING_TYPE_GENERATOR);
+    private final Map<ThingUID, ServiceRegistration<?>> discoveryServiceRegs = new ConcurrentHashMap<>();
+    private final HttpClient httpClient;
+
+    @Activate
+    public GeneracMobileLinkHandlerFactory(final @Reference HttpClientFactory httpClientFactory) {
+        this.httpClient = httpClientFactory.getCommonHttpClient();
+    }
+
+    @Override
+    public boolean supportsThingType(ThingTypeUID thingTypeUID) {
+        return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
+    }
+
+    @Override
+    protected @Nullable ThingHandler createHandler(Thing thing) {
+        ThingTypeUID thingTypeUID = thing.getThingTypeUID();
+
+        if (THING_TYPE_GENERATOR.equals(thingTypeUID)) {
+            return new GeneracMobileLinkGeneratorHandler(thing);
+        }
+
+        if (THING_TYPE_ACCOUNT.equals(thingTypeUID)) {
+            GeneracMobileLinkDiscoveryService discoveryService = new GeneracMobileLinkDiscoveryService();
+            GeneracMobileLinkAccountHandler accountHandler = new GeneracMobileLinkAccountHandler((Bridge) thing,
+                    httpClient, discoveryService);
+            discoveryServiceRegs.put(accountHandler.getThing().getUID(), bundleContext
+                    .registerService(DiscoveryService.class.getName(), discoveryService, new Hashtable<>()));
+            return accountHandler;
+        }
+
+        return null;
+    }
+
+    @Override
+    protected synchronized void removeHandler(ThingHandler thingHandler) {
+        if (thingHandler instanceof GeneracMobileLinkAccountHandler) {
+            ServiceRegistration<?> serviceReg = discoveryServiceRegs.remove(thingHandler.getThing().getUID());
+            if (serviceReg != null) {
+                serviceReg.unregister();
+            }
+        }
+    }
+}
diff --git a/bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/handler/GeneracMobileLinkAccountHandler.java b/bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/handler/GeneracMobileLinkAccountHandler.java
new file mode 100644 (file)
index 0000000..c19b5a2
--- /dev/null
@@ -0,0 +1,251 @@
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.generacmobilelink.internal.handler;
+
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.api.ContentProvider;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.client.api.Result;
+import org.eclipse.jetty.client.util.BufferingResponseListener;
+import org.eclipse.jetty.client.util.StringContentProvider;
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpStatus;
+import org.openhab.binding.generacmobilelink.internal.GeneracMobileLinkBindingConstants;
+import org.openhab.binding.generacmobilelink.internal.config.GeneracMobileLinkAccountConfiguration;
+import org.openhab.binding.generacmobilelink.internal.discovery.GeneracMobileLinkDiscoveryService;
+import org.openhab.binding.generacmobilelink.internal.dto.ErrorResponseDTO;
+import org.openhab.binding.generacmobilelink.internal.dto.GeneratorStatusDTO;
+import org.openhab.binding.generacmobilelink.internal.dto.GeneratorStatusResponseDTO;
+import org.openhab.binding.generacmobilelink.internal.dto.LoginRequestDTO;
+import org.openhab.binding.generacmobilelink.internal.dto.LoginResponseDTO;
+import org.openhab.core.thing.Bridge;
+import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingStatus;
+import org.openhab.core.thing.ThingStatusDetail;
+import org.openhab.core.thing.ThingUID;
+import org.openhab.core.thing.binding.BaseBridgeHandler;
+import org.openhab.core.thing.binding.ThingHandler;
+import org.openhab.core.types.Command;
+import org.openhab.core.types.RefreshType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.FieldNamingPolicy;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+/**
+ * The {@link GeneracMobileLinkAccountHandler} is responsible for connecting to the MobileLink cloud service and
+ * discovering generator things
+ *
+ * @author Dan Cunningham - Initial contribution
+ */
+@NonNullByDefault
+public class GeneracMobileLinkAccountHandler extends BaseBridgeHandler {
+    private static final String BASE_URL = "https://api.mobilelinkgen.com";
+    private static final String SHARED_KEY = "GeneseeDepot13";
+    private final Logger logger = LoggerFactory.getLogger(GeneracMobileLinkAccountHandler.class);
+    private final Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create();
+    private @Nullable Future<?> pollFuture;
+    private @Nullable String authToken;
+    private @Nullable GeneratorStatusResponseDTO generators;
+    private GeneracMobileLinkDiscoveryService discoveryService;
+    private HttpClient httpClient;
+    private int refreshIntervalSeconds = 60;
+
+    public GeneracMobileLinkAccountHandler(Bridge bridge, HttpClient httpClient,
+            GeneracMobileLinkDiscoveryService discoveryService) {
+        super(bridge);
+        this.httpClient = httpClient;
+        this.discoveryService = discoveryService;
+    }
+
+    @Override
+    public void initialize() {
+        updateStatus(ThingStatus.UNKNOWN);
+        authToken = null;
+        restartPoll();
+    }
+
+    @Override
+    public void dispose() {
+        stopPoll();
+    }
+
+    @Override
+    public void handleCommand(ChannelUID channelUID, Command command) {
+        if (command instanceof RefreshType) {
+            updateGeneratorThings();
+        }
+    }
+
+    @Override
+    public void childHandlerInitialized(ThingHandler childHandler, Thing childThing) {
+        GeneratorStatusResponseDTO generatorsLocal = generators;
+        if (generatorsLocal != null) {
+            Optional<GeneratorStatusDTO> generatorOpt = generatorsLocal.stream()
+                    .filter(g -> String.valueOf(g.gensetID).equals(childThing.getUID().getId())).findFirst();
+            if (generatorOpt.isPresent()) {
+                ((GeneracMobileLinkGeneratorHandler) childHandler).updateGeneratorStatus(generatorOpt.get());
+            }
+        }
+    }
+
+    private void stopPoll() {
+        Future<?> localPollFuture = pollFuture;
+        if (localPollFuture != null) {
+            localPollFuture.cancel(true);
+        }
+    }
+
+    private void restartPoll() {
+        stopPoll();
+        pollFuture = scheduler.scheduleWithFixedDelay(this::poll, 0, refreshIntervalSeconds, TimeUnit.SECONDS);
+    }
+
+    private void poll() {
+        try {
+            if (authToken == null) {
+                logger.debug("Attempting Login");
+                login();
+            }
+            getStatuses(true);
+        } catch (InterruptedException e) {
+        }
+    }
+
+    private synchronized void login() throws InterruptedException {
+        GeneracMobileLinkAccountConfiguration config = getConfigAs(GeneracMobileLinkAccountConfiguration.class);
+        refreshIntervalSeconds = config.refreshInterval;
+        HTTPResult result = sendRequest(BASE_URL + "/Users/login", HttpMethod.POST, null,
+                new StringContentProvider(
+                        gson.toJson(new LoginRequestDTO(SHARED_KEY, config.username, config.password))),
+                "application/json");
+        if (result.responseCode == HttpStatus.OK_200) {
+            LoginResponseDTO loginResponse = gson.fromJson(result.content, LoginResponseDTO.class);
+            if (loginResponse != null) {
+                authToken = loginResponse.authToken;
+                updateStatus(ThingStatus.ONLINE);
+            }
+        } else {
+            handleErrorResponse(result);
+            if (thing.getStatusInfo().getStatusDetail() == ThingStatusDetail.CONFIGURATION_ERROR) {
+                // bad credentials, stop trying to login
+                stopPoll();
+            }
+        }
+    }
+
+    private void getStatuses(boolean retry) throws InterruptedException {
+        if (authToken == null) {
+            return;
+        }
+        HTTPResult result = sendRequest(BASE_URL + "/Generator/GeneratorStatus", HttpMethod.GET, authToken, null, null);
+        if (result.responseCode == HttpStatus.OK_200) {
+            generators = gson.fromJson(result.content, GeneratorStatusResponseDTO.class);
+            updateGeneratorThings();
+            if (getThing().getStatus() != ThingStatus.ONLINE) {
+                updateStatus(ThingStatus.ONLINE);
+            }
+        } else {
+            if (retry) {
+                logger.debug("Retrying status request");
+                getStatuses(false);
+            } else {
+                handleErrorResponse(result);
+            }
+        }
+    }
+
+    private HTTPResult sendRequest(String url, HttpMethod method, @Nullable String token,
+            @Nullable ContentProvider content, @Nullable String contentType) throws InterruptedException {
+        try {
+            Request request = httpClient.newRequest(url).method(method).timeout(10, TimeUnit.SECONDS);
+            if (token != null) {
+                request = request.header("AuthToken", token);
+            }
+            if (content != null & contentType != null) {
+                request = request.content(content, contentType);
+            }
+            logger.trace("Sending {} to {}", request.getMethod(), request.getURI());
+            final CompletableFuture<HTTPResult> futureResult = new CompletableFuture<>();
+            request.send(new BufferingResponseListener() {
+                @NonNullByDefault({})
+                @Override
+                public void onComplete(Result result) {
+                    futureResult.complete(new HTTPResult(result.getResponse().getStatus(), getContentAsString()));
+                }
+            });
+            HTTPResult result = futureResult.get();
+            logger.trace("Response - status: {} content: {}", result.responseCode, result.content);
+            return result;
+        } catch (ExecutionException e) {
+            return new HTTPResult(0, e.getMessage());
+        }
+    }
+
+    private void handleErrorResponse(HTTPResult result) {
+        switch (result.responseCode) {
+            case HttpStatus.UNAUTHORIZED_401:
+                // the server responds with a 500 error in some cases when credentials are not correct
+            case HttpStatus.INTERNAL_SERVER_ERROR_500:
+                // server returned a valid error response
+                ErrorResponseDTO error = gson.fromJson(result.content, ErrorResponseDTO.class);
+                if (error != null && error.errorCode > 0) {
+                    updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
+                            "Unauthorized: " + result.content);
+                    authToken = null;
+                    break;
+                }
+            default:
+                updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, result.content);
+        }
+    }
+
+    private void updateGeneratorThings() {
+        GeneratorStatusResponseDTO generatorsLocal = generators;
+        if (generatorsLocal != null) {
+            generatorsLocal.forEach(generator -> {
+                Thing thing = getThing().getThing(new ThingUID(GeneracMobileLinkBindingConstants.THING_TYPE_GENERATOR,
+                        getThing().getUID(), String.valueOf(generator.gensetID)));
+                if (thing == null) {
+                    discoveryService.generatorDiscovered(generator, getThing().getUID());
+                } else {
+                    ThingHandler handler = thing.getHandler();
+                    if (handler != null) {
+                        ((GeneracMobileLinkGeneratorHandler) handler).updateGeneratorStatus(generator);
+                    }
+                }
+            });
+        }
+    }
+
+    public static class HTTPResult {
+        public @Nullable String content;
+        public final int responseCode;
+
+        public HTTPResult(int responseCode, @Nullable String content) {
+            this.responseCode = responseCode;
+            this.content = content;
+        }
+    }
+}
diff --git a/bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/handler/GeneracMobileLinkGeneratorHandler.java b/bundles/org.openhab.binding.generacmobilelink/src/main/java/org/openhab/binding/generacmobilelink/internal/handler/GeneracMobileLinkGeneratorHandler.java
new file mode 100644 (file)
index 0000000..b12d168
--- /dev/null
@@ -0,0 +1,99 @@
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.generacmobilelink.internal.handler;
+
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+
+import javax.measure.quantity.Time;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.binding.generacmobilelink.internal.dto.GeneratorStatusDTO;
+import org.openhab.core.library.types.DateTimeType;
+import org.openhab.core.library.types.DecimalType;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.types.StringType;
+import org.openhab.core.library.unit.Units;
+import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingStatus;
+import org.openhab.core.thing.binding.BaseThingHandler;
+import org.openhab.core.types.Command;
+import org.openhab.core.types.RefreshType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link GeneracMobileLinkGeneratorHandler} is responsible for updating a generator things's channels
+ *
+ * @author Dan Cunningham - Initial contribution
+ */
+@NonNullByDefault
+public class GeneracMobileLinkGeneratorHandler extends BaseThingHandler {
+    private final Logger logger = LoggerFactory.getLogger(GeneracMobileLinkGeneratorHandler.class);
+    private @Nullable GeneratorStatusDTO status;
+
+    public GeneracMobileLinkGeneratorHandler(Thing thing) {
+        super(thing);
+    }
+
+    @Override
+    public void handleCommand(ChannelUID channelUID, Command command) {
+        if (command instanceof RefreshType) {
+            updateState();
+        }
+    }
+
+    @Override
+    public void initialize() {
+        updateStatus(ThingStatus.UNKNOWN);
+    }
+
+    protected void updateGeneratorStatus(GeneratorStatusDTO status) {
+        this.status = status;
+        updateStatus(ThingStatus.ONLINE);
+        updateState();
+    }
+
+    protected void updateState() {
+        final GeneratorStatusDTO localStatus = status;
+        if (localStatus != null) {
+            updateState("connected", OnOffType.from(localStatus.connected));
+            updateState("greenLight", OnOffType.from(localStatus.greenLightLit));
+            updateState("yellowLight", OnOffType.from(localStatus.yellowLightLit));
+            updateState("redLight", OnOffType.from(localStatus.redLightLit));
+            updateState("blueLight", OnOffType.from(localStatus.blueLightLit));
+            try {
+                // API returns a format like 12/20/2020
+                updateState("statusDate",
+                        new DateTimeType(LocalDate
+                                .parse(localStatus.generatorStatusDate, DateTimeFormatter.ofPattern("MM/dd/yyyy"))
+                                .atStartOfDay(ZoneId.systemDefault())));
+            } catch (IllegalArgumentException | DateTimeParseException e) {
+                logger.debug("Could not parse statusDate", e);
+            }
+            updateState("status", new StringType(localStatus.generatorStatus));
+            updateState("currentAlarmDescription", new StringType(localStatus.currentAlarmDescription));
+            updateState("runHours", new QuantityType<Time>(localStatus.runHours, Units.HOUR));
+            updateState("exerciseHours", new QuantityType<Time>(localStatus.exerciseHours, Units.HOUR));
+            updateState("fuelType", new DecimalType(localStatus.fuelType));
+            updateState("fuelLevel", QuantityType.valueOf(localStatus.fuelLevel, Units.PERCENT));
+            updateState("batteryVoltage", new StringType(localStatus.batteryVoltage));
+            updateState("serviceStatus", OnOffType.from(localStatus.generatorServiceStatus));
+        }
+    }
+}
diff --git a/bundles/org.openhab.binding.generacmobilelink/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.generacmobilelink/src/main/resources/OH-INF/binding/binding.xml
new file mode 100644 (file)
index 0000000..6d7faa9
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<binding:binding id="generacmobilelink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
+       xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
+
+       <name>GeneracMobileLink Binding</name>
+       <description>This binding monitors Generac manufactured generators through the MobileLink cloud service.</description>
+
+</binding:binding>
diff --git a/bundles/org.openhab.binding.generacmobilelink/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.binding.generacmobilelink/src/main/resources/OH-INF/config/config.xml
new file mode 100644 (file)
index 0000000..71bc70e
--- /dev/null
@@ -0,0 +1,30 @@
+<config-description:config-descriptions
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
+       xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0 https://openhab.org/schemas/config-description-1.0.0.xsd">
+
+       <config-description uri="thing-type:generacmobilelink:account">
+               <parameter name="username" type="text" required="true">
+                       <label>Username</label>
+                       <description>Account username</description>
+               </parameter>
+               <parameter name="password" type="text" required="true">
+                       <label>Password</label>
+                       <description>Account password</description>
+                       <context>password</context>
+               </parameter>
+               <parameter name="refreshInterval" type="integer" min="30" required="true" unit="s">
+                       <label>Refresh Interval</label>
+                       <description>Specifies the refresh interval in seconds</description>
+                       <default>60</default>
+               </parameter>
+       </config-description>
+
+       <config-description uri="thing-type:generacmobilelink:generator">
+               <parameter name="generatorId" type="text" required="true">
+                       <label>Generator ID</label>
+                       <description>Generator ID</description>
+               </parameter>
+       </config-description>
+
+</config-description:config-descriptions>
diff --git a/bundles/org.openhab.binding.generacmobilelink/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.generacmobilelink/src/main/resources/OH-INF/thing/thing-types.xml
new file mode 100644 (file)
index 0000000..0208948
--- /dev/null
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<thing:thing-descriptions bindingId="generacmobilelink"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
+       xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
+
+       <bridge-type id="account">
+               <label>MobileLink Account</label>
+               <description>MobileLink Cloud Account</description>
+               <config-description-ref uri="thing-type:generacmobilelink:account"/>
+       </bridge-type>
+
+       <thing-type id="generator">
+               <supported-bridge-type-refs>
+                       <bridge-type-ref id="account"/>
+               </supported-bridge-type-refs>
+               <label>MobileLink Generator</label>
+               <description>MobileLink Generator</description>
+               <channels>
+                       <channel id="connected" typeId="connected"/>
+                       <channel id="greenLight" typeId="greenLight"/>
+                       <channel id="yellowLight" typeId="yellowLight"/>
+                       <channel id="redLight" typeId="redLight"/>
+                       <channel id="blueLight" typeId="blueLight"/>
+                       <channel id="statusDate" typeId="statusDate"/>
+                       <channel id="status" typeId="status"/>
+                       <channel id="currentAlarmDescription" typeId="currentAlarmDescription"/>
+                       <channel id="runHours" typeId="runHours"/>
+                       <channel id="exerciseHours" typeId="exerciseHours"/>
+                       <channel id="fuelType" typeId="fuelType"/>
+                       <channel id="fuelLevel" typeId="fuelLevel"/>
+                       <channel id="batteryVoltage" typeId="batteryVoltage"/>
+                       <channel id="serviceStatus" typeId="serviceStatus"/>
+               </channels>
+               <representation-property>generatorId</representation-property>
+               <config-description-ref uri="thing-type:generacmobilelink:generator"/>
+       </thing-type>
+
+       <channel-type id="connected">
+               <item-type>Switch</item-type>
+               <label>Connected</label>
+               <state readOnly="true"/>
+       </channel-type>
+       <channel-type id="greenLight">
+               <item-type>Switch</item-type>
+               <label>Green Light Status</label>
+               <state readOnly="true"/>
+       </channel-type>
+       <channel-type id="yellowLight">
+               <item-type>Switch</item-type>
+               <label>Yellow Light Status</label>
+               <state readOnly="true"/>
+       </channel-type>
+       <channel-type id="redLight">
+               <item-type>Switch</item-type>
+               <label>Red Light Status</label>
+               <state readOnly="true"/>
+       </channel-type>
+       <channel-type id="blueLight">
+               <item-type>Switch</item-type>
+               <label>Blue Light Status</label>
+               <state readOnly="true"/>
+       </channel-type>
+       <channel-type id="statusDate">
+               <item-type>DateTime</item-type>
+               <label>Last Status Date</label>
+               <state readOnly="true"/>
+       </channel-type>
+       <channel-type id="status">
+               <item-type>String</item-type>
+               <label>Status</label>
+               <state readOnly="true"/>
+       </channel-type>
+       <channel-type id="currentAlarmDescription">
+               <item-type>String</item-type>
+               <label>Current Alarm Description</label>
+               <state readOnly="true"/>
+       </channel-type>
+       <channel-type id="runHours">
+               <item-type>Number:Time</item-type>
+               <label>Number of Hours Run</label>
+               <state readOnly="true" pattern="%d %unit%"/>
+       </channel-type>
+       <channel-type id="exerciseHours">
+               <item-type>Number:Time</item-type>
+               <label>Number of Hours Exercised</label>
+               <state readOnly="true" pattern="%d %unit%"/>
+       </channel-type>
+       <channel-type id="fuelType">
+               <item-type>Number</item-type>
+               <label>Fuel Type</label>
+               <state readOnly="true"/>
+       </channel-type>
+       <channel-type id="fuelLevel">
+               <item-type>Number:Dimensionless</item-type>
+               <label>Fuel Level</label>
+               <state readOnly="true"/>
+       </channel-type>
+       <channel-type id="batteryVoltage">
+               <item-type>String</item-type>
+               <label>Battery Voltage Status</label>
+               <state readOnly="true"/>
+       </channel-type>
+       <channel-type id="serviceStatus">
+               <item-type>Switch</item-type>
+               <label>Service Status</label>
+               <state readOnly="true"/>
+       </channel-type>
+</thing:thing-descriptions>
index be4b669c6d73f8049ab31aab9be0aee5c57bb6d1..45d609f7d3c8b008c56dfbb63285afc4b9a8cf41 100644 (file)
     <module>org.openhab.binding.ftpupload</module>
     <module>org.openhab.binding.gardena</module>
     <module>org.openhab.binding.gce</module>
+    <module>org.openhab.binding.generacmobilelink</module>
     <module>org.openhab.binding.goecharger</module>
     <module>org.openhab.binding.globalcache</module>
     <module>org.openhab.binding.gpstracker</module>