]> git.basschouten.com Git - openhab-addons.git/commitdiff
[smgw] Initial contribution (#16017)
authorJ-N-K <github@klug.nrw>
Sun, 17 Dec 2023 09:13:00 +0000 (10:13 +0100)
committerGitHub <noreply@github.com>
Sun, 17 Dec 2023 09:13:00 +0000 (10:13 +0100)
Signed-off-by: Jan N. Klug <github@klug.nrw>
14 files changed:
CODEOWNERS
bom/openhab-addons/pom.xml
bundles/org.openhab.binding.smgw/NOTICE [new file with mode: 0644]
bundles/org.openhab.binding.smgw/README.md [new file with mode: 0644]
bundles/org.openhab.binding.smgw/pom.xml [new file with mode: 0644]
bundles/org.openhab.binding.smgw/src/main/feature/feature.xml [new file with mode: 0644]
bundles/org.openhab.binding.smgw/src/main/java/org/openhab/binding/smgw/internal/SmgwBindingConstants.java [new file with mode: 0644]
bundles/org.openhab.binding.smgw/src/main/java/org/openhab/binding/smgw/internal/SmgwConfiguration.java [new file with mode: 0644]
bundles/org.openhab.binding.smgw/src/main/java/org/openhab/binding/smgw/internal/SmgwHandler.java [new file with mode: 0644]
bundles/org.openhab.binding.smgw/src/main/java/org/openhab/binding/smgw/internal/SmgwHandlerFactory.java [new file with mode: 0644]
bundles/org.openhab.binding.smgw/src/main/resources/OH-INF/addon/addon.xml [new file with mode: 0644]
bundles/org.openhab.binding.smgw/src/main/resources/OH-INF/i18n/smgw.properties [new file with mode: 0644]
bundles/org.openhab.binding.smgw/src/main/resources/OH-INF/thing/thing-types.xml [new file with mode: 0644]
bundles/pom.xml

index 5d950a8dd22a854701c9ff9898c24919450cb7e4..5d1a045d195618a8754d6d34ff23f2d8c2124253 100644 (file)
 /bundles/org.openhab.binding.smaenergymeter/ @monnimeter
 /bundles/org.openhab.binding.smartmeter/ @msteigenberger
 /bundles/org.openhab.binding.smartthings/ @BobRak
+/bundles/org.openhab.binding.smgw/ @J-N-K
 /bundles/org.openhab.binding.smhi/ @pacive
 /bundles/org.openhab.binding.smsmodem/ @dalgwen
 /bundles/org.openhab.binding.sncf/ @clinique
index be4b7c5991a02519a95162df8a7e35d31558d67e..5c9c312d92101e63f25eee89bf2318e2eed5b44b 100644 (file)
       <artifactId>org.openhab.binding.smartthings</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.openhab.addons.bundles</groupId>
+      <artifactId>org.openhab.binding.smgw</artifactId>
+      <version>${project.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.openhab.addons.bundles</groupId>
       <artifactId>org.openhab.binding.smhi</artifactId>
diff --git a/bundles/org.openhab.binding.smgw/NOTICE b/bundles/org.openhab.binding.smgw/NOTICE
new file mode 100644 (file)
index 0000000..0ca708b
--- /dev/null
@@ -0,0 +1,20 @@
+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
+
+== Third-party Content
+
+jsoup
+* License: MIT License
+* Project: https://jsoup.org/
+* Source:  https://github.com/jhy/jsoup
diff --git a/bundles/org.openhab.binding.smgw/README.md b/bundles/org.openhab.binding.smgw/README.md
new file mode 100644 (file)
index 0000000..1e0b3a1
--- /dev/null
@@ -0,0 +1,36 @@
+# PPC SMGW Binding
+
+The PPC SMGW binding adds support for PPC Smart Meter Gateways.
+The gateway is commonly installed by the network operator to allow remote access to a smart meter.
+It also provides a HAN (home area network) interface for local access.
+
+To use the HAN interface you need to connect it to your local network with an ethernet cable.
+
+## Supported Things
+
+- `smgw`: A smart meter gateway device.
+
+## Thing Configuration
+
+### `smgw` Thing Configuration
+
+| Name       | Type | Description                          | Default        | Required | Advanced |
+|------------|------|--------------------------------------|----------------|----------|----------|
+| `hostname` | text | Hostname or IP address of the device | `192.168.1.200 | no       | no       |
+| `username` | text | Username to access the device        | N/A            | yes      | no       |
+| `password` | text | Password to access the device        | N/A            | yes      | no       |
+
+The default value for the hostname matches the default value according to PPC's documentation.
+Check with your network operator's documentation if DHCP has been enabled or a different fixed address has been set.
+
+Username and password are typically supplied by the network operator.
+Login with certificate is not supported.
+
+## Channels
+
+| Channel     | Type          | Read/Write | Description                                    |
+|-------------|---------------|------------|------------------------------------------------|
+| `meter`     | Number:Energy | R          | The meter reading of the smart meter.          |
+| `timestamp` | DateTime      | R          | The date and time for which the meter reading. |
+
+Channels are refreshed every 900s.
diff --git a/bundles/org.openhab.binding.smgw/pom.xml b/bundles/org.openhab.binding.smgw/pom.xml
new file mode 100644 (file)
index 0000000..0efdc5e
--- /dev/null
@@ -0,0 +1,30 @@
+<?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 https://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>4.1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>org.openhab.binding.smgw</artifactId>
+
+  <name>openHAB Add-ons :: Bundles :: PPC SMGW Binding</name>
+
+  <properties>
+    <jsoup.version>1.15.3</jsoup.version>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.jsoup</groupId>
+      <artifactId>jsoup</artifactId>
+      <version>${jsoup.version}</version>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git a/bundles/org.openhab.binding.smgw/src/main/feature/feature.xml b/bundles/org.openhab.binding.smgw/src/main/feature/feature.xml
new file mode 100644 (file)
index 0000000..8038710
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<features name="org.openhab.binding.smgw-${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-smgw" description="PPC SMGW Binding" version="${project.version}">
+               <feature>openhab-runtime-base</feature>
+               <bundle dependency="true">mvn:org.jsoup/jsoup/1.15.3</bundle>
+               <bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.smgw/${project.version}</bundle>
+       </feature>
+</features>
diff --git a/bundles/org.openhab.binding.smgw/src/main/java/org/openhab/binding/smgw/internal/SmgwBindingConstants.java b/bundles/org.openhab.binding.smgw/src/main/java/org/openhab/binding/smgw/internal/SmgwBindingConstants.java
new file mode 100644 (file)
index 0000000..652ab38
--- /dev/null
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2010-2023 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.smgw.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.thing.ThingTypeUID;
+
+/**
+ * The {@link SmgwBindingConstants} class defines common constants, which are
+ * used across the whole binding.
+ *
+ * @author Jan N. Klug - Initial contribution
+ */
+@NonNullByDefault
+public class SmgwBindingConstants {
+    private static final String BINDING_ID = "smgw";
+
+    public static final ThingTypeUID THING_TYPE_SMGW = new ThingTypeUID(BINDING_ID, "smgw");
+
+    public static final String CHANNEL_METER = "meter";
+    public static final String CHANNEL_TIMESTAMP = "timestamp";
+}
diff --git a/bundles/org.openhab.binding.smgw/src/main/java/org/openhab/binding/smgw/internal/SmgwConfiguration.java b/bundles/org.openhab.binding.smgw/src/main/java/org/openhab/binding/smgw/internal/SmgwConfiguration.java
new file mode 100644 (file)
index 0000000..4869cf1
--- /dev/null
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2010-2023 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.smgw.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link SmgwConfiguration} class contains fields mapping thing configuration parameters.
+ *
+ * @author Jan N. Klug - Initial contribution
+ */
+@NonNullByDefault
+public class SmgwConfiguration {
+    public String hostname = "192.168.1.200";
+    public String username = "";
+    public String password = "";
+}
diff --git a/bundles/org.openhab.binding.smgw/src/main/java/org/openhab/binding/smgw/internal/SmgwHandler.java b/bundles/org.openhab.binding.smgw/src/main/java/org/openhab/binding/smgw/internal/SmgwHandler.java
new file mode 100644 (file)
index 0000000..20193c6
--- /dev/null
@@ -0,0 +1,232 @@
+/**
+ * Copyright (c) 2010-2023 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.smgw.internal;
+
+import static org.openhab.binding.smgw.internal.SmgwBindingConstants.CHANNEL_METER;
+import static org.openhab.binding.smgw.internal.SmgwBindingConstants.CHANNEL_TIMESTAMP;
+
+import java.net.CookieStore;
+import java.net.HttpCookie;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+import javax.measure.quantity.Energy;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.api.Authentication;
+import org.eclipse.jetty.client.api.AuthenticationStore;
+import org.eclipse.jetty.client.api.Response;
+import org.eclipse.jetty.client.api.Result;
+import org.eclipse.jetty.client.util.BufferingResponseListener;
+import org.eclipse.jetty.client.util.DigestAuthentication;
+import org.eclipse.jetty.client.util.StringContentProvider;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpStatus;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.openhab.core.library.types.DateTimeType;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.scheduler.CronScheduler;
+import org.openhab.core.scheduler.ScheduledCompletableFuture;
+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.binding.BaseThingHandler;
+import org.openhab.core.types.Command;
+import org.openhab.core.types.RefreshType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link SmgwHandler} is responsible for refreshing the smart meter's data and handling REFRESH commands.
+ *
+ * @author Jan N. Klug - Initial contribution
+ */
+@NonNullByDefault
+public class SmgwHandler extends BaseThingHandler {
+    private static final URI URI_NOT_SET = URI.create("");
+    private final Logger logger = LoggerFactory.getLogger(SmgwHandler.class);
+    private final HttpClient httpClient;
+    private final CronScheduler cronScheduler;
+    private SmgwConfiguration config = new SmgwConfiguration();
+    private URI uri = URI_NOT_SET;
+    private @Nullable ScheduledCompletableFuture<?> cronJob;
+
+    public SmgwHandler(Thing thing, HttpClient httpClient, CronScheduler cronScheduler) {
+        super(thing);
+        this.httpClient = httpClient;
+        this.cronScheduler = cronScheduler;
+    }
+
+    @Override
+    public void handleCommand(ChannelUID channelUID, Command command) {
+        if (command instanceof RefreshType && !URI_NOT_SET.equals(uri)) {
+            cancelRefreshJob();
+            getData();
+        }
+    }
+
+    @Override
+    public void initialize() {
+        config = getConfigAs(SmgwConfiguration.class);
+        try {
+            uri = new URI("https://" + config.hostname + "/cgi-bin/hanservice.cgi");
+        } catch (URISyntaxException e) {
+            uri = URI_NOT_SET;
+            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
+                    "Could not create URI from given hostname");
+            return;
+        }
+
+        updateStatus(ThingStatus.UNKNOWN);
+        getData();
+    }
+
+    @Override
+    public void dispose() {
+        cancelRefreshJob();
+    }
+
+    private void cancelRefreshJob() {
+        ScheduledCompletableFuture<?> cronJob = this.cronJob;
+        if (cronJob != null) {
+            cronJob.cancel(true);
+            this.cronJob = null;
+        }
+    }
+
+    private void getData() {
+        if (URI_NOT_SET.equals(uri)) {
+            logger.warn("getData() called, but URI is not set. Please describe what happened and report a bug.");
+            return;
+        }
+        // clear cookies
+        CookieStore cookieStore = httpClient.getCookieStore();
+        List<HttpCookie> cookies = cookieStore.get(uri);
+        cookies.forEach(cookie -> cookieStore.remove(uri, cookie));
+
+        // clear auth
+        AuthenticationStore authStore = httpClient.getAuthenticationStore();
+        Authentication.Result authResult = authStore.findAuthenticationResult(uri);
+        if (authResult != null) {
+            authStore.removeAuthenticationResult(authResult);
+        }
+        Authentication authentication = authStore.findAuthentication("Digest", uri, Authentication.ANY_REALM);
+        if (authentication != null) {
+            authStore.removeAuthentication(authentication);
+        }
+
+        // add new auth
+        authStore.addAuthentication(
+                new DigestAuthentication(uri, Authentication.ANY_REALM, config.username, config.password));
+
+        CompletableFuture<SmgwResponse> future = new CompletableFuture<>();
+        httpClient.newRequest(uri).send(new ResponseListener(future));
+        future.thenCompose(this::onLoginSuccess).thenCompose(this::onMeterForm).handle(this::onShowMeterValue);
+    }
+
+    private CompletableFuture<SmgwResponse> onLoginSuccess(SmgwResponse response) {
+        Element tknElement = response.document().selectFirst("input[name='tkn']");
+        if (tknElement == null) {
+            return CompletableFuture.failedFuture(new IllegalStateException("Could not determine tkn"));
+        }
+        String tkn = tknElement.val();
+        String showMeterValuesForm = "tkn=" + tkn + "&action=meterform";
+        CompletableFuture<SmgwResponse> future = new CompletableFuture<>();
+        httpClient.POST(uri).content(new StringContentProvider(showMeterValuesForm)).send(new ResponseListener(future));
+        return future;
+    }
+
+    private CompletableFuture<SmgwResponse> onMeterForm(SmgwResponse response) {
+        Element tknElement = response.document().selectFirst("input[name='tkn']");
+        Element midElement = response.document().selectFirst("select[name='mid'] option");
+        if (tknElement == null || midElement == null) {
+            return CompletableFuture.failedFuture(new IllegalStateException("Could not determine mid or tkn"));
+        }
+        String tkn = tknElement.val();
+        String mid = midElement.val();
+        String localDate = LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE);
+
+        String showMeterValues = "tkn=" + tkn + "&mid=" + mid + "&action=showMeterValues&from=" + localDate + "&to="
+                + localDate;
+
+        CompletableFuture<SmgwResponse> future = new CompletableFuture<>();
+        httpClient.POST(uri).content(new StringContentProvider(showMeterValues))
+                .header(HttpHeader.COOKIE, response.cookies()).send(new ResponseListener(future));
+
+        return future;
+    }
+
+    private @Nullable Object onShowMeterValue(@Nullable SmgwResponse response, @Nullable Throwable t) {
+        if (t != null || response == null) {
+            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
+        } else {
+            Element valueElement = response.document().selectFirst("#table_metervalues_col_wert");
+            Element unitElement = response.document().selectFirst("#table_metervalues_col_einheit");
+            Element dateTimeElement = response.document().selectFirst("#table_metervalues_col_timestamp");
+            if (valueElement == null || unitElement == null || dateTimeElement == null) {
+                updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
+            } else {
+                QuantityType<Energy> value = new QuantityType<>(valueElement.text() + " " + unitElement.text());
+                DateTimeType dateTime = DateTimeType.valueOf(dateTimeElement.text().replace(" ", "T"));
+
+                updateState(CHANNEL_METER, value);
+                updateState(CHANNEL_TIMESTAMP, dateTime);
+                updateStatus(ThingStatus.ONLINE);
+            }
+        }
+        ScheduledCompletableFuture<?> cronJob = this.cronJob;
+        if (cronJob == null || cronJob.isDone()) {
+            this.cronJob = cronScheduler.schedule(this::getData, "5 0/15 * * * ? *");
+        }
+        return null;
+    }
+
+    private static class ResponseListener extends BufferingResponseListener {
+        private final Logger logger = LoggerFactory.getLogger(ResponseListener.class);
+        private final CompletableFuture<SmgwResponse> resultFuture;
+
+        public ResponseListener(CompletableFuture<SmgwResponse> resultFuture) {
+            this.resultFuture = resultFuture;
+        }
+
+        @Override
+        public void onComplete(@NonNullByDefault({}) Result result) {
+            if (result.isSucceeded()) {
+                Response response = result.getResponse();
+                int status = response.getStatus();
+                if (HttpStatus.isSuccess(status)) {
+                    String setCookies = response.getHeaders().get(HttpHeader.SET_COOKIE);
+                    String cookies = setCookies != null ? setCookies
+                            : result.getRequest().getHeaders().get(HttpHeader.COOKIE);
+                    Document doc = Jsoup.parse(getContentAsString());
+                    resultFuture.complete(new SmgwResponse(cookies, doc));
+                    return;
+                }
+            }
+            logger.warn("Failed to request {}", result.getRequest().getURI());
+            resultFuture.completeExceptionally(new IllegalStateException());
+        }
+    }
+
+    private record SmgwResponse(String cookies, Document document) {
+    }
+}
diff --git a/bundles/org.openhab.binding.smgw/src/main/java/org/openhab/binding/smgw/internal/SmgwHandlerFactory.java b/bundles/org.openhab.binding.smgw/src/main/java/org/openhab/binding/smgw/internal/SmgwHandlerFactory.java
new file mode 100644 (file)
index 0000000..af54aec
--- /dev/null
@@ -0,0 +1,89 @@
+/**
+ * Copyright (c) 2010-2023 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.smgw.internal;
+
+import static org.openhab.binding.smgw.internal.SmgwBindingConstants.*;
+
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.openhab.core.io.net.http.HttpClientFactory;
+import org.openhab.core.scheduler.CronScheduler;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingTypeUID;
+import org.openhab.core.thing.binding.BaseThingHandlerFactory;
+import org.openhab.core.thing.binding.ThingHandler;
+import org.openhab.core.thing.binding.ThingHandlerFactory;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link SmgwHandlerFactory} is responsible for creating things and thing
+ * handlers.
+ *
+ * @author Jan N. Klug - Initial contribution
+ */
+@NonNullByDefault
+@Component(service = ThingHandlerFactory.class)
+public class SmgwHandlerFactory extends BaseThingHandlerFactory {
+    private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_SMGW);
+    private final Logger logger = LoggerFactory.getLogger(SmgwHandlerFactory.class);
+
+    private final HttpClient httpClient;
+    private final CronScheduler cronScheduler;
+
+    @Activate
+    public SmgwHandlerFactory(@Reference HttpClientFactory clientFactory, @Reference CronScheduler cronScheduler) {
+        this.cronScheduler = cronScheduler;
+        this.httpClient = clientFactory.createHttpClient("smgw", new SslContextFactory.Client(true));
+        try {
+            this.httpClient.start();
+        } catch (Exception e) {
+            // catching exception is necessary due to the signature of HttpClient.start()
+            logger.warn("Failed to start http client: {}", e.getMessage());
+            throw new IllegalStateException("Could not create HttpClient");
+        }
+    }
+
+    @Deactivate
+    public void deactivate() {
+        try {
+            httpClient.stop();
+        } catch (Exception e) {
+            logger.warn("Failed to stop http client: {}", e.getMessage());
+        }
+    }
+
+    @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_SMGW.equals(thingTypeUID)) {
+            return new SmgwHandler(thing, httpClient, cronScheduler);
+        }
+
+        return null;
+    }
+}
diff --git a/bundles/org.openhab.binding.smgw/src/main/resources/OH-INF/addon/addon.xml b/bundles/org.openhab.binding.smgw/src/main/resources/OH-INF/addon/addon.xml
new file mode 100644 (file)
index 0000000..559a16e
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<addon:addon id="smgw" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:addon="https://openhab.org/schemas/addon/v1.0.0"
+       xsi:schemaLocation="https://openhab.org/schemas/addon/v1.0.0 https://openhab.org/schemas/addon-1.0.0.xsd">
+
+       <type>binding</type>
+       <name>PPC SMGW Binding</name>
+       <description>This integrates the PPC Smart Meter Gateways.</description>
+
+       <connection>local</connection>
+
+</addon:addon>
diff --git a/bundles/org.openhab.binding.smgw/src/main/resources/OH-INF/i18n/smgw.properties b/bundles/org.openhab.binding.smgw/src/main/resources/OH-INF/i18n/smgw.properties
new file mode 100644 (file)
index 0000000..5ceb328
--- /dev/null
@@ -0,0 +1,22 @@
+# add-on
+
+addon.smgw.name = PPC SMGW Binding
+addon.smgw.description = This integrates the PPC Smart Meter Gateways.
+
+# thing types
+
+thing-type.smgw.smgw.label = Smartmeter Gateway
+thing-type.smgw.smgw.description = A Smartmeter Gateway
+thing-type.smgw.smgw.channel.meter.label = Meter Reading
+
+# thing types config
+
+thing-type.config.smgw.smgw.hostname.label = Hostname
+thing-type.config.smgw.smgw.hostname.description = Hostname or IP address of the device
+thing-type.config.smgw.smgw.password.label = Password
+thing-type.config.smgw.smgw.username.label = Username
+
+# channel types
+
+channel-type.smgw.timestamp.label = Timestamp
+channel-type.smgw.timestamp.description = The timestamp of the meter reading.
diff --git a/bundles/org.openhab.binding.smgw/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.smgw/src/main/resources/OH-INF/thing/thing-types.xml
new file mode 100644 (file)
index 0000000..4692ec2
--- /dev/null
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<thing:thing-descriptions bindingId="smgw"
+       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">
+
+       <!-- Sample Thing Type -->
+       <thing-type id="smgw">
+               <label>Smartmeter Gateway</label>
+               <description>A Smartmeter Gateway</description>
+
+               <channels>
+                       <channel id="meter" typeId="system.electric-energy">
+                               <label>Meter Reading</label>
+                       </channel>
+                       <channel id="timestamp" typeId="timestamp">
+                       </channel>
+               </channels>
+
+               <config-description>
+                       <parameter name="hostname" type="text">
+                               <context>network-address</context>
+                               <label>Hostname</label>
+                               <description>Hostname or IP address of the device</description>
+                               <default>192.168.1.200</default>
+                       </parameter>
+                       <parameter name="username" type="text" required="true">
+                               <label>Username</label>
+                       </parameter>
+                       <parameter name="password" type="text" required="true">
+                               <context>password</context>
+                               <label>Password</label>
+                       </parameter>
+               </config-description>
+
+       </thing-type>
+
+       <channel-type id="timestamp">
+               <item-type>DateTime</item-type>
+               <label>Timestamp</label>
+               <description>The timestamp of the meter reading.</description>
+               <state readOnly="true"/>
+       </channel-type>
+
+</thing:thing-descriptions>
index 5c6100d5296f75848972499411006c52d13d8d16..9d53ead3623efa7b4a678fff0e0042ce2d473673 100644 (file)
     <module>org.openhab.binding.smaenergymeter</module>
     <module>org.openhab.binding.smartmeter</module>
     <module>org.openhab.binding.smartthings</module>
+    <module>org.openhab.binding.smgw</module>
     <module>org.openhab.binding.smhi</module>
     <module>org.openhab.binding.smsmodem</module>
     <module>org.openhab.binding.sncf</module>