]> git.basschouten.com Git - openhab-addons.git/commitdiff
[tasmotaplug] Initial contribution (#15857)
authormlobstein <michael.lobstein@gmail.com>
Fri, 10 Nov 2023 22:51:43 +0000 (16:51 -0600)
committerGitHub <noreply@github.com>
Fri, 10 Nov 2023 22:51:43 +0000 (23:51 +0100)
Signed-off-by: Michael Lobstein <michael.lobstein@gmail.com>
14 files changed:
CODEOWNERS
bom/openhab-addons/pom.xml
bundles/org.openhab.binding.tasmotaplug/NOTICE [new file with mode: 0644]
bundles/org.openhab.binding.tasmotaplug/README.md [new file with mode: 0644]
bundles/org.openhab.binding.tasmotaplug/pom.xml [new file with mode: 0644]
bundles/org.openhab.binding.tasmotaplug/src/main/feature/feature.xml [new file with mode: 0644]
bundles/org.openhab.binding.tasmotaplug/src/main/java/org/openhab/binding/tasmotaplug/internal/TasmotaPlugBindingConstants.java [new file with mode: 0644]
bundles/org.openhab.binding.tasmotaplug/src/main/java/org/openhab/binding/tasmotaplug/internal/TasmotaPlugConfiguration.java [new file with mode: 0644]
bundles/org.openhab.binding.tasmotaplug/src/main/java/org/openhab/binding/tasmotaplug/internal/TasmotaPlugHandlerFactory.java [new file with mode: 0644]
bundles/org.openhab.binding.tasmotaplug/src/main/java/org/openhab/binding/tasmotaplug/internal/handler/TasmotaPlugHandler.java [new file with mode: 0644]
bundles/org.openhab.binding.tasmotaplug/src/main/resources/OH-INF/addon/addon.xml [new file with mode: 0644]
bundles/org.openhab.binding.tasmotaplug/src/main/resources/OH-INF/i18n/tasmotaplug.properties [new file with mode: 0644]
bundles/org.openhab.binding.tasmotaplug/src/main/resources/OH-INF/thing/thing-types.xml [new file with mode: 0644]
bundles/pom.xml

index 6f9aa3f0d9ecb5748a078eaab392315374f23d60..6d8ddc9c790abbc1341a9f20b667fa91add55981 100644 (file)
 /bundles/org.openhab.binding.tado/ @dfrommi @andrewfg
 /bundles/org.openhab.binding.tankerkoenig/ @dolic @JueBag
 /bundles/org.openhab.binding.tapocontrol/ @wildcs
+/bundles/org.openhab.binding.tasmotaplug/ @mlobstein
 /bundles/org.openhab.binding.telegram/ @ZzetT
 /bundles/org.openhab.binding.teleinfo/ @Nokyyz @olivierkeke
 /bundles/org.openhab.binding.tellstick/ @openhab/add-ons-maintainers
index 95eba8ac828c2c2df701a9c672cd3146a5b91bf8..9f322e518bc05dd0930dd2e2657582b8bd571997 100644 (file)
       <artifactId>org.openhab.binding.tapocontrol</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.openhab.addons.bundles</groupId>
+      <artifactId>org.openhab.binding.tasmotaplug</artifactId>
+      <version>${project.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.openhab.addons.bundles</groupId>
       <artifactId>org.openhab.binding.telegram</artifactId>
diff --git a/bundles/org.openhab.binding.tasmotaplug/NOTICE b/bundles/org.openhab.binding.tasmotaplug/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.tasmotaplug/README.md b/bundles/org.openhab.binding.tasmotaplug/README.md
new file mode 100644 (file)
index 0000000..9ef89d2
--- /dev/null
@@ -0,0 +1,77 @@
+# TasmotaPlug Binding
+
+This binding connects Tasmota flashed smart plugs with 1, 2, 3 or 4 relay channels to openHAB.
+The plug must report the status of the relay via the url `http://$PLUG_IP/cm?cmnd=Power` in order for the binding to work.
+See the [Tasmota Supported Devices Repository](https://templates.blakadder.com/plug.html) for a list of supported plugs.
+
+## Supported Things
+
+There is exactly one supported thing type, which represents any supported Tasmota smart plug.
+It has the `plug` id.
+Multiple Things can be added if more than one plug is to be controlled.
+
+## Discovery
+
+Discovery is not supported. All things must be added manually.
+
+## Thing Configuration
+
+At minimum, the host name must be specified.
+The refresh interval and number of channels can be overridden from the default.
+
+| Parameter   | Description                                                                             |
+|-------------|-----------------------------------------------------------------------------------------|
+| hostName    | The host name or IP address of the plug. Mandatory.                                     |
+| refresh     | Overrides the refresh interval of the plug status. Optional, the default is 30 seconds. |
+| numChannels | Number of channels on the Tasmota Plug (1-4). Optional, the default is 1                |
+| username    | Username for authentication with the Tasmota Plug. Default 'admin'                      |
+| password    | Password for authentication with the Tasmota Plug, if not supplied auth is disabled.    |
+
+## Channels
+
+The number of channels depends of on the `numChannels` configuration parameter.
+Channels above the number specified are automatically removed.
+Therefore `numChannels` cannot be changed upward after Thing creation.
+If the number of channels must be increased, delete the Thing and re-create it with the correct number.
+
+| Channel ID | Item Type | Description                             |
+|------------|-----------|-----------------------------------------|
+| power      | Switch    | Turns the smart plug relay #1 ON or OFF |
+| power2     | Switch    | Turns the smart plug relay #2 ON or OFF |
+| power3     | Switch    | Turns the smart plug relay #3 ON or OFF |
+| power4     | Switch    | Turns the smart plug relay #4 ON or OFF |
+
+## Full Example
+
+tasmotaplug.things:
+
+```java
+tasmotaplug:plug:plug1 "Plug 1" [ hostName="192.168.10.1", refresh=30 ]
+tasmotaplug:plug:plug2 "Plug 2" [ hostName="myplug2", refresh=30 ]
+```
+
+tasmotaplug.items:
+
+```java
+Switch Plug1 "Plug 1 Power" { channel="tasmotaplug:plug:plug1:power" }
+
+Switch Plug2a "4ch Power 1" { channel="tasmotaplug:plug:plug2:power" }
+Switch Plug2b "4ch Power 2" { channel="tasmotaplug:plug:plug2:power2" }
+Switch Plug2c "4ch Power 3" { channel="tasmotaplug:plug:plug2:power3" }
+Switch Plug2d "4ch Power 4" { channel="tasmotaplug:plug:plug2:power4" }
+```
+
+tasmotaplug.sitemap:
+
+```perl
+sitemap tasmotaplug label="My Tasmota Plugs" {
+    Frame label="Plugs" {
+        Switch item=Plug1
+
+        Switch item=Plug2a
+        Switch item=Plug2b
+        Switch item=Plug2c
+        Switch item=Plug2d
+    }
+}
+```
diff --git a/bundles/org.openhab.binding.tasmotaplug/pom.xml b/bundles/org.openhab.binding.tasmotaplug/pom.xml
new file mode 100644 (file)
index 0000000..f6a4ab4
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 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.tasmotaplug</artifactId>
+
+  <name>openHAB Add-ons :: Bundles :: Tasmota Plug Binding</name>
+
+</project>
diff --git a/bundles/org.openhab.binding.tasmotaplug/src/main/feature/feature.xml b/bundles/org.openhab.binding.tasmotaplug/src/main/feature/feature.xml
new file mode 100644 (file)
index 0000000..21fbcfa
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<features name="org.openhab.binding.tasmotaplug-${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-tasmotaplug" description="Tasmota Plug Binding" version="${project.version}">
+               <feature>openhab-runtime-base</feature>
+               <bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.tasmotaplug/${project.version}</bundle>
+       </feature>
+</features>
diff --git a/bundles/org.openhab.binding.tasmotaplug/src/main/java/org/openhab/binding/tasmotaplug/internal/TasmotaPlugBindingConstants.java b/bundles/org.openhab.binding.tasmotaplug/src/main/java/org/openhab/binding/tasmotaplug/internal/TasmotaPlugBindingConstants.java
new file mode 100644 (file)
index 0000000..98539aa
--- /dev/null
@@ -0,0 +1,52 @@
+/**
+ * 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.tasmotaplug.internal;
+
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.thing.ThingTypeUID;
+
+/**
+ * The {@link TasmotaPlugBinding} class defines common constants, which are
+ * used across the whole binding.
+ *
+ * @author Michael Lobstein - Initial contribution
+ */
+@NonNullByDefault
+public class TasmotaPlugBindingConstants {
+    public static final String BINDING_ID = "tasmotaplug";
+
+    public static final int DEFAULT_REFRESH_PERIOD_SEC = 30;
+    public static final int DEFAULT_NUM_CHANNELS = 1;
+
+    public static final String CMD_URI = "/cm?cmnd=%s";
+    public static final String CMD_URI_AUTH = "/cm?user=%s&password=%s&cmnd=%s";
+
+    public static final String ON = "ON";
+    public static final String OFF = "OFF";
+    public static final String BLANK = "";
+
+    // List of all Thing Type UIDs
+    public static final ThingTypeUID THING_TYPE_PLUG = new ThingTypeUID(BINDING_ID, "plug");
+
+    // List of all Channel id's
+    public static final String POWER = "power";
+    public static final String POWER2 = "power2";
+    public static final String POWER3 = "power3";
+    public static final String POWER4 = "power4";
+
+    public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_PLUG);
+    public static final List<String> SUPPORTED_CHANNEL_IDS = List.of(POWER, POWER2, POWER3, POWER4);
+}
diff --git a/bundles/org.openhab.binding.tasmotaplug/src/main/java/org/openhab/binding/tasmotaplug/internal/TasmotaPlugConfiguration.java b/bundles/org.openhab.binding.tasmotaplug/src/main/java/org/openhab/binding/tasmotaplug/internal/TasmotaPlugConfiguration.java
new file mode 100644 (file)
index 0000000..865091e
--- /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.tasmotaplug.internal;
+
+import static org.openhab.binding.tasmotaplug.internal.TasmotaPlugBindingConstants.*;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link TasmotaPlugConfiguration} is the class used to match the
+ * thing configuration.
+ *
+ * @author Michael Lobstein - Initial contribution
+ */
+@NonNullByDefault
+public class TasmotaPlugConfiguration {
+    public String hostName = BLANK;
+    public int refresh = DEFAULT_REFRESH_PERIOD_SEC;
+    public int numChannels = DEFAULT_NUM_CHANNELS;
+    public String username = BLANK;
+    public String password = BLANK;
+}
diff --git a/bundles/org.openhab.binding.tasmotaplug/src/main/java/org/openhab/binding/tasmotaplug/internal/TasmotaPlugHandlerFactory.java b/bundles/org.openhab.binding.tasmotaplug/src/main/java/org/openhab/binding/tasmotaplug/internal/TasmotaPlugHandlerFactory.java
new file mode 100644 (file)
index 0000000..8469333
--- /dev/null
@@ -0,0 +1,64 @@
+/**
+ * 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.tasmotaplug.internal;
+
+import static org.openhab.binding.tasmotaplug.internal.TasmotaPlugBindingConstants.THING_TYPE_PLUG;
+
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.client.HttpClient;
+import org.openhab.binding.tasmotaplug.internal.handler.TasmotaPlugHandler;
+import org.openhab.core.io.net.http.HttpClientFactory;
+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.Reference;
+
+/**
+ * The {@link TasmotaPlugHandlerFactory} is responsible for creating things and thing
+ * handlers.
+ *
+ * @author Michael Lobstein - Initial contribution
+ */
+@NonNullByDefault
+@Component(service = ThingHandlerFactory.class, configurationPid = "binding.tasmotaplug")
+public class TasmotaPlugHandlerFactory extends BaseThingHandlerFactory {
+
+    private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_PLUG);
+    private final HttpClient httpClient;
+
+    @Activate
+    public TasmotaPlugHandlerFactory(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) {
+        if (THING_TYPE_PLUG.equals(thing.getThingTypeUID())) {
+            return new TasmotaPlugHandler(thing, httpClient);
+        }
+
+        return null;
+    }
+}
diff --git a/bundles/org.openhab.binding.tasmotaplug/src/main/java/org/openhab/binding/tasmotaplug/internal/handler/TasmotaPlugHandler.java b/bundles/org.openhab.binding.tasmotaplug/src/main/java/org/openhab/binding/tasmotaplug/internal/handler/TasmotaPlugHandler.java
new file mode 100644 (file)
index 0000000..b122315
--- /dev/null
@@ -0,0 +1,202 @@
+/**
+ * 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.tasmotaplug.internal.handler;
+
+import static org.eclipse.jetty.http.HttpStatus.OK_200;
+import static org.openhab.binding.tasmotaplug.internal.TasmotaPlugBindingConstants.*;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.stream.IntStream;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.openhab.binding.tasmotaplug.internal.TasmotaPlugConfiguration;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.thing.Channel;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link TasmotaPlugHandler} is responsible for handling commands, which are
+ * sent to one of the channels.
+ *
+ * @author Michael Lobstein - Initial contribution
+ */
+@NonNullByDefault
+public class TasmotaPlugHandler extends BaseThingHandler {
+    private static final String PASSWORD_REGEX = "&password=(.*)&";
+    private static final String PASSWORD_MASK = "&password=xxxx&";
+
+    private final Logger logger = LoggerFactory.getLogger(TasmotaPlugHandler.class);
+    private final HttpClient httpClient;
+
+    private @Nullable ScheduledFuture<?> refreshJob;
+
+    private String plugHost = BLANK;
+    private int refreshPeriod = DEFAULT_REFRESH_PERIOD_SEC;
+    private int numChannels = DEFAULT_NUM_CHANNELS;
+    private boolean isAuth = false;
+    private String user = BLANK;
+    private String pass = BLANK;
+
+    public TasmotaPlugHandler(Thing thing, HttpClient httpClient) {
+        super(thing);
+        this.httpClient = httpClient;
+    }
+
+    @Override
+    public void initialize() {
+        logger.debug("Initializing TasmotaPlug handler.");
+        TasmotaPlugConfiguration config = getConfigAs(TasmotaPlugConfiguration.class);
+
+        final String hostName = config.hostName;
+        final String username = config.username;
+        final String password = config.password;
+        refreshPeriod = config.refresh;
+        numChannels = config.numChannels;
+
+        if (hostName.isBlank()) {
+            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
+                    "@text/offline.configuration-error-hostname");
+            return;
+        }
+
+        if (!username.isBlank() && !password.isBlank()) {
+            isAuth = true;
+            user = username;
+            pass = password;
+        }
+
+        plugHost = "http://" + hostName;
+
+        // remove the channels we are not using
+        if (this.numChannels < SUPPORTED_CHANNEL_IDS.size()) {
+            List<Channel> channels = new ArrayList<>(this.getThing().getChannels());
+
+            List<Integer> channelsToRemove = IntStream.range(this.numChannels + 1, SUPPORTED_CHANNEL_IDS.size() + 1)
+                    .boxed().toList();
+
+            channelsToRemove.forEach(channel -> {
+                channels.removeIf(c -> (c.getUID().getId().equals(POWER + channel)));
+            });
+            updateThing(editThing().withChannels(channels).build());
+        }
+
+        updateStatus(ThingStatus.UNKNOWN);
+        startAutomaticRefresh();
+    }
+
+    @Override
+    public void dispose() {
+        logger.debug("Disposing the TasmotaPlug handler.");
+
+        ScheduledFuture<?> refreshJob = this.refreshJob;
+        if (refreshJob != null) {
+            refreshJob.cancel(true);
+            this.refreshJob = null;
+        }
+    }
+
+    @Override
+    public void handleCommand(ChannelUID channelUID, Command command) {
+        if (channelUID.getId().contains(POWER)) {
+            if (command instanceof OnOffType) {
+                getCommand(channelUID.getId(), command);
+            } else {
+                updateChannelState(channelUID.getId());
+            }
+        } else {
+            logger.warn("Unsupported command: {}", command.toString());
+        }
+    }
+
+    /**
+     * Start the job to periodically update the state of the plug
+     */
+    private void startAutomaticRefresh() {
+        ScheduledFuture<?> refreshJob = this.refreshJob;
+        if (refreshJob == null || refreshJob.isCancelled()) {
+            refreshJob = null;
+            this.refreshJob = scheduler.scheduleWithFixedDelay(() -> {
+                SUPPORTED_CHANNEL_IDS.stream().limit(numChannels).forEach(channelId -> {
+                    updateChannelState(channelId);
+                });
+            }, 0, refreshPeriod, TimeUnit.SECONDS);
+        }
+    }
+
+    private void updateChannelState(String channelId) {
+        final String plugState = getCommand(channelId, null);
+        if (plugState.contains(ON)) {
+            updateState(channelId, OnOffType.ON);
+        } else if (plugState.contains(OFF)) {
+            updateState(channelId, OnOffType.OFF);
+        }
+    }
+
+    private String getCommand(String channelId, @Nullable Command command) {
+        final String plugChannel = channelId.substring(0, 1).toUpperCase() + channelId.substring(1);
+        String url;
+
+        if (isAuth) {
+            url = String.format(CMD_URI_AUTH, user, pass, plugChannel);
+        } else {
+            url = String.format(CMD_URI, plugChannel);
+        }
+
+        if (command != null) {
+            url += "%20" + command;
+        }
+
+        try {
+            logger.trace("Sending GET request to {}{}", plugHost, maskPassword(url));
+            ContentResponse contentResponse = httpClient.GET(plugHost + url);
+            logger.trace("Response: {}", contentResponse.getContentAsString());
+
+            if (contentResponse.getStatus() != OK_200) {
+                updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
+                        "@text/offline.communication-error.http-failure [\"" + contentResponse.getStatus() + "\"]");
+                return BLANK;
+            }
+
+            updateStatus(ThingStatus.ONLINE);
+            return contentResponse.getContentAsString();
+        } catch (TimeoutException | ExecutionException e) {
+            logger.debug("Error executing Tasmota GET request: '{}{}', {}", plugHost, maskPassword(url),
+                    e.getMessage());
+            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
+        } catch (InterruptedException e) {
+            logger.debug("InterruptedException executing Tasmota GET request: '{}{}', {}", plugHost, maskPassword(url),
+                    e.getMessage());
+            Thread.currentThread().interrupt();
+        }
+        return BLANK;
+    }
+
+    private String maskPassword(String input) {
+        return isAuth ? input.replaceAll(PASSWORD_REGEX, PASSWORD_MASK) : input;
+    }
+}
diff --git a/bundles/org.openhab.binding.tasmotaplug/src/main/resources/OH-INF/addon/addon.xml b/bundles/org.openhab.binding.tasmotaplug/src/main/resources/OH-INF/addon/addon.xml
new file mode 100644 (file)
index 0000000..f45da95
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<addon:addon id="tasmotaplug" 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>Tasmota Plug Binding</name>
+       <description>Controls Wi-Fi Smart Plugs flashed with Tasmota</description>
+       <connection>local</connection>
+
+</addon:addon>
diff --git a/bundles/org.openhab.binding.tasmotaplug/src/main/resources/OH-INF/i18n/tasmotaplug.properties b/bundles/org.openhab.binding.tasmotaplug/src/main/resources/OH-INF/i18n/tasmotaplug.properties
new file mode 100644 (file)
index 0000000..c388401
--- /dev/null
@@ -0,0 +1,35 @@
+# add-on
+
+addon.tasmotaplug.name = Tasmota Plug Binding
+addon.tasmotaplug.description = Controls Wi-Fi Smart Plugs flashed with Tasmota
+
+# thing types
+
+thing-type.tasmotaplug.plug.label = Plug
+thing-type.tasmotaplug.plug.description = Tasmota Smart Plug
+thing-type.tasmotaplug.plug.channel.power.label = Power
+thing-type.tasmotaplug.plug.channel.power.description = Controls the smart plug relay for the 1st channel
+thing-type.tasmotaplug.plug.channel.power2.label = Power 2
+thing-type.tasmotaplug.plug.channel.power2.description = Controls the smart plug relay for the 2nd channel
+thing-type.tasmotaplug.plug.channel.power3.label = Power 3
+thing-type.tasmotaplug.plug.channel.power3.description = Controls the smart plug relay for the 3rd channel
+thing-type.tasmotaplug.plug.channel.power4.label = Power 4
+thing-type.tasmotaplug.plug.channel.power4.description = Controls the smart plug relay for the 4th channel
+
+# thing types config
+
+thing-type.config.tasmotaplug.plug.hostName.label = Plug Host Name/IP Address
+thing-type.config.tasmotaplug.plug.hostName.description = Host name or IP address of the plug
+thing-type.config.tasmotaplug.plug.numChannels.label = Number of Channels
+thing-type.config.tasmotaplug.plug.numChannels.description = Number of channels on the Tasmota plug (1-4) default 1
+thing-type.config.tasmotaplug.plug.password.label = Password
+thing-type.config.tasmotaplug.plug.password.description = Tasmota password
+thing-type.config.tasmotaplug.plug.refresh.label = Refresh Interval
+thing-type.config.tasmotaplug.plug.refresh.description = Specifies the refresh interval in seconds
+thing-type.config.tasmotaplug.plug.username.label = Username
+thing-type.config.tasmotaplug.plug.username.description = Tasmota username
+
+# thing status descriptions
+
+offline.communication-error.http-failure = Tasmota http response code was: {0}
+offline.configuration-error-hostname = Plug hostname must be specified
diff --git a/bundles/org.openhab.binding.tasmotaplug/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.tasmotaplug/src/main/resources/OH-INF/thing/thing-types.xml
new file mode 100644 (file)
index 0000000..1382b7c
--- /dev/null
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<thing:thing-descriptions bindingId="tasmotaplug"
+       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">
+
+       <!-- Tasmota Plug Thing -->
+       <thing-type id="plug">
+               <label>Plug</label>
+               <description>
+                       Tasmota Smart Plug
+               </description>
+
+               <channels>
+                       <channel id="power" typeId="system.power">
+                               <label>Power</label>
+                               <description>Controls the smart plug relay for the 1st channel</description>
+                       </channel>
+                       <channel id="power2" typeId="system.power">
+                               <label>Power 2</label>
+                               <description>Controls the smart plug relay for the 2nd channel</description>
+                       </channel>
+                       <channel id="power3" typeId="system.power">
+                               <label>Power 3</label>
+                               <description>Controls the smart plug relay for the 3rd channel</description>
+                       </channel>
+                       <channel id="power4" typeId="system.power">
+                               <label>Power 4</label>
+                               <description>Controls the smart plug relay for the 4th channel</description>
+                       </channel>
+               </channels>
+
+               <config-description>
+                       <parameter name="hostName" type="text" required="true">
+                               <context>network-address</context>
+                               <label>Plug Host Name/IP Address</label>
+                               <description>Host name or IP address of the plug</description>
+                       </parameter>
+                       <parameter name="refresh" type="integer" min="1" required="false" unit="s">
+                               <label>Refresh Interval</label>
+                               <description>Specifies the refresh interval in seconds</description>
+                               <default>30</default>
+                       </parameter>
+                       <parameter name="numChannels" type="integer" min="1" max="4" required="false">
+                               <label>Number of Channels</label>
+                               <description>Number of channels on the Tasmota plug (1-4) default 1</description>
+                               <default>1</default>
+                       </parameter>
+                       <parameter name="username" type="text">
+                               <label>Username</label>
+                               <description>Tasmota username</description>
+                               <default>admin</default>
+                               <advanced>true</advanced>
+                       </parameter>
+                       <parameter name="password" type="text" required="false">
+                               <context>password</context>
+                               <label>Password</label>
+                               <description>Tasmota password</description>
+                               <advanced>true</advanced>
+                       </parameter>
+               </config-description>
+
+       </thing-type>
+
+</thing:thing-descriptions>
index b58688b52dbfa0706b01322feb7aec1385b8d177..e992b98ac4dfc46fb1b357b46372bdb52549043b 100644 (file)
     <module>org.openhab.binding.tado</module>
     <module>org.openhab.binding.tankerkoenig</module>
     <module>org.openhab.binding.tapocontrol</module>
+    <module>org.openhab.binding.tasmotaplug</module>
     <module>org.openhab.binding.telegram</module>
     <module>org.openhab.binding.teleinfo</module>
     <module>org.openhab.binding.tellstick</module>