mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 07:02:02 +01:00
[Broadlinkthermostat] Initial contribution (#9260)
Signed-off-by: Florian Mueller <f.l.o.mueller@web.de>
This commit is contained in:
parent
f9fbb765fb
commit
a58676dc41
@ -38,6 +38,7 @@
|
||||
/bundles/org.openhab.binding.boschindego/ @jofleck
|
||||
/bundles/org.openhab.binding.boschshc/ @stefan-kaestle @coeing @GerdZanker
|
||||
/bundles/org.openhab.binding.bosesoundtouch/ @marvkis @tratho
|
||||
/bundles/org.openhab.binding.broadlinkthermostat/ @flo_02_mu
|
||||
/bundles/org.openhab.binding.bsblan/ @hypetsch
|
||||
/bundles/org.openhab.binding.bticinosmarther/ @MrRonfo
|
||||
/bundles/org.openhab.binding.buienradar/ @gedejong
|
||||
|
@ -176,6 +176,11 @@
|
||||
<artifactId>org.openhab.binding.bosesoundtouch</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.broadlinkthermostat</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.bsblan</artifactId>
|
||||
|
20
bundles/org.openhab.binding.broadlinkthermostat/NOTICE
Normal file
20
bundles/org.openhab.binding.broadlinkthermostat/NOTICE
Normal file
@ -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
|
||||
|
||||
broadlink-java-api
|
||||
* License: MIT License
|
||||
* Project: https://github.com/mob41/broadlink-java-api
|
||||
* Source: https://github.com/mob41/broadlink-java-api
|
67
bundles/org.openhab.binding.broadlinkthermostat/README.md
Normal file
67
bundles/org.openhab.binding.broadlinkthermostat/README.md
Normal file
@ -0,0 +1,67 @@
|
||||
# Broadlink Thermostat Binding
|
||||
|
||||
The binding integrates devices based on Broadlinkthermostat controllers.
|
||||
As the binding uses the [broadlink-java-api](https://github.com/mob41/broadlink-java-api), theoretically all devices supported by the api can be integrated with this binding.
|
||||
|
||||
## Supported Things
|
||||
|
||||
*Note:* So far only the Floureon Thermostat has been tested! The other things are "best guess" implementations.
|
||||
|
||||
| Things | Description | Thing Type |
|
||||
|-------------------------|---------------------------------------------------------------|----------------------|
|
||||
| Floureon Thermostat | Broadlinkthermostat based Thermostat sold with the branding Floureon | floureonthermostat |
|
||||
| Hysen Thermostat | Broadlinkthermostat based Thermostat sold with the branding Hysen | hysenthermostat |
|
||||
|
||||
## Discovery
|
||||
|
||||
Broadlinkthermostat devices are discovered on the network by sending a specific broadcast message.
|
||||
Authentication is automatically sent after creating the thing.
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
Two parameter are required for creating things:
|
||||
|
||||
- `host`: The hostname or IP address of the device.
|
||||
- `mac` : The network MAC of the device.
|
||||
|
||||
The autodiscovery process finds both parts automatically.
|
||||
|
||||
## Channels
|
||||
|
||||
### Floureon-/Hysenthermostat
|
||||
|
||||
| Channel Type ID | Item Type | Description |
|
||||
|-------------------------------|--------------------|----------------------------------------------------------------------|
|
||||
| power | Switch | Switch display on/off and enable/disables heating |
|
||||
| mode | String | Current mode of the thermostat (`auto` or `manual`) |
|
||||
| sensor | String | The sensor (`internal`/`external`) used for triggering the thermostat|
|
||||
| roomtemperature | Number:Temperature | Room temperature, measured directly at the device |
|
||||
| roomtemperatureexternalsensor | Number:Temperature | Room temperature, measured by an external sensor |
|
||||
| active | Switch | Show if thermostat is currently actively heating |
|
||||
| setpoint | Number:Temperature | Temperature setpoint that open/close valve |
|
||||
| temperatureoffset | Number:Temperature | Manual temperature adjustment |
|
||||
| remotelock | Switch | Locks the device to only allow remote actions |
|
||||
| time | DateTime | The time and day of week of the device |
|
||||
|
||||
## Full Example
|
||||
|
||||
demo.things:
|
||||
|
||||
```
|
||||
Thing broadlinkthermostat:floureonthermostat:bathroomthermostat "Bathroom Thermostat" [ host="192.168.0.23", mac="00:10:FA:6E:38:4A"]
|
||||
```
|
||||
|
||||
demo.items:
|
||||
|
||||
```
|
||||
Number:Temperature Bathroom_Thermostat_Temperature "Room temperature [%.1f %unit%]" <temperature> { channel="broadlinkthermostat:floureonthermostat:bathroomthermostat:roomtemperature"}
|
||||
Number:Temperature Bathroom_Thermostat_Temperature_Ext "Room temperature (ext) [%.1f %unit%]" <temperature> { channel="broadlinkthermostat:floureonthermostat:bathroomthermostat:roomtemperature"}
|
||||
Number:Temperature Bathroom_Thermostat_Setpoint "Setpoint [%.1f %unit%]" <temperature> { channel="broadlinkthermostat:floureonthermostat:bathroomthermostat:setpoint"}
|
||||
Switch Bathroom_Thermostat_Power "Power" { channel="broadlinkthermostat:floureonthermostat:bathroomthermostat:power"}
|
||||
Switch Bathroom_Thermostat_Active "Active" { channel="broadlinkthermostat:floureonthermostat:bathroomthermostat:active"}
|
||||
String Bathroom_Thermostat_Mode "Mode" { channel="broadlinkthermostat:floureonthermostat:bathroomthermostat:mode"}
|
||||
String Bathroom_Thermostat_Sensor "Sensor" { channel="broadlinkthermostat:floureonthermostat:bathroomthermostat:sensor"}
|
||||
Switch Bathroom_Thermostat_Lock "Lock" <lock> { channel="broadlinkthermostat:floureonthermostat:bathroomthermostat:remotelock"}
|
||||
DateTime Bathroom_Thermostat_Time "Time [%1$tm/%1$td %1$tH:%1$tM]" <time> { channel="broadlinkthermostat:floureonthermostat:bathroomthermostat:time"}
|
||||
|
||||
```
|
26
bundles/org.openhab.binding.broadlinkthermostat/pom.xml
Normal file
26
bundles/org.openhab.binding.broadlinkthermostat/pom.xml
Normal file
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_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.broadlinkthermostat</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: Broadlink Thermostat Binding</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.github.mob41.blapi</groupId>
|
||||
<artifactId>broadlink-java-api</artifactId>
|
||||
<version>1.0.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.broadlinkthermostat-${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-broadlinkthermostat" description="Broadlink Thermostat Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<feature dependency="true">openhab.tp-jaxb</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.broadlinkthermostat/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.broadlinkthermostat.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link BroadlinkThermostatBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Florian Mueller - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BroadlinkThermostatBindingConstants {
|
||||
|
||||
private static final String BINDING_ID = "broadlinkthermostat";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID FLOUREON_THERMOSTAT_THING_TYPE = new ThingTypeUID(BINDING_ID,
|
||||
"floureonthermostat");
|
||||
public static final ThingTypeUID HYSEN_THERMOSTAT_THING_TYPE = new ThingTypeUID(BINDING_ID, "hysenthermostat");
|
||||
public static final ThingTypeUID UNKNOWN_BROADLINKTHERMOSTAT_THING_TYPE = new ThingTypeUID(BINDING_ID,
|
||||
"unknownbroadlinkthermostatdevice");
|
||||
|
||||
// List of all Channel ids
|
||||
public static final String ROOM_TEMPERATURE = "roomtemperature";
|
||||
public static final String ROOM_TEMPERATURE_EXTERNAL_SENSOR = "roomtemperatureexternalsensor";
|
||||
public static final String SETPOINT = "setpoint";
|
||||
public static final String POWER = "power";
|
||||
public static final String MODE = "mode";
|
||||
public static final String SENSOR = "sensor";
|
||||
public static final String TEMPERATURE_OFFSET = "temperatureoffset";
|
||||
public static final String ACTIVE = "active";
|
||||
public static final String REMOTE_LOCK = "remotelock";
|
||||
public static final String TIME = "time";
|
||||
|
||||
// Config properties
|
||||
public static final String HOST = "host";
|
||||
public static final String DESCRIPTION = "description";
|
||||
|
||||
public static final String MODE_AUTO = "auto";
|
||||
public static final String SENSOR_INTERNAL = "internal";
|
||||
public static final String SENSOR_EXTERNAL = "external";
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.broadlinkthermostat.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link BroadlinkThermostatConfig} class holds the configuration properties of the thing.
|
||||
*
|
||||
* @author Florian Mueller - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class BroadlinkThermostatConfig {
|
||||
private String host;
|
||||
private String macAddress;
|
||||
|
||||
public BroadlinkThermostatConfig() {
|
||||
this.host = "0.0.0.0";
|
||||
this.macAddress = "00:00:00:00";
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public void setHost(String host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public String getMacAddress() {
|
||||
return macAddress;
|
||||
}
|
||||
|
||||
public void setMacAddress(String macAddress) {
|
||||
this.macAddress = macAddress;
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.broadlinkthermostat.internal;
|
||||
|
||||
import static org.openhab.binding.broadlinkthermostat.internal.BroadlinkThermostatBindingConstants.*;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.broadlinkthermostat.internal.handler.FloureonThermostatHandler;
|
||||
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.Component;
|
||||
|
||||
/**
|
||||
* The {@link BroadlinkThermostatHandlerFactory} is responsible for creating things and thing handlers.
|
||||
*
|
||||
* @author Florian Mueller - Initial contribution
|
||||
*/
|
||||
@Component(configurationPid = "binding.broadlinkthermostat", service = ThingHandlerFactory.class)
|
||||
@NonNullByDefault
|
||||
public class BroadlinkThermostatHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(FLOUREON_THERMOSTAT_THING_TYPE,
|
||||
HYSEN_THERMOSTAT_THING_TYPE, UNKNOWN_BROADLINKTHERMOSTAT_THING_TYPE);
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
if (FLOUREON_THERMOSTAT_THING_TYPE.equals(thingTypeUID) || HYSEN_THERMOSTAT_THING_TYPE.equals(thingTypeUID)) {
|
||||
return new FloureonThermostatHandler(thing);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,194 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.broadlinkthermostat.internal.discovery;
|
||||
|
||||
import static org.openhab.binding.broadlinkthermostat.internal.BroadlinkThermostatBindingConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.broadlinkthermostat.internal.BroadlinkThermostatBindingConstants;
|
||||
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.config.discovery.DiscoveryService;
|
||||
import org.openhab.core.net.NetworkAddressService;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.github.mob41.blapi.BLDevice;
|
||||
|
||||
/**
|
||||
* The {@link BroadlinkThermostatDiscoveryService} is responsible for discovering Broadlinkthermostat devices through
|
||||
* Broadcast.
|
||||
*
|
||||
* @author Florian Mueller - Initial contribution
|
||||
*/
|
||||
@Component(service = DiscoveryService.class, configurationPid = "discovery.broadlinkthermostat")
|
||||
@NonNullByDefault
|
||||
public class BroadlinkThermostatDiscoveryService extends AbstractDiscoveryService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(BroadlinkThermostatDiscoveryService.class);
|
||||
|
||||
private final NetworkAddressService networkAddressService;
|
||||
|
||||
private static final Set<ThingTypeUID> DISCOVERABLE_THING_TYPES_UIDS = Set.of(FLOUREON_THERMOSTAT_THING_TYPE,
|
||||
UNKNOWN_BROADLINKTHERMOSTAT_THING_TYPE);
|
||||
private static final int DISCOVERY_TIMEOUT_SECONDS = 30;
|
||||
private @Nullable ScheduledFuture<?> backgroundDiscoveryFuture;
|
||||
|
||||
@Activate
|
||||
public BroadlinkThermostatDiscoveryService(@Reference NetworkAddressService networkAddressService) {
|
||||
super(DISCOVERABLE_THING_TYPES_UIDS, DISCOVERY_TIMEOUT_SECONDS);
|
||||
this.networkAddressService = networkAddressService;
|
||||
}
|
||||
|
||||
private void createScanner() {
|
||||
|
||||
long timestampOfLastScan = getTimestampOfLastScan();
|
||||
BLDevice[] blDevices = new BLDevice[0];
|
||||
try {
|
||||
@Nullable
|
||||
InetAddress sourceAddress = getIpAddress();
|
||||
if (sourceAddress != null) {
|
||||
logger.debug("Using source address {} for sending out broadcast request.", sourceAddress);
|
||||
blDevices = BLDevice.discoverDevices(sourceAddress, 0, DISCOVERY_TIMEOUT_SECONDS * 1000);
|
||||
} else {
|
||||
blDevices = BLDevice.discoverDevices(DISCOVERY_TIMEOUT_SECONDS * 1000);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.debug("Error while trying to discover broadlinkthermostat devices: {}", e.getMessage());
|
||||
}
|
||||
logger.debug("Discovery service found {} broadlinkthermostat devices.", blDevices.length);
|
||||
|
||||
for (BLDevice dev : blDevices) {
|
||||
logger.debug("Broadlinkthermostat device {} of type {} with Host {} and MAC {}", dev.getDeviceDescription(),
|
||||
Integer.toHexString(dev.getDeviceType()), dev.getHost(), dev.getMac());
|
||||
|
||||
ThingUID thingUID;
|
||||
String id = dev.getHost().replaceAll("\\.", "-");
|
||||
logger.debug("Device ID with IP address replacement: {}", id);
|
||||
try {
|
||||
id = getHostnameWithoutDomain(InetAddress.getByName(dev.getHost()).getHostName());
|
||||
logger.debug("Device ID with DNS name: {}", id);
|
||||
} catch (UnknownHostException e) {
|
||||
logger.debug("Discovered device with IP {} does not have a DNS name, using IP as thing UID.",
|
||||
dev.getHost());
|
||||
}
|
||||
|
||||
switch (dev.getDeviceDescription()) {
|
||||
case "Floureon Thermostat":
|
||||
thingUID = new ThingUID(FLOUREON_THERMOSTAT_THING_TYPE, id);
|
||||
break;
|
||||
case "Hysen Thermostat":
|
||||
thingUID = new ThingUID(HYSEN_THERMOSTAT_THING_TYPE, id);
|
||||
break;
|
||||
default:
|
||||
thingUID = new ThingUID(UNKNOWN_BROADLINKTHERMOSTAT_THING_TYPE, id);
|
||||
}
|
||||
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(BroadlinkThermostatBindingConstants.HOST, dev.getHost());
|
||||
properties.put(Thing.PROPERTY_MAC_ADDRESS, dev.getMac().getMacString());
|
||||
properties.put(BroadlinkThermostatBindingConstants.DESCRIPTION, dev.getDeviceDescription());
|
||||
|
||||
logger.debug("Property map: {}", properties);
|
||||
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties)
|
||||
.withLabel(dev.getDeviceDescription() + " (" + id + ")")
|
||||
.withRepresentationProperty(Thing.PROPERTY_MAC_ADDRESS).build();
|
||||
|
||||
thingDiscovered(discoveryResult);
|
||||
}
|
||||
removeOlderResults(timestampOfLastScan);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startScan() {
|
||||
scheduler.execute(this::createScanner);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startBackgroundDiscovery() {
|
||||
logger.trace("Starting background scan for Broadlinkthermostat devices");
|
||||
ScheduledFuture<?> currentBackgroundDiscoveryFuture = backgroundDiscoveryFuture;
|
||||
if (currentBackgroundDiscoveryFuture != null) {
|
||||
currentBackgroundDiscoveryFuture.cancel(true);
|
||||
}
|
||||
backgroundDiscoveryFuture = scheduler.scheduleWithFixedDelay(this::createScanner, 0, 60, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stopBackgroundDiscovery() {
|
||||
logger.trace("Stopping background scan for Broadlinkthermostat devices");
|
||||
@Nullable
|
||||
ScheduledFuture<?> backgroundDiscoveryFuture = this.backgroundDiscoveryFuture;
|
||||
if (backgroundDiscoveryFuture != null && !backgroundDiscoveryFuture.isCancelled()) {
|
||||
if (backgroundDiscoveryFuture.cancel(true)) {
|
||||
this.backgroundDiscoveryFuture = null;
|
||||
}
|
||||
}
|
||||
stopScan();
|
||||
}
|
||||
|
||||
private @Nullable InetAddress getIpAddress() {
|
||||
return getIpFromNetworkAddressService().orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses openHAB's NetworkAddressService to determine the local primary network interface.
|
||||
*
|
||||
* @return local ip or <code>empty</code> if configured primary IP is not set or could not be parsed.
|
||||
*/
|
||||
private Optional<InetAddress> getIpFromNetworkAddressService() {
|
||||
String ipAddress = networkAddressService.getPrimaryIpv4HostAddress();
|
||||
if (ipAddress == null) {
|
||||
logger.warn("No network interface could be found.");
|
||||
return Optional.empty();
|
||||
}
|
||||
try {
|
||||
return Optional.of(InetAddress.getByName(ipAddress));
|
||||
} catch (UnknownHostException e) {
|
||||
logger.warn("Configured primary IP cannot be parsed: {} Details: {}", ipAddress, e.getMessage());
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private String getHostnameWithoutDomain(String hostname) {
|
||||
String broadlinkthermostatRegex = "BroadLink-OEM[-A-Za-z0-9]{12}.*";
|
||||
if (hostname.matches(broadlinkthermostatRegex)) {
|
||||
String[] dotSeparatedString = hostname.split("\\.");
|
||||
logger.debug("Found original broadlink DNS name {}, removing domain", hostname);
|
||||
return dotSeparatedString[0].replaceAll("\\.", "-");
|
||||
} else {
|
||||
logger.debug("DNS name does not match original broadlink name: {}, using it without modification. ",
|
||||
hostname);
|
||||
return hostname.replaceAll("\\.", "-");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.broadlinkthermostat.internal.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.broadlinkthermostat.internal.BroadlinkThermostatConfig;
|
||||
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.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.github.mob41.blapi.BLDevice;
|
||||
|
||||
/**
|
||||
* The {@link BroadlinkThermostatHandler} is the device handler class for a broadlinkthermostat device.
|
||||
*
|
||||
* @author Florian Mueller - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class BroadlinkThermostatHandler extends BaseThingHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(BroadlinkThermostatHandler.class);
|
||||
|
||||
@Nullable
|
||||
BLDevice blDevice;
|
||||
private @Nullable ScheduledFuture<?> scanJob;
|
||||
@Nullable
|
||||
String host;
|
||||
@Nullable
|
||||
String macAddress;
|
||||
|
||||
/**
|
||||
* Creates a new instance of this class for the {@link Thing}.
|
||||
*
|
||||
* @param thing the thing that should be handled, not null
|
||||
*/
|
||||
BroadlinkThermostatHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
void authenticate(boolean reauth) {
|
||||
logger.debug("Authenticating with broadlinkthermostat device {}...", thing.getLabel());
|
||||
try {
|
||||
BLDevice blDevice = this.blDevice;
|
||||
if (blDevice != null && blDevice.auth(reauth)) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Error while authenticating broadlinkthermostat device " + thing.getLabel() + ":" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
BroadlinkThermostatConfig config = getConfigAs(BroadlinkThermostatConfig.class);
|
||||
host = config.getHost();
|
||||
macAddress = config.getMacAddress();
|
||||
|
||||
// schedule a new scan every minute
|
||||
scanJob = scheduler.scheduleWithFixedDelay(this::refreshData, 0, 1, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
protected abstract void refreshData();
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
ScheduledFuture<?> currentScanJob = scanJob;
|
||||
if (currentScanJob != null) {
|
||||
currentScanJob.cancel(true);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,279 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.broadlinkthermostat.internal.handler;
|
||||
|
||||
import static org.openhab.binding.broadlinkthermostat.internal.BroadlinkThermostatBindingConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.cache.ExpiringCache;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
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.SIUnits;
|
||||
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.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.github.mob41.blapi.FloureonDevice;
|
||||
import com.github.mob41.blapi.dev.hysen.AdvancedStatusInfo;
|
||||
import com.github.mob41.blapi.dev.hysen.BaseStatusInfo;
|
||||
import com.github.mob41.blapi.dev.hysen.SensorControl;
|
||||
import com.github.mob41.blapi.mac.Mac;
|
||||
import com.github.mob41.blapi.pkt.cmd.hysen.SetTimeCommand;
|
||||
|
||||
/**
|
||||
* The {@link FloureonThermostatHandler} is responsible for handling thermostats labeled as Floureon Thermostat.
|
||||
*
|
||||
* @author Florian Mueller - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FloureonThermostatHandler extends BroadlinkThermostatHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(FloureonThermostatHandler.class);
|
||||
private @Nullable FloureonDevice floureonDevice;
|
||||
|
||||
private static final long CACHE_EXPIRY = TimeUnit.SECONDS.toSeconds(3);
|
||||
private final ExpiringCache<AdvancedStatusInfo> advancedStatusInfoExpiringCache = new ExpiringCache<>(CACHE_EXPIRY,
|
||||
this::refreshAdvancedStatus);
|
||||
|
||||
/**
|
||||
* Creates a new instance of this class for the {@link FloureonThermostatHandler}.
|
||||
*
|
||||
* @param thing the thing that should be handled, not null
|
||||
*/
|
||||
public FloureonThermostatHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new instance of a {@link FloureonThermostatHandler}.
|
||||
*/
|
||||
@Override
|
||||
public void initialize() {
|
||||
super.initialize();
|
||||
if (host != null && macAddress != null) {
|
||||
try {
|
||||
blDevice = new FloureonDevice(host, new Mac(macAddress));
|
||||
this.floureonDevice = (FloureonDevice) blDevice;
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} catch (IOException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Could not find broadlinkthermostat device at host" + host + "with MAC+" + macAddress + ": "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("Command: {}", command.toFullString());
|
||||
authenticate(false);
|
||||
|
||||
if (command == RefreshType.REFRESH) {
|
||||
refreshData();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (channelUID.getIdWithoutGroup()) {
|
||||
case SETPOINT:
|
||||
handleSetpointCommand(channelUID, command);
|
||||
break;
|
||||
case POWER:
|
||||
handlePowerCommand(channelUID, command);
|
||||
break;
|
||||
case MODE:
|
||||
handleModeCommand(channelUID, command);
|
||||
break;
|
||||
case SENSOR:
|
||||
handleSensorCommand(channelUID, command);
|
||||
break;
|
||||
case REMOTE_LOCK:
|
||||
handleRemoteLockCommand(channelUID, command);
|
||||
break;
|
||||
case TIME:
|
||||
handleSetTimeCommand(channelUID, command);
|
||||
break;
|
||||
default:
|
||||
logger.warn("Channel {} does not support command {}", channelUID, command);
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePowerCommand(ChannelUID channelUID, Command command) {
|
||||
FloureonDevice floureonDevice = this.floureonDevice;
|
||||
if (command instanceof OnOffType && floureonDevice != null) {
|
||||
try {
|
||||
floureonDevice.setPower(command == OnOffType.ON);
|
||||
} catch (Exception e) {
|
||||
logger.warn("Error while setting power of {} to {}: {}", thing.getUID(), command, e.getMessage());
|
||||
}
|
||||
} else {
|
||||
logger.warn("Channel {} does not support command {}", channelUID, command);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleModeCommand(ChannelUID channelUID, Command command) {
|
||||
FloureonDevice floureonDevice = this.floureonDevice;
|
||||
if (command instanceof StringType && floureonDevice != null) {
|
||||
try {
|
||||
if (MODE_AUTO.equals(command.toFullString())) {
|
||||
floureonDevice.switchToAuto();
|
||||
} else {
|
||||
floureonDevice.switchToManual();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("Error while setting power off {} to {}: {}", thing.getUID(), command, e.getMessage());
|
||||
}
|
||||
} else {
|
||||
logger.warn("Channel {} does not support command {}", channelUID, command);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSetpointCommand(ChannelUID channelUID, Command command) {
|
||||
FloureonDevice floureonDevice = this.floureonDevice;
|
||||
if (command instanceof QuantityType && floureonDevice != null) {
|
||||
try {
|
||||
QuantityType<?> temperatureQuantityType = ((QuantityType<?>) command).toUnit(SIUnits.CELSIUS);
|
||||
if (temperatureQuantityType != null) {
|
||||
floureonDevice.setThermostatTemp(temperatureQuantityType.doubleValue());
|
||||
} else {
|
||||
logger.warn("Could not convert {} to °C", command);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("Error while setting setpoint of {} to {}: {}", thing.getUID(), command, e.getMessage());
|
||||
}
|
||||
|
||||
} else {
|
||||
logger.warn("Channel {} does not support command {}", channelUID, command);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSensorCommand(ChannelUID channelUID, Command command) {
|
||||
FloureonDevice floureonDevice = this.floureonDevice;
|
||||
if (command instanceof StringType && floureonDevice != null) {
|
||||
try {
|
||||
BaseStatusInfo statusInfo = floureonDevice.getBasicStatus();
|
||||
if (SENSOR_INTERNAL.equals(command.toFullString())) {
|
||||
floureonDevice.setMode(statusInfo.getAutoMode(), statusInfo.getLoopMode(), SensorControl.INTERNAL);
|
||||
} else if (SENSOR_EXTERNAL.equals(command.toFullString())) {
|
||||
floureonDevice.setMode(statusInfo.getAutoMode(), statusInfo.getLoopMode(), SensorControl.EXTERNAL);
|
||||
} else {
|
||||
floureonDevice.setMode(statusInfo.getAutoMode(), statusInfo.getLoopMode(),
|
||||
SensorControl.INTERNAL_TEMP_EXTERNAL_LIMIT);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("Error while trying to set sensor mode {}: {}", command, e.getMessage());
|
||||
}
|
||||
} else {
|
||||
logger.warn("Channel {} does not support command {}", channelUID, command);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleRemoteLockCommand(ChannelUID channelUID, Command command) {
|
||||
FloureonDevice floureonDevice = this.floureonDevice;
|
||||
if (command instanceof OnOffType && floureonDevice != null) {
|
||||
try {
|
||||
floureonDevice.setLock(command == OnOffType.ON);
|
||||
} catch (Exception e) {
|
||||
logger.warn("Error while setting remote lock of {} to {}: {}", thing.getUID(), command, e.getMessage());
|
||||
}
|
||||
} else {
|
||||
logger.warn("Channel {} does not support command {}", channelUID, command);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSetTimeCommand(ChannelUID channelUID, Command command) {
|
||||
if (command instanceof DateTimeType) {
|
||||
ZonedDateTime zonedDateTime = ((DateTimeType) command).getZonedDateTime();
|
||||
try {
|
||||
new SetTimeCommand(tob(zonedDateTime.getHour()), tob(zonedDateTime.getMinute()),
|
||||
tob(zonedDateTime.getSecond()), tob(zonedDateTime.getDayOfWeek().getValue()))
|
||||
.execute(floureonDevice);
|
||||
} catch (Exception e) {
|
||||
logger.warn("Error while setting time of {} to {}: {}", thing.getUID(), command, e.getMessage());
|
||||
}
|
||||
} else {
|
||||
logger.warn("Channel {} does not support command {}", channelUID, command);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private AdvancedStatusInfo refreshAdvancedStatus() {
|
||||
if (ThingStatus.ONLINE != thing.getStatus()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
FloureonDevice floureonDevice = this.floureonDevice;
|
||||
if (floureonDevice != null) {
|
||||
try {
|
||||
AdvancedStatusInfo advancedStatusInfo = floureonDevice.getAdvancedStatus();
|
||||
if (advancedStatusInfo == null) {
|
||||
logger.warn("Device {} did not return any data. Trying to reauthenticate...", thing.getUID());
|
||||
authenticate(true);
|
||||
advancedStatusInfo = floureonDevice.getAdvancedStatus();
|
||||
}
|
||||
if (advancedStatusInfo == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Device not responding.");
|
||||
return null;
|
||||
}
|
||||
return advancedStatusInfo;
|
||||
} catch (Exception e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Error while retrieving data for " + thing.getUID() + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void refreshData() {
|
||||
|
||||
AdvancedStatusInfo advancedStatusInfo = advancedStatusInfoExpiringCache.getValue();
|
||||
if (advancedStatusInfo == null) {
|
||||
return;
|
||||
}
|
||||
logger.trace("Retrieved data from device {}: {}", thing.getUID(), advancedStatusInfo);
|
||||
updateState(ROOM_TEMPERATURE, new QuantityType<>(advancedStatusInfo.getRoomTemp(), SIUnits.CELSIUS));
|
||||
updateState(ROOM_TEMPERATURE_EXTERNAL_SENSOR,
|
||||
new QuantityType<>(advancedStatusInfo.getExternalTemp(), SIUnits.CELSIUS));
|
||||
updateState(SETPOINT, new QuantityType<>(advancedStatusInfo.getThermostatTemp(), SIUnits.CELSIUS));
|
||||
updateState(POWER, OnOffType.from(advancedStatusInfo.getPower()));
|
||||
updateState(MODE, StringType.valueOf(advancedStatusInfo.getAutoMode() ? "auto" : "manual"));
|
||||
updateState(SENSOR, StringType.valueOf(advancedStatusInfo.getSensorControl().name()));
|
||||
updateState(TEMPERATURE_OFFSET, new QuantityType<>(advancedStatusInfo.getDif(), SIUnits.CELSIUS));
|
||||
updateState(ACTIVE, OnOffType.from(advancedStatusInfo.getActive()));
|
||||
updateState(REMOTE_LOCK, OnOffType.from(advancedStatusInfo.getRemoteLock()));
|
||||
updateState(TIME, new DateTimeType(getTimestamp(advancedStatusInfo)));
|
||||
}
|
||||
|
||||
private ZonedDateTime getTimestamp(AdvancedStatusInfo advancedStatusInfo) {
|
||||
ZonedDateTime now = ZonedDateTime.now();
|
||||
return now.with(
|
||||
LocalTime.of(advancedStatusInfo.getHour(), advancedStatusInfo.getMin(), advancedStatusInfo.getSec()));
|
||||
}
|
||||
|
||||
private static byte tob(int in) {
|
||||
return (byte) (in & 0xff);
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="broadlinkthermostat" 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>Broadlinkthermostat Binding</name>
|
||||
<description>This is the binding for Broadlinkthermostat devices.</description>
|
||||
</binding:binding>
|
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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:broadlinkthermostat:floureonandhysenthermostat">
|
||||
<parameter name="host" type="text" required="true">
|
||||
<label>Hostname</label>
|
||||
<description>The hostname/IP address the device is bound to, e.g. 192.168.0.2</description>
|
||||
<context>network-address</context>
|
||||
</parameter>
|
||||
<parameter name="macAddress" type="text" required="true">
|
||||
<label>MAC Address</label>
|
||||
<description>The unique MAC address of the device, e.g. 00:10:FA:6E:38:4A</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
</config-description:config-descriptions>
|
@ -0,0 +1,136 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="broadlinkthermostat"
|
||||
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">
|
||||
|
||||
<!-- Floureon Thermostat Thing Type -->
|
||||
<thing-type id="floureonthermostat">
|
||||
<label>Floureon Thermostat</label>
|
||||
<description>A heating device thermostat</description>
|
||||
|
||||
<channels>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="mode" typeId="mode"/>
|
||||
<channel id="sensor" typeId="sensor"/>
|
||||
<channel id="roomtemperature" typeId="roomtemperature"/>
|
||||
<channel id="roomtemperatureexternalsensor" typeId="roomtemperatureexternalsensor"/>
|
||||
<channel id="active" typeId="active"/>
|
||||
<channel id="setpoint" typeId="setpoint"/>
|
||||
<channel id="temperatureoffset" typeId="temperatureoffset"/>
|
||||
<channel id="remotelock" typeId="remotelock"/>
|
||||
<channel id="time" typeId="time"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>host</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:broadlinkthermostat:floureonandhysenthermostat"/>
|
||||
</thing-type>
|
||||
<thing-type id="hysenthermostat">
|
||||
<label>Hysen Thermostat</label>
|
||||
<description>A heating device thermostat</description>
|
||||
|
||||
<channels>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="mode" typeId="mode"/>
|
||||
<channel id="sensor" typeId="sensor"/>
|
||||
<channel id="roomtemperature" typeId="roomtemperature"/>
|
||||
<channel id="roomtemperatureexternalsensor" typeId="roomtemperatureexternalsensor"/>
|
||||
<channel id="active" typeId="active"/>
|
||||
<channel id="setpoint" typeId="setpoint"/>
|
||||
<channel id="temperatureoffset" typeId="temperatureoffset"/>
|
||||
<channel id="remotelock" typeId="remotelock"/>
|
||||
<channel id="time" typeId="time"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>host</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:broadlinkthermostat:floureonandhysenthermostat"/>
|
||||
</thing-type>
|
||||
|
||||
<channel-type id="power">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Power</label>
|
||||
<description>Switch display on/off and enable/disables heating</description>
|
||||
<category>Switch</category>
|
||||
</channel-type>
|
||||
<channel-type id="mode">
|
||||
<item-type>String</item-type>
|
||||
<label>Mode</label>
|
||||
<description>Current mode of the thermostat</description>
|
||||
<state>
|
||||
<options>
|
||||
<option value="auto">auto</option>
|
||||
<option value="manual">manual</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
<channel-type id="sensor">
|
||||
<item-type>String</item-type>
|
||||
<label>Sensor</label>
|
||||
<description>The sensor (internal/external) used for triggering the thermostat</description>
|
||||
<category>Sensor</category>
|
||||
<state>
|
||||
<options>
|
||||
<option value="internal">internal</option>
|
||||
<option value="external">external</option>
|
||||
<option value="internal_temp_external_limit">internal control temperature; external limit temperature</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
<channel-type id="active">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Active</label>
|
||||
<description>Shows if thermostat is currently actively heating</description>
|
||||
<category>Switch</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
<channel-type id="roomtemperature">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Temperature</label>
|
||||
<description>Room temperature, measured directly at the device</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.1f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
<channel-type id="roomtemperatureexternalsensor">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Temperature Ext. Sensor</label>
|
||||
<description>Room temperature, measured by the external sensor</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.1f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
<channel-type id="setpoint">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Setpoint</label>
|
||||
<description>Temperature setpoint that open/close valve</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.1f %unit%" step="0.5"/>
|
||||
</channel-type>
|
||||
<channel-type id="temperatureoffset">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Temperature Offset</label>
|
||||
<description>Manual temperature adjustment</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.1f %unit%" step="0.5" min="-2.5" max="2.5"/>
|
||||
</channel-type>
|
||||
<channel-type id="temperature">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Temperature</label>
|
||||
<description>Temperature</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.1f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
<channel-type id="remotelock">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Remote Lock</label>
|
||||
<description>Locks the device to only allow remote actions</description>
|
||||
<category>Lock</category>
|
||||
</channel-type>
|
||||
<channel-type id="time">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Time</label>
|
||||
<description>The time and day of week</description>
|
||||
<category>Time</category>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
@ -69,6 +69,7 @@
|
||||
<module>org.openhab.binding.boschindego</module>
|
||||
<module>org.openhab.binding.boschshc</module>
|
||||
<module>org.openhab.binding.bosesoundtouch</module>
|
||||
<module>org.openhab.binding.broadlinkthermostat</module>
|
||||
<module>org.openhab.binding.bsblan</module>
|
||||
<module>org.openhab.binding.bticinosmarther</module>
|
||||
<module>org.openhab.binding.buienradar</module>
|
||||
|
Loading…
Reference in New Issue
Block a user