[freeathomesystem] Initial contribution (#13703)

Signed-off-by: Andras Uhrin <andras.uhrin@gmail.com>
This commit is contained in:
Andras Uhrin 2024-04-20 18:14:54 +02:00 committed by GitHub
parent 6db28f5b46
commit f466c88406
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
38 changed files with 5761 additions and 0 deletions

View File

@ -114,6 +114,7 @@
/bundles/org.openhab.binding.folderwatcher/ @goopilot /bundles/org.openhab.binding.folderwatcher/ @goopilot
/bundles/org.openhab.binding.folding/ @fa2k /bundles/org.openhab.binding.folding/ @fa2k
/bundles/org.openhab.binding.foobot/ @airboxlab @Hilbrand /bundles/org.openhab.binding.foobot/ @airboxlab @Hilbrand
/bundles/org.openhab.binding.freeathomesystem/ @andrasU
/bundles/org.openhab.binding.freebox/ @lolodomo /bundles/org.openhab.binding.freebox/ @lolodomo
/bundles/org.openhab.binding.freeboxos/ @clinique /bundles/org.openhab.binding.freeboxos/ @clinique
/bundles/org.openhab.binding.freecurrency/ @J-N-K /bundles/org.openhab.binding.freecurrency/ @J-N-K

View File

@ -561,6 +561,11 @@
<artifactId>org.openhab.binding.foobot</artifactId> <artifactId>org.openhab.binding.foobot</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.freeathomesystem</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.openhab.addons.bundles</groupId> <groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.freebox</artifactId> <artifactId>org.openhab.binding.freebox</artifactId>

View File

@ -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

View File

@ -0,0 +1,143 @@
# ABB/Busch-free@home Smart Home binding
openHAB ABB/Busch-free@home binding based on the offical free@home local API.
# Description
This binding allows you to connect your free@home Smart Home system from ABB / Busch-Jaeger to openHAB and to control and observe most of the components.
It requires a System Access Point with version 2.6.1 or higher.
# Supported Devices
**Network Gateway / System Access Point**
- ABB / Busch-Jaeger System Access Point 2.0
**Sensors and Actuators**
- Switch Actuator Sensor with single and multiple channels (wired and wireless)
- Dimming Actuator Sensor with single and multiple channels (wired, wireless and flex)
- Motion detection with and without actuator (wired, wireless and flex)
- Switch Actuator 4-channel
- Dimming Actuator 4- and 6-channel
- Door opener actuator
- Door ring sensor
- Hue devices (untested)
**Blinds and Windows**
- Shutter Actuator with single and multiple channels (wired and wireless)
- Blind Actuator with single and multiple channels (wired and wireless)
- Attic window actuator
- Awning actuator
**Room Temperature Control**
- Room temperature controller master without fan
- Room temperature controller master with fan
- Room temperature controller slave
**Other devices** (e.g. movement detector, ring sensor and door opener)
- IP-touch panel (function: door opener, door ring sensor)
- Virtual devices (e.g. virtual switch, RTC and detectors)
**Information about virtual devices**
Virtual device in the free@home smart-home system needs continuous keep-alive signal otherwise the free@home device is marked as unresponsive.
This keep-alive signal must be provided by a user script or set the TTL value of the virtual device to "-1" during the creation of the virtual device.
# Tested SysAP Versions
| Version | Supported |
|---------|-----------|
| 2.6.1 | yes |
| 2.6.3 | yes |
| 3.1.1 | yes |
# Setup / Installation
## Prerequisites
To make use of this Binding first the local free@home API has to be activated.
The API is disabled by default.
1. Open the free@home next app
1. Browse to "Settings ⇨ free@home settings ⇨ local API and activate the checkbox
## Setup and Discovery
The free@home bridge shall be added manually.
Once it is added as a Thing with correct credentials, the scan of free@home devices will be possible.
## free@home components as openHAB Things
The ABB/Busch free@home system is calling its smart home components as free@home devices.
The free@home system devices can have one or multiple channels depending the device's features.
During the scanning process the openHAB binding will detect only the devices IDs.
The device features will be detected at the point in time, when a openHAB Thing is created.
At the of the creation the free@home binding will automatically create the relevant channels without any further configuration.
If a free@home system device has multiple smart-home channels (e.g. 4x DIN/rail Actuator), the newly created Thing will get all relevant channels to operate all actuators existing inside the free@home device.
## Sensors and Actuators of free@home Devices as Things in openHAB
The free@home system supports sensors and actuators.
The connection of sensors and actuators are done on the free@home system dashboard.
If a Thing channel is a free@home device sensor channel, this channel is read only.
## Bridge Configuration
There are several settings for a bridge:
| Parameter | Description |
|--------------------------|-----------------------------------------|
| **ipAddress** (required) | Network address of the free@home SysAP |
| **username** (required) | Valid user name for the free@home SysAP |
| **password** (required) | Password of the user |
## Examples for .things
Things are all discovered automatically and visible on the openHAB UI after pushing the scan button
In order to manually configure a Thing:
```java
Bridge freeathomesystem:bridge:mysysap [ ipAddress="...", username="...", password="..." ]
{
Thing device ABB700000001
Thing device ABB700000012
}
```
The only parameter needed to create a Thing is the free@home device ID, which you can find as sticker on the device.
The creation of the openHAB channels to operate the free@home device is happening automatically based on the device features detected online.
## Examples for .items
Sample for the free@home thermostat device
```java
Switch Livingroom_Thermostat_Switch "Thermostat Siwtch" <temperature> (Livingroom) { channel="freeathomesystem:device:312095ad75:ABB700000001:ch0000#controller-on-off-request" }
Switch LivingRoom_Thermostat_EcoOnOff "Thermostat Eco Activation" <switch> (Livingroom) { channel="freeathomesystem:device:312095ad75:ABB700000001:ch0000#eco-mode-on-off-request" }
Number LivingRoom_Thermostat_MeasuredTemperature "Measured Temperature" <temperature> (Livingroom) ["Temperature"] { channel="freeathomesystem:device:312095ad75:ABB700000001:ch0000#measured-temperature" }
Number LivingRoom_Thermostat_SetpointTemperature "Setpoint Temperature" <temperature> (Livingroom) ["Setpoint", "Temperature"] { channel="freeathomesystem:device:312095ad75:ABB700000001:ch0000#absolute-setpoint-temperature" }
Number LivingRoom_ThermostatHeatingActive "Thermostat Heating Active" <temperature> (Livingroom) ["Status"] { channel="freeathomesystem:device:312095ad75:ABB700000001:ch0000#heating-active" }
Number LivingRoom_ThermostatHeatingDemand "Thermostat Heating Demand" <temperature> (Livingroom) ["Status"] { channel="freeathomesystem:device:312095ad75:ABB700000001:ch0000#status-indication" }
```
Sample for the free@home device for switch
```java
Switch Livingroom_Switch "Livingroom Switch" <switch> (Livingroom) ["Light"] { channel="freeathomesystem:device:312095ad75:ABB700000012:ch0000#switch-on-off" }
Switch Livingroom_Lamp "Livingroom Lamp" <switch> (Livingroom) ["Light"] { channel="freeathomesystem:device:312095ad75:ABB700000012:ch0006#switch-on-off" }
Switch Livingroom_Aux "Livingroom Aux Switch" <switch> (Livingroom) ["Light"] { channel="freeathomesystem:device:312095ad75:ABB700000012:ch000b#switch-on-off" }
```
# Communities
[openHAB community of this binding](https://community.openhab.org/t/abb-busch-jager-free-home-official-rest-api/141698)
[Busch-Jaeger Community](https://community.busch-jaeger.de/)
[free@home user group Facebook DE](https://www.facebook.com/groups/738242583015188)
[free@home user group Facebook EN](https://www.facebook.com/groups/452502972031360)

View File

@ -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.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.binding.freeathomesystem</artifactId>
<name>openHAB Add-ons :: Bundles :: FreeAtHomeSystem Binding</name>
</project>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.freeathomesystem-${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-freeathomesystem" description="FreeAtHomeSystem Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.freeathomesystem/${project.version}</bundle>
</feature>
</features>

View File

@ -0,0 +1,42 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link FreeAtHomeSystemBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Andras Uhrin - Initial contribution
*/
@NonNullByDefault
public class FreeAtHomeSystemBindingConstants {
public static final String CONFIG_DESCRIPTION_URI_THING_PREFIX = "thing-type";
public static final String BINDING_ID = "freeathomesystem";
// List of all Thing Type UIDs
public static final String BRIDGE_TYPE_ID = "gateway";
public static final String DEVICE_TYPE_ID = "device";
// List of all Thing Type UIDs
public static final ThingTypeUID BRIDGE_TYPE_UID = new ThingTypeUID(BINDING_ID, BRIDGE_TYPE_ID);
public static final ThingTypeUID DEVICE_TYPE_UID = new ThingTypeUID(BINDING_ID, DEVICE_TYPE_ID);
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(BRIDGE_TYPE_UID, DEVICE_TYPE_UID);
}

View File

@ -0,0 +1,136 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal;
import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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.freeathomesystem.internal.datamodel.FreeAtHomeDeviceDescription;
import org.openhab.binding.freeathomesystem.internal.handler.FreeAtHomeBridgeHandler;
import org.openhab.binding.freeathomesystem.internal.util.FreeAtHomeHttpCommunicationException;
import org.openhab.core.config.discovery.AbstractThingHandlerDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link FreeAtHomeSystemDiscoveryService} is responsible for performing discovery of things
*
* @author Andras Uhrin - Initial contribution
*/
@NonNullByDefault
public class FreeAtHomeSystemDiscoveryService extends AbstractThingHandlerDiscoveryService<FreeAtHomeBridgeHandler> {
private final Logger logger = LoggerFactory.getLogger(FreeAtHomeSystemDiscoveryService.class);
private @Nullable ScheduledFuture<?> backgroundDiscoveryJob = null;
private static final long BACKGROUND_DISCOVERY_DELAY = 1L;
private boolean isScanTerminated;
Runnable runnable = new Runnable() {
@Override
public void run() {
ThingUID bridgeUID = thingHandler.getThing().getUID();
List<String> deviceList;
try {
deviceList = thingHandler.getDeviceDeviceList();
for (int i = 0; (i < deviceList.size()) && !isScanTerminated; i++) {
FreeAtHomeDeviceDescription device = thingHandler.getFreeatHomeDeviceDescription(deviceList.get(i));
ThingUID uid = new ThingUID(FreeAtHomeSystemBindingConstants.DEVICE_TYPE_UID, bridgeUID,
device.deviceId);
Map<String, Object> properties = new HashMap<>(1);
properties.put("deviceId", device.deviceId);
properties.put("interface", device.interfaceType);
String deviceLabel = device.deviceLabel;
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(uid).withLabel(deviceLabel)
.withRepresentationProperty("deviceId").withBridge(bridgeUID).withProperties(properties)
.build();
thingDiscovered(discoveryResult);
logger.debug("Thing discovered - DeviceId: {} - Device label: {}", device.getDeviceId(),
device.getDeviceLabel());
}
stopScan();
} catch (FreeAtHomeHttpCommunicationException e) {
logger.debug("Communication error in device discovery with the bridge: {}",
thingHandler.getThing().getLabel());
} catch (RuntimeException e) {
logger.debug("Scanning interrupted");
}
}
};
public FreeAtHomeSystemDiscoveryService(int timeout) {
super(FreeAtHomeBridgeHandler.class, FreeAtHomeSystemBindingConstants.SUPPORTED_THING_TYPES_UIDS, timeout,
false);
}
public FreeAtHomeSystemDiscoveryService() {
this(90);
}
@Override
public Set<ThingTypeUID> getSupportedThingTypes() {
return Set.of(FreeAtHomeSystemBindingConstants.BRIDGE_TYPE_UID);
}
@Override
protected void startScan() {
if (backgroundDiscoveryJob == null) {
this.removeOlderResults(Instant.now().toEpochMilli());
isScanTerminated = false;
backgroundDiscoveryJob = scheduler.schedule(runnable, BACKGROUND_DISCOVERY_DELAY, TimeUnit.SECONDS);
}
}
@Override
protected synchronized void stopScan() {
super.stopScan();
isScanTerminated = true;
ScheduledFuture<?> localDiscoveryJob = backgroundDiscoveryJob;
if (localDiscoveryJob != null) {
localDiscoveryJob.cancel(true);
}
backgroundDiscoveryJob = null;
removeOlderResults(Instant.now().toEpochMilli());
}
@Override
public void deactivate() {
removeOlderResults(Instant.now().toEpochMilli());
}
}

View File

@ -0,0 +1,116 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal;
import static org.openhab.binding.freeathomesystem.internal.FreeAtHomeSystemBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.freeathomesystem.internal.handler.FreeAtHomeBridgeHandler;
import org.openhab.binding.freeathomesystem.internal.handler.FreeAtHomeDeviceHandler;
import org.openhab.binding.freeathomesystem.internal.type.FreeAtHomeChannelTypeProvider;
import org.openhab.binding.freeathomesystem.internal.type.FreeAtHomeThingTypeProvider;
import org.openhab.core.i18n.LocaleProvider;
import org.openhab.core.i18n.TranslationProvider;
import org.openhab.core.io.net.http.HttpClientFactory;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.ComponentContext;
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 FreeAtHomeSystemHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Andras Uhrin - Initial contribution
*/
@NonNullByDefault
@Component(configurationPid = "binding.freeathomesystem", service = ThingHandlerFactory.class)
public class FreeAtHomeSystemHandlerFactory extends BaseThingHandlerFactory {
private final Logger logger = LoggerFactory.getLogger(FreeAtHomeSystemHandlerFactory.class);
private final HttpClient httpClient;
private final FreeAtHomeChannelTypeProvider channelTypeProvider;
private final TranslationProvider i18nProvider;
private final LocaleProvider localeProvider;
@Activate
public FreeAtHomeSystemHandlerFactory(@Reference FreeAtHomeThingTypeProvider thingTypeProvider,
@Reference FreeAtHomeChannelTypeProvider channelTypeProvider, @Reference TranslationProvider i18nProvider,
@Reference LocaleProvider localeProvider, @Reference HttpClientFactory httpClientFactory,
ComponentContext componentContext) {
super.activate(componentContext);
this.channelTypeProvider = channelTypeProvider;
this.i18nProvider = i18nProvider;
this.localeProvider = localeProvider;
// create httpClient
httpClient = httpClientFactory.createHttpClient(FreeAtHomeSystemBindingConstants.BINDING_ID);
// Configure client
httpClient.setFollowRedirects(false);
httpClient.setMaxConnectionsPerDestination(1);
httpClient.setMaxRequestsQueuedPerDestination(50);
// Set timeouts
httpClient.setIdleTimeout(-1);
httpClient.setConnectTimeout(5000);
try {
// Start HttpClient.
httpClient.start();
} catch (Exception ex) {
logger.error("Could not create HttpClient: {}", ex.getMessage());
throw new IllegalStateException("Could not create HttpClient", ex);
}
}
@Deactivate
public void deactivate() {
try {
httpClient.stop();
} catch (Exception ex) {
logger.warn("Failed to stop HttpClient: {}", ex.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 (BRIDGE_TYPE_UID.equals(thingTypeUID)) {
return new FreeAtHomeBridgeHandler((Bridge) thing, httpClient);
} else if (DEVICE_TYPE_UID.equals(thingTypeUID)) {
return new FreeAtHomeDeviceHandler(thing, channelTypeProvider, i18nProvider, localeProvider);
}
return null;
}
}

View File

@ -0,0 +1,31 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.configuration;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link FreeAtHomeBridgeHandlerConfiguration} class contains fields mapping thing configuration parameters.
*
* @author Andras Uhrin - Initial contribution
*/
@NonNullByDefault
public class FreeAtHomeBridgeHandlerConfiguration {
/**
* Bridgeconfiguration parameter.
*/
public String ipAddress = "";
public String username = "";
public String password = "";
}

View File

@ -0,0 +1,25 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.configuration;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link FreeAtHomeDeviceHandlerConfiguration} class contains fields mapping device configuration parameters.
*
* @author Andras Uhrin - Initial contribution
*/
@NonNullByDefault
public class FreeAtHomeDeviceHandlerConfiguration {
public String deviceId = "";
}

View File

@ -0,0 +1,116 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.datamodel;
import java.util.Iterator;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonObject;
/**
*
* @author Andras Uhrin - Initial contribution
*
*/
@NonNullByDefault
public class FreeAtHomeDatapoint {
private final Logger logger = LoggerFactory.getLogger(FreeAtHomeDatapoint.class);
enum DatapointDirection {
UNKNOWN,
INPUT,
OUTPUT,
INPUTOUTPUT,
INPUT_AS_OUTPUT
};
public String channelId = "";
private String datapointId = "";
DatapointDirection searchForDatapoint(DatapointDirection direction, int neededPairingIDFunction, String channelId,
JsonObject jsonObjectOfChannel) {
DatapointDirection resultingDirection = DatapointDirection.UNKNOWN;
boolean foundId = false;
JsonObject localDatapoints = null;
switch (direction) {
case INPUT: {
localDatapoints = jsonObjectOfChannel.getAsJsonObject("inputs");
resultingDirection = DatapointDirection.INPUT;
break;
}
case INPUT_AS_OUTPUT: {
localDatapoints = jsonObjectOfChannel.getAsJsonObject("inputs");
resultingDirection = DatapointDirection.OUTPUT;
break;
}
case OUTPUT: {
localDatapoints = jsonObjectOfChannel.getAsJsonObject("outputs");
resultingDirection = DatapointDirection.OUTPUT;
break;
}
default: {
localDatapoints = jsonObjectOfChannel.getAsJsonObject("outputs");
resultingDirection = DatapointDirection.OUTPUT;
break;
}
}
Set<String> keys = localDatapoints.keySet();
Iterator<String> iter = keys.iterator();
// Scan datapoints for pairingID IDs
while (iter.hasNext() && !foundId) {
String datapointId = iter.next();
JsonObject datapointJsonObject = localDatapoints.getAsJsonObject(datapointId);
int pairingIDFunction = datapointJsonObject.get("pairingID").getAsInt();
if (pairingIDFunction == neededPairingIDFunction) {
this.channelId = channelId;
this.datapointId = datapointId;
logger.debug("Datapoint is found - channel {} - datapoint {}", this.channelId, this.datapointId);
foundId = true;
}
}
// id not found, add dummy
if (!foundId) {
this.channelId = "";
this.datapointId = "";
resultingDirection = DatapointDirection.UNKNOWN;
logger.debug("Needed datapoint is not found - channel {} - pairingId {}", channelId,
neededPairingIDFunction);
}
return resultingDirection;
}
public String getChannelIdforDatapoint() {
return channelId;
}
public String getDatapointId() {
return datapointId;
}
}

View File

@ -0,0 +1,262 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.datamodel;
import static org.openhab.binding.freeathomesystem.internal.datamodel.FreeAtHomeDatapoint.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.freeathomesystem.internal.util.FreeAtHomeGeneralException;
import org.openhab.binding.freeathomesystem.internal.util.PidTranslationUtils;
import org.openhab.binding.freeathomesystem.internal.valuestateconverter.BooleanValueStateConverter;
import org.openhab.binding.freeathomesystem.internal.valuestateconverter.DecimalValueStateConverter;
import org.openhab.binding.freeathomesystem.internal.valuestateconverter.ShuttercontrolValueStateConverter;
import org.openhab.binding.freeathomesystem.internal.valuestateconverter.ValueStateConverter;
import org.openhab.core.library.CoreItemFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonObject;
/**
*
* @author Andras Uhrin - Initial contribution
*
*/
@NonNullByDefault
public class FreeAtHomeDatapointGroup {
private final Logger logger = LoggerFactory.getLogger(FreeAtHomeDatapointGroup.class);
public enum DatapointGroupDirection {
UNDEFINED,
INPUT,
OUTPUT,
INPUTOUTPUT
}
private DatapointGroupDirection datapointGroupDirection;
private int pairingId;
private String functionString = "";
private @Nullable FreeAtHomeDatapoint inputDatapoint;
private @Nullable FreeAtHomeDatapoint outputDatapoint;
FreeAtHomeDatapointGroup() {
datapointGroupDirection = DatapointGroupDirection.UNDEFINED;
inputDatapoint = null;
outputDatapoint = null;
}
boolean addDatapointToGroup(DatapointDirection direction, int neededPairingId, String channelId,
JsonObject jsonObjectOfChannel) {
FreeAtHomeDatapoint newDatapoint = new FreeAtHomeDatapoint();
DatapointDirection resultingDirection = newDatapoint.searchForDatapoint(direction, neededPairingId, channelId,
jsonObjectOfChannel);
if (resultingDirection != DatapointDirection.UNKNOWN) {
switch (resultingDirection) {
case INPUT: {
inputDatapoint = newDatapoint;
pairingId = neededPairingId;
break;
}
case OUTPUT: {
outputDatapoint = newDatapoint;
if (inputDatapoint == null) {
pairingId = neededPairingId;
}
break;
}
case INPUTOUTPUT:
case INPUT_AS_OUTPUT:
case UNKNOWN:
break;
}
}
if (inputDatapoint != null && outputDatapoint != null) {
datapointGroupDirection = DatapointGroupDirection.INPUTOUTPUT;
} else {
if (inputDatapoint == null && outputDatapoint != null) {
datapointGroupDirection = DatapointGroupDirection.OUTPUT;
} else {
if (inputDatapoint != null && outputDatapoint == null) {
datapointGroupDirection = DatapointGroupDirection.INPUT;
} else {
datapointGroupDirection = DatapointGroupDirection.UNDEFINED;
}
}
}
return resultingDirection != DatapointDirection.UNKNOWN;
}
public void applyChangesForVirtualDevice() {
// The input and output datapoints are meant from the device point of view. Because the virtual devices are
// outside of the free@home system the input and output datapoint must be switched
@Nullable
FreeAtHomeDatapoint localDatapoint = inputDatapoint;
inputDatapoint = outputDatapoint;
outputDatapoint = localDatapoint;
if (inputDatapoint != null && outputDatapoint != null) {
datapointGroupDirection = DatapointGroupDirection.INPUTOUTPUT;
} else {
if (inputDatapoint == null && outputDatapoint != null) {
datapointGroupDirection = DatapointGroupDirection.OUTPUT;
} else {
if (inputDatapoint != null && outputDatapoint == null) {
datapointGroupDirection = DatapointGroupDirection.INPUT;
} else {
datapointGroupDirection = DatapointGroupDirection.UNDEFINED;
}
}
}
return;
}
public @Nullable FreeAtHomeDatapoint getInputDatapoint() {
return inputDatapoint;
}
public @Nullable FreeAtHomeDatapoint getOutputDatapoint() {
return outputDatapoint;
}
public DatapointGroupDirection getDirection() {
return datapointGroupDirection;
}
public boolean isDecimal() throws FreeAtHomeGeneralException {
return PidTranslationUtils.PID_VALUETYPE_DECIMAL
.equals(PidTranslationUtils.getValueTypeForPairingId(String.format("0x%04X", pairingId)));
}
public boolean isInteger() throws FreeAtHomeGeneralException {
return PidTranslationUtils.PID_VALUETYPE_INTEGER
.equals(PidTranslationUtils.getValueTypeForPairingId(String.format("0x%04X", pairingId)));
}
public boolean isReadOnly() {
return (DatapointGroupDirection.INPUTOUTPUT == datapointGroupDirection) ? false
: ((DatapointGroupDirection.INPUT == datapointGroupDirection) ? false : true);
}
public int getMax() throws FreeAtHomeGeneralException {
return PidTranslationUtils.getMax(String.format("0x%04X", pairingId));
}
public int getMin() throws FreeAtHomeGeneralException {
return PidTranslationUtils.getMin(String.format("0x%04X", pairingId));
}
public String getLabel() throws FreeAtHomeGeneralException {
return PidTranslationUtils.getShortTextForPairingId(String.format("0x%04X", pairingId));
}
public String getDescription() throws FreeAtHomeGeneralException {
return PidTranslationUtils.getDescriptionTextForPairingId(String.format("0x%04X", pairingId));
}
public String getValueType() throws FreeAtHomeGeneralException {
return PidTranslationUtils.getValueTypeForPairingId(String.format("0x%04X", pairingId));
}
public String getTypePattern() throws FreeAtHomeGeneralException {
String pattern = "";
functionString = PidTranslationUtils.getValueTypeForPairingId(String.format("0x%04X", pairingId));
switch (functionString) {
case PidTranslationUtils.PID_VALUETYPE_DECIMAL:
pattern = "%.1f";
break;
case PidTranslationUtils.PID_VALUETYPE_INTEGER:
pattern = "%d";
break;
default:
pattern = "";
logger.debug("Type pattern not found for PairingID {} - using default",
String.format("0x%04X", pairingId));
break;
}
return pattern;
}
public ValueStateConverter getValueStateConverter() throws FreeAtHomeGeneralException {
ValueStateConverter valueStateConverter = new BooleanValueStateConverter();
functionString = PidTranslationUtils.getValueTypeForPairingId(String.format("0x%04X", pairingId));
switch (functionString) {
case PidTranslationUtils.PID_VALUETYPE_BOOLEAN:
valueStateConverter = new BooleanValueStateConverter();
break;
case PidTranslationUtils.PID_VALUETYPE_DECIMAL:
case PidTranslationUtils.PID_VALUETYPE_INTEGER:
valueStateConverter = new DecimalValueStateConverter();
break;
case PidTranslationUtils.PID_VALUETYPE_STRING:
break;
case PidTranslationUtils.PID_VALUETYPE_SHUTTERMOVEMENT:
valueStateConverter = new ShuttercontrolValueStateConverter();
break;
default:
valueStateConverter = new DecimalValueStateConverter();
logger.debug("Value converter not found for PairingID {} - using default",
String.format("0x%04X", pairingId));
break;
}
return valueStateConverter;
}
public String getOpenHabItemType() throws FreeAtHomeGeneralException {
String itemTypeString = "";
functionString = PidTranslationUtils.getValueTypeForPairingId(String.format("0x%04X", pairingId));
switch (functionString) {
case PidTranslationUtils.PID_VALUETYPE_BOOLEAN:
itemTypeString = CoreItemFactory.SWITCH;
break;
case PidTranslationUtils.PID_VALUETYPE_DECIMAL:
case PidTranslationUtils.PID_VALUETYPE_INTEGER:
itemTypeString = CoreItemFactory.NUMBER;
break;
case PidTranslationUtils.PID_VALUETYPE_SHUTTERMOVEMENT:
itemTypeString = CoreItemFactory.ROLLERSHUTTER;
break;
default:
itemTypeString = CoreItemFactory.NUMBER;
logger.debug("Item type constant not found for PairingID {} - using default",
String.format("0x%04X", pairingId));
break;
}
return itemTypeString;
}
public String getOpenHabCategory() throws FreeAtHomeGeneralException {
return PidTranslationUtils.getCategoryForPairingId(String.format("0x%04X", pairingId));
}
}

View File

@ -0,0 +1,543 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.datamodel;
import static org.openhab.binding.freeathomesystem.internal.datamodel.FreeAtHomeDatapoint.*;
import static org.openhab.binding.freeathomesystem.internal.util.FidTranslationUtils.*;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.freeathomesystem.internal.util.FidTranslationUtils;
import org.openhab.binding.freeathomesystem.internal.util.FreeAtHomeGeneralException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonObject;
/**
* The {@link FreeAtHomeDeviceChannel} holding the information of device channels
*
* @author Andras Uhrin - Initial contribution
*
*/
@NonNullByDefault
public class FreeAtHomeDeviceChannel {
private final Logger logger = LoggerFactory.getLogger(FreeAtHomeDeviceChannel.class);
private String channelLabel = "";
private String channelId = "";
private String channelFunctionID = "";
private List<FreeAtHomeDatapointGroup> datapointGroups = new ArrayList<>();
public boolean createChannelFromJson(String deviceLabel, String channelId, JsonObject jsonObjectOfChannels,
boolean isScene, boolean isRule) {
JsonObject channelObject = jsonObjectOfChannels.getAsJsonObject(channelId);
channelFunctionID = channelObject.get("functionID").getAsString();
// check whether this is a valid channel
if (channelFunctionID.isEmpty()) {
// invalid channel found
logger.info("Invalid channel function ID found - Devicelabel: {} Channel: {}", deviceLabel, channelId);
return false;
}
if (!channelFunctionID.isEmpty()) {
channelLabel = channelObject.get("displayName").getAsString();
if (channelLabel.isEmpty()) {
channelLabel = deviceLabel;
}
}
if (isScene) {
channelFunctionID = channelFunctionID.substring(0, channelFunctionID.length() - 1) + "0";
}
switch (Integer.parseInt(channelFunctionID, 16)) {
case FID_PANEL_SWITCH_SENSOR:
case FID_SWITCH_SENSOR: {
this.channelId = channelId;
logger.debug("Switch sensor channel found - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
case FID_PANEL_DIMMING_SENSOR:
case FID_DIMMING_SENSOR: {
this.channelId = channelId;
logger.debug("Dimming sensor channel found - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 17, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
case FID_TRIGGER:
case FID_SWITCH_ACTUATOR: {
this.channelId = channelId;
logger.debug("Switch actuator channel created - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 256, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 1, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
case FID_MOVEMENT_DETECTOR_FLEX:
case FID_MOVEMENT_DETECTOR: {
this.channelId = channelId;
logger.debug("Movement detector channel found - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 6, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 7, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1027, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT_AS_OUTPUT, 256, channelId,
channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
case FID_ROOM_TEMPERATURE_CONTROLLER_MASTER_WITHOUT_FAN:
case FID_RADIATOR_ACTUATOR_MASTER: {
this.channelId = channelId;
if (Integer.parseInt(channelFunctionID, 16) == FID_RADIATOR_ACTUATOR_MASTER) {
logger.debug("Radiator actuator channel - Channel FID: {}", channelFunctionID);
} else {
logger.debug("Room temperature actuator channel - Channel FID: {}", channelFunctionID);
}
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 304, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 333, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 331, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 54, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 51, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 320, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 68, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 58, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 56, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 66, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
// Additional channel for RTC device
if (Integer.parseInt(channelFunctionID, 16) == FID_ROOM_TEMPERATURE_CONTROLLER_MASTER_WITHOUT_FAN) {
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 48, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
}
break;
}
case FID_WINDOW_DOOR_POSITION_SENSOR:
case FID_WINDOW_DOOR_SENSOR: {
this.channelId = channelId;
logger.debug("Window/Door position sensor channel created - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 53, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 41, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
case FID_SCENE_TRIGGER: {
this.channelId = channelId;
logger.debug("Scene trigger channel - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 4, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
case FID_RULE_SWITCH: {
this.channelId = channelId;
logger.debug("Rule channel - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 61698, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 61697, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
case FID_DES_DOOR_OPENER_ACTUATOR: {
this.channelId = channelId;
logger.debug("Door opener actuator channel - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 256, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 2, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
case FID_DES_LEVEL_CALL_SENSOR:
case FID_DES_DOOR_RINGING_SENSOR: {
this.channelId = channelId;
logger.debug("Door ring sensor channel - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 2, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
case FID_DES_LIGHT_SWITCH_ACTUATOR: {
this.channelId = channelId;
logger.debug("DES light switch channel - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 256, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 2, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
case FID_DIMMING_ACTUATOR_FLEX:
case FID_DIMMING_ACTUATOR: {
this.channelId = channelId;
logger.debug("Dimming actuator channel - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 272, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 17, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 256, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 1, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
case FID_AWNING_ACTUATOR:
case FID_ATTIC_WINDOW_ACTUATOR:
case FID_BLIND_ACTUATOR:
case FID_SHUTTER_ACTUATOR: {
this.channelId = channelId;
logger.debug("Shutter actuator channel - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 32, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 288, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 33, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 288, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 289, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 35, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
case FID_BRIGHTNESS_SENSOR: {
this.channelId = channelId;
logger.debug("Brightness sensor channel - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1026, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1027, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
case FID_RAIN_SENSOR: {
this.channelId = channelId;
logger.debug("Rain sensor channel - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 39, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1029, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1030, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
case FID_TEMPERATURE_SENSOR: {
this.channelId = channelId;
logger.debug("Temperature sensor channel - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
if (newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 38, channelId, channelObject)) {
datapointGroups.add(newDatapointGroup);
}
newDatapointGroup = new FreeAtHomeDatapointGroup();
if (newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1024, channelId, channelObject)) {
datapointGroups.add(newDatapointGroup);
}
newDatapointGroup = new FreeAtHomeDatapointGroup();
if (newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 304, channelId, channelObject)) {
datapointGroups.add(newDatapointGroup);
}
break;
}
case FID_WIND_SENSOR: {
this.channelId = channelId;
logger.debug("Wind sensor channel - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 37, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1025, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1028, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
case FID_AIRQUALITYSENSOR_CO: {
this.channelId = channelId;
logger.debug("AQS CO channel - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1564, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
case FID_AIRQUALITYSENSOR_CO2: {
this.channelId = channelId;
logger.debug("AQS CO2 channel - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1563, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
case FID_AIRQUALITYSENSOR_HUMIDITY: {
this.channelId = channelId;
logger.debug("AQS Humidity channel - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 337, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
case FID_AIRQUALITYSENSOR_PRESSURE: {
this.channelId = channelId;
logger.debug("AQS Pressure channel - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1562, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
case FID_AIRQUALITYSENSOR_NO2: {
this.channelId = channelId;
logger.debug("AQS NO2 channel - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1565, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
case FID_AIRQUALITYSENSOR_O3: {
this.channelId = channelId;
logger.debug("AQS O3 channel - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1566, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
case FID_AIRQUALITYSENSOR_PM10: {
this.channelId = channelId;
logger.debug("AQS PM10 channel - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1567, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
case FID_AIRQUALITYSENSOR_VOC: {
this.channelId = channelId;
logger.debug("AQS VOC channel - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1569, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
case FID_AIRQUALITYSENSOR_PM25: {
this.channelId = channelId;
logger.debug("AQS PM25 channel - Channel FID: {}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1568, channelId, channelObject);
datapointGroups.add(newDatapointGroup);
break;
}
default: {
logger.debug("Unknown channel found - Channel FID: {}", channelFunctionID);
return false;
}
}
return true;
}
public String getChannelIdforDatapoint() {
return channelId;
}
public String getChannelLabel() {
return channelLabel;
}
public String getChannelId() {
return channelId;
}
public String getFunctionId() {
return channelFunctionID;
}
public @Nullable String getFunctionIdText() throws FreeAtHomeGeneralException {
String functionIdText = FidTranslationUtils
.getFunctionIdText(String.format("0x%04X", Integer.parseInt(channelFunctionID, 16)));
return functionIdText;
}
public int getNumberOfDatapointGroup() {
return datapointGroups.size();
}
public FreeAtHomeDatapointGroup getDatapointGroup(int idx) {
return datapointGroups.get(idx);
}
public void applyChangesForVirtualDevice() {
for (FreeAtHomeDatapointGroup localDatapointGroup : datapointGroups) {
localDatapointGroup.applyChangesForVirtualDevice();
}
}
}

View File

@ -0,0 +1,154 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.datamodel;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
/**
* The {@link FreeAtHomeDeviceDescription} is responsible for determining the device type
* based on the received json string
*
* @author Andras Uhrin - Initial contribution
*
*/
@NonNullByDefault
public class FreeAtHomeDeviceDescription {
private final Logger logger = LoggerFactory.getLogger(FreeAtHomeDeviceDescription.class);
// interface strings
public static final String DEVICE_INTERFACE_UNKNOWN_TYPE = "unknown";
public static final String DEVICE_INTERFACE_WIRELESS_TYPE = "wireless";
public static final String DEVICE_INTERFACE_VIRTUAL_TYPE = "virtual";
public static final String DEVICE_INTERFACE_WIRED_TYPE = "wired";
public static final String DEVICE_INTERFACE_HUE_TYPE = "hue";
public String deviceLabel = "";
public String deviceId = "";
public String interfaceType = "";
public boolean validDevice = false;
private boolean sceneIsDetected;
private boolean ruleIsDetected;
public List<FreeAtHomeDeviceChannel> listOfChannels = new ArrayList<>();
public FreeAtHomeDeviceDescription() {
validDevice = false;
}
public FreeAtHomeDeviceDescription(JsonObject jsonObject, String id) {
// set the device ID
deviceId = id;
// set the device invalid at first
validDevice = false;
sceneIsDetected = id.toLowerCase().startsWith("ffff48");
ruleIsDetected = id.toLowerCase().startsWith("ffff4a");
JsonObject jsonObjectOfId = jsonObject.getAsJsonObject(id);
if (jsonObjectOfId == null) {
return;
}
JsonElement jsonObjectOfInterface = jsonObjectOfId.get("interface");
if (jsonObjectOfInterface != null) {
String interfaceString = jsonObjectOfInterface.getAsString();
if (interfaceString.toLowerCase().startsWith("vdev:")) {
interfaceType = DEVICE_INTERFACE_VIRTUAL_TYPE;
} else if (interfaceString.toLowerCase().startsWith("hue")) {
interfaceType = DEVICE_INTERFACE_HUE_TYPE;
} else if (interfaceString.toLowerCase().startsWith("rf")) {
interfaceType = DEVICE_INTERFACE_WIRELESS_TYPE;
} else if (interfaceString.toLowerCase().startsWith("tp")) {
interfaceType = DEVICE_INTERFACE_WIRED_TYPE;
} else {
interfaceType = DEVICE_INTERFACE_UNKNOWN_TYPE;
}
} else {
interfaceType = DEVICE_INTERFACE_UNKNOWN_TYPE;
}
JsonElement jsonObjectOfDeviceLabel = jsonObjectOfId.get("displayName");
if (jsonObjectOfDeviceLabel == null) {
this.deviceLabel = "NoName";
} else {
this.deviceLabel = jsonObjectOfDeviceLabel.getAsString();
}
if (this.deviceLabel.isEmpty()) {
this.deviceLabel = "NoName";
}
JsonObject jsonObjectOfChannels = jsonObjectOfId.getAsJsonObject("channels");
logger.debug("Detecting device features - device id: {} - device label: {}", this.deviceId, this.deviceLabel);
if (jsonObjectOfChannels != null) {
// Scan channels for functions
for (String nextChannel : jsonObjectOfChannels.keySet()) {
FreeAtHomeDeviceChannel newChannel = new FreeAtHomeDeviceChannel();
if (newChannel.createChannelFromJson(deviceLabel, nextChannel, jsonObjectOfChannels, sceneIsDetected,
ruleIsDetected)) {
if (interfaceType == DEVICE_INTERFACE_VIRTUAL_TYPE) {
newChannel.applyChangesForVirtualDevice();
}
listOfChannels.add(newChannel);
}
}
}
}
public boolean isRule() {
return ruleIsDetected;
}
public boolean isScene() {
return sceneIsDetected;
}
public boolean isVirtual() {
return interfaceType == DEVICE_INTERFACE_VIRTUAL_TYPE;
}
public int getNumberOfChannels() {
return listOfChannels.size();
}
public FreeAtHomeDeviceChannel getChannel(int idx) {
return listOfChannels.get(idx);
}
public String getDeviceId() {
return deviceId;
}
public String getDeviceLabel() {
return deviceLabel;
}
}

View File

@ -0,0 +1,897 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.handler;
import java.io.IOException;
import java.io.StringReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.AuthenticationStore;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.util.BasicAuthentication;
import org.eclipse.jetty.client.util.StringContentProvider;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.api.WebSocketListener;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.openhab.binding.freeathomesystem.internal.FreeAtHomeSystemDiscoveryService;
import org.openhab.binding.freeathomesystem.internal.configuration.FreeAtHomeBridgeHandlerConfiguration;
import org.openhab.binding.freeathomesystem.internal.datamodel.FreeAtHomeDeviceDescription;
import org.openhab.binding.freeathomesystem.internal.util.FreeAtHomeHttpCommunicationException;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import com.google.gson.stream.JsonReader;
/**
* The {@link FreeAtHomeBridgeHandler} is responsible for handling the free@home bridge and
* its main communication.
*
* @author Andras Uhrin - Initial contribution
*
*/
@NonNullByDefault
public class FreeAtHomeBridgeHandler extends BaseBridgeHandler implements WebSocketListener {
private final Logger logger = LoggerFactory.getLogger(FreeAtHomeBridgeHandler.class);
private Map<String, FreeAtHomeDeviceHandler> mapEventListeners = new ConcurrentHashMap<>();
// Clients for the network communication
private HttpClient httpClient;
private @Nullable WebSocketClient websocketClient = null;
private FreeAtHomeWebsocketMonitorThread socketMonitor = new FreeAtHomeWebsocketMonitorThread();
private @Nullable QueuedThreadPool jettyThreadPool = null;
private volatile @Nullable Session websocketSession = null;
private String sysApUID = "00000000-0000-0000-0000-000000000000";
private String ipAddress = "";
private String username = "";
private String password = "";
private String baseUrl = "";
private String authField = "";
private Lock lock = new ReentrantLock();
private AtomicBoolean httpConnectionOK = new AtomicBoolean(false);
private Condition websocketSessionEstablished = lock.newCondition();
int numberOfComponents = 0;
private static final int BRIDGE_WEBSOCKET_RECONNECT_DELAY = 60;
private static final int BRIDGE_WEBSOCKET_TIMEOUT = 90;
private static final int BRIDGE_WEBSOCKET_KEEPALIVE = 50;
private static final String BRIDGE_URL_GETDEVICELIST = "/rest/devicelist";
public FreeAtHomeBridgeHandler(Bridge thing, HttpClient client) {
super(thing);
httpClient = client;
}
/**
* stub method for handlCommand
*/
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
logger.warn("Unknown handle command for the bridge - channellUID {}, command {}", channelUID, command);
}
@Override
public Collection<Class<? extends ThingHandlerService>> getServices() {
return List.of(FreeAtHomeSystemDiscoveryService.class);
}
/**
* Method to get the device list
*/
public List<String> getDeviceDeviceList() throws FreeAtHomeHttpCommunicationException {
List<String> listOfComponentId = new ArrayList<String>();
boolean ret = false;
listOfComponentId.clear();
String url = baseUrl + BRIDGE_URL_GETDEVICELIST;
// Perform a simple GET and wait for the response.
try {
HttpClient client = httpClient;
Request req = client.newRequest(url);
if (req == null) {
throw new FreeAtHomeHttpCommunicationException(0,
"Invalid request object in getDeviceDeviceList with the URL [ " + url + " ]");
}
ContentResponse response = req.send();
// Get component List
String componentListString = new String(response.getContent());
JsonElement jsonTree = JsonParser.parseString(componentListString);
// check the output
if (!jsonTree.isJsonObject()) {
throw new FreeAtHomeHttpCommunicationException(0,
"Invalid jsonObject in getDeviceDeviceList with the URL [ " + url + " ]");
}
JsonObject jsonObject = jsonTree.getAsJsonObject();
// Get the main object
JsonElement listOfComponents = jsonObject.get(sysApUID);
if (listOfComponents == null) {
throw new FreeAtHomeHttpCommunicationException(0,
"Devices Section is missing in getDeviceDeviceList with the URL [ " + url + " ]");
}
JsonArray array = listOfComponents.getAsJsonArray();
this.numberOfComponents = array.size();
for (int i = 0; i < array.size(); i++) {
JsonElement basicElement = array.get(i);
listOfComponentId.add(basicElement.getAsString());
}
ret = true;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
logger.debug("Error to build up the Component list [ {} ]", e.getMessage());
throw new FreeAtHomeHttpCommunicationException(0,
"Http communication interrupted [ " + e.getMessage() + " ]");
} catch (ExecutionException | TimeoutException e) {
logger.debug("Error to build up the Component list [ {} ]", e.getMessage());
throw new FreeAtHomeHttpCommunicationException(0,
"Http communication interrupted in getDeviceList [ " + e.getMessage() + " ]");
}
// Scan finished but error. clear the list
if (!ret) {
listOfComponentId.clear();
}
return listOfComponentId;
}
/**
* Method to send http request to get the device description
*/
public FreeAtHomeDeviceDescription getFreeatHomeDeviceDescription(String id)
throws FreeAtHomeHttpCommunicationException {
FreeAtHomeDeviceDescription device = new FreeAtHomeDeviceDescription();
String url = baseUrl + "/rest/device/" + sysApUID + "/" + id;
try {
HttpClient client = httpClient;
Request req = client.newRequest(url);
if (req == null) {
throw new FreeAtHomeHttpCommunicationException(0,
"Invalid request object in getDatapoint with the URL [ " + url + " ]");
}
ContentResponse response;
response = req.send();
// Get component List
String deviceString = new String(response.getContent());
JsonReader reader = new JsonReader(new StringReader(deviceString));
reader.setLenient(true);
JsonElement jsonTree = JsonParser.parseReader(reader);
if (!jsonTree.isJsonObject()) {
throw new FreeAtHomeHttpCommunicationException(0,
"No data is received by getDatapoint with the URL [ " + url + " ]");
}
if (!jsonTree.isJsonObject()) {
throw new FreeAtHomeHttpCommunicationException(0,
"Invalid jsonObject in getFreeatHomeDeviceDescription with the URL [ " + url + " ]");
}
// check the output
JsonObject jsonObject = jsonTree.getAsJsonObject();
if (!jsonObject.isJsonObject()) {
throw new FreeAtHomeHttpCommunicationException(0,
"Main jsonObject is invalid in getFreeatHomeDeviceDescription with the URL [ " + url + " ]");
}
jsonObject = jsonObject.getAsJsonObject(sysApUID);
if (!jsonObject.isJsonObject()) {
throw new FreeAtHomeHttpCommunicationException(0,
"jsonObject is invalid in getFreeatHomeDeviceDescription with the URL [ " + url + " ]");
}
jsonObject = jsonObject.getAsJsonObject("devices");
if (!jsonObject.isJsonObject()) {
throw new FreeAtHomeHttpCommunicationException(0,
"Devices Section is missing in getFreeatHomeDeviceDescription with the URL [ " + url + " ]");
}
device = new FreeAtHomeDeviceDescription(jsonObject, id);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
logger.debug("No communication possible to get device list - Communication interrupt [ {} ]",
e.getMessage());
throw new FreeAtHomeHttpCommunicationException(0,
"Http communication interrupted [ " + e.getMessage() + " ]");
} catch (ExecutionException | TimeoutException e) {
logger.debug("No communication possible to get device list - Communication interrupt [ {} ]",
e.getMessage());
throw new FreeAtHomeHttpCommunicationException(0,
"Http communication interrupted in getDeviceList [ " + e.getMessage() + " ]");
}
return device;
}
/**
* Method to get datapoint values for devices
*/
public String getDatapoint(String deviceId, String channel, String datapoint)
throws FreeAtHomeHttpCommunicationException {
String url = baseUrl + "/rest/datapoint/" + sysApUID + "/" + deviceId + "." + channel + "." + datapoint;
try {
Request req = httpClient.newRequest(url);
logger.debug("Get datapoint by url: {}", url);
if (req == null) {
throw new FreeAtHomeHttpCommunicationException(0,
"Invalid request object in getDatapoint with the URL [ " + url + " ]");
}
ContentResponse response = req.send();
if (response.getStatus() != 200) {
throw new FreeAtHomeHttpCommunicationException(response.getStatus(), response.getReason());
}
String deviceString = new String(response.getContent());
JsonReader reader = new JsonReader(new StringReader(deviceString));
reader.setLenient(true);
JsonElement jsonTree = JsonParser.parseReader(reader);
if (!jsonTree.isJsonObject()) {
throw new FreeAtHomeHttpCommunicationException(0,
"No data is received by getDatapoint with the URL [ " + url + " ]");
}
JsonObject jsonObject = jsonTree.getAsJsonObject();
jsonObject = jsonObject.getAsJsonObject(sysApUID);
JsonArray jsonValueArray = jsonObject.getAsJsonArray("values");
JsonElement element = jsonValueArray.get(0);
String value = element.getAsString();
if (value.isEmpty()) {
value = "0";
}
return value;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"@text/comm-error.error-in-sysap-com");
throw new FreeAtHomeHttpCommunicationException(0,
"Http communication interrupted [ " + e.getMessage() + " ]");
} catch (ExecutionException | TimeoutException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"@text/comm-error.error-in-sysap-com");
throw new FreeAtHomeHttpCommunicationException(0,
"Http communication timout or execution interrupted [ " + e.getMessage() + " ]");
} catch (JsonParseException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"@text/comm-error.error-in-sysap-com");
throw new FreeAtHomeHttpCommunicationException(0,
"Invalid JSON file is received by getDatapoint with the URL [ " + e.getMessage() + " ]");
}
}
/**
* Method to set datapoint values in channels
*/
public boolean setDatapoint(String deviceId, String channel, String datapoint, String valueString)
throws FreeAtHomeHttpCommunicationException {
String url = baseUrl + "/rest/datapoint/" + sysApUID + "/" + deviceId + "." + channel + "." + datapoint;
try {
Request req = httpClient.newRequest(url);
if (req == null) {
throw new FreeAtHomeHttpCommunicationException(0,
"Invalid request object in getDatapoint with the URL [ " + url + " ]");
}
req.content(new StringContentProvider(valueString));
req.method(HttpMethod.PUT);
logger.debug("Set datapoint by url: {} value: {}", url, valueString);
ContentResponse response = req.send();
if (response.getStatus() != 200) {
throw new FreeAtHomeHttpCommunicationException(response.getStatus(), response.getReason());
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"@text/comm-error.error-in-sysap-com");
throw new FreeAtHomeHttpCommunicationException(0,
"Http communication interrupted [ " + e.getMessage() + " ]");
} catch (ExecutionException | TimeoutException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"@text/comm-error.error-in-sysap-com");
throw new FreeAtHomeHttpCommunicationException(0,
"Http communication interrupted [ " + e.getMessage() + " ]");
}
return true;
}
/**
* Method to process socket events
*/
public void setDatapointOnWebsocketFeedback(String receivedText) {
JsonReader reader = new JsonReader(new StringReader(receivedText));
reader.setLenient(true);
JsonElement jsonTree = JsonParser.parseReader(reader);
// check the output
if (jsonTree.isJsonObject()) {
JsonObject jsonObject = jsonTree.getAsJsonObject();
jsonObject = jsonObject.getAsJsonObject(sysApUID);
jsonObject = jsonObject.getAsJsonObject("datapoints");
Set<String> keys = jsonObject.keySet();
Iterator<String> iter = keys.iterator();
while (iter.hasNext()) {
String eventDatapointID = iter.next();
JsonElement element = jsonObject.get(eventDatapointID);
String value = element.getAsString();
String[] parts = eventDatapointID.split("/");
FreeAtHomeDeviceHandler deviceHandler = mapEventListeners.get(parts[0]);
if (deviceHandler != null) {
deviceHandler.onDeviceStateChanged(eventDatapointID, value);
}
logger.debug("Socket event processed: event-datapoint-ID {} value {}", eventDatapointID, value);
}
}
}
public void markDeviceRemovedOnWebsocketFeedback(String receivedText) {
JsonReader reader = new JsonReader(new StringReader(receivedText));
reader.setLenient(true);
JsonElement jsonTree = JsonParser.parseReader(reader);
// check the output
if (jsonTree.isJsonObject()) {
JsonObject jsonObject = jsonTree.getAsJsonObject();
jsonObject = jsonObject.getAsJsonObject(sysApUID);
JsonArray jsonArray = jsonObject.getAsJsonArray("devicesRemoved");
for (JsonElement element : jsonArray) {
FreeAtHomeDeviceHandler deviceHandler = mapEventListeners.get(element.getAsString());
if (deviceHandler != null) {
deviceHandler.onDeviceRemoved();
logger.debug("Device removal processed");
}
}
}
}
public void registerDeviceStateListener(String deviceID, FreeAtHomeDeviceHandler deviceHandler) {
mapEventListeners.put(deviceID, deviceHandler);
}
public void unregisterDeviceStateListener(String deviceID) {
mapEventListeners.remove(deviceID);
}
/**
* Method to open Http connection
*/
public boolean openHttpConnection() {
boolean ret = false;
try {
// Add authentication credentials.
AuthenticationStore auth = httpClient.getAuthenticationStore();
URI uri1 = new URI(baseUrl);
auth.addAuthenticationResult(new BasicAuthentication.BasicResult(uri1, username, password));
String url = baseUrl + BRIDGE_URL_GETDEVICELIST;
Request req = httpClient.newRequest(url);
ContentResponse res = req.send();
// check status
if (res.getStatus() == HttpStatus.OK_200) {
// response OK
httpConnectionOK.set(true);
ret = true;
logger.debug("HTTP connection to SysAP is OK");
} else {
// response NOK, set error
httpConnectionOK.set(false);
ret = false;
}
} catch (URISyntaxException | InterruptedException | ExecutionException | TimeoutException ex) {
logger.debug("Initial HTTP connection to SysAP is not successful");
ret = false;
}
return ret;
}
/**
* Method to connect the websocket session
*/
public boolean connectWebsocketSession() {
boolean ret = false;
URI uri = URI.create("ws://" + ipAddress + "/fhapi/v1/api/ws");
String authString = username + ":" + password;
// create base64 encoder
Base64.Encoder bas64Encoder = Base64.getEncoder();
// Encoding string using encoder object
String authStringEnc = bas64Encoder.encodeToString(authString.getBytes());
authField = "Basic " + authStringEnc;
WebSocketClient localWebsocketClient = websocketClient;
try {
// Start socket client
if (localWebsocketClient != null) {
localWebsocketClient.setMaxTextMessageBufferSize(8 * 1024);
localWebsocketClient.setMaxIdleTimeout(BRIDGE_WEBSOCKET_TIMEOUT * 60 * 1000);
localWebsocketClient.setConnectTimeout(BRIDGE_WEBSOCKET_TIMEOUT * 60 * 1000);
localWebsocketClient.start();
ClientUpgradeRequest request = new ClientUpgradeRequest();
request.setHeader("Authorization", authField);
request.setTimeout(BRIDGE_WEBSOCKET_TIMEOUT, TimeUnit.MINUTES);
localWebsocketClient.connect(this, uri, request);
logger.debug("Websocket connection to SysAP is OK, timeout: {}", BRIDGE_WEBSOCKET_TIMEOUT);
ret = true;
} else {
ret = false;
}
} catch (Exception e) {
logger.debug("Error by opening Websocket connection [{}]", e.getMessage());
if (localWebsocketClient != null) {
try {
localWebsocketClient.stop();
ret = false;
} catch (Exception e1) {
logger.debug("Error by opening Websocket connection [{}]", e1.getMessage());
ret = false;
}
} else {
ret = false;
}
}
return ret;
}
/**
* Method to close the websocket connection
*/
public void closeWebSocketConnection() {
socketMonitor.interrupt();
QueuedThreadPool localThreadPool = jettyThreadPool;
if (localThreadPool != null) {
try {
localThreadPool.stop();
} catch (Exception e1) {
logger.debug("Error by closing Websocket connection [{}]", e1.getMessage());
}
jettyThreadPool = null;
}
WebSocketClient localWebSocketClient = websocketClient;
if (localWebSocketClient != null) {
try {
localWebSocketClient.stop();
} catch (Exception e2) {
logger.debug("Error by closing Websocket connection [{}]", e2.getMessage());
}
websocketClient = null;
}
}
/**
* Method to open the websocket connection
*/
public boolean openWebSocketConnection() {
boolean ret = false;
QueuedThreadPool localThreadPool = jettyThreadPool;
if (localThreadPool == null) {
jettyThreadPool = new QueuedThreadPool();
localThreadPool = jettyThreadPool;
if (localThreadPool != null) {
localThreadPool.setName(FreeAtHomeBridgeHandler.class.getSimpleName());
localThreadPool.setDaemon(true);
localThreadPool.setStopTimeout(0);
ret = true;
}
}
WebSocketClient localWebSocketClient = websocketClient;
if (localWebSocketClient == null) {
websocketClient = new WebSocketClient(httpClient);
localWebSocketClient = websocketClient;
if (localWebSocketClient != null) {
localWebSocketClient.setExecutor(jettyThreadPool);
socketMonitor.start();
ret = true;
} else {
ret = false;
}
} else {
ret = true;
}
return ret;
}
/**
* Method to initialize the bridge
*/
@Override
public void initialize() {
httpConnectionOK.set(false);
// load configuration
FreeAtHomeBridgeHandlerConfiguration locConfig = getConfigAs(FreeAtHomeBridgeHandlerConfiguration.class);
ipAddress = locConfig.ipAddress;
if (ipAddress.isBlank()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"@text/conf-error.ip-address-missing");
return;
}
password = locConfig.password;
if (password.isBlank()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"@text/conf-error.password-missing");
return;
}
username = locConfig.username;
if (username.isBlank()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"@text/conf-error.username-missing");
return;
}
// build base URL
baseUrl = "http://" + ipAddress + "/fhapi/v1/api";
updateStatus(ThingStatus.UNKNOWN);
scheduler.execute(() -> {
boolean thingReachable = true;
// Open Http connection
if (!openHttpConnection()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"@text/comm-error.http-wrongpass-or-ip");
thingReachable = false;
}
// Open the websocket connection for immediate status updates
if (!openWebSocketConnection()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"@text/comm-error.not-able-open-websocketconnection");
thingReachable = false;
}
if (thingReachable) {
updateStatus(ThingStatus.ONLINE);
}
});
}
/**
* Method to dispose
*/
@Override
public void dispose() {
// let run out the thread
socketMonitor.interrupt();
closeWebSocketConnection();
}
/**
* Thread that maintains connection via Websocket.
*/
private class FreeAtHomeWebsocketMonitorThread extends Thread {
// initial delay to initiate connection
private AtomicInteger reconnectDelay = new AtomicInteger();
public FreeAtHomeWebsocketMonitorThread() {
}
@Override
public void run() {
// set initial connect delay to 0
reconnectDelay.set(0);
try {
while (!isInterrupted()) {
if (httpConnectionOK.get()) {
if (connectSession()) {
while (isSocketConnectionAlive()) {
TimeUnit.SECONDS.sleep(BRIDGE_WEBSOCKET_KEEPALIVE);
logger.debug("Sending keep-alive message {}", System.currentTimeMillis());
sendWebsocketKeepAliveMessage("keep-alive");
}
}
logger.debug("Socket connection closed");
reconnectDelay.set(BRIDGE_WEBSOCKET_RECONNECT_DELAY);
} else {
TimeUnit.SECONDS.sleep(BRIDGE_WEBSOCKET_RECONNECT_DELAY);
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"@text/comm-error.general-websocket-issue");
} catch (IOException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"@text/comm-error.websocket-keep-alive-error");
}
}
private boolean connectSession() throws InterruptedException {
int delay = reconnectDelay.get();
if (delay > 0) {
logger.debug("Delaying (re)connect request by {} seconds.", reconnectDelay);
TimeUnit.SECONDS.sleep(delay);
}
logger.debug("Server connecting to websocket");
if (!connectWebsocketSession()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"@text/comm-error.general-websocket-issue");
reconnectDelay.set(BRIDGE_WEBSOCKET_RECONNECT_DELAY);
return false;
}
if (websocketSession == null) {
lock.lock();
try {
websocketSessionEstablished.await();
} finally {
lock.unlock();
}
}
return true;
}
}
/**
* Send keep-alive message to SysAp
*/
public void sendWebsocketKeepAliveMessage(String message) throws IOException {
Session localSession = websocketSession;
if (localSession != null) {
localSession.getRemote().sendString(message);
}
}
/**
* Get socket alive state
*
* @throws InterruptedException
*/
public boolean isSocketConnectionAlive() throws InterruptedException {
Session localSession = websocketSession;
return (localSession != null) ? localSession.isOpen() : false;
}
/**
* Socket closed. Report the state
*/
@Override
public void onWebSocketClose(int statusCode, @Nullable String reason) {
websocketSession = null;
logger.debug("Socket Closed: [ {} ] {}", statusCode, reason);
}
/**
* Socket connected. store the session for later use
*/
@Override
public void onWebSocketConnect(@Nullable Session session) {
Session localSession = session;
if (localSession != null) {
websocketSession = localSession;
localSession.setIdleTimeout(-1);
logger.debug("Socket Connected - Timeout {} - sesson: {}", localSession.getIdleTimeout(), session);
} else {
logger.debug("Socket Connected - Timeout (invalid) - sesson: (invalid)");
}
lock.lock();
try {
websocketSessionEstablished.signal();
} finally {
lock.unlock();
}
}
/**
* Error caused. Report the state
*/
@Override
public void onWebSocketError(@Nullable Throwable cause) {
websocketSession = null;
if (cause != null) {
logger.debug("Socket Error: {}", cause.getLocalizedMessage());
} else {
logger.debug("Socket Error: unknown");
}
}
/**
* Binary message received. It shall not happen with the free@home SysAp
*/
@Override
@NonNullByDefault({})
public void onWebSocketBinary(byte[] payload, int offset, int len) {
logger.debug("Binary message received via websocket");
}
/**
* Text message received. Processing will be started
*/
@Override
public void onWebSocketText(@Nullable String message) {
if (message != null) {
if (message.toLowerCase(Locale.US).contains("bye")) {
Session localSession = websocketSession;
if (localSession != null) {
localSession.close(StatusCode.NORMAL, "Thanks");
}
logger.debug("Websocket connection closed: {} ", message);
} else {
logger.debug("Received websocket text: {} ", message);
setDatapointOnWebsocketFeedback(message);
markDeviceRemovedOnWebsocketFeedback(message);
}
} else {
logger.debug("Invalid message string");
}
}
}

View File

@ -0,0 +1,635 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.handler;
import java.math.BigDecimal;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.freeathomesystem.internal.configuration.FreeAtHomeDeviceHandlerConfiguration;
import org.openhab.binding.freeathomesystem.internal.datamodel.FreeAtHomeDatapoint;
import org.openhab.binding.freeathomesystem.internal.datamodel.FreeAtHomeDatapointGroup;
import org.openhab.binding.freeathomesystem.internal.datamodel.FreeAtHomeDeviceChannel;
import org.openhab.binding.freeathomesystem.internal.datamodel.FreeAtHomeDeviceDescription;
import org.openhab.binding.freeathomesystem.internal.type.FreeAtHomeChannelTypeProvider;
import org.openhab.binding.freeathomesystem.internal.util.FreeAtHomeGeneralException;
import org.openhab.binding.freeathomesystem.internal.util.FreeAtHomeHttpCommunicationException;
import org.openhab.binding.freeathomesystem.internal.util.UidUtils;
import org.openhab.binding.freeathomesystem.internal.valuestateconverter.ValueStateConverter;
import org.openhab.core.i18n.LocaleProvider;
import org.openhab.core.i18n.TranslationProvider;
import org.openhab.core.library.types.StopMoveType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.Bridge;
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.ThingUID;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.builder.ChannelBuilder;
import org.openhab.core.thing.binding.builder.ThingBuilder;
import org.openhab.core.thing.type.AutoUpdatePolicy;
import org.openhab.core.thing.type.ChannelKind;
import org.openhab.core.thing.type.ChannelType;
import org.openhab.core.thing.type.ChannelTypeBuilder;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State;
import org.openhab.core.types.StateDescriptionFragmentBuilder;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link FreeAtHomeDeviceHandler} is responsible for handling the generic free@home device main communication
* and thing updates
*
* @author Andras Uhrin - Initial contribution
*
*/
@NonNullByDefault
public class FreeAtHomeDeviceHandler extends BaseThingHandler implements FreeAtHomeDeviceStateListener {
private static final String CHANNEL_URI = "channel-type:freeathomesystem:config";
private final Logger logger = LoggerFactory.getLogger(FreeAtHomeDeviceHandler.class);
private FreeAtHomeDeviceDescription device = new FreeAtHomeDeviceDescription();
private FreeAtHomeChannelTypeProvider channelTypeProvider;
private TranslationProvider i18nProvider;
private Locale locale;
private Bundle bundle;
private Map<ChannelUID, FreeAtHomeDatapointGroup> mapChannelUID = new HashMap<ChannelUID, FreeAtHomeDatapointGroup>();
private Map<String, ChannelUID> mapEventToChannelUID = new HashMap<String, ChannelUID>();
public FreeAtHomeDeviceHandler(Thing thing, FreeAtHomeChannelTypeProvider channelTypeProvider,
TranslationProvider i18nProvider, LocaleProvider localeProvider) {
super(thing);
this.channelTypeProvider = channelTypeProvider;
this.i18nProvider = i18nProvider;
this.bundle = FrameworkUtil.getBundle(getClass());
this.locale = localeProvider.getLocale();
}
@Override
public void initialize() {
updateStatus(ThingStatus.UNKNOWN);
scheduler.execute(() -> {
FreeAtHomeDeviceHandlerConfiguration config = getConfigAs(FreeAtHomeDeviceHandlerConfiguration.class);
Bridge bridge = this.getBridge();
String locDeviceId = config.deviceId;
if (bridge != null) {
ThingHandler handler = bridge.getHandler();
if (handler instanceof FreeAtHomeBridgeHandler bridgeHandler) {
if (!locDeviceId.isBlank()) {
try {
device = bridgeHandler.getFreeatHomeDeviceDescription(locDeviceId);
updateChannels();
} catch (FreeAtHomeHttpCommunicationException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"@text/comm-error.error-in-sysap-com");
} catch (FreeAtHomeGeneralException e) {
logger.debug("General error in the binding - during initialization {}",
device.getDeviceId());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"@text/conf-error.general-binding-error");
}
// register device for status updates
bridgeHandler.registerDeviceStateListener(device.getDeviceId(), this);
updateStatus(ThingStatus.ONLINE);
logger.debug("Device created - device id: {}", device.getDeviceId());
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"@text/conf-error.invalid-deviceconfig");
logger.debug("Device cannot be created: device ID is null!");
}
}
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR,
"@text/conf-error.bridge-not-configured");
logger.debug("Device cannot be created: no bridge is configured!");
return;
}
});
}
@Override
public void dispose() {
Bridge bridge = this.getBridge();
// Unregister device and specific channel for event based state updated
if (bridge != null) {
ThingHandler handler = bridge.getHandler();
if (handler instanceof FreeAtHomeBridgeHandler bridgeHandler) {
bridgeHandler.unregisterDeviceStateListener(device.getDeviceId());
}
}
// Remove mapping tables
mapChannelUID.clear();
mapEventToChannelUID.clear();
logger.debug("Device removed - device id: {}", device.getDeviceId());
}
private void handleRefreshCommand(FreeAtHomeBridgeHandler freeAtHomeBridge, FreeAtHomeDatapointGroup dpg,
ChannelUID channelUID) {
String valueStr = "0";
String channelID = "ch000";
String datapointID = "0";
// Check whether it is a INPUT only datapoint group
if (dpg.getDirection() == FreeAtHomeDatapointGroup.DatapointGroupDirection.INPUT) {
FreeAtHomeDatapoint datapoint = dpg.getInputDatapoint();
if (datapoint != null) {
channelID = datapoint.channelId;
datapointID = datapoint.getDatapointId();
}
} else {
FreeAtHomeDatapoint datapoint = dpg.getOutputDatapoint();
if (datapoint != null) {
channelID = datapoint.channelId;
datapointID = datapoint.getDatapointId();
}
}
try {
valueStr = freeAtHomeBridge.getDatapoint(device.getDeviceId(), channelID, datapointID);
ValueStateConverter vsc = dpg.getValueStateConverter();
updateState(channelUID, vsc.convertToState(valueStr));
} catch (FreeAtHomeHttpCommunicationException e) {
logger.debug("Communication error during refresh command {} - at channel {} - Error string {}",
device.getDeviceId(), channelUID.getAsString(), e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"@text/comm-error.error-in-sysap-com");
} catch (FreeAtHomeGeneralException e) {
logger.debug("General error in the binding - during REFRESH command {} - at channel {} - Error string {}",
device.getDeviceId(), channelUID.getAsString(), e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"@text/conf-error.general-binding-error");
}
}
private void handleSetCommand(FreeAtHomeBridgeHandler freeAtHomeBridge, FreeAtHomeDatapointGroup dpg,
ChannelUID channelUID, Command command) {
State state = null;
String valueString = "0";
// initial error handling. look for the data point group validity
FreeAtHomeDatapoint datapoint = dpg.getInputDatapoint();
if (datapoint == null) {
logger.debug("Invalid parameter in handleSetCommand - DeviceId - {} - at channel {}", device.getDeviceId(),
channelUID.getAsString());
return;
}
try {
ValueStateConverter vsc = dpg.getValueStateConverter();
if (command instanceof StopMoveType) {
valueString = "0";
} else {
state = ((State) command);
valueString = vsc.convertToValueString(state);
}
freeAtHomeBridge.setDatapoint(device.getDeviceId(), datapoint.channelId, datapoint.getDatapointId(),
valueString);
if (!device.isScene()) {
if (state != null) {
updateState(channelUID, state);
} else {
updateState(channelUID, new StringType("STOP"));
}
}
} catch (FreeAtHomeHttpCommunicationException e) {
logger.debug(
"Communication error during set command {} - at channel {} - full command {} - Error string {}",
device.getDeviceId(), channelUID.getAsString(), command.toFullString(), e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"@text/comm-error.error-in-sysap-com");
} catch (FreeAtHomeGeneralException e) {
logger.debug("General error in the binding - during SET command {} - at channel {} - Error string {}",
device.getDeviceId(), channelUID.getAsString(), e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"@text/conf-error.general-binding-error");
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
FreeAtHomeBridgeHandler freeAtHomeBridge = null;
Bridge bridge = this.getBridge();
if (bridge != null) {
ThingHandler handler = bridge.getHandler();
if (handler instanceof FreeAtHomeBridgeHandler bridgeHandler) {
freeAtHomeBridge = bridgeHandler;
}
}
if (freeAtHomeBridge != null) {
updateStatus(ThingStatus.ONLINE);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR,
"@text/conf-error.invalid-bridge");
return;
}
FreeAtHomeDatapointGroup dpg = mapChannelUID.get(channelUID);
// is the datapointgroup invalid
if (dpg == null) {
logger.debug("Handle command for device (but invalid datapointgroup) {} - at channel {} - full command {}",
device.getDeviceId(), channelUID.getAsString(), command.toFullString());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"@text/conf-error.invalid-deviceconfig");
} else {
if (command instanceof RefreshType) {
handleRefreshCommand(freeAtHomeBridge, dpg, channelUID);
} else {
handleSetCommand(freeAtHomeBridge, dpg, channelUID, command);
}
logger.debug("Handle command for device {} - at channel {} - full command {}", device.getDeviceId(),
channelUID.getAsString(), command.toFullString());
}
}
public void onDeviceRemoved() {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.GONE);
}
public void onDeviceStateChanged(String event, String valueString) {
// Get the channle UID belonging to this event
ChannelUID channelUID = mapEventToChannelUID.get(event);
try {
if (channelUID != null) {
// get the value State Converter for the channel
FreeAtHomeDatapointGroup dpg = mapChannelUID.get(channelUID);
if (dpg != null) {
State state;
state = dpg.getValueStateConverter().convertToState(valueString);
// Handle state change
handleEventBasedUpdate(channelUID, state);
// if it is virtual device, give a feedback to free@home also
if (isThingHandlesVirtualDevice()) {
feedbackForVirtualDevice(channelUID, valueString);
}
}
}
} catch (FreeAtHomeGeneralException e) {
logger.debug("General error in the binding during onDeviceStateChange");
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"@text/conf-error.general-binding-error");
}
}
private void handleEventBasedUpdate(ChannelUID channelUID, State state) {
this.updateState(channelUID, state);
}
private void feedbackForVirtualDevice(ChannelUID channelUID, String valueString) {
FreeAtHomeBridgeHandler freeAtHomeBridge = null;
FreeAtHomeDatapointGroup dpg = mapChannelUID.get(channelUID);
Bridge bridge = this.getBridge();
if (bridge != null) {
ThingHandler handler = bridge.getHandler();
if (handler instanceof FreeAtHomeBridgeHandler bridgeHandler) {
freeAtHomeBridge = bridgeHandler;
}
}
if (freeAtHomeBridge == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, "@text/gen-error.no-bridge-avail");
return;
}
if (dpg == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"@text/conf-error.datapointgroup-invalid");
return;
}
FreeAtHomeDatapoint inputDatapoint = dpg.getInputDatapoint();
if (inputDatapoint == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"@text/conf-error.inputdatapoint-invalid");
return;
}
if ((dpg.getDirection() != FreeAtHomeDatapointGroup.DatapointGroupDirection.INPUT)
|| (dpg.getDirection() != FreeAtHomeDatapointGroup.DatapointGroupDirection.INPUTOUTPUT)) {
logger.debug("Handle feedback for virtual device {} - at channel {} - but wrong config",
device.getDeviceId(), channelUID.getAsString());
}
try {
freeAtHomeBridge.setDatapoint(device.getDeviceId(), inputDatapoint.channelId,
inputDatapoint.getDatapointId(), valueString);
updateStatus(ThingStatus.ONLINE);
logger.debug("Handle feedback for virtual device {} - at channel {} - value {}", device.getDeviceId(),
channelUID.getAsString(), valueString);
} catch (FreeAtHomeHttpCommunicationException e) {
logger.debug("Communication error during set command {} - at channel {} - value {} - Error string {}",
device.getDeviceId(), channelUID.getAsString(), valueString, e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"@text/comm-error.not-able-open-httpconnection");
}
}
public ChannelTypeUID createChannelTypeForDatapointgroup(FreeAtHomeDatapointGroup dpg,
ChannelTypeUID channelTypeUID) throws FreeAtHomeGeneralException {
StateDescriptionFragmentBuilder stateFragment = StateDescriptionFragmentBuilder.create();
stateFragment.withReadOnly(dpg.isReadOnly());
stateFragment.withPattern(dpg.getTypePattern());
if (dpg.isDecimal() || dpg.isInteger()) {
BigDecimal min = new BigDecimal(dpg.getMin());
BigDecimal max = new BigDecimal(dpg.getMax());
stateFragment.withMinimum(min).withMaximum(max);
}
try {
URI configDescriptionUriChannel = new URI(CHANNEL_URI);
ChannelTypeBuilder<?> channelTypeBuilder = ChannelTypeBuilder
.state(channelTypeUID,
String.format("%s-%s-%s-%s", dpg.getLabel(), dpg.getOpenHabItemType(),
dpg.getOpenHabCategory(), "type"),
dpg.getOpenHabItemType())
.withCategory(dpg.getOpenHabCategory()).withStateDescriptionFragment(stateFragment.build());
ChannelType channelType = channelTypeBuilder.isAdvanced(false)
.withConfigDescriptionURI(configDescriptionUriChannel)
.withDescription(String.format("Type for channel - %s ", dpg.getLabel())).build();
channelTypeProvider.addChannelType(channelType);
logger.debug("Channel type created {} - label: {} - category: {}", channelTypeUID.getAsString(),
dpg.getLabel(), dpg.getOpenHabCategory());
} catch (URISyntaxException e) {
logger.debug("Channel config URI cannot created for datapoint - datapoint group: {}", dpg.getLabel());
}
return channelTypeUID;
}
public void updateChannels() throws FreeAtHomeGeneralException {
// define update policy
AutoUpdatePolicy policy = AutoUpdatePolicy.DEFAULT;
if (device.isScene()) {
policy = AutoUpdatePolicy.VETO;
}
// Initialize channels
List<Channel> thingChannels = new ArrayList<>(this.getThing().getChannels());
if (thingChannels.isEmpty()) {
ThingBuilder thingBuilder = editThing();
ThingUID thingUID = thing.getUID();
for (int i = 0; i < device.getNumberOfChannels(); i++) {
FreeAtHomeDeviceChannel channel = device.getChannel(i);
for (int j = 0; j < channel.getNumberOfDatapointGroup(); j++) {
FreeAtHomeDatapointGroup dpg = channel.getDatapointGroup(j);
Map<String, String> channelProps = new HashMap<>();
FreeAtHomeDatapoint inputDatapoint = dpg.getInputDatapoint();
FreeAtHomeDatapoint outputDatapoint = dpg.getOutputDatapoint();
if (inputDatapoint != null) {
channelProps.put("input", inputDatapoint.getDatapointId());
}
if (outputDatapoint != null) {
channelProps.put("output", outputDatapoint.getDatapointId());
}
ChannelTypeUID channelTypeUID = UidUtils.generateChannelTypeUID(dpg.getValueType(),
dpg.isReadOnly());
if (channelTypeProvider.getChannelType(channelTypeUID, null) == null) {
channelTypeUID = createChannelTypeForDatapointgroup(dpg, channelTypeUID);
}
ChannelUID channelUID = new ChannelUID(thingUID, channel.getChannelId(),
dpg.getLabel().substring(4));
String channelLabel = String.format("%s",
i18nProvider.getText(bundle, dpg.getLabel(), "-", locale));
String channelDescription = String.format("(%s) %s", channel.getChannelLabel(),
i18nProvider.getText(bundle, dpg.getDescription(), "-", locale));
Channel thingChannel = ChannelBuilder.create(channelUID)
.withAcceptedItemType(dpg.getOpenHabItemType()).withKind(ChannelKind.STATE)
.withProperties(channelProps).withLabel(capitalizeWordsInLabel(channelLabel))
.withDescription(channelDescription).withType(channelTypeUID).withAutoUpdatePolicy(policy)
.build();
thingChannels.add(thingChannel);
logger.debug("Thing channel created - device: {} - channelUID: {} - channel label: {}",
device.getDeviceId() + device.getDeviceLabel(), channelUID.getAsString(), channelLabel);
// in case of output channel, register it for updates
if (outputDatapoint != null) {
String eventDatapointID = new String(device.getDeviceId() + "/" + channel.getChannelId() + "/"
+ outputDatapoint.getDatapointId());
mapEventToChannelUID.put(eventDatapointID, channelUID);
}
// add the datapoint group to the mapping channel
mapChannelUID.put(channelUID, dpg);
if (dpg.getInputDatapoint() == null) {
logger.debug(
"Thing channel registered - device: {} - channelUID: {} - channel label: {} - category: {}",
device.getDeviceId() + device.getDeviceLabel(), channelUID.getAsString(),
dpg.getLabel(), dpg.getOpenHabCategory());
} else {
logger.debug(
"Thing channel registered - device: {} - channelUID: {} - channel label: {} - category: {}",
device.getDeviceId() + device.getDeviceLabel(), channelUID.getAsString(),
dpg.getLabel(), dpg.getOpenHabCategory());
}
}
thingBuilder.withChannels(thingChannels);
updateThing(thingBuilder.build());
}
} else {
reloadChannelTypes();
}
thingChannels.forEach(channel -> {
if (isLinked(channel.getUID())) {
channelLinked(channel.getUID());
}
});
}
private void reloadChannelTypes() throws FreeAtHomeGeneralException {
Bridge bridge = this.getBridge();
ThingUID thingUID = thing.getUID();
try {
if (bridge != null) {
ThingHandler handler = bridge.getHandler();
if (handler instanceof FreeAtHomeBridgeHandler bridgeHandler) {
device = bridgeHandler.getFreeatHomeDeviceDescription(device.getDeviceId());
}
}
} catch (FreeAtHomeHttpCommunicationException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"@text/comm-error.error-in-sysap-com");
}
for (int i = 0; i < device.getNumberOfChannels(); i++) {
FreeAtHomeDeviceChannel channel = device.getChannel(i);
for (int j = 0; j < channel.getNumberOfDatapointGroup(); j++) {
FreeAtHomeDatapointGroup dpg = channel.getDatapointGroup(j);
ChannelTypeUID channelTypeUID = UidUtils.generateChannelTypeUID(dpg.getValueType(), dpg.isReadOnly());
if (channelTypeProvider.getChannelType(channelTypeUID, null) == null) {
channelTypeUID = createChannelTypeForDatapointgroup(dpg, channelTypeUID);
}
ChannelUID channelUID = new ChannelUID(thingUID, channel.getChannelId());
FreeAtHomeDatapoint outputDatapoint = dpg.getOutputDatapoint();
// in case of output channel, register it for updates
if (outputDatapoint != null) {
String eventDatapointID = new String(device.getDeviceId() + "/" + channel.getChannelId() + "/"
+ outputDatapoint.getDatapointId());
mapEventToChannelUID.put(eventDatapointID, channelUID);
}
// add the datapoint group to the mapping channel
mapChannelUID.put(channelUID, dpg);
logger.debug("Thing channelType reloaded - Device: {} - channelTypeUID: {}",
device.getDeviceId() + device.getDeviceLabel(), channelTypeUID.getAsString());
}
}
}
public void removeChannels() {
Bridge bridge = this.getBridge();
try {
if (bridge != null) {
ThingHandler handler = bridge.getHandler();
if (handler instanceof FreeAtHomeBridgeHandler bridgeHandler) {
device = bridgeHandler.getFreeatHomeDeviceDescription(device.getDeviceId());
}
}
} catch (FreeAtHomeHttpCommunicationException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"@text/comm-error.error-in-sysap-com");
}
mapChannelUID.clear();
mapEventToChannelUID.clear();
}
private String capitalizeWordsInLabel(String label) {
// splliting up words using split function
String[] words = label.split(" ");
for (int i = 0; i < words.length; i++) {
// taking letter individually from sentences
String firstLetter = words[i].substring(0, 1);
String restOfWord = words[i].substring(1);
// making first letter uppercase using toUpperCase function
firstLetter = firstLetter.toUpperCase();
words[i] = firstLetter + restOfWord;
}
// joining the words together to make a sentence
return String.join(" ", words);
}
private boolean isThingHandlesVirtualDevice() {
return device.isVirtual();
}
}

View File

@ -0,0 +1,29 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link FreeAtHomeDeviceStateListener} is responsible for response the device state changes from SysAp
* and thing updates
*
* @author Andras Uhrin - Initial contribution
*
*/
@NonNullByDefault
public interface FreeAtHomeDeviceStateListener {
void onDeviceRemoved();
void onDeviceStateChanged(String event, String valueString);
}

View File

@ -0,0 +1,28 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.type;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.type.ChannelType;
import org.openhab.core.thing.type.ChannelTypeProvider;
/**
*
* @author Andras Uhrin - Initial contribution
*
*/
@NonNullByDefault
public interface FreeAtHomeChannelTypeProvider extends ChannelTypeProvider {
public void addChannelType(ChannelType channelType);
}

View File

@ -0,0 +1,65 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.thing.type.ChannelType;
import org.openhab.core.thing.type.ChannelTypeProvider;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.osgi.service.component.annotations.Component;
/**
*
* @author Andras Uhrin - Initial contribution
*
*/
@Component(service = { FreeAtHomeChannelTypeProvider.class, ChannelTypeProvider.class })
@NonNullByDefault
public class FreeAtHomeChannelTypeProviderImpl implements FreeAtHomeChannelTypeProvider {
private final Map<ChannelTypeUID, ChannelType> channelTypesByUID = new HashMap<>();
@Override
public Collection<ChannelType> getChannelTypes(@Nullable Locale locale) {
Collection<ChannelType> result = new ArrayList<>();
for (ChannelTypeUID uid : channelTypesByUID.keySet()) {
ChannelType channelType = channelTypesByUID.get(uid);
if (channelType != null) {
result.add(channelType);
}
}
return result;
}
@Override
public @Nullable ChannelType getChannelType(@Nullable ChannelTypeUID channelTypeUID, @Nullable Locale locale) {
return channelTypesByUID.get(channelTypeUID);
}
@Override
public void addChannelType(@Nullable ChannelType channelType) {
if (channelType != null) {
channelTypesByUID.put(channelType.getUID(), channelType);
}
}
}

View File

@ -0,0 +1,31 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.type;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.binding.ThingTypeProvider;
import org.openhab.core.thing.type.ThingType;
/**
*
* @author Andras Uhrin - Initial contribution
*
*/
@NonNullByDefault
public interface FreeAtHomeThingTypeProvider extends ThingTypeProvider {
/**
* Adds the ThingType to this provider.
*/
public void addThingType(ThingType thingType);
}

View File

@ -0,0 +1,55 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.type;
import java.util.Collection;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.ThingTypeProvider;
import org.openhab.core.thing.type.ThingType;
import org.osgi.service.component.annotations.Component;
/**
*
* @author Andras Uhrin - Initial contribution
*
*/
@Component(service = { FreeAtHomeThingTypeProvider.class, ThingTypeProvider.class })
@NonNullByDefault
public class FreeAtHomeThingTypeProviderImpl implements FreeAtHomeThingTypeProvider {
private final Map<ThingTypeUID, ThingType> thingTypesByUID = new HashMap<>();
@Override
public Collection<ThingType> getThingTypes(@Nullable Locale locale) {
Map<ThingTypeUID, ThingType> copy = new HashMap<>(thingTypesByUID);
return copy.values();
}
@Override
public @Nullable ThingType getThingType(ThingTypeUID thingTypeUID, @Nullable Locale locale) {
return thingTypesByUID.get(thingTypeUID);
}
@Override
public void addThingType(@Nullable ThingType thingType) {
if (thingType != null) {
thingTypesByUID.put(thingType.getUID(), thingType);
}
}
}

View File

@ -0,0 +1,362 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.util;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* The {@link FidTranslationUtils} having constant values for json parsing
*
* @author Andras Uhrin - Initial contribution
*
*/
@NonNullByDefault
public class FidTranslationUtils {
public static final int FID_UNKNOWN = 0xFFFFAAFF; // Unknown
// free@home constants
public static final int FID_SWITCH_SENSOR = 0x0000; // Control element
public static final int FID_DIMMING_SENSOR = 0x0001; // Dimming sensor
public static final int FID_BLIND_SENSOR = 0x0003; // Blind sensor
public static final int FID_STAIRCASE_LIGHT_SENSOR = 0x0004; // Stairwell light sensor
public static final int FID_FORCE_ON_OFF_SENSOR = 0x0005; // Force On/Off sensor
public static final int FID_SCENE_SENSOR = 0x0006; // Scene sensor
public static final int FID_SWITCH_ACTUATOR = 0x0007; // Switch actuator
public static final int FID_SHUTTER_ACTUATOR = 0x0009; // Blind actuator
public static final int FID_ROOM_TEMPERATURE_CONTROLLER_MASTER_WITH_FAN = 0x000A; // Room temperature controller
// with fan speed level
public static final int FID_ROOM_TEMPERATURE_CONTROLLER_SLAVE = 0x000B; // Room temperature controller extension
// unit
public static final int FID_WIND_ALARM_SENSOR = 0x000C; // Wind Alarm
public static final int FID_FROST_ALARM_SENSOR = 0x000D; // Frost Alarm
public static final int FID_RAIN_ALARM_SENSOR = 0x000E; // Rain Alarm
public static final int FID_WINDOW_DOOR_SENSOR = 0x000F; // Window sensor
public static final int FID_MOVEMENT_DETECTOR = 0x0011; // Movement Detector
public static final int FID_DIMMING_ACTUATOR = 0x0012; // Dim actuator
public static final int FID_RADIATOR_ACTUATOR = 0x0014; // Radiator
public static final int FID_UNDERFLOOR_HEATING = 0x0015; // Underfloor heating
public static final int FID_FAN_COIL = 0x0016; // Fan Coil
public static final int FID_TWO_LEVEL_CONTROLLER = 0x0017; // Two-level controller
public static final int FID_DES_DOOR_OPENER_ACTUATOR = 0x001A; // Door opener
public static final int FID_PROXY = 0x001B; // Proxy
public static final int FID_DES_LEVEL_CALL_ACTUATOR = 0x001D; // Door Map.entry System Call Level Actuator
public static final int FID_DES_LEVEL_CALL_SENSOR = 0x001E; // Door Map.entry System Call Level Sensor
public static final int FID_DES_DOOR_RINGING_SENSOR = 0x001F; // Door call
public static final int FID_DES_AUTOMATIC_DOOR_OPENER_ACTUATOR = 0x0020; // Automatic door opener
public static final int FID_DES_LIGHT_SWITCH_ACTUATOR = 0x0021; // Corridor light
public static final int FID_ROOM_TEMPERATURE_CONTROLLER_MASTER_WITHOUT_FAN = 0x0023; // Room temperature controller
public static final int FID_COOLING_ACTUATOR = 0x0024; // Cooling mode
public static final int FID_HEATING_ACTUATOR = 0x0027; // Heating mode
public static final int FID_FORCE_UP_DOWN_SENSOR = 0x0028; // Force-position blind
public static final int FID_HEATING_COOLING_ACTUATOR = 0x0029; // Auto. heating/cooling mode
public static final int FID_HEATING_COOLING_SENSOR = 0x002A; // Switchover heating/cooling
public static final int FID_DES_DEVICE_SETTINGS = 0x002B; // Device settings
public static final int FID_RGB_W_ACTUATOR = 0x002E; // Dim actuator
public static final int FID_RGB_ACTUATOR = 0x002F; // Dim actuator
public static final int FID_PANEL_SWITCH_SENSOR = 0x0030; // Control element
public static final int FID_PANEL_DIMMING_SENSOR = 0x0031; // Dimming sensor
public static final int FID_PANEL_BLIND_SENSOR = 0x0033; // Blind sensor
public static final int FID_PANEL_STAIRCASE_LIGHT_SENSOR = 0x0034; // Stairwell light sensor
public static final int FID_PANEL_FORCE_ON_OFF_SENSOR = 0x0035; // Force On/Off sensor
public static final int FID_PANEL_FORCE_UP_DOWN_SENSOR = 0x0036; // Force-position blind
public static final int FID_PANEL_SCENE_SENSOR = 0x0037; // Scene sensor
public static final int FID_PANEL_ROOM_TEMPERATURE_CONTROLLER_SLAVE = 0x0038; // Room temperature controller
// extension unit
public static final int FID_PANEL_FAN_COIL_SENSOR = 0x0039; // Fan coil sensor
public static final int FID_PANEL_RGB_CT_SENSOR = 0x003A; // RGB + warm white/cold white sensor
public static final int FID_PANEL_RGB_SENSOR = 0x003B; // RGB sensor
public static final int FID_PANEL_CT_SENSOR = 0x003C; // Warm white/cold white sensor
public static final int FID_ADDITIONAL_HEATING_ACTUATOR = 0x003D; // Add. stage for heating mode
public static final int FID_RADIATOR_ACTUATOR_MASTER = 0x003E; // Radiator thermostate
public static final int FID_RADIATOR_ACTUATOR_SLAVE = 0x003F; // Room temperature controller extension unit
public static final int FID_BRIGHTNESS_SENSOR = 0x0041; // Brightness sensor
public static final int FID_RAIN_SENSOR = 0x0042; // Rain sensor
public static final int FID_TEMPERATURE_SENSOR = 0x0043; // Temperature sensor
public static final int FID_WIND_SENSOR = 0x0044; // Wind sensor
public static final int FID_TRIGGER = 0x0045; // Trigger
public static final int FID_FCA_2_PIPE_HEATING = 0x0047; // Heating mode
public static final int FID_FCA_2_PIPE_COOLING = 0x0048; // Cooling mode
public static final int FID_FCA_2_PIPE_HEATING_COOLING = 0x0049; // Auto. heating/cooling mode
public static final int FID_FCA_4_PIPE_HEATING_AND_COOLING = 0x004A; // Two valves for heating and cooling
public static final int FID_WINDOW_DOOR_ACTUATOR = 0x004B; // Window/Door
public static final int FID_INVERTER_INFO = 0x004E; // ABC
public static final int FID_METER_INFO = 0x004F; // ABD
public static final int FID_BATTERY_INFO = 0x0050; // ACD
public static final int FID_PANEL_TIMER_PROGRAM_SWITCH_SENSOR = 0x0051; // Timer program switch sensor
public static final int FID_DOMUSTECH_ZONE = 0x0055; // Zone
public static final int FID_CENTRAL_HEATING_ACTUATOR = 0x0056; // Central heating actuator
public static final int FID_CENTRAL_COOLING_ACTUATOR = 0x0057; // Central cooling actuator
public static final int FID_HOUSE_KEEPING = 0x0059; // Housekeeping
public static final int FID_MEDIA_PLAYER = 0x005A; // Media Player
public static final int FID_PANEL_ROOM_TEMPERATURE_CONTROLLER_SLAVE_FOR_BATTERY_DEVICE = 0x005B; // Panel Room
// Temperature
// Controller Slave
// For Battery
// Device
public static final int FID_PANEL_MEDIA_PLAYER_SENSOR = 0x0060; // Media Player Sensor
public static final int FID_BLIND_ACTUATOR = 0x0061; // Roller blind actuator
public static final int FID_ATTIC_WINDOW_ACTUATOR = 0x0062; // Attic window actuator
public static final int FID_AWNING_ACTUATOR = 0x0063; // Awning actuator
public static final int FID_WINDOW_DOOR_POSITION_SENSOR = 0x0064; // WindowDoor Position Sensor
public static final int FID_WINDOW_DOOR_POSITION_ACTUATOR = 0x0065; // Window/Door position
public static final int FID_MEDIA_PLAYBACK_CONTROL_SENSOR = 0x0066; // Media playback control sensor
public static final int FID_MEDIA_VOLUME_SENSOR = 0x0067; // Media volume sensor
public static final int FID_DISHWASHER = 0x0068; // Dishwasher
public static final int FID_LAUNDRY = 0x0069; // Laundry
public static final int FID_DRYER = 0x006A; // Dryer
public static final int FID_OVEN = 0x006B; // Oven
public static final int FID_FRIDGE = 0x006C; // Fridge
public static final int FID_FREEZER = 0x006D; // Freezer
public static final int FID_HOOD = 0x006E; // Hood
public static final int FID_COFFEE_MACHINE = 0x006F; // Coffee machine
public static final int FID_FRIDGE_FREEZER = 0x0070; // Fridge/Freezer
public static final int FID_TIMER_PROGRAM_OR_ALERT_SWITCH_SENSOR = 0x0071; // Timer program switch sensor
public static final int FID_CEILING_FAN_ACTUATOR = 0x0073; // Ceiling fan actuator
public static final int FID_CEILING_FAN_SENSOR = 0x0074; // Ceiling fan sensor
public static final int FID_SPLIT_UNIT_GATEWAY = 0x0075; // Room temperature controller with fan speed level
public static final int FID_ZONE = 0x0076; // Zone
public static final int FID_24H_ZONE = 0x0077; // Safety
public static final int FID_EXTERNAL_IR_SENSOR_BX80 = 0x0078; // External IR Sensor BX80
public static final int FID_EXTERNAL_IR_SENSOR_VXI = 0x0079; // External IR Sensor VXI
public static final int FID_EXTERNAL_IR_SENSOR_MINI = 0x007A; // External IR Sensor Mini
public static final int FID_EXTERNAL_IR_SENSOR_HIGH_ALTITUDE = 0x007B; // External IR Sensor High Altitude
public static final int FID_EXTERNAL_IR_SENSOR_CURTAIN = 0x007C; // External IR Sensor Curtain
public static final int FID_SMOKE_DETECTOR = 0x007D; // Smoke Detector
public static final int FID_CARBON_MONOXIDE_SENSOR = 0x007E; // Carbon Monoxide Sensor
public static final int FID_METHANE_DETECTOR = 0x007F; // Methane Detector
public static final int FID_GAS_SENSOR_LPG = 0x0080; // Gas Sensor LPG
public static final int FID_FLOOD_DETECTION = 0x0081; // Flood Detection
public static final int FID_DOMUS_CENTRAL_UNIT_NEXTGEN = 0x0082; // secure@home Central Unit
public static final int FID_THERMOSTAT = 0x0083; // Thermostat
public static final int FID_PANEL_DOMUS_ZONE_SENSOR = 0x0084; // secure@home Zone Sensor
public static final int FID_THERMOSTAT_SLAVE = 0x0085; // Slave thermostat
public static final int FID_DOMUS_SECURE_INTEGRATION = 0x0086; // secure@home Integration Logic
public static final int FID_ADDITIONAL_COOLING_ACTUATOR = 0x0087; // Add. stage for cooling mode
public static final int FID_TWO_LEVEL_HEATING_ACTUATOR = 0x0088; // Two Level Heating Actuator
public static final int FID_TWO_LEVEL_COOLING_ACTUATOR = 0x0089; // Two Level Cooling Actuator
public static final int FID_GLOBAL_ZONE = 0x008E; // Zone
public static final int FID_VOLUME_UP_SENSOR = 0x008F; // Volume up
public static final int FID_VOLUME_DOWN_SENSOR = 0x0090; // Volume down
public static final int FID_PLAY_PAUSE_SENSOR = 0x0091; // Play/pause
public static final int FID_NEXT_FAVORITE_SENSOR = 0x0092; // Next favorite
public static final int FID_NEXT_SONG_SENSOR = 0x0093; // Next song
public static final int FID_PREVIOUS_SONG_SENSOR = 0x0094; // Previous song
public static final int FID_HOME_APPLIANCE_SENSOR = 0x0095; // Home appliance sensor
public static final int FID_HEAT_SENSOR = 0x0096; // Heat sensor
public static final int FID_ZONE_SWITCHING = 0x0097; // Zone switching
public static final int FID_SECURE_AT_HOME_FUNCTION = 0x0098; // Button function
public static final int FID_COMPLEX_CONFIGURATION = 0x0099; // Advanced configuration
public static final int FID_DOMUS_CENTRAL_UNIT_BASIC = 0x009A; // secure@home Central Unit Basic
public static final int FID_DOMUS_REPEATER = 0x009B; // Repeater
public static final int FID_DOMUS_SCENE_TRIGGER = 0x009C; // Remote scene control
public static final int FID_DOMUSWINDOWCONTACT = 0x009D; // Window sensor
public static final int FID_DOMUSMOVEMENTDETECTOR = 0x009E; // Movement Detector
public static final int FID_DOMUSCURTAINDETECTOR = 0x009F; // External IR Sensor Curtain
public static final int FID_DOMUSSMOKEDETECTOR = 0x00A0; // Smoke Detector
public static final int FID_DOMUSFLOODDETECTOR = 0x00A1; // Flood Detection
public static final int FID_PANEL_SUG_SENSOR = 0x00A3; // Sensor for air-conditioning unit
public static final int FID_TWO_LEVEL_HEATING_COOLING_ACTUATOR = 0x00A4; // Two-point controller for heating or
// cooling
public static final int FID_PANEL_THERMOSTAT_CONTROLLER_SLAVE = 0x00A5; // Slave thermostat
public static final int FID_WALLBOX = 0x00A6; // Wallbox
public static final int FID_PANEL_WALLBOX = 0x00A7; // Wallbox
public static final int FID_DOOR_LOCK_CONTROL = 0x00A8; // Door lock control
public static final int FID_VRV_GATEWAY = 0x00AA; // Room temperature controller with fan speed level
public static final int FID_SCENE_TRIGGER = 0x4800; // Scene trigger
public static final int FID_RULE_SWITCH = 0x4A00; // Scene trigger
// FID added based on tests
public static final int FID_AIRQUALITYSENSOR_PRESSURE = 0x0E017;
public static final int FID_AIRQUALITYSENSOR_CO2 = 0x0E018;
public static final int FID_AIRQUALITYSENSOR_CO = 0x0E019;
public static final int FID_AIRQUALITYSENSOR_NO2 = 0x0E01A;
public static final int FID_AIRQUALITYSENSOR_O3 = 0x0E01B;
public static final int FID_AIRQUALITYSENSOR_PM10 = 0x0E01C;
public static final int FID_AIRQUALITYSENSOR_PM25 = 0x0E01D;
public static final int FID_AIRQUALITYSENSOR_VOC = 0x0E01E;
public static final int FID_AIRQUALITYSENSOR_HUMIDITY = 0x0B03F;
public static final int FID_MOVEMENT_DETECTOR_FLEX = 0x1090;
public static final int FID_DIMMING_ACTUATOR_FLEX = 0x1810;
private static final Map<String, String> MAP_FUNCTION_ID = Map.ofEntries(Map.entry("0x0000", "fid-control-element"), // FID_SWITCH_SENSOR
Map.entry("0x0001", "fid-dimming-sensor"), // FID_DIMMING_SENSOR
Map.entry("0x0003", "fid-blind-sensor"), // FID_BLIND_SENSOR
Map.entry("0x0004", "fid-stairwell-light-sensor"), // FID_STAIRCASE_LIGHT_SENSOR
Map.entry("0x0005", "fid-force-on/off-sensor"), // FID_FORCE_ON_OFF_SENSOR
Map.entry("0x0006", "fid-scene-sensor"), // FID_SCENE_SENSOR
Map.entry("0x0007", "fid-switch-actuator"), // FID_SWITCH_ACTUATOR
Map.entry("0x0009", "fid-blind-actuator"), // FID_SHUTTER_ACTUATOR
Map.entry("0x000A", "fid-room-temperature-controller-with-fan-speed-level"), // FID_ROOM_TEMPERATURE_CONTROLLER_MASTER_WITH_FAN
Map.entry("0x000B", "fid-room-temperature-controller-extension-unit"), // FID_ROOM_TEMPERATURE_CONTROLLER_SLAVE
Map.entry("0x000C", "fid-wind-alarm"), // FID_WIND_ALARM_SENSOR
Map.entry("0x000D", "fid-frost-alarm"), // FID_FROST_ALARM_SENSOR
Map.entry("0x000E", "fid-rain-alarm"), // FID_RAIN_ALARM_SENSOR
Map.entry("0x000F", "fid-window-sensor"), // FID_WINDOW_DOOR_SENSOR
Map.entry("0x0011", "fid-movement-detector"), // FID_MOVEMENT_DETECTOR
Map.entry("0x0012", "fid-dim-actuator"), // FID_DIMMING_ACTUATOR
Map.entry("0x0014", "fid-radiator"), // FID_RADIATOR_ACTUATOR
Map.entry("0x0015", "fid-underfloor-heating"), // FID_UNDERFLOOR_HEATING
Map.entry("0x0016", "fid-fan-coil"), // FID_FAN_COIL
Map.entry("0x0017", "fid-two-level-controller"), // FID_TWO_LEVEL_CONTROLLER
Map.entry("0x001A", "fid-door-opener"), // FID_DES_DOOR_OPENER_ACTUATOR
Map.entry("0x001B", "fid-proxy"), // FID_PROXY
Map.entry("0x001D", "fid-door-map.entry-system-call-level-actuator"), // FID_DES_LEVEL_CALL_ACTUATOR
Map.entry("0x001E", "fid-door-map.entry-system-call-level-sensor"), // FID_DES_LEVEL_CALL_SENSOR
Map.entry("0x001F", "fid-door-call"), // FID_DES_DOOR_RINGING_SENSOR
Map.entry("0x0020", "fid-automatic-door-opener"), // FID_DES_AUTOMATIC_DOOR_OPENER_ACTUATOR
Map.entry("0x0021", "fid-corridor-light"), // FID_DES_LIGHT_SWITCH_ACTUATOR
Map.entry("0x0023", "fid-room-temperature-controller"), // FID_ROOM_TEMPERATURE_CONTROLLER_MASTER_WITHOUT_FAN
Map.entry("0x0024", "fid-cooling-mode"), // FID_COOLING_ACTUATOR
Map.entry("0x0027", "fid-heating-mode"), // FID_HEATING_ACTUATOR
Map.entry("0x0028", "fid-force-position-blind"), // FID_FORCE_UP_DOWN_SENSOR
Map.entry("0x0029", "fid-auto.-heating/cooling-mode"), // FID_HEATING_COOLING_ACTUATOR
Map.entry("0x002A", "fid-switchover-heating/cooling"), // FID_HEATING_COOLING_SENSOR
Map.entry("0x002B", "fid-device-settings"), // FID_DES_DEVICE_SETTINGS
Map.entry("0x002E", "fid-dim-actuator"), // FID_RGB_W_ACTUATOR
Map.entry("0x002F", "fid-dim-actuator"), // FID_RGB_ACTUATOR
Map.entry("0x0030", "fid-control-element"), // FID_PANEL_SWITCH_SENSOR
Map.entry("0x0031", "fid-dimming-sensor"), // FID_PANEL_DIMMING_SENSOR
Map.entry("0x0033", "fid-blind-sensor"), // FID_PANEL_BLIND_SENSOR
Map.entry("0x0034", "fid-stairwell-light-sensor"), // FID_PANEL_STAIRCASE_LIGHT_SENSOR
Map.entry("0x0035", "fid-force-on/off-sensor"), // FID_PANEL_FORCE_ON_OFF_SENSOR
Map.entry("0x0036", "fid-force-position-blind"), // FID_PANEL_FORCE_UP_DOWN_SENSOR
Map.entry("0x0037", "fid-scene-sensor"), // FID_PANEL_SCENE_SENSOR
Map.entry("0x0038", "fid-room-temperature-controller-extension-unit"), // FID_PANEL_ROOM_TEMPERATURE_CONTROLLER_SLAVE
Map.entry("0x0039", "fid-fan-coil-sensor"), // FID_PANEL_FAN_COIL_SENSOR
Map.entry("0x003A", "fid-rgb-+-warm-white/cold-white-sensor"), // FID_PANEL_RGB_CT_SENSOR
Map.entry("0x003B", "fid-rgb-sensor"), // FID_PANEL_RGB_SENSOR
Map.entry("0x003C", "fid-warm-white/cold-white-sensor"), // FID_PANEL_CT_SENSOR
Map.entry("0x003D", "fid-add.-stage-for-heating-mode"), // FID_ADDITIONAL_HEATING_ACTUATOR
Map.entry("0x003E", "fid-radiator-thermostate"), // FID_RADIATOR_ACTUATOR_MASTER
Map.entry("0x003F", "fid-room-temperature-controller-extension-unit"), // FID_RADIATOR_ACTUATOR_SLAVE
Map.entry("0x0041", "fid-brightness-sensor"), // FID_BRIGHTNESS_SENSOR
Map.entry("0x0042", "fid-rain-sensor"), // FID_RAIN_SENSOR
Map.entry("0x0043", "fid-temperature-sensor"), // FID_TEMPERATURE_SENSOR
Map.entry("0x0044", "fid-wind-sensor"), // FID_WIND_SENSOR
Map.entry("0x0045", "fid-trigger"), // FID_TRIGGER
Map.entry("0x0047", "fid-heating-mode"), // FID_FCA_2_PIPE_HEATING
Map.entry("0x0048", "fid-cooling-mode"), // FID_FCA_2_PIPE_COOLING
Map.entry("0x0049", "fid-auto.-heating/cooling-mode"), // FID_FCA_2_PIPE_HEATING_COOLING
Map.entry("0x004A", "fid-two-valves-for-heating-and-cooling"), // FID_FCA_4_PIPE_HEATING_AND_COOLING
Map.entry("0x004B", "fid-window/door"), // FID_WINDOW_DOOR_ACTUATOR
Map.entry("0x004E", "fid-abc"), // FID_INVERTER_INFO
Map.entry("0x004F", "fid-abd"), // FID_METER_INFO
Map.entry("0x0050", "fid-acd"), // FID_BATTERY_INFO
Map.entry("0x0051", "fid-timer-program-switch-sensor"), // FID_PANEL_TIMER_PROGRAM_SWITCH_SENSOR
Map.entry("0x0055", "fid-zone"), // FID_DOMUSTECH_ZONE
Map.entry("0x0056", "fid-central-heating-actuator"), // FID_CENTRAL_HEATING_ACTUATOR
Map.entry("0x0057", "fid-central-cooling-actuator"), // FID_CENTRAL_COOLING_ACTUATOR
Map.entry("0x0059", "fid-housekeeping"), // FID_HOUSE_KEEPING
Map.entry("0x005A", "fid-media-player"), // FID_MEDIA_PLAYER
Map.entry("0x005B", "fid-panel-room-temperature-controller-slave-for-battery-device"), // FID_PANEL_ROOM_TEMPERATURE_CONTROLLER_SLAVE_FOR_BATTERY_DEVICE
Map.entry("0x0060", "fid-media-player-sensor"), // FID_PANEL_MEDIA_PLAYER_SENSOR
Map.entry("0x0061", "fid-roller-blind-actuator"), // FID_BLIND_ACTUATOR
Map.entry("0x0062", "fid-attic-window-actuator"), // FID_ATTIC_WINDOW_ACTUATOR
Map.entry("0x0063", "fid-awning-actuator"), // FID_AWNING_ACTUATOR
Map.entry("0x0064", "fid-windowdoor-position-sensor"), // FID_WINDOW_DOOR_POSITION_SENSOR
Map.entry("0x0065", "fid-window/door-position"), // FID_WINDOW_DOOR_POSITION_ACTUATOR
Map.entry("0x0066", "fid-media-playback-control-sensor"), // FID_MEDIA_PLAYBACK_CONTROL_SENSOR
Map.entry("0x0067", "fid-media-volume-sensor"), // FID_MEDIA_VOLUME_SENSOR
Map.entry("0x0068", "fid-dishwasher"), // FID_DISHWASHER
Map.entry("0x0069", "fid-laundry"), // FID_LAUNDRY
Map.entry("0x006A", "fid-dryer"), // FID_DRYER
Map.entry("0x006B", "fid-oven"), // FID_OVEN
Map.entry("0x006C", "fid-fridge"), // FID_FRIDGE
Map.entry("0x006D", "fid-freezer"), // FID_FREEZER
Map.entry("0x006E", "fid-hood"), // FID_HOOD
Map.entry("0x006F", "fid-coffee-machine"), // FID_COFFEE_MACHINE
Map.entry("0x0070", "fid-fridge/freezer"), // FID_FRIDGE_FREEZER
Map.entry("0x0071", "fid-timer-program-switch-sensor"), // FID_TIMER_PROGRAM_OR_ALERT_SWITCH_SENSOR
Map.entry("0x0073", "fid-ceiling-fan-actuator"), // FID_CEILING_FAN_ACTUATOR
Map.entry("0x0074", "fid-ceiling-fan-sensor"), // FID_CEILING_FAN_SENSOR
Map.entry("0x0075", "fid-room-temperature-controller-with-fan-speed-level"), // FID_SPLIT_UNIT_GATEWAY
Map.entry("0x0076", "fid-zone"), // FID_ZONE
Map.entry("0x0077", "fid-safety"), // FID_24H_ZONE
Map.entry("0x0078", "fid-external-ir-sensor-bx80"), // FID_EXTERNAL_IR_SENSOR_BX80
Map.entry("0x0079", "fid-external-ir-sensor-vxi"), // FID_EXTERNAL_IR_SENSOR_VXI
Map.entry("0x007A", "fid-external-ir-sensor-mini"), // FID_EXTERNAL_IR_SENSOR_MINI
Map.entry("0x007B", "fid-external-ir-sensor-high-altitude"), // FID_EXTERNAL_IR_SENSOR_HIGH_ALTITUDE
Map.entry("0x007C", "fid-external-ir-sensor-curtain"), // FID_EXTERNAL_IR_SENSOR_CURTAIN
Map.entry("0x007D", "fid-smoke-detector"), // FID_SMOKE_DETECTOR
Map.entry("0x007E", "fid-carbon-monoxide-sensor"), // FID_CARBON_MONOXIDE_SENSOR
Map.entry("0x007F", "fid-methane-detector"), // FID_METHANE_DETECTOR
Map.entry("0x0080", "fid-gas-sensor-lpg"), // FID_GAS_SENSOR_LPG
Map.entry("0x0081", "fid-flood-detection"), // FID_FLOOD_DETECTION
Map.entry("0x0082", "fid-secure@home-central-unit"), // FID_DOMUS_CENTRAL_UNIT_NEXTGEN
Map.entry("0x0083", "fid-thermostat"), // FID_THERMOSTAT
Map.entry("0x0084", "fid-secure@home-zone-sensor"), // FID_PANEL_DOMUS_ZONE_SENSOR
Map.entry("0x0085", "fid-slave-thermostat"), // FID_THERMOSTAT_SLAVE
Map.entry("0x0086", "fid-secure@home-integration-logic"), // FID_DOMUS_SECURE_INTEGRATION
Map.entry("0x0087", "fid-add.-stage-for-cooling-mode"), // FID_ADDITIONAL_COOLING_ACTUATOR
Map.entry("0x0088", "fid-two-level-heating-actuator"), // FID_TWO_LEVEL_HEATING_ACTUATOR
Map.entry("0x0089", "fid-two-level-cooling-actuator"), // FID_TWO_LEVEL_COOLING_ACTUATOR
Map.entry("0x008E", "fid-zone"), // FID_GLOBAL_ZONE
Map.entry("0x008F", "fid-volume-up"), // FID_VOLUME_UP_SENSOR
Map.entry("0x0090", "fid-volume-down"), // FID_VOLUME_DOWN_SENSOR
Map.entry("0x0091", "fid-play/pause"), // FID_PLAY_PAUSE_SENSOR
Map.entry("0x0092", "fid-next-favorite"), // FID_NEXT_FAVORITE_SENSOR
Map.entry("0x0093", "fid-next-song"), // FID_NEXT_SONG_SENSOR
Map.entry("0x0094", "fid-previous-song"), // FID_PREVIOUS_SONG_SENSOR
Map.entry("0x0095", "fid-home-appliance-sensor"), // FID_HOME_APPLIANCE_SENSOR
Map.entry("0x0096", "fid-heat-sensor"), // FID_HEAT_SENSOR
Map.entry("0x0097", "fid-zone-switching"), // FID_ZONE_SWITCHING
Map.entry("0x0098", "fid-button-function"), // FID_SECURE_AT_HOME_FUNCTION
Map.entry("0x0099", "fid-advanced-configuration"), // FID_COMPLEX_CONFIGURATION
Map.entry("0x009A", "fid-secure@home-central-unit-basic"), // FID_DOMUS_CENTRAL_UNIT_BASIC
Map.entry("0x009B", "fid-repeater"), // FID_DOMUS_REPEATER
Map.entry("0x009C", "fid-remote-scene-control"), // FID_DOMUS_SCENE_TRIGGER
Map.entry("0x009D", "fid-window-sensor"), // FID_DOMUSWINDOWCONTACT
Map.entry("0x009E", "fid-movement-detector"), // FID_DOMUSMOVEMENTDETECTOR
Map.entry("0x009F", "fid-external-ir-sensor-curtain"), // FID_DOMUSCURTAINDETECTOR
Map.entry("0x00A0", "fid-smoke-detector"), // FID_DOMUSSMOKEDETECTOR
Map.entry("0x00A1", "fid-flood-detection"), // FID_DOMUSFLOODDETECTOR
Map.entry("0x00A3", "fid-sensor-for-air-conditioning-unit"), // FID_PANEL_SUG_SENSOR
Map.entry("0x00A4", "fid-two-point-controller-for-heating-or-cooling"), // FID_TWO_LEVEL_HEATING_COOLING_ACTUATOR
Map.entry("0x00A5", "fid-slave-thermostat"), // FID_PANEL_THERMOSTAT_CONTROLLER_SLAVE
Map.entry("0x00A6", "fid-wallbox"), // FID_WALLBOX
Map.entry("0x00A7", "fid-wallbox"), // FID_PANEL_WALLBOX
Map.entry("0x00A8", "fid-door-lock-control"), // FID_DOOR_LOCK_CONTROL
Map.entry("0x00AA", "fid-room-temperature-controller-with-fan-speed-level"), // FID_VRV_GATEWAY
Map.entry("0x4800", "fid-scene-trigger"), // FID_SCENE_TRIGGER
Map.entry("0x4A00", "fid-rule-switch"), // FID_RULE_SWITCH
Map.entry("0xE017", "fid-air-quality-sensor-pressure"), // FID_AIRQUALITYSENSOR_PRESSURE
Map.entry("0xE018", "fid-air-quality-sensor-co2"), // FID_AIRQUALITYSENSOR_CO2
Map.entry("0xE019", "fid-air-quality-sensor-co"), // FID_AIRQUALITYSENSOR_CO
Map.entry("0xE01A", "fid-air-quality-sensor-no2"), // FID_AIRQUALITYSENSOR_NO2
Map.entry("0xE01B", "fid-air-quality-sensor-o3"), // FID_AIRQUALITYSENSOR_O3
Map.entry("0xE01C", "fid-air-quality-sensor-pm10"), // FID_AIRQUALITYSENSOR_PM10
Map.entry("0xE01D", "fid-air-quality-sensor-pm25"), // FID_AIRQUALITYSENSOR_PM25
Map.entry("0xE01E", "fid-air-quality-sensor-voc"), // FID_AIRQUALITYSENSOR_VOC
Map.entry("0xB03F", "fid-air-quality-sensor-humidity"), // FID_AIRQUALITYSENSOR_HUMIDITY
Map.entry("0x1090", "fid-movement-detector-flex"), // FID_MOVEMENT_DETECTOR_FLEX
Map.entry("0x1810", "fid-dim-actuator-flex") // FID_SWITCH_ACTUATOR_FLEX
);
@Nullable
public static String getFunctionIdText(String Key) throws FreeAtHomeGeneralException {
String result = MAP_FUNCTION_ID.get(Key);
if (result != null) {
return MAP_FUNCTION_ID.get(Key);
} else {
throw new FreeAtHomeGeneralException(0,
String.format("%s - Key:%s", "FID is not in the translation table", Key));
}
}
}

View File

@ -0,0 +1,73 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.util;
import java.util.Objects;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* The {@link FreeAtHomeGeneralException} is responsible for handling general exceptions in the free@home binding
*
* @author Andras Uhrin - Initial contribution
*
*/
@NonNullByDefault
public class FreeAtHomeGeneralException extends Exception {
private static final long serialVersionUID = -835448863173642860L;
private String errorMessage = "Unknown_Exception";
private int errorCode = 0;
public FreeAtHomeGeneralException(int errorCode, String message) {
super(message);
this.errorMessage = message;
this.errorCode = errorCode;
}
public @Nullable String getMessage() {
return this.errorMessage;
}
public int getErrorCode() {
return this.errorCode;
}
@Override
public String toString() {
return "FreeAtHomeHttpCommunicationException [errorMessage=" + errorMessage + ", errorCode=" + errorCode + "]";
}
@Override
public int hashCode() {
return Objects.hash(errorCode, errorMessage);
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
FreeAtHomeGeneralException other = (FreeAtHomeGeneralException) obj;
return errorCode == other.errorCode && Objects.equals(errorMessage, other.errorMessage);
}
}

View File

@ -0,0 +1,74 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.util;
import java.util.Objects;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* The {@link FreeAtHomeHttpCommunicationException} is responsible for handling the communication exception to the SysAp
* via HTTP link
*
* @author Andras Uhrin - Initial contribution
*
*/
@NonNullByDefault
public class FreeAtHomeHttpCommunicationException extends Exception {
private static final long serialVersionUID = -817364286035448863L;
private String errorMessage = "Unknown_Exception";
private int errorCode;
public FreeAtHomeHttpCommunicationException(int errorCode, String message) {
super(message);
this.errorMessage = message;
this.errorCode = errorCode;
}
public @Nullable String getMessage() {
return this.errorMessage;
}
public int getErrorCode() {
return this.errorCode;
}
@Override
public String toString() {
return "FreeAtHomeHttpCommunicationException [errorMessage=" + errorMessage + ", errorCode=" + errorCode + "]";
}
@Override
public int hashCode() {
return Objects.hash(errorCode, errorMessage);
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
FreeAtHomeHttpCommunicationException other = (FreeAtHomeHttpCommunicationException) obj;
return errorCode == other.errorCode && Objects.equals(errorMessage, other.errorMessage);
}
}

View File

@ -0,0 +1,54 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.util;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link PIdContainerClass} is a helper class for pairing IDs
*
* @author Andras Uhrin - Initial contribution
*
*/
@NonNullByDefault
public class PIdContainerClass {
String valueType;
String category;
int min;
int max;
String label;
String description;
PIdContainerClass(String pValueType, String pCategory, String pMin, String pMax, String pLabel,
String pDescription) {
this.valueType = pValueType;
this.category = pCategory;
if (pMax.isEmpty()) {
this.min = 0;
} else {
this.min = Integer.parseInt(pMin);
}
if (pMax.isEmpty()) {
this.max = 100;
} else {
this.max = Integer.parseInt(pMax);
}
this.label = pLabel;
this.description = pDescription;
}
}

View File

@ -0,0 +1,829 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.util;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link PidTranslationUtils} supporting the translation from pairing IDs into openHAB types
*
* @author Andras Uhrin - Initial contribution
*
*/
@NonNullByDefault
public class PidTranslationUtils {
public static final String PID_VALUETYPE_UNKNOWN = "unknown";
public static final String PID_VALUETYPE_BOOLEAN = "boolean";
public static final String PID_VALUETYPE_DECIMAL = "decimal";
public static final String PID_VALUETYPE_INTEGER = "integer";
public static final String PID_VALUETYPE_STRING = "string";
public static final String PID_VALUETYPE_SHUTTERMOVEMENT = "shuttermovement";
public static final String PID_VALUETYPE_ENUM = "enum";
public static final String CATEGORY_UNDEFINED = "-";
public static final String CATEGORY_BATTERY = "Battery";
public static final String CATEGORY_ALARM = "Alarm";
public static final String CATEGORY_HUMIDITY = "Humidity";
public static final String CATEGORY_TEMPERATURE = "Temperature";
public static final String CATEGORY_MOTION = "Motion";
public static final String CATEGORY_PRESSURE = "Pressure";
public static final String CATEGORY_SMOKE = "Smoke";
public static final String CATEGORY_WATER = "Water";
public static final String CATEGORY_WIND = "Wind";
public static final String CATEGORY_RAIN = "Rain";
public static final String CATEGORY_ENERGY = "Energy";
public static final String CATEGORY_BLINDS = "Blinds";
public static final String CATEGORY_CONTACT = "Contact";
public static final String CATEGORY_SWITCH = "Switch";
private static final Map<String, PIdContainerClass> MAP_PAIRING_ID = Map.ofEntries(
Map.entry("0x0001",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_SWITCH, "0", "1", "pid-switch-on-off",
"pid-switch-on-off-text")),
Map.entry("0x0002",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_SWITCH, "", "", "pid-timed-start-stop",
"pid-timed-start-stop-text")),
Map.entry("0x0003",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_SWITCH, "", "", "pid-force-position",
"pid-force-position-text")),
Map.entry("0x0004",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_SWITCH, "", "", "pid-scene-control",
"pid-scene-control-text")),
Map.entry("0x0006",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_MOTION, "", "",
"pid-movement-under-consideration-of-brightness",
"pid-movement-under-consideration-of-brightness-text")),
Map.entry("0x0007",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_MOTION, "", "", "pid-presence",
"pid-presence-text")),
Map.entry("0x0010",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_UNDEFINED, "", "", "pid-relative-set-value",
"pid-relative-set-value-text")),
Map.entry("0x0011",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_UNDEFINED, "", "", "pid-absolute-set-value",
"pid-absolute-set-value-text")),
Map.entry("0x0012",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_UNDEFINED, "", "", "pid-night",
"pid-night-text")),
Map.entry("0x0013",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_UNDEFINED, "", "", "pid-invalid-string-id",
"pid-invalid-string-id-text")),
Map.entry("0x0015",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-rgb-color",
"pid-rgb-color-text")),
Map.entry("0x0016",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-color-temperature",
"pid-color-temperature-text")),
Map.entry("0x0017",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-hsv",
"pid-hsv-text")),
Map.entry("0x0018",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-hue",
"pid-hue-text")),
Map.entry("0x0019",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-saturation",
"pid-saturation-text")),
Map.entry("0x0020",
new PIdContainerClass(PID_VALUETYPE_SHUTTERMOVEMENT, CATEGORY_BLINDS, "", "", "pid-move-up-down",
"pid-move-up-down-text")),
Map.entry("0x0021",
new PIdContainerClass(PID_VALUETYPE_SHUTTERMOVEMENT, CATEGORY_BLINDS, "", "", "pid-adjust-up-down",
"pid-adjust-up-down-text")),
Map.entry("0x0023",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_BLINDS, "0", "100",
"pid-set-absolute-position-blinds", "pid-set-absolute-position-blinds-text")),
Map.entry("0x0024",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_BLINDS, "0", "100",
"pid-set-absolute-position-slats", "pid-set-absolute-position-slats-text")),
Map.entry("0x0025",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_WIND, "", "", "pid-wind-alarm",
"pid-wind-alarm-text")),
Map.entry("0x0026",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_TEMPERATURE, "", "", "pid-frost-alarm",
"pid-frost-alarm-text")),
Map.entry("0x0027",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_RAIN, "", "", "pid-rain-alarm",
"pid-rain-alarm-text")),
Map.entry("0x0028",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_UNDEFINED, "", "", "pid-force-position-blind",
"pid-force-position-blind-text")),
Map.entry("0x0029",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_UNDEFINED, "", "", "pid-window-door-position",
"pid-window-door-position-text")),
Map.entry("0x0030",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_TEMPERATURE, "", "",
"pid-actuating-value-heating", "pid-actuating-value-heating-text")),
Map.entry("0x0031",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_UNDEFINED, "", "", "pid-fan-level-heating",
"pid-fan-level-heating-text")),
Map.entry("0x0032",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_TEMPERATURE, "", "",
"pid-actuating-value-cooling", "pid-actuating-value-cooling-text")),
Map.entry("0x0033",
new PIdContainerClass(PID_VALUETYPE_DECIMAL, CATEGORY_TEMPERATURE, "7", "30",
"pid-set-value-temperature", "pid-set-value-temperature-text")),
Map.entry("0x0034",
new PIdContainerClass(PID_VALUETYPE_DECIMAL, CATEGORY_TEMPERATURE, "7", "30",
"pid-relative-set-point-temperature", "pid-relative-set-point-temperature-text")),
Map.entry("0x0035",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_UNDEFINED, "", "", "pid-window-door",
"pid-window-door-text")),
Map.entry("0x0036",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_TEMPERATURE, "", "", "pid-status-indication",
"pid-status-indication-text")),
Map.entry("0x0037",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_SWITCH, "", "",
"pid-fan-manual-heating-on-off", "pid-fan-manual-heating-on-off-text")),
Map.entry("0x0038",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_SWITCH, "", "", "pid-controller-on-off",
"pid-controller-on-off-text")),
Map.entry("0x0039",
new PIdContainerClass(PID_VALUETYPE_DECIMAL, CATEGORY_TEMPERATURE, "7", "30",
"pid-relative-set-point-request", "pid-relative-set-point-request-text")),
Map.entry("0x003A",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_SWITCH, "", "", "pid-eco-mode-on-off-request",
"pid-eco-mode-on-off-request-text")),
Map.entry("0x003B",
new PIdContainerClass(PID_VALUETYPE_DECIMAL, CATEGORY_TEMPERATURE, "7", "30",
"pid-comfort-temperature", "pid-comfort-temperature-text")),
Map.entry("0x0040",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_UNDEFINED, "", "", "pid-fan-level-request",
"pid-fan-level-request-text")),
Map.entry("0x0041",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_SWITCH, "", "",
"pid-fan-manual-on-off-request", "pid-fan-manual-on-off-request-text")),
Map.entry("0x0042",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_SWITCH, "", "",
"pid-controller-on-off-request", "pid-controller-on-off-request-text")),
Map.entry("0x0044",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_SWITCH, "", "", "pid-eco-mode-on-off-request",
"pid-eco-mode-on-off-request-text")),
Map.entry("0x0100",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_SWITCH, "", "", "pid-info-on-off",
"pid-info-on-off-text")),
Map.entry("0x0101",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_UNDEFINED, "", "", "pid-force-position-info",
"pid-force-position-info-text")),
Map.entry("0x0105",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_UNDEFINED, "", "", "pid-sysap-infoonoff",
"pid-sysap-infoonoff-text")),
Map.entry("0x0106",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_UNDEFINED, "", "", "pid-sysap-infoforce",
"pid-sysap-infoforce-text")),
Map.entry("0x0110",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_UNDEFINED, "", "",
"pid-info-actual-dimming-value", "pid-info-actual-dimming-value-text")),
Map.entry("0x0111",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_UNDEFINED, "", "", "pid-info-error",
"pid-info-error-text")),
Map.entry("0x0115",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_UNDEFINED, "", "",
"pid-sysap-infocurrentdimmingvalue", "pid-sysap-infocurrentdimmingvalue-text")),
Map.entry("0x0116",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_UNDEFINED, "", "", "pid-sysap-infoerror",
"pid-sysap-infoerror-text")),
Map.entry("0x0118",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-info-color-temperature", "pid-info-color-temperature-text")),
Map.entry("0x011A",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-sysap-info-color-temperature", "pid-sysap-info-color-temperature-text")),
Map.entry("0x011B",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-info-hsv",
"pid-info-hsv-text")),
Map.entry("0x011C",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-sysap-info-hsv",
"pid-sysap-info-hsv-text")),
Map.entry("0x011D",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-info-color-mode",
"pid-info-color-mode-text")),
Map.entry("0x011E",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-sysap-info-color-mode", "pid-sysap-info-color-mode-text")),
Map.entry("0x0120",
new PIdContainerClass(PID_VALUETYPE_SHUTTERMOVEMENT, CATEGORY_BLINDS, "", "",
"pid-info-move-up-down", "pid-info-move-up-down-text")),
Map.entry("0x0121",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_BLINDS, "", "",
"pid-current-absolute-position-blinds-percentage",
"pid-current-absolute-position-blinds-percentage-text")),
Map.entry("0x0122",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-current-absolute-position-slats-percentage",
"pid-current-absolute-position-slats-percentage-text")),
Map.entry("0x0125",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-sysap-infomoveupdown",
"pid-sysap-infomoveupdown-text")),
Map.entry("0x0126",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-sysap-infocurrentabsoluteblindspercentage",
"pid-sysap-infocurrentabsoluteblindspercentage-text")),
Map.entry("0x0127",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-sysap-infocurrentabsoluteslatspercentage",
"pid-sysap-infocurrentabsoluteslatspercentage-text")),
Map.entry("0x0130",
new PIdContainerClass(PID_VALUETYPE_DECIMAL, CATEGORY_TEMPERATURE, "7", "30",
"pid-measured-temperature", "pid-measured-temperature-text")),
Map.entry("0x0131",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-info-value-heating",
"pid-info-value-heating-text")),
Map.entry("0x0132",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_TEMPERATURE, "", "", "pid-info-value-cooling",
"pid-info-value-cooling-text")),
Map.entry("0x0135",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_TEMPERATURE, "", "",
"pid-switchover-heating-cooling", "pid-switchover-heating-cooling-text")),
Map.entry("0x0136",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-actuating-fan-stage-heating", "pid-actuating-fan-stage-heating-text")),
Map.entry("0x0140",
new PIdContainerClass(PID_VALUETYPE_DECIMAL, CATEGORY_TEMPERATURE, "7", "30",
"pid-absolute-setpoint-temperature", "pid-absolute-setpoint-temperature-text")),
Map.entry("0x0141",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-additional-heating-value-info", "pid-additional-heating-value-info-text")),
Map.entry("0x0142",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_TEMPERATURE, "", "",
"pid-additional-cooling-value-info", "pid-additional-cooling-value-info-text")),
Map.entry("0x0143",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-control-value-additional-heating", "pid-control-value-additional-heating-text")),
Map.entry("0x0144",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_TEMPERATURE, "", "",
"pid-control-value-additional-cooling", "pid-control-value-additional-cooling-text")),
Map.entry("0x0145",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-info-actuating-fan-stage-heating", "pid-info-actuating-fan-stage-heating-text")),
Map.entry("0x0146",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-info-actuating-fan-manual-on-off-heating",
"pid-info-actuating-fan-manual-on-off-heating-text")),
Map.entry("0x0147",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_TEMPERATURE, "", "",
"pid-actuating-fan-stage-cooling", "pid-actuating-fan-stage-cooling-text")),
Map.entry("0x0149",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_TEMPERATURE, "", "",
"pid-info-fan-stage-cooling", "pid-info-fan-stage-cooling-text")),
Map.entry("0x014A",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_TEMPERATURE, "", "",
"pid-info-fan-manual-on-off-cooling", "pid-info-fan-manual-on-off-cooling-text")),
Map.entry("0x014B",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_TEMPERATURE, "", "", "pid-heating-active",
"pid-heating-active-text")),
Map.entry("0x014C",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_TEMPERATURE, "", "", "pid-cooling-active",
"pid-cooling-active-text")),
Map.entry("0x014D",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_TEMPERATURE, "", "", "pid-heating-demand",
"pid-heating-demand-text")),
Map.entry("0x014E",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_TEMPERATURE, "", "", "pid-cooling-demand",
"pid-cooling-demand-text")),
Map.entry("0x014F",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_TEMPERATURE, "", "",
"pid-heating-demand-feedback-signal", "pid-heating-demand-feedback-signal-text")),
Map.entry("0x0150",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_TEMPERATURE, "", "",
"pid-cooling-demand-feedback-signal", "pid-cooling-demand-feedback-signal-text")),
Map.entry("0x0151",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_HUMIDITY, "", "", "pid-humidity",
"pid-humidity-text")),
Map.entry("0x0152",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-aux-on-off-request",
"pid-aux-on-off-request-text")),
Map.entry("0x0153",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-aux-on-off-response",
"pid-aux-on-off-response-text")),
Map.entry("0x0154",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_SWITCH, "", "", "pid-heating-on-off-request",
"pid-heating-on-off-request-text")),
Map.entry("0x0155",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_SWITCH, "", "", "pid-cooling-on-off-request",
"pid-cooling-on-off-request-text")),
Map.entry("0x0156",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-operation-mode",
"pid-operation-mode-text")),
Map.entry("0x0157",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-swing-h-v",
"pid-swing-h-v-text")),
Map.entry("0x0158",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-supported-features",
"pid-supported-features-text")),
Map.entry("0x0159",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-extended-status-indication", "pid-extended-status-indication-text")),
Map.entry("0x015A",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-extended-status-indication", "pid-extended-status-indication-text")),
Map.entry("0x015B",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-aux-heating-on-off-request", "pid-aux-heating-on-off-request-text")),
Map.entry("0x015C",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-emergency-heating-on-off-request", "pid-emergency-heating-on-off-request-text")),
Map.entry("0x0160",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-relative-fan-speed-control", "pid-relative-fan-speed-control-text")),
Map.entry("0x0161",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-absolute-fan-speed-control", "pid-absolute-fan-speed-control-text")),
Map.entry("0x0162",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-info-absolute-fan-speed", "pid-info-absolute-fan-speed-text")),
Map.entry("0x0163",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-sysap-infoactualfanspeed", "pid-sysap-infoactualfanspeed-text")),
Map.entry("0x01A0",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-notification-flags",
"pid-notification-flags-text")),
Map.entry("0x0280",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-power-rc",
"pid-power-rc-text")),
Map.entry("0x0281",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-power-rh",
"pid-power-rh-text")),
Map.entry("0x0282",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-proximity-status",
"pid-proximity-status-text")),
Map.entry("0x0290",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-brightness-sensor",
"pid-brightness-sensor-text")),
Map.entry("0x0291",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-last-touch",
"pid-last-touch-text")),
Map.entry("0x0292",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-led-backlighting-night-mode", "pid-led-backlighting-night-mode-text")),
Map.entry("0x02C0",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-locator-beep",
"pid-locator-beep-text")),
Map.entry("0x02C1",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-switch-test-alarm",
"pid-switch-test-alarm-text")),
Map.entry("0x02C3",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-fire-alarm-active",
"pid-fire-alarm-active-text")),
Map.entry("0x0400",
new PIdContainerClass(PID_VALUETYPE_DECIMAL, CATEGORY_TEMPERATURE, "", "",
"pid-outside-temperature", "pid-outside-temperature-text")),
Map.entry("0x0401",
new PIdContainerClass(PID_VALUETYPE_DECIMAL, CATEGORY_WIND, "", "", "pid-wind-force",
"pid-wind-force-text")),
Map.entry("0x0402",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_UNDEFINED, "", "", "pid-brightness-alarm",
"pid-brightness-alarm-text")),
Map.entry("0x0403",
new PIdContainerClass(PID_VALUETYPE_DECIMAL, CATEGORY_UNDEFINED, "", "", "pid-lux-value",
"pid-lux-value-text")),
Map.entry("0x0404",
new PIdContainerClass(PID_VALUETYPE_DECIMAL, CATEGORY_WIND, "", "", "pid-wind-speed",
"pid-wind-speed-text")),
Map.entry("0x0405",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_RAIN, "", "", "pid-rain-detection",
"pid-rain-detection-text")),
Map.entry("0x0406",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_RAIN, "", "", "pid-rain-sensor-frequency",
"pid-rain-sensor-frequency-text")),
Map.entry("0x0440",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-play",
"pid-play-text")),
Map.entry("0x0441",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-pause",
"pid-pause-text")),
Map.entry("0x0442",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-next",
"pid-next-text")),
Map.entry("0x0443",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-previous",
"pid-previous-text")),
Map.entry("0x0444",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-play-mode",
"pid-play-mode-text")),
Map.entry("0x0445",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-mute",
"pid-mute-text")),
Map.entry("0x0446",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-relative-volume-control", "pid-relative-volume-control-text")),
Map.entry("0x0447",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-absolute-volume-control", "pid-absolute-volume-control-text")),
Map.entry("0x0448",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-group-membership",
"pid-group-membership-text")),
Map.entry("0x0449",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-play-favorite",
"pid-play-favorite-text")),
Map.entry("0x044A",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-play-next-favorite",
"pid-play-next-favorite-text")),
Map.entry("0x0460",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-playback-status",
"pid-playback-status-text")),
Map.entry("0x0461",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-current-item-metadata-info", "pid-current-item-metadata-info-text")),
Map.entry("0x0462",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-info-mute",
"pid-info-mute-text")),
Map.entry("0x0463",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-info-actual-volume",
"pid-info-actual-volume-text")),
Map.entry("0x0464",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-allowed-playback-actions", "pid-allowed-playback-actions-text")),
Map.entry("0x0465",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-info-group-membership", "pid-info-group-membership-text")),
Map.entry("0x0466",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-info-playing-favorite", "pid-info-playing-favorite-text")),
Map.entry("0x0467",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-absolute-group-volume-control", "pid-absolute-group-volume-control-text")),
Map.entry("0x0468",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-info-absolute-group-volume", "pid-info-absolute-group-volume-text")),
Map.entry("0x0469",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-media-source",
"pid-media-source-text")),
Map.entry("0x04A0",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-solar-power-production", "pid-solar-power-production-text")),
Map.entry("0x04A1",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-inverter-output-power", "pid-inverter-output-power-text")),
Map.entry("0x04A2",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-solar-energy-(today)",
"pid-solar-energy-(today)-text")),
Map.entry("0x04A3",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-injected-energy-(today)", "pid-injected-energy-(today)-text")),
Map.entry("0x04A4",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-purchased-energy-(today)", "pid-purchased-energy-(today)-text")),
Map.entry("0x04A5",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-inverter-alarm",
"pid-inverter-alarm-text")),
Map.entry("0x04A6",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-self-consumption",
"pid-self-consumption-text")),
Map.entry("0x04A7",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-self-sufficiency",
"pid-self-sufficiency-text")),
Map.entry("0x04A8",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-home-power-consumption", "pid-home-power-consumption-text")),
Map.entry("0x04A9",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-power-to-grid",
"pid-power-to-grid-text")),
Map.entry("0x04AA",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-consumed-energy-(today)", "pid-consumed-energy-(today)-text")),
Map.entry("0x04AB",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-meter-alarm",
"pid-meter-alarm-text")),
Map.entry("0x04AC",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-battery-level",
"pid-battery-level-text")),
Map.entry("0x04AD",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-battery-power",
"pid-battery-power-text")),
Map.entry("0x04B0",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-boost",
"pid-boost-text")),
Map.entry("0x04B1",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-stop-charging-reuqest", "pid-stop-charging-reuqest-text")),
Map.entry("0x04B2",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-enable-charging-reuqest", "pid-enable-charging-reuqest-text")),
Map.entry("0x04B3",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-info-boost",
"pid-info-boost-text")),
Map.entry("0x04B4",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-info-wallbox-status",
"pid-info-wallbox-status-text")),
Map.entry("0x04B5",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-info-charging",
"pid-info-charging-text")),
Map.entry("0x04B6",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-info-charging-enabled", "pid-info-charging-enabled-text")),
Map.entry("0x04B7",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-info-installed-power",
"pid-info-installed-power-text")),
Map.entry("0x04B8",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-info-transmitted-energy", "pid-info-transmitted-energy-text")),
Map.entry("0x04B9",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-info-car-range",
"pid-info-car-range-text")),
Map.entry("0x04BA",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-info-charging-duration", "pid-info-charging-duration-text")),
Map.entry("0x04BB",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-info-current-limit",
"pid-info-current-limit-text")),
Map.entry("0x04BC",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-info-current-limit-for-group", "pid-info-current-limit-for-group-text")),
Map.entry("0x04BD",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-album-cover-url",
"pid-album-cover-url-text")),
Map.entry("0x0501",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-secure@home-central-unit", "pid-secure@home-central-unit-text")),
Map.entry("0x0502",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-domusdisarmcounter",
"pid-domusdisarmcounter-text")),
Map.entry("0x0504",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-intrusion-alarm",
"pid-intrusion-alarm-text")),
Map.entry("0x0505",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-safety-alarm",
"pid-safety-alarm-text")),
Map.entry("0x0507",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-infoconfigurationstatus", "pid-infoconfigurationstatus-text")),
Map.entry("0x0508",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-enable-configuration",
"pid-enable-configuration-text")),
Map.entry("0x0509",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-disarming-led",
"pid-disarming-led-text")),
Map.entry("0x050A",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-aes-key",
"pid-aes-key-text")),
Map.entry("0x050B",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-zone-status",
"pid-zone-status-text")),
Map.entry("0x050E",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-time",
"pid-time-text")),
Map.entry("0x0600",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-start-stop",
"pid-start-stop-text")),
Map.entry("0x0601",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-pause-resume",
"pid-pause-resume-text")),
Map.entry("0x0602",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-select-program",
"pid-select-program-text")),
Map.entry("0x0603",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-delayed-start-time",
"pid-delayed-start-time-text")),
Map.entry("0x0604",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-info-status",
"pid-info-status-text")),
Map.entry("0x0605",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-info-remote-start-enabled", "pid-info-remote-start-enabled-text")),
Map.entry("0x0606",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-info-program",
"pid-info-program-text")),
Map.entry("0x0607",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-info-finish-time",
"pid-info-finish-time-text")),
Map.entry("0x0608",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-info-delayed-start",
"pid-info-delayed-start-text")),
Map.entry("0x0609",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-info-door",
"pid-info-door-text")),
Map.entry("0x060A",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-info-door-alarm",
"pid-info-door-alarm-text")),
Map.entry("0x060B",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-switch-supercool",
"pid-switch-supercool-text")),
Map.entry("0x060C",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-switch-superfreeze",
"pid-switch-superfreeze-text")),
Map.entry("0x060D",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-info-switch-supercool", "pid-info-switch-supercool-text")),
Map.entry("0x060E",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-info-switch-superfreeze", "pid-info-switch-superfreeze-text")),
Map.entry("0x060F",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-measured-temperature",
"pid-measured-temperature-text")),
Map.entry("0x0610",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-measured-temperature",
"pid-measured-temperature-text")),
Map.entry("0x0611",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-set-value-temperature", "pid-set-value-temperature-text")),
Map.entry("0x0612",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-set-value-temperature", "pid-set-value-temperature-text")),
Map.entry("0x0613",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-change-operation",
"pid-change-operation-text")),
Map.entry("0x0614",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-detailed-status-info",
"pid-detailed-status-info-text")),
Map.entry("0x0615",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-info-remaining-time",
"pid-info-remaining-time-text")),
Map.entry("0x0616",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-time-of-last-status-change", "pid-time-of-last-status-change-text")),
Map.entry("0x0618",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-lock-unlock-door-command", "pid-lock-unlock-door-command-text")),
Map.entry("0x0619",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-info-locked-unlocked",
"pid-info-locked-unlocked-text")),
Map.entry("0xF001",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-time",
"pid-time-text")),
Map.entry("0xF002",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-date",
"pid-date-text")),
Map.entry("0xF003",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-notification",
"pid-notification-text")),
Map.entry("0xF101",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_SWITCH, "", "", "pid-switch-entity-on-off",
"pid-switch-entity-on-off-text")),
Map.entry("0xF102",
new PIdContainerClass(PID_VALUETYPE_BOOLEAN, CATEGORY_SWITCH, "", "",
"pid-info-switch-entity-on-off", "pid-info-switch-entity-on-off-text")),
Map.entry("0xF104",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-consistency-tag",
"pid-consistency-tag-text")),
Map.entry("0xF105",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-battery-status",
"pid-battery-status-text")),
Map.entry("0xF106",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-stay-awake",
"pid-stay-awake-text")),
Map.entry("0xF107",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-proxy-switch",
"pid-proxy-switch-text")),
Map.entry("0xF108",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-proxy1",
"pid-proxy1-text")),
Map.entry("0xF109",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-proxy2",
"pid-proxy2-text")),
Map.entry("0xF10A",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-proxy4",
"pid-proxy4-text")),
Map.entry("0xF10B",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-cyclic-sleep-time",
"pid-cyclic-sleep-time-text")),
Map.entry("0xF10C",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-presence",
"pid-presence-text")),
Map.entry("0xF10D",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-measured-temperature-1", "pid-measured-temperature-1-text")),
Map.entry("0xF10E",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-standby-statistics",
"pid-standby-statistics-text")),
Map.entry("0xF10F",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-heartbeat-delay",
"pid-heartbeat-delay-text")),
Map.entry("0xF110",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "", "pid-info-heartbeat-delay",
"pid-info-heartbeat-delay-text")),
Map.entry("0xFF01",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-measured-temperature-1", "pid-measured-temperature-1-text")),
Map.entry("0xFF02",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-measured-temperature-2", "pid-measured-temperature-2-text")),
Map.entry("0xFF03",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-measured-temperature-3", "pid-measured-temperature-3-text")),
Map.entry("0xFF04",
new PIdContainerClass(PID_VALUETYPE_UNKNOWN, CATEGORY_UNDEFINED, "", "",
"pid-measured-temperature-4", "pid-measured-temperature-4-text")),
Map.entry("0x061A",
new PIdContainerClass(PID_VALUETYPE_DECIMAL, CATEGORY_PRESSURE, "", "",
"pid-air-quality-pressure-value", "pid-air-quality-pressure-value-text")),
Map.entry("0x061B",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_UNDEFINED, "", "",
"pid-air-quality-co2-value", "pid-air-quality-co2-value-text")),
Map.entry("0x061C",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_UNDEFINED, "", "", "pid-air-quality-co-value",
"pid-air-quality-co-value-text")),
Map.entry("0x061D",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_UNDEFINED, "", "",
"pid-air-quality-no2-value", "pid-air-quality-no2-value-text")),
Map.entry("0x061E",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_UNDEFINED, "", "", "pid-air-quality-o3-value",
"pid-air-quality-o3-value-text")),
Map.entry("0x061F",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_UNDEFINED, "", "",
"pid-air-quality-pm10-value", "pid-air-quality-pm10-value-text")),
Map.entry("0x0620",
new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_UNDEFINED, "", "",
"pid-air-quality-pm25-value", "pid-air-quality-pm25-value-text")),
Map.entry("0x0621", new PIdContainerClass(PID_VALUETYPE_INTEGER, CATEGORY_UNDEFINED, "", "",
"pid-air-quality-voc-value", "pid-air-quality-voc-value-text")));
public static String getShortTextForPairingId(String Key) throws FreeAtHomeGeneralException {
PIdContainerClass desc = MAP_PAIRING_ID.get(Key);
if (desc == null) {
throw new FreeAtHomeGeneralException(0,
String.format("%s - Key:%s", "PID is not in the translation table", Key));
}
return desc.label;
}
public static String getDescriptionTextForPairingId(String Key) throws FreeAtHomeGeneralException {
PIdContainerClass desc = MAP_PAIRING_ID.get(Key);
if (desc == null) {
throw new FreeAtHomeGeneralException(0,
String.format("%s - Key:%s", "PID is not in the translation table", Key));
}
return desc.description;
}
public static String getValueTypeForPairingId(String Key) throws FreeAtHomeGeneralException {
PIdContainerClass desc = MAP_PAIRING_ID.get(Key);
if (desc == null) {
throw new FreeAtHomeGeneralException(0,
String.format("%s - Key:%s", "PID is not in the translation table", Key));
}
return desc.valueType;
}
public static String getItemTypeForPairingId(String Key) throws FreeAtHomeGeneralException {
PIdContainerClass desc = MAP_PAIRING_ID.get(Key);
if (desc == null) {
throw new FreeAtHomeGeneralException(0,
String.format("%s - Key:%s", "PID is not in the translation table", Key));
}
return desc.category;
}
public static String getCategoryForPairingId(String Key) throws FreeAtHomeGeneralException {
PIdContainerClass desc = MAP_PAIRING_ID.get(Key);
if (desc == null) {
throw new FreeAtHomeGeneralException(0,
String.format("%s - Key:%s", "PID is not in the translation table", Key));
}
return desc.category;
}
public static String getPatternForPairingId(String Key) throws FreeAtHomeGeneralException {
PIdContainerClass desc = MAP_PAIRING_ID.get(Key);
if (desc == null) {
throw new FreeAtHomeGeneralException(0,
String.format("%s - Key:%s", "PID is not in the translation table", Key));
}
return desc.category;
}
public static int getMax(String Key) throws FreeAtHomeGeneralException {
PIdContainerClass desc = MAP_PAIRING_ID.get(Key);
if (desc == null) {
throw new FreeAtHomeGeneralException(0,
String.format("%s - Key:%s", "PID is not in the translation table", Key));
}
return desc.max;
}
public static int getMin(String Key) throws FreeAtHomeGeneralException {
PIdContainerClass desc = MAP_PAIRING_ID.get(Key);
if (desc == null) {
throw new FreeAtHomeGeneralException(0,
String.format("%s - Key:%s", "PID is not in the translation table", Key));
}
return desc.min;
}
}

View File

@ -0,0 +1,44 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.util;
import static org.openhab.binding.freeathomesystem.internal.FreeAtHomeSystemBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.type.ChannelTypeUID;
/**
*
* @author Andras Uhrin - Initial contribution
*
*/
@NonNullByDefault
public class UidUtils {
public static ChannelTypeUID generateChannelTypeUID(String valueType, boolean isReadOnly) {
String channelNameString;
if (isReadOnly) {
channelNameString = valueType + "-ro";
} else {
channelNameString = valueType;
}
return new ChannelTypeUID(BINDING_ID, channelNameString);
}
public static ThingTypeUID generateThingUID() {
return new ThingTypeUID(BINDING_ID, DEVICE_TYPE_ID);
}
}

View File

@ -0,0 +1,60 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.valuestateconverter;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.types.State;
/**
* The {@link BinaryValueStateConverter} is a value converter for integer values with a specific mask
*
* @author Andras Uhrin - Initial contribution
*
*/
@NonNullByDefault
public class BinaryValueStateConverter implements ValueStateConverter {
private int maskValue;
public BinaryValueStateConverter(int mask) {
maskValue = mask;
}
@Override
public State convertToState(String value) {
int intValue = Integer.decode(value);
int result;
result = intValue & maskValue;
if (maskValue == result) {
return OnOffType.ON;
} else {
return OnOffType.OFF;
}
}
@Override
public String convertToValueString(State state) {
if (state.equals(OnOffType.ON)) {
return "1";
}
if (state.equals(OnOffType.OFF)) {
return "0";
}
return "";
}
}

View File

@ -0,0 +1,45 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.valuestateconverter;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.types.State;
/**
* The {@link DecimalValueStateConverter} is a value converter for boolean values
*
* @author Andras Uhrin - Initial contribution
*
*/
@NonNullByDefault
public class BooleanValueStateConverter implements ValueStateConverter {
@Override
public State convertToState(String value) {
return OnOffType.from(value);
}
@Override
public String convertToValueString(State state) {
if (state.equals(OnOffType.ON)) {
return "1";
}
if (state.equals(OnOffType.OFF)) {
return "0";
}
return "";
}
}

View File

@ -0,0 +1,37 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.valuestateconverter;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.State;
/**
* The {@link DecimalValueStateConverter} is a value converter for decimal values
*
* @author Andras Uhrin - Initial contribution
*
*/
@NonNullByDefault
public class DecimalValueStateConverter implements ValueStateConverter {
@Override
public State convertToState(String value) {
return new DecimalType(value);
}
@Override
public String convertToValueString(State state) {
return ((DecimalType) state).toString();
}
}

View File

@ -0,0 +1,79 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.valuestateconverter;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.library.types.StopMoveType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.library.types.UpDownType;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
/**
* The {@link ShuttercontrolValueStateConverter} is a value converter for shutter movement
*
* @author Andras Uhrin - Initial contribution
*
*/
@NonNullByDefault
public class ShuttercontrolValueStateConverter implements ValueStateConverter {
@Override
public State convertToState(String value) {
State ret = UpDownType.DOWN;
switch (value) {
default:
case "0":
ret = new StringType("STOP");
break;
case "2":
ret = UpDownType.UP;
break;
case "3":
ret = UpDownType.DOWN;
break;
}
return ret;
}
@Override
public String convertToValueString(State state) {
String valueString = "0";
String stateString = "STOP";
if (state instanceof UpDownType) {
stateString = ((UpDownType) state).toString();
}
if (((Command) state) instanceof StopMoveType) {
stateString = "STOP";
}
switch (stateString) {
default:
case "STOP":
valueString = "0";
break;
case "UP":
valueString = "0";
break;
case "DOWN":
valueString = "1";
break;
}
return valueString;
}
}

View File

@ -0,0 +1,29 @@
/**
* Copyright (c) 2010-2024 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.freeathomesystem.internal.valuestateconverter;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.types.State;
/**
* The {@link ValueStateConverter} base class for the value state converters
*
* @author Andras Uhrin - Initial contribution
*
*/
@NonNullByDefault
public interface ValueStateConverter {
public State convertToState(String value);
public String convertToValueString(State state);
}

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<addon:addon id="freeathomesystem" 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>FreeAtHomeSystem Binding</name>
<description>This is the binding for free@home system.</description>
<connection>local</connection>
</addon:addon>

View File

@ -0,0 +1,652 @@
# add-on
addon.freeathomesystem.name = FreeAtHomeSystem Binding
addon.freeathomesystem.description = This is the binding for free@home system.
# thing types
thing-type.freeathomesystem.device.label = free@home Device
thing-type.freeathomesystem.device.description = This represents the generic free@home device
thing-type.freeathomesystem.gateway.label = free@home Gateway
thing-type.freeathomesystem.gateway.description = This gateway represents the free@home Gateway
# thing types config
thing-type.config.freeathomesystem.device.deviceId.label = Device Id
thing-type.config.freeathomesystem.device.deviceId.description = This is the unique id of the free@home device (Please do not modify after the Thing is generated)
thing-type.config.freeathomesystem.gateway.group.identification.label = SysAP Setting
thing-type.config.freeathomesystem.gateway.group.identification.description = SysAP network address and user settings
thing-type.config.freeathomesystem.gateway.ipAddress.label = Sysap IP Address
thing-type.config.freeathomesystem.gateway.ipAddress.description = IP Address of the Busch-Jaeger Gateway
thing-type.config.freeathomesystem.gateway.password.label = Password
thing-type.config.freeathomesystem.gateway.password.description = Password for gateway
thing-type.config.freeathomesystem.gateway.username.label = User Name
thing-type.config.freeathomesystem.gateway.username.description = The login name
# localized error text
comm-error.not-able-open-httpconnection = Cannot open http connection, wrong password
comm-error.http-wrongpass-or-ip = Cannot open http connection, wrong password or IP address
comm-error.not-able-open-websocketconnection = Cannot open websocket connection
comm-error.general-websocket-issue = General issue in websocket connection
comm-error.websocket-keep-alive-error = Websocket keep alive error
comm-error.wrong-credentials = Wrong credentials for SysAP
comm-error.error-in-sysap-com = Error in SysAp communication
conf-error.general-binding-error = General binding error!
conf-error.datapointgroup-invalid = Datapoint group is not valid!
conf-error.inputdatapoint-invalid = Input Datapoint is not valid!
conf-error.invalid-deviceconfig = Invalid device configuration!
conf-error.invalid-bridge = Invalid bridge!
conf-error.bridge-not-configured = Bridge not configured!
conf-error.ip-address-missing = IP address is not specified!
conf-error.username-missing = User name is not specified!
conf-error.password-missing = Password is not specified!
conf-error.device-desc-null = Device description is NULL!
gen-error.no-bridge-avail = No bridge available!
# localized info text for function id
fid-dimming-sensor = Dimming sensor
fid-blind-sensor = Blind sensor
fid-stairwell-light-sensor = Stairwell light sensor
fid-force-on/off-sensor = Force On/Off sensor
fid-scene-sensor = Scene sensor
fid-switch-actuator = Switch actuator
fid-blind-actuator = Blind actuator
fid-room-temperature-controller-with-fan-speed-level = Room temperature controller with fan speed level
fid-room-temperature-controller-extension-unit = Room temperature controller extension unit
fid-wind-alarm = Wind Alarm
fid-frost-alarm = Frost Alarm
fid-rain-alarm = Rain Alarm
fid-window-sensor = Window sensor
fid-movement-detector = Movement Detector
fid-dim-actuator = Dim actuator
fid-radiator = Radiator
fid-underfloor-heating = Underfloor heating
fid-fan-coil = Fan Coil
fid-two-level-controller = Two-level controller
fid-door-opener = Door opener
fid-proxy = Proxy
fid-door-map.entry-system-call-level-actuator = Door Map.entry System Call Level Actuator
fid-door-map.entry-system-call-level-sensor = Door Map.entry System Call Level Sensor
fid-door-call = Door call
fid-automatic-door-opener = Automatic door opener
fid-corridor-light = Corridor light
fid-room-temperature-controller = Room temperature controller
fid-cooling-mode = Cooling mode
fid-heating-mode = Heating mode
fid-force-position-blind = Force-position blind
fid-auto.-heating/cooling-mode = Auto. heating/cooling mode
fid-switchover-heating/cooling = Switchover heating/cooling
fid-device-settings = Device settings
fid-dim-actuator = Dim actuator
fid-dim-actuator = Dim actuator
fid-control-element = Control element
fid-dimming-sensor = Dimming sensor
fid-blind-sensor = Blind sensor
fid-stairwell-light-sensor = Stairwell light sensor
fid-force-on/off-sensor = Force On/Off sensor
fid-force-position-blind = Force-position blind
fid-scene-sensor = Scene sensor
fid-room-temperature-controller-extension-unit = Room temperature controller extension unit
fid-fan-coil-sensor = Fan coil sensor
fid-rgb-+-warm-white/cold-white-sensor = RGB + warm white/cold white sensor
fid-rgb-sensor = RGB sensor
fid-warm-white/cold-white-sensor = Warm white/cold white sensor
fid-add.-stage-for-heating-mode = Add. stage for heating mode
fid-radiator-thermostate = Radiator thermostate
fid-room-temperature-controller-extension-unit = Room temperature controller extension unit
fid-brightness-sensor = Brightness sensor
fid-rain-sensor = Rain sensor
fid-temperature-sensor = Temperature sensor
fid-wind-sensor = Wind sensor
fid-trigger = Trigger
fid-heating-mode = Heating mode
fid-cooling-mode = Cooling mode
fid-auto.-heating/cooling-mode = Auto. heating/cooling mode
fid-two-valves-for-heating-and-cooling = Two valves for heating and cooling
fid-window/door = Window/Door
fid-abc = ABC
fid-abd = ABD
fid-acd = ACD
fid-timer-program-switch-sensor = Timer program switch sensor
fid-zone = Zone
fid-central-heating-actuator = Central heating actuator
fid-central-cooling-actuator = Central cooling actuator
fid-housekeeping = Housekeeping
fid-media-player = Media Player
fid-panel-room-temperature-controller-slave-for-battery-device = Panel Room Temperature Controller Slave For Battery Device
fid-media-player-sensor = Media Player Sensor
fid-roller-blind-actuator = Roller blind actuator
fid-attic-window-actuator = Attic window actuator
fid-awning-actuator = Awning actuator
fid-windowdoor-position-sensor = WindowDoor Position Sensor
fid-window/door-position = Window/Door position
fid-media-playback-control-sensor = Media playback control sensor
fid-media-volume-sensor = Media volume sensor
fid-dishwasher = Dishwasher
fid-laundry = Laundry
fid-dryer = Dryer
fid-oven = Oven
fid-fridge = Fridge
fid-freezer = Freezer
fid-hood = Hood
fid-coffee-machine = Coffee machine
fid-fridge/freezer = Fridge/Freezer
fid-timer-program-switch-sensor = Timer program switch sensor
fid-ceiling-fan-actuator = Ceiling fan actuator
fid-ceiling-fan-sensor = Ceiling fan sensor
fid-room-temperature-controller-with-fan-speed-level = Room temperature controller with fan speed level
fid-zone = Zone
fid-safety = Safety
fid-external-ir-sensor-bx80 = External IR Sensor BX80
fid-external-ir-sensor-vxi = External IR Sensor VXI
fid-external-ir-sensor-mini = External IR Sensor Mini
fid-external-ir-sensor-high-altitude = External IR Sensor High Altitude
fid-external-ir-sensor-curtain = External IR Sensor Curtain
fid-smoke-detector = Smoke Detector
fid-carbon-monoxide-sensor = Carbon Monoxide Sensor
fid-methane-detector = Methane Detector
fid-gas-sensor-lpg = Gas Sensor LPG
fid-flood-detection = Flood Detection
fid-secure@home-central-unit = secure@home Central Unit
fid-thermostat = Thermostat
fid-secure@home-zone-sensor = secure@home Zone Sensor
fid-slave-thermostat = Slave thermostat
fid-secure@home-integration-logic = secure@home Integration Logic
fid-add.-stage-for-cooling-mode = Add. stage for cooling mode
fid-two-level-heating-actuator = Two Level Heating Actuator
fid-two-level-cooling-actuator = Two Level Cooling Actuator
fid-zone = Zone
fid-volume-up = Volume up
fid-volume-down = Volume down
fid-play/pause = Play/pause
fid-next-favorite = Next favorite
fid-next-song = Next song
fid-previous-song = Previous song
fid-home-appliance-sensor = Home appliance sensor
fid-heat-sensor = Heat sensor
fid-zone-switching = Zone switching
fid-button-function = Button function
fid-advanced-configuration = Advanced configuration
fid-secure@home-central-unit-basic = secure@home Central Unit Basic
fid-repeater = Repeater
fid-remote-scene-control = Remote scene control
fid-window-sensor = Window sensor
fid-movement-detector = Movement Detector
fid-external-ir-sensor-curtain = External IR Sensor Curtain
fid-smoke-detector = Smoke Detector
fid-flood-detection = Flood Detection
fid-sensor-for-air-conditioning-unit = Sensor for air-conditioning unit
fid-two-point-controller-for-heating-or-cooling = Two-point controller for heating or cooling
fid-slave-thermostat = Slave thermostat
fid-wallbox = Wallbox
fid-door-lock-control = Door lock control
fid-room-temperature-controller-with-fan-speed-level = Room temperature controller with fan speed level
fid-scene-trigger = Scene trigger
fid-rule-switch = Rule Switch
fid-air-quality-sensor-pressure = Air quality sensor Pressure
fid-air-quality-sensor-co2 = Air quality sensor CO2
fid-air-quality-sensor-co = Air quality sensor CO
fid-air-quality-sensor-no2 = Air quality sensor NO2
fid-air-quality-sensor-o3 = Air quality sensor O3
fid-air-quality-sensor-pm10 = Air quality sensor PM10
fid-air-quality-sensor-pm25 = Air quality sensor PM25
fid-air-quality-sensor-voc = Air quality sensor VOC
fid-air-quality-sensor-humidity = Air quality sensor humidity
fid-movement-detector-fle = Movement detector (flex)
fid-dim-actuator-flex = Dim actuator (flex)
# localized info text for pairing id
pid-switch-on-off = Switch
pid-timed-start-stop = Timed Start/Stop
pid-force-position = Force-position
pid-scene-control = Scene Control
pid-movement-under-consideration-of-brightness = Movement under consideration of brightness
pid-presence = Presence
pid-relative-set-value = Relative Set Value
pid-absolute-set-value = Set Value
pid-night = Night
pid-invalid-string-id = invalid string id
pid-rgb-color = RGB color
pid-color-temperature = Color Temperature
pid-hsv = HSV
pid-hue = HUE
pid-saturation = Saturation
pid-move-up-down = Move Up/Down
pid-adjust-up-down = Adjust Up/Down
pid-set-absolute-position-blinds = Blinds Position
pid-set-absolute-position-slats = Slats Position
pid-wind-alarm = Wind Alarm
pid-frost-alarm = Frost Alarm
pid-rain-alarm = Rain Alarm
pid-force-position-blind = Force-position blind
pid-window-door-position = Window/Door position
pid-actuating-value-heating = Actuating Value Heating
pid-fan-level-heating = Fan Level Heating
pid-actuating-value-cooling = Actuating Value Cooling
pid-set-value-temperature = Set Value Temperature
pid-relative-set-point-temperature = Relative Setpoint Temperature
pid-window-door = Window/Door
pid-status-indication = Status
pid-fan-manual-heating-on-off = Fan Manual Heating
pid-controller-on-off = Controller
pid-relative-set-point-request = Relative Setpoint Request
pid-eco-mode-on-off-request = Eco mode
pid-comfort-temperature = Comfort Temperature
pid-fan-level-request = Fan Level
pid-fan-manual-on-off-request = Fan Switch
pid-controller-on-off-request = Controller Switch
pid-eco-mode-on-off-request = Eco mode
pid-info-on-off = Status info
pid-force-position-info = Force-position
pid-sysap-infoonoff = SysAP-InfoOnOff
pid-sysap-infoforce = SysAP-InfoForce
pid-info-actual-dimming-value = Dimming Value
pid-info-error = Error INfo
pid-sysap-infocurrentdimmingvalue = SysAP-InfoCurrentDimmingValue
pid-sysap-infoerror = SysAP-InfoError
pid-info-color-temperature = Color Temperature
pid-sysap-info-color-temperature = SysAP-Info Color Temperature
pid-info-hsv = HSV
pid-sysap-info-hsv = SysAP Info HSV
pid-info-color-mode = Color Mode
pid-sysap-info-color-mode = SysAP Info Color Mode
pid-info-move-up-down = Move Up/Down
pid-current-absolute-position-blinds-percentage = Blinds Position
pid-current-absolute-position-slats-percentage = Slats Position
pid-sysap-infomoveupdown = SysAP-InfoMoveUpDown
pid-sysap-infocurrentabsoluteblindspercentage = SysAP-InfoCurrentAbsoluteBlindsPercentage
pid-sysap-infocurrentabsoluteslatspercentage = SysAP-InfoCurrentAbsoluteSlatsPercentage
pid-measured-temperature = Measured Temperature
pid-info-value-heating = Heating Value
pid-info-value-cooling = cooling Value
pid-switchover-heating-cooling = Switchover heating/cooling
pid-actuating-fan-stage-heating = Fan Heating Control
pid-absolute-setpoint-temperature = Setpoint temperature
pid-additional-heating-value-info = Additional heating Info
pid-additional-cooling-value-info = Additional cooling Info
pid-control-value-additional-heating = Additional heating Control
pid-control-value-additional-cooling = Additional cooling Control
pid-info-actuating-fan-stage-heating = Fan Heating Info
pid-info-actuating-fan-manual-on-off-heating = Fan Manual On/Off Heating
pid-actuating-fan-stage-cooling = Fan Cooling Control
pid-info-fan-stage-cooling = Fan Cooling Info
pid-info-fan-manual-on-off-cooling = Fan Manual On/Off Cooling
pid-heating-active = Heating active
pid-cooling-active = Cooling active
pid-heating-demand = Heating demand
pid-cooling-demand = Cooling demand
pid-heating-demand-feedback-signal = Heating demand feedback
pid-cooling-demand-feedback-signal = Cooling demand feedback
pid-humidity = Humidity
pid-aux-on-off-request = Aux Switch
pid-aux-on-off-response = Aux Swicth response
pid-heating-on-off-request = Heating
pid-cooling-on-off-request = Cooling
pid-operation-mode = Operation mode
pid-swing-h-v = Swing H/V
pid-supported-features = Features
pid-extended-status-indication = Extended Status Indication
pid-extended-status-indication = Extended Status Indication
pid-aux-heating-on-off-request = Aux Heating
pid-emergency-heating-on-off-request = Emergency Heating
pid-relative-fan-speed-control = Relative fan speed
pid-absolute-fan-speed-control = Fan speed
pid-info-absolute-fan-speed = Fan speed feedback
pid-sysap-infoactualfanspeed = SysAP-InfoActualFanSpeed
pid-notification-flags = Notification flags
pid-power-rc = Power RC
pid-power-rh = Power RH
pid-proximity-status = Proximity status
pid-brightness-sensor = Brightness
pid-last-touch = Last touch
pid-led-backlighting-night-mode = LED backlighting
pid-locator-beep = Locator beep
pid-switch-test-alarm = Switch test alarm
pid-fire-alarm-active = Fire alarm
pid-outside-temperature = Outside temperature
pid-wind-force = Wind force
pid-brightness-alarm = Brightness alarm
pid-lux-value = Lux value
pid-wind-speed = Wind speed
pid-rain-detection = Rain detection
pid-rain-sensor-frequency = Rain sensor frequency
pid-play = Play
pid-pause = Pause
pid-next = Next
pid-previous = Previous
pid-play-mode = Play mode
pid-mute = Mute
pid-relative-volume-control = Relative volume control
pid-absolute-volume-control = Absolute volume control
pid-group-membership = Group membership
pid-play-favorite = Play favorite
pid-play-next-favorite = Play next favorite
pid-playback-status = Playback status
pid-current-item-metadata-info = Current item metadata
pid-info-mute = Mute Info
pid-info-actual-volume = Actual volume
pid-allowed-playback-actions = Playback actions
pid-info-group-membership = Group membership Info
pid-info-playing-favorite = Playing favorite Info
pid-absolute-group-volume-control = Group Volume
pid-info-absolute-group-volume = Group Volume INfo
pid-media-source = Media source
pid-solar-power-production = Power production
pid-inverter-output-power = Inverter output power
pid-solar-energy-(today) = Solar energy (today)
pid-injected-energy-(today) = Injected energy (today)
pid-purchased-energy-(today) = Purchased energy (today)
pid-inverter-alarm = Inverter alarm
pid-self-consumption = Self-consumption
pid-self-sufficiency = Self-sufficiency
pid-home-power-consumption = Home power consumption
pid-power-to-grid = Power to grid
pid-consumed-energy-(today) = Consumed energy (today)
pid-meter-alarm = Meter alarm
pid-battery-level = Battery level
pid-battery-power = Battery power
pid-boost = Boost
pid-stop-charging-reuqest = Stop charging
pid-enable-charging-reuqest = Enable charging
pid-info-boost = Boost Info
pid-info-wallbox-status = Wallbox status
pid-info-charging = Charging INfo
pid-info-charging-enabled = Charging enabled
pid-info-installed-power = Installed power
pid-info-transmitted-energy = Transmitted energy
pid-info-car-range = Car range
pid-info-charging-duration = Charging duration
pid-info-current-limit = Current limit
pid-info-current-limit-for-group = Current limit for group
pid-album-cover-url = Cover
pid-secure@home-central-unit = secure@home Central Unit
pid-domusdisarmcounter = DomusDisarmCounter
pid-intrusion-alarm = Intrusion Alarm
pid-safety-alarm = Safety Alarm
pid-infoconfigurationstatus = InfoConfigurationStatus
pid-enable-configuration = Enable configuration
pid-disarming-led = Disarming LED
pid-aes-key = AES Key
pid-zone-status = Zone status
pid-time = Time
pid-start-stop = Start / Stop
pid-pause-resume = Pause / Resume
pid-select-program = Select program
pid-delayed-start-time = Delayed start time
pid-info-status = Status
pid-info-remote-start-enabled = Remote start enabled
pid-info-program = Program
pid-info-finish-time = Finish time
pid-info-delayed-start = Delayed start
pid-info-door = Door
pid-info-door-alarm = Door alarm
pid-switch-supercool = Supercool Info
pid-switch-superfreeze = Superfreeze Info
pid-info-switch-supercool = Supercool switch
pid-info-switch-superfreeze = Superfreeze switch
pid-measured-temperature = Measured Temperature
pid-set-value-temperature = Set Value Temperature
pid-change-operation = Operation
pid-detailed-status-info = Status
pid-info-remaining-time = Remaining time
pid-time-of-last-status-change = Time of last change
pid-lock-unlock-door-command = Door lock
pid-info-locked-unlocked = Door Status
pid-time = Time
pid-date = Date
pid-notification = Notification
pid-switch-entity-on-off = Switch
pid-info-switch-entity-on-off = Switch feedback
pid-consistency-tag = Consistency Tag
pid-battery-status = Battery Status
pid-stay-awake = Stay awake!
pid-proxy-switch = Proxy switch
pid-proxy1 = Proxy 1Byte
pid-proxy2 = Proxy 2Byte
pid-proxy4 = Proxy 4Byte
pid-cyclic-sleep-time = Sleep time
pid-presence = Presence
pid-measured-temperature-1 = Measured temperature
pid-standby-statistics = Standby Statistics
pid-heartbeat-delay = Heartbeat delay
pid-info-heartbeat-delay = Heartbeat delay
pid-measured-temperature-1 = Measured temperature
pid-measured-temperature-2 = Measured temperature
pid-measured-temperature-3 = Measured temperature
pid-measured-temperature-4 = Measured temperature
pid-air-quality-pressure-value = Pressure value
pid-air-quality-co2-value = CO2 value
pid-air-quality-co-value = CO value
pid-air-quality-no2-value = NO2 value
pid-air-quality-o3-value = O3 value
pid-air-quality-pm10-value = PM10 value
pid-air-quality-pm25-value = PM25 value
pid-air-quality-voc-value = VOC value
# localized info text for pairing id description
pid-switch-on-off-text = Actual value of the switch
pid-timed-start-stop-text = Switch for staircase lightning or movement detection
pid-force-position-text = Forces value dependent high priority on or off state
pid-scene-control-text = Recall or learn the set value related to encoded scene number
pid-movement-under-consideration-of-brightness-text = Activation of an autonomous switch off function triggered by an movement detector
pid-presence-text = Presence triggered by a movement detector to be used by other devices
pid-relative-set-value-text = Relative dimming value
pid-absolute-set-value-text = Controls the set value
pid-night-text = Toggle between day and night (where day = 0 / night = 1)
pid-invalid-string-id-text = Resets load failures / short circuits / etc
pid-rgb-color-text = RGB Color value of the light
pid-color-temperature-text = Color temperature value of the light
pid-hue-text = Hue value of the light
pid-saturation-text = Saturation value of the light
pid-move-up-down-text = Moves sunblind up and down
pid-adjust-up-down-text = Stops the sunblind and to step it up/down
pid-set-absolute-position-blinds-text = Moves the sunblinds into a specified position
pid-set-absolute-position-slats-text = Moves the slats into a specified position
pid-rain-alarm-text = State of the rain sensor (sent cyclically and on COV)
pid-force-position-blind-text = Forces value dependent high priority up or down state
pid-window-door-position-text = Delivers position for Window/Door (Open / Tilted / Closed)
pid-actuating-value-heating-text = Determines the through flow volume of the control valve
pid-fan-level-heating-text = Display value of the fan coil speed. (0=off / 1=lowest - 5=fastest)
pid-actuating-value-cooling-text = Determines the through flow volume of the control valve
pid-set-value-temperature-text = Defines the displayed set point temperature of the system
pid-relative-set-point-temperature-text = Defines the relative set point temperature of the system
pid-window-door-text = Status indication - Open = 1 / closed = 0
pid-status-indication-text = States indication - on/off heating/cool
pid-fan-manual-heating-on-off-text = Switches Fan in manual control mode (master to slave)
pid-controller-on-off-text = Switches controller on or off. Off means protection mode
pid-relative-set-point-request-text = Request for a new relative set point value
pid-eco-mode-on-off-request-text = Switches eco mode on or off
pid-comfort-temperature-text = Sends the current comfort temperature
pid-fan-level-request-text = Request for a new manual fan stage
pid-fan-manual-on-off-request-text = WARNING: DO NOT USE!!!! Request for switching fan in manual/auto mode
pid-controller-on-off-request-text = Request for switching controller on or off. Off means protection mode
pid-eco-mode-on-off-request-text = Indicates ECO mode
pid-info-on-off-text = Reflects the binary state of the actuator
pid-force-position-info-text = Indicates the cause of forced operation (0 = not forced)
pid-sysap-infoonoff-text = Reflects the binary state of the actuator group
pid-sysap-infoforce-text = Indicates whether the actuator group is forced (1) or not forced (0)
pid-info-actual-dimming-value-text = Reflects the actual value of the actuator
pid-info-error-text = Indicates load failures / short circuits / etc
pid-sysap-infocurrentdimmingvalue-text = Reflects the actual value of the actuator group
pid-sysap-infoerror-text = Indicates load failures / short circuits / etc
pid-info-color-temperature-text = Color temperature
pid-sysap-info-color-temperature-text = Color temperature
pid-info-hsv-text = Hue (2 Byte) Saturation (1 Byte)
pid-sysap-info-hsv-text = Hue (2 Byte) Saturation (1 Byte)
pid-info-color-mode-text = Hsv or color mode
pid-sysap-info-color-mode-text = Hsv or color mode info
pid-info-move-up-down-text = Indicates the status of moving and last moving direction
pid-current-absolute-position-blinds-percentage-text = Indicate the current position of the sunblinds in percentage
pid-current-absolute-position-slats-percentage-text = Indicate the current position of the slats in percentage
pid-sysap-infomoveupdown-text = Indicates the status of moving and last moving direction of the actuator group
pid-sysap-infocurrentabsoluteblindspercentage-text = Indicate the current position of the sunblinds in percentage of the actuator group
pid-sysap-infocurrentabsoluteslatspercentage-text = Indicate the current position of the slats in percentage of the actuator group
pid-measured-temperature-text = Indicates the actual measured temperature
pid-info-value-heating-text = States the current flow volume of the control valve
pid-info-value-cooling-text = States the current flow volume of the control valve
pid-switchover-heating-cooling-text = Switch between heating and cooling: heating = 0 / cooling = 1
pid-actuating-fan-stage-heating-text = Requests a new manual fan stage from actuator in heating mode
pid-absolute-setpoint-temperature-text = Set point temperature input for timer
pid-additional-heating-value-info-text = Heating feedback
pid-additional-cooling-value-info-text = Cooling feedback
pid-info-actuating-fan-stage-heating-text = Feedback from actuating fan stage
pid-info-actuating-fan-manual-on-off-heating-text = Feedback from actuating fan stage (manual on/off)
pid-actuating-fan-stage-cooling-text = Requests a new manual fan stage from actuator in cooling mode
pid-info-fan-stage-cooling-text = Feedback for current fan stage in cooling mode
pid-info-fan-manual-on-off-cooling-text = Feedback for manual fan control cooling mode
pid-heating-active-text = Heating active
pid-cooling-active-text = Cooling active
pid-heating-demand-text = Heating demand
pid-cooling-demand-text = Cooling demand
pid-heating-demand-feedback-signal-text = Heating demand feedback signal
pid-cooling-demand-feedback-signal-text = Cooling demand feedback signal
pid-humidity-text = Measured Humidity
pid-aux-on-off-request-text = Aux On/Off
pid-aux-on-off-response-text = Aux On/Off response
pid-heating-on-off-request-text = Heating On/Off
pid-cooling-on-off-request-text = Cooling On/Off
pid-operation-mode-text = Operation mode
pid-swing-h-v-text = Swing H/V
pid-supported-features-text = Supported features
pid-extended-status-indication-text = Extended Status Indication
pid-aux-heating-on-off-request-text = Aux Heating On Off Reques
pid-emergency-heating-on-off-request-text = Emergency Heating On Off Request
pid-relative-fan-speed-control-text = Relative control of the set value
pid-absolute-fan-speed-control-text = Absolute control of the set value
pid-info-absolute-fan-speed-text = Reflects the actual value of the actuator
pid-sysap-infoactualfanspeed-text = Reflects the actual value of the actuator
pid-notification-flags-text = Notifications of RF devices (e. g. Battery low)
pid-power-rc-text = Bool Value 1
pid-power-rh-text = Bool Value 2
pid-proximity-status-text = Bool Value 3
pid-brightness-sensor-text = Scaling Value 1
pid-last-touch-text = Scaling Value 2
pid-led-backlighting-night-mode-text = Scaling Value 3
pid-locator-beep-text = Locator Beep
pid-switch-test-alarm-text = Switch Test Alarm
pid-fire-alarm-active-text = Fire-Alarm Active
pid-outside-temperature-text = Outdoor Temperature
pid-wind-force-text = Wind force
pid-brightness-alarm-text = Brightness alarm
pid-lux-value-text = Weatherstation brightness level
pid-wind-speed-text = Wind speed
pid-wind-alarm-text = Triggers if the wind speed is higher than the threshold
pid-frost-alarm-text = Triggers if the temperature is lower than the threshold
pid-rain-detection-text = Rain detection
pid-rain-sensor-frequency-text = Rain sensor frequency
pid-play-text = Start playing
pid-pause-text = Pause/Stop playing
pid-next-text = Play next title
pid-previous-text = Play previous title
pid-play-mode-text = Play mode (shuffle / repeat)
pid-relative-volume-control-text = Relative volume control. See also relative dimming
pid-absolute-volume-control-text = Set player volume
pid-group-membership-text = Group membership
pid-play-favorite-text = Play favorite
pid-play-next-favorite-text = Play next favorite
pid-playback-status-text = Playback status
pid-current-item-metadata-info-text = Current item metadata info
pid-info-mute-text = Info mute
pid-info-actual-volume-text = Info actual volume
pid-allowed-playback-actions-text = Allowed playback actions
pid-info-playing-favorite-text = Info playing favorite
pid-absolute-group-volume-control-text = Group Volume Control
pid-info-absolute-group-volume-text = Info Group Volume
pid-media-source-text = Media source
pid-solar-power-production-text = Power from the sun
pid-inverter-output-power-text = Output power of inverter (pbatt+Psun)
pid-solar-energy-(today)-text = Produced Energy
pid-injected-energy-(today)-text = Energy into the grid
pid-purchased-energy-(today)-text = Energy from the grid
pid-inverter-alarm-text = Inverter is working in stand alone mode
pid-self-consumption-text = production PV/ Total consumption
pid-self-sufficiency-text = Consumption from PV/ Total consumption
pid-home-power-consumption-text = Power in home (PV and grid)
pid-power-to-grid-text = Power from and to the grid: Purchased (less than 0), Injection (more than 0)
pid-consumed-energy-(today)-text = Energy bought from grid per day
pid-meter-alarm-text = Meter communication loss
pid-battery-level-text = Battery level
pid-battery-power-text = Batter power: Discharge (less then 0), Charge (more then 0)
pid-boost-text = Boos status - 1: Boost enable request, 0: boost disable request
pid-stop-charging-reuqest-text = Stop charging request - 1: Stop charging session requested, 0: n/a, will be resetted when cable is unplugged
pid-enable-charging-reuqest-text = Enable charging - 1: Enable charging when cable is plugged in, 0: Disable next charging session but charge until cable is plugged
pid-info-boost-text = Boots info - 1: Boost enabled, 0: boost disabled
pid-info-wallbox-status-text = Wallbox status 00000001: car plugged in, 00000002: Authorization granted, 00000004: Not charging, battery fully loaded, 40000000: charging stopped due to blackout prevention, 80000000: Ground fault error
pid-info-charging-text = Charging status - 1: Charging, 0: Not charging
pid-info-charging-enabled-text = Charging status - 1: Charging enabled for next session, 0: Charging disabled for next session
pid-info-installed-power-text = Installed power (e.g. 20 kW)
pid-info-transmitted-energy-text = Energy transmitted so far per session (in Wh)
pid-info-car-range-text = Car range in km per sessions
pid-info-charging-duration-text = Start of charging session (in minutes in UTC)
pid-info-current-limit-text = Limit for charger (in kW)
pid-info-current-limit-for-group-text = Limit for group of charger (in kW)
pid-album-cover-url-text = Album cover URL
pid-secure@home-central-unit-text = Encrypted control datapoint for domus alarm center
pid-domusdisarmcounter-text = Info about the next counter to disarm the system
pid-intrusion-alarm-text = Intrusion alarm active
pid-safety-alarm-text = Safety Alarm active
pid-infoconfigurationstatus-text = Domus alarm device negative feedback and configuration info.
pid-enable-configuration-text = Encrypted control datapoint for entering configuration mode
pid-disarming-led-text = Arm/Disarm a Zone
pid-aes-key-text = Manufacturer ID + Serial + AES Key
pid-zone-status-text = Zone status
pid-time-text = Absolute number of seconds when the zone will be armed
pid-start-stop-text = Starts / Stops operation
pid-pause-resume-text = Pause / Resume
pid-select-program-text = Select program
pid-delayed-start-time-text = Delayed start time
pid-info-status-text = Info status
pid-info-remote-start-enabled-text = Info remote start enabled
pid-info-program-text = Info program
pid-info-finish-time-text = Info finish time
pid-info-delayed-start-text = Info delayed start
pid-info-door-text = Info door
pid-info-door-alarm-text = Info door alarm
pid-switch-supercool-text = Switch supercool
pid-switch-superfreeze-text = Switch superfreeze
pid-info-switch-supercool-text = Info switch supercool
pid-info-switch-superfreeze-text = Info switch superfreeze
pid-measured-temperature-text = Measured Temperature
pid-measured-temperature-text = Measured Temperature
pid-set-value-temperature-text = Set Value Temperature
pid-set-value-temperature-text = Set Value Temperature
pid-change-operation-text = Change operation
pid-detailed-status-info-text = Detailed status info
pid-info-remaining-time-text = Remaining time till status change (start, finish, etc.)
pid-time-of-last-status-change-text = Time of last status change (start, finish, etc.)
pid-lock-unlock-door-command-text = Lock/Unlock door command (1 Bit)
pid-info-locked-unlocked-text = Info Lock/Unlock door(1 Bit)
pid-time-text = Current local time
pid-date-text = Current local date
pid-notification-text = Notification from message center
pid-switch-entity-on-off-text = Entity control e.g. activate an alert or timer program
pid-info-switch-entity-on-off-text = Reflects the active state of an entity e.g. alert or timer program
pid-consistency-tag-text = Notifications of RF devices (e. g. Battery low)
pid-battery-status-text = Notifications of RF devices (e. g. Battery low)
pid-stay-awake-text = Notifications of RF devices (e. g. Battery low)
pid-proxy-switch-text = Proxy switch
pid-proxy1-text = Proxy, 1 byte
pid-proxy2-text = Proxy, 2 byte
pid-proxy4-text = Proxy, 4 byte
pid-cyclic-sleep-time-text = Time of sleep cycles
pid-presence-text = SysAP presence
pid-measured-temperature-1-text = SysAP temperature
pid-standby-statistics-text = Statistics about standby usage for battery devices
pid-heartbeat-delay-text = Time period between two heartbeats
pid-info-heartbeat-delay-text = Time period between two heartbeats
pid-measured-temperature-1-text = For debug purposes
pid-measured-temperature-2-text = For debug purposes
pid-measured-temperature-3-text = For debug purposes
pid-measured-temperature-4-text = For debug purposes
pid-air-quality-pressure-value-text = Air quality sensor value - Pressure value
pid-air-quality-co2-value-text = Air quality sensor value - CO2 value
pid-air-quality-co-value-text = Air quality sensor value - CO value
pid-air-quality-no2-value-text = Air quality sensor value - NO2 value
pid-air-quality-o3-value-text = Air quality sensor value - O3 value
pid-air-quality-pm10-value-text = Air quality sensor value - PM10 value
pid-air-quality-pm25-value-text = Air quality sensor value - PM25 value
pid-air-quality-voc-value-text = Air quality sensor value - VOC value

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="freeathomesystem"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<bridge-type id="gateway">
<label>free@home Gateway</label>
<description>This gateway represents the free@home Gateway</description>
<config-description>
<parameter-group name="identification">
<label>SysAP Setting</label>
<description>SysAP network address and user settings</description>
<advanced>false</advanced>
</parameter-group>
<parameter name="ipAddress" type="text" required="true" groupName="identification">
<context>network-address</context>
<label>Sysap IP Address</label>
<description>IP Address of the Busch-Jaeger Gateway</description>
</parameter>
<parameter name="username" type="text" required="true" groupName="identification">
<label>User Name</label>
<description>The login name</description>
</parameter>
<parameter name="password" type="text" required="true" groupName="identification">
<label>Password</label>
<context>password</context>
<description>Password for gateway</description>
</parameter>
</config-description>
</bridge-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="freeathomesystem"
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">
<thing-type id="device" listed="false">
<supported-bridge-type-refs>
<bridge-type-ref id="gateway"/>
</supported-bridge-type-refs>
<label>free@home Device</label>
<description>This represents the generic free@home device</description>
<properties>
<property name="vendor">Busch&amp;Jäger - ABB</property>
<property name="modelId">Generic free@home Device</property>
</properties>
<representation-property>deviceId</representation-property>
<config-description>
<parameter name="deviceId" type="text" required="true">
<label>Device Id</label>
<description>This is the unique id of the free@home device (Please do not modify after the Thing is generated)</description>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>

View File

@ -146,6 +146,7 @@
<module>org.openhab.binding.folderwatcher</module> <module>org.openhab.binding.folderwatcher</module>
<module>org.openhab.binding.folding</module> <module>org.openhab.binding.folding</module>
<module>org.openhab.binding.foobot</module> <module>org.openhab.binding.foobot</module>
<module>org.openhab.binding.freeathomesystem</module>
<module>org.openhab.binding.freebox</module> <module>org.openhab.binding.freebox</module>
<module>org.openhab.binding.freeboxos</module> <module>org.openhab.binding.freeboxos</module>
<module>org.openhab.binding.freecurrency</module> <module>org.openhab.binding.freecurrency</module>