[livisismarthome] New binding (successor of innogysmarthome with local API and some improvements) (#12440)

- Initial version added (copied and renamed from the innogysmarthome binding)
- The local API is now used, authorization, bridge initialization and discovery is already working
- Potential NullPointerExceptions fixed
- Adding battery-low-Channel support for ISC2
- More optimizations and local API changes in the ReadMe
- The key button counter channels are now updated correctly. The according trigger channels should now also work fine.
- Bug fixes regarding button pressed event. The pressed event is now executed along with short and long press events, so if someone want to react on a button press (short or long), the PRESSED trigger event can get checked. And the pressed event isn't senseless executed on a binding restart anymore.
- Error messages improved
- Deprecation-Notice
- New deprecation warning integrated in the innogysmarthome binding
- Livisi renamed to LIVISI
- SHC channels are now initialized correctly
- New "status" channel for the SHC with the values ACTIVE, INITIALIZING and SHUTTINGDOWN
- Code and documentation optimizations
- Fix for PT-PSS action
- Support for SHC classic - The websocket is hosted on another port.
- Update for Temperature-Channel-Definitions and Translations (de)
- Update for Power-Channel-Definitions
- Further translations (de) for devices and channels
- Refactoring branch integrated (some tests added and a lot of code optimizations for example smaller methods, better method names, more simple flows without continue and return in void methods, improved NULL handling, etc.)
- Code optimization (special handling for VariableActuator removed which seems to be not required anymore)
- The thing status is now set to offline when the device is not reachable (even on binding start up)
- The thing status is now set to online again when the device is reachable again
- Clearer description of the invert switch of the RollerShutter (ISR2)
- Copyright notices corrected
- Imports optimized
- Changed handling of pointTemperature (QuantityType instead of DecimalType)
- Code optimization (device status listeners are now registered with device id, so it isn't necessary anymore to call all listeners to find the right matching listener for the device event).
- Code optimization (not working mDNS bridge discovery removed).
- Explicit idle timeout removed (seems not to be required anymore for the local API and may cause problems with SHC 1, there occur EOFExceptions)
- Code optimizations (Debug code removed which isn't required anymore)
- Warn message added which is logged when the temperature to set is not between min and max temperature (this can happen when the user uses the REST-API instead of MainUI or probably also when set via a rule).
- Code optimizations (stronger/consequent use of QuantityType instead of DecimalType)
- Temperature values outside the possible range of 6 - 30 °C are now set to 6 / 30 °C. Therefore a temperature channel can get set to 0 °C for example by a rule and this is automatically changed to 6 °C (and causes a debug message).
- Code optimizations
- Bug fixes regarding UnitsOfMeasurements (Number:Power)
- Tests repaired
- The local API returns "[]" for empty objects which should only get used for arrays... This is now handled by the binding with replacing "[]" by "null". This error occurred with SHC 1, it isn't known if SHC 2 is also affected.
- Number:Dimensionless (percent) introduced for humidity and luminance
- Button events are now supported for SHC 1 (Classic), but without information about short or long press (isn't available for this SHC model).
- Button events are now supported for SHC 1 (Classic), but without information about short or long press (isn't available for this SHC model).
- The configVersion is now also available for SHC 1 bridges.
- More changes to Descriptions, Translations, Icons, Channel-Order, Channel-Config
- Trace logging of responses added to increase the traceability
- The SHC channels should now also get filled for SHC classic
- cpu, memory and disc channels are now defined as percentage (Number:Dimensionless)
- Jetty-HttpClient replaced by simple UrlConnection, because Jetty-HttpClient has problems with high frequency execution of requests. There were EOFExceptions with SHC classic when 2 or more requests were executed within the same second...
- Readme updated
- Copyright notices corrected
- Additions in ReadMe for RST2 / WRT
- The bridge channels (cpu, memory, disc and operation state) are now updated every minute for SHC 1 / classic (because there are no such events for SHC 1 / classic)
- Bug-fix for SHC 1 / classic: Device attributes are now updated correctly for SHC 1 / classic (there is another response structure, which caused that some attributes were not found / update). This should have affected battery low and reachable (thing status) information.
- There are also raw events which report changes regarding the bridge channels (cpu, memory, disc and operation status). There are now processed.
- Token request JSON changed to lower-case (to be compatible with the new SHC firmware update and this should enable to use the standard logics)
- SHC 2 can now get authenticated with the OAuth 2.0 standard logics of OpenHAB (with x-www-form-urlencoded instead of json). The old special json logic is still there to support SHC 1 (but SHC 1 will also get updated soon).
- SHC 1 supports now short and long button pressed events
- Outdated custom login logics removed. SHC 2 and SHC 1 / classic supports now OAuth 2.0 login requests, therefore the default login logics of OpenHAB can now get used.
- README updated for the required software version of SHC 1 / classic
- Code review findings fixed
- Code review findings fixed (Channel Ids renamed to lowerCamelCase)
- Unused code removed
- Code review findings fixed (Device status messages localized)
- Code review findings fixed (label of BooleanStateActuator renamed)
- Code review findings fixed (hard-coded units resolved)
- Code review findings fixed (unit of measurements changed form Power to Energy when it is unit Wh instead of W)
- Code review findings fixed (thing status BRIDGE_OFFLINE changed to COMMUNICATION_ERROR, because BRIDGE_OFFLINE is intended for sub/child devices, not for the bridge thing)
- Code review findings fixed ("initialize" is now returned faster and all requests are executed asynchronously)
- Code review findings fixed ("initialize" is now returned faster and all requests are executed asynchronously)
- Compiler warnings fixed
- Code review findings fixed
- Code review findings fixed (channel ids renamed)
- Code review findings fixed (tags for temperature and humidity added)
- Code review findings fixed (properties renamed to lowerCamelCase like the default properties)
- Code review findings fixed (non-null warnings fixed, performance increased by reducing requests)
- Code review findings fixed (non-null warnings fixed)
- Code review findings fixed (non-null warnings fixed in tests)
- Copyright notices updated
- Unnecessary log line removed
- Code review findings fixed (non-null warnings fixed in tests)
- Test fixed (WebSocketClient can't get mocked completely which caused an Exception)
- Code review findings fixed (various code optimizations)
- Code review findings fixed (channel-type-ids renamed to lowerCamelCase)
- Code review findings fixed (translation simplified)
- Code review findings fixed (temperature point handling converted in UoM)
- Code review findings fixed (Exception handling improved)
- Code review findings fixed (offline state precised when the bridge isn't found/configured)
- Code review findings fixed (exception logs deactivated within tests to reduce to console output when running the tests)
- Code review findings fixed (thing status is now checked instead of bridge status)
- Code review findings fixed (DeviceStructureManager can now be marked as NonNull because it is initialized within the initialize method)
- Code review findings fixed (LivisiClient can now be marked as NonNull because it is initialized within the initialize method)
- Code review findings fixed (OAuthService can now be marked as NonNull because it is initialized within the initialize method)
- Code review findings fixed (unnecessary type check removed)
- Code review findings fixed (warning messages within tests reduced)
- Code review findings fixed (more when the bridge connection state changes)
- Code review findings fixed (reconnect job changed from scheduleAtFixedRate to scheduleWithFixedDelay - recommended by the SAT warnings).
- Code review findings fixed (unused method removed).
- Representation property introduced to auto-ignore textual defined things at discovery/scan
- Code review findings fixed (more detailed error message for SHC not reachable added).
- Fix ChannelTypeID in Readme.md sample
- Code review findings fixed ("/event/ControllerConnectivityChanged" doesn't change the bridge thing to offline anymore, because it isn't important for the local API anymore).
- Code review findings fixed (point temperature commands with DecimalType instead of QuantityType can now also get handled).
- Tests added regarding handleCommand
- Code optimization (constant for the "invert" channel parameter added)
- Code optimization (log messages within tests avoided)

Signed-off-by: Sven Strohschein <sven.strohschein@gmail.com>
Co-authored-by: RalphSester <ralph.sester@sester-edv.de>
This commit is contained in:
Sven Strohschein 2022-06-14 23:21:39 +02:00 committed by GitHub
parent 960be6bc83
commit 25660991e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
116 changed files with 16114 additions and 1 deletions

View File

@ -168,6 +168,7 @@
/bundles/org.openhab.binding.linky/ @clinique @lolodomo
/bundles/org.openhab.binding.linuxinput/ @t-8ch
/bundles/org.openhab.binding.lirc/ @kabili207
/bundles/org.openhab.binding.livisismarthome/ @Novanic
/bundles/org.openhab.binding.logreader/ @paulianttila
/bundles/org.openhab.binding.loxone/ @ppieczul
/bundles/org.openhab.binding.luftdateninfo/ @weymann

View File

@ -836,6 +836,11 @@
<artifactId>org.openhab.binding.lirc</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.livisismarthome</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.logreader</artifactId>

View File

@ -3,7 +3,13 @@
The binding integrates the [innogy SmartHome](https://innogy.com/smarthome) system into openHAB.
It uses the official API 1.1 as provided by innogy as cloud service.
As all status updates and commands have to go through the API, a permanent internet connection is required.
Currently there is no API for a direct communication with the innogy SmartHome Controller (SHC).
*Notice!*
*This binding is deprecated!*
*LIVISI (formally innogy) has implemented a local API on their SHC from Software Version 1.2.XX.XXX.
Please migrate to the "LIVISI SmartHome Binding" which is using the new local API and requires neither the LIVISI-cloud-servers nor an internet connection.*
## Supported things

View File

@ -140,6 +140,9 @@ public class InnogyBridgeHandler extends BaseBridgeHandler
@Override
public void initialize() {
logger.debug("Initializing innogy SmartHome BridgeHandler...");
logger.warn(
"The innogy SmartHome binding is deprecated and discontinued and will be removed with the next release of OpenHAB! Please migrate to the newer LIVISI SmartHome binding (which uses a local API which requires no backend servers and no internet connection).");
final InnogyBridgeConfiguration bridgeConfiguration = getConfigAs(InnogyBridgeConfiguration.class);
if (checkConfig(bridgeConfiguration)) {
this.bridgeConfiguration = bridgeConfiguration;

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,214 @@
# LIVISI SmartHome Binding
The binding integrates the [LIVISI (RWE/innogy) SmartHome](https://www.livisi.de) system into openHAB.
The binding is the successor of the innogy SmartHome openHAB binding, which was communicating with the LIVISI cloud servers over the Internet.
This binding communicates directly with LIVISI SmartHome Controllers (SHC) and not through the LIVISI cloud services.
On your SHC you need a minimum software version of 1.2.XX.XXX (SHC 2) or 1.914-3.1.XXXX.XX (SHC 1 / classic) with activated "Local SmartHome".
## Supported things
### Bridge
The LIVISI SmartHome Controller (SHC) is the bridge, that provides the central communication with the devices.
Without the SHC, you cannot communicate with the devices.
### Devices
The following table shows all supported and tested devices and their channels.
The channels are described in detail in the next chapter.
| Device | Description | Supported channels |
|--------|--------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|
| SHC | SmartHome Controller (Bridge) | status, cpu, disk, memory (updated by events; SHC classic: Updated every minute) |
| BRC8 | Basic Remote Controller | button1 ... button8, button1Count ... button8Count, batteryLow |
| ISC2 | In Wall Smart Controller | button1, button2, button1Count, button2Count, batteryLow |
| ISD2 | In Wall Smart Dimmer | button1, button2, button1Count, button2Count, dimmer |
| ISR2 | In Wall Smart Rollershutter | button1, button2, button1Count, button2Count, rollershutter |
| ISS2 | In Wall Smart Switch | button1, button2, button1Count, button2Count, switch |
| PSD | Pluggable Smart Dimmer | dimmer |
| PSS | Pluggable Smart Switch, indoor | switch |
| PSSO | Pluggable Smart Switch, outdoor | switch |
| BT-PSS | Bluetooth Pluggable Smart Switch, indoor | switch |
| RST | Radiator Mounted Smart Thermostat | targetTemperature, currentTemperature, frostWarning, humidity, moldWarning, operationMode, windowReductionActive, batteryLow |
| RST2 | Radiator Mounted Smart Thermostat (newer two battery version since 2018) | targetTemperature, currentTemperature, frostWarning, humidity, moldWarning, operationMode, windowReductionActive, batteryLow |
| | VariableActuator | switch |
| WDS | Window Door Sensor | contact, batteryLow |
| WMD | Wall Mounted Motion Detector, indoor | motionCount, luminance, batteryLow |
| WMDO | Wall Mounted Motion Detector, outdoor | motionCount, luminance, batteryLow |
| WRT | Wall Mounted Room Thermostat | targetTemperature, currentTemperature, frostWarning, humidity, moldWarning, operationMode, windowReductionActive, batteryLow |
| WSC2 | Wall Mounted Smart Controller | button1, button2, button1Count, button2Count, batteryLow |
| WSD | Wall Mounted Smoke Detector, old version | smoke, alarm, batteryLow |
| WSD2 | Wall Mounted Smoke Detector, new version | smoke, alarm, batteryLow |
Powermeter devices
| Device | Description | Supported channels |
|-----------------|----------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| AnalogMeter | The Analog Meter from the LIVISI EnergyControl product | energyConsumptionMonthKwh, absoluteEnergyConsumption, energyConsumptionMonthEuro, energyConsumptionDayEuro, energyConsumptionDayKwh |
| GenerationMeter | The Generation Meter from the LIVISI PowerControlSolar product | energyGenerationMonthKwh, totalEnergyGeneration, energyGenerationMonthEuro, energyGenerationDayEuro, energyGenerationDayKwh, powerGenerationWatt |
| SmartMeter | The Smart Meter from the LIVISI PowerControl product. | energyConsumptionMonthKwh, absoluteEnergyConsumption, energyConsumptionMonthEuro, energyConsumptionDayEuro, energyConsumptionDayKwh, powerConsumptionWatt |
| Two-Way-Meter | The Two-Way-Meter from the LIVISI PowerControlSolar product | energyMonthKwh, totalEnergy, energyMonthEuro, energyDayEuro, energyDayKwh, energyFeedMonthKwh, totalEnergyFed, energyFeedMonthEuro, energyFeedDayEuro, energyFeedDayKwh, powerWatt |
## Discovery
The bridge (SHC) can not be discovered automatically. It must be added manually (see below under "Configuration").
After the bridge is added, devices are discovered automatically.
As there is no background discovery implemented at the moment, you have to start the discovery manually.
However, only devices will appear that are added in the LIVISI SmartHome app before, because the LIVISI Binding does not support the coupling of devices to the bridge.
## Channels
| Channel Type ID | Item Type | Description | Available on thing |
|-----------------------|---------------|---------------------------------------------------------------------------|-------------------------------------------------------------|
| alarm | Switch | Switches the alarm (ON/OFF) | WSD, WSD2 |
| batteryLow | Switch | Indicates, if the battery is low (ON/OFF) | BRC8, ISC2, RST, RST2, WDS, WMD, WMD0, WRT, WSC2, WSD, WSD2 |
| contact | Contact | Indicates the contact state (OPEN/CLOSED) | WDS |
| cpu | Number | CPU-Usage of the SHC in percent | SHC (bridge) |
| dimmer | Dimmer | Allows to dimm a light device | ISD2, PSD |
| disk | Number | Disk-Usage of the SHC in percent | SHC (bridge) |
| frostWarning | Switch | active, if the measured temperature is too low (ON/OFF) | RST, RST2, WRT |
| humidity | Number | Relative humidity in percent | RST, RST2, WRT |
| button1 | - | Trigger channel for rules, fires with each push | BRC8, ISC2, ISD2, ISR2, ISS2, WSC2 |
| button2 | - | Trigger channel for rules, fires with each push | BRC8, ISC2, ISD2, ISR2, ISS2, WSC2 |
| button3 | - | Trigger channel for rules, fires with each push | BRC8 |
| button4 | - | Trigger channel for rules, fires with each push | BRC8 |
| button5 | - | Trigger channel for rules, fires with each push | BRC8 |
| button6 | - | Trigger channel for rules, fires with each push | BRC8 |
| button7 | - | Trigger channel for rules, fires with each push | BRC8 |
| button8 | - | Trigger channel for rules, fires with each push | BRC8 |
| button1Count | Number | Number of button pushes for button 1, increased with each push | BRC8, ISC2, ISD2, ISR2, ISS2, WSC2 |
| button2Count | Number | Number of button pushes for button 2, increased with each push | BRC8, ISC2, ISD2, ISR2, ISS2, WSC2 |
| button3Count | Number | Number of button pushes for button 3, increased with each push | BRC8 |
| button4Count | Number | Number of button pushes for button 4, increased with each push | BRC8 |
| button5Count | Number | Number of button pushes for button 5, increased with each push | BRC8 |
| button6Count | Number | Number of button pushes for button 6, increased with each push | BRC8 |
| button7Count | Number | Number of button pushes for button 7, increased with each push | BRC8 |
| button8Count | Number | Number of button pushes for button 8, increased with each push | BRC8 |
| luminance | Number | Indicates the measured luminance in percent | WMD, WMD0 |
| memory | Number | Memory-Usage of the SHC in percent | SHC (bridge) |
| moldWarning | Switch | Active, if the measured humidity is too low (ON/OFF) | RST, RST2, WRT |
| motionCount | Number | Number of detected motions, increases with each detected motion | WMD, WMDO |
| operationMode | String | The mode of a thermostat (auto/manual) | RST, RST2, WRT |
| rollershutter | Rollershutter | Controls a roller shutter | ISR2 |
| targetTemperature | Number | Sets the target temperature in °C (min 6 °C, max 30 °C) | RST, RST2, WRT |
| smoke | Switch | Indicates, if smoke was detected (ON/OFF) | WSD, WSD2 |
| status | String | Status of the SHC (ACTIVE/NORMAL, INITIALIZING/REBOOTING or SHUTTINGDOWN) | SHC (bridge) |
| switch | Switch | A switch to turn the device or variable on/off (ON/OFF) | ISS2, PSS, PSSO, VariableActuator |
| currentTemperature | Number | Holds the actual temperature in °C | RST, RST2, WRT |
| windowReductionActive | Switch | Indicates if a linked window is open and temperature reduced (ON/OFF) | RST, RST2, WRT |
The `rollershutter` channel has a `boolean` parameter `invert`.
It is `false` by default.
This means `100` on LIVISI is `UP` and `0` is `DOWN`.
When `invert` is `true` than `0` on LIVISI is `UP` and `100` is `DOWN`.
## Triggers
| Trigger Type | Description | Available on thing |
|---------------|-----------------------------------------------|-------------------------------------|
| SHORT_PRESSED | Fired when you press a button short | BRC8, ISC2, ISD2, ISR2, ISS2, WSC2 |
| LONG_PRESSED | Fired when you press a button longer | BRC8, ISC2, ISD2, ISR2, ISS2, WSC2 |
| PRESSED | Fired when you press a button (short or long) | BRC8, ISC2, ISD2, ISR2, ISS2, WSC2 |
## Thing configuration
### Configuring the SmartHome Controller (SHC)
The SmartHome Controller (SHC) can be configured in the UI as follows:
When adding the "LIVISI SmartHome Controller" via the Inbox, you have to define the hostname or local IP address and the password for the local user.
Save your changes. The SHC should now login and go online.
### Discovering devices
All devices bound to the bridge are found by the discovery service once the SHC is online.
As device discovery is not implemented as a background service, you should start it manually in the Inbox to find all devices.
Now you can add all devices from your Inbox as things.
### File based configuration
As an alternative to the automatic discovery process and graphical configuration using the UI, LIVISI things can be configured manually.
The LIVISI SmartHome Controller (SHC) can be configured using the following syntax:
```
Bridge livisismarthome:bridge:<bridge-id> "Livisi: SmartHome Controller (SHC)" [ host="192.168.0.99", password="SomethingSecret", webSocketIdleTimeout=900]
```
** *Security warning!**
The communication between the binding and the SHC is not encrypted and can be traced.
So be careful and secure your local network from unauthorized access.
All other LIVISI devices can be added using the following syntax:
```
Thing WDS <thing-id> "<thing-name>" @ "<room-name>" [ id="<the-device-id>" ]
```
The device ID (e.g. e9a74941a3807b57332214f346fb1129) can be found in the UI inbox, as you find it below all things there in the form `livisismarthome:<device-type>:<bridge-id>:<the-device-id>` (example: `livisismarthome:WSC2:SMARTHOME01:e9a74941a3807b57332214f346fb1129`).
However, a full example .things configuration look like this:
```
Bridge livisismarthome:bridge:mybride "LIVISI SmartHome Controller" {
Thing ISD2 myDimmer "Dimmer Kitchen" @ "Kitchen" [ id="<device-id>" ]
Thing ISS2 myLightSwitch "Light Livingroom" @ "Livingroom" [ id="<device-id>" ]
Thing PSS myTVSwitch "TV" @ "Livingroom" [ id="<device-id>" ]
Thing RST myHeating "Thermostat Livingroom" @ "Livingroom" [ id="<device-id>" ]
Thing ISR2 myRollerShutter1 "RollerShutter" @ "Livingroom" [ id="<device-id>" ]
Thing ISR2 myRollerShutter2 "RollerShutter (inverted)" @ "Livingroom" [ id="<device-id>" ] {Type rollershutterActuator : rollershutter [invert=true]}
Thing VariableActuator myLivisiVariable "My Variable" [ id="<device-id>" ]
Thing WDS myWindowContact "Window Kitchen" @ "Kitchen" [ id="<device-id>" ]
Thing WMD myMotionSensor "Motion entry" @ "Entry" [ id="<device-id>" ]
Thing WSC2 myPushButton "Pushbutton" @ "Living" [ id="<device-id>" ]
Thing WSD mySmokeDetector "Smoke detector Livingroom" @ "Living" [ id="<device-id>" ]
}
```
## Items configuration
You can then configure your items in your *.items config files as usual, for example:
```
Contact myWindowContact "Kitchen" <window> {channel="livisismarthome:WDS:mybridge:myWindowContact:contact"}
Switch myWindowContactBattery "Battery low" <battery> {channel="livisismarthome:WDS:mybridge:myWindowContact:batteryLow"}
Number myHeatingTemp "Bath [%.1f °C]" <temperature> {channel="livisismarthome:RST:mybridge:myHeating:currentTemperature"}
Number myHeatingModeTempTarget "Settemp bath [%.1f °C]" <temperature> {channel="livisismarthome:RST:mybridge:myHeating:targetTemperature"}
String myHeatingMode "Mode bath [%s]" <temperature> {channel="livisismarthome:RST:mybridge:myHeating:operationMode"}
Number myHeatingHumidity "Bath [%.1f %%]" <humidity> {channel="livisismarthome:RST:mybridge:myHeating:humidity"}
```
## Sitemap configuration
Example:
```
sitemap default label="Home" {
Frame {
Text item=myHeatingTemp label="Temperature"
Text item=myHeatingHumidity label="Humidity"
Switch item=myHeatingMode label="Mode" mappings=[Manu="Manual", Auto="Auto"]
Setpoint item=myHeatingModeTempTarget label="Target temperature" minValue=16 maxValue=25 step=1
}
}
```
## Rules example for push-buttons
Push-buttons provide trigger channels, that can only be used in rules.
Here is an example rule:
```
rule "Button triggered rule"
when
Channel 'livisismarthome:WSC2:mybridge:myPushButton:button1' triggered PRESSED
then
// do something...
logInfo("testlogger", "Button 1 pressed")
end
```

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>3.3.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.binding.livisismarthome</artifactId>
<name>openHAB Add-ons :: Bundles :: LIVISI SmartHome Binding</name>
</project>

View File

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

View File

@ -0,0 +1,184 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link LivisiBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Oliver Kuhl - Initial contribution
* @author Sven Strohschein - Renamed from Innogy to Livisi
*/
@NonNullByDefault
public class LivisiBindingConstants {
public static final String BINDING_ID = "livisismarthome";
public static final String USERNAME = "admin";
public static final long REINITIALIZE_DELAY_SECONDS = 30;
public static final long BRIDGE_REFRESH_SECONDS = 60;
// properties
public static final String PROPERTY_ID = "id";
public static final String PROPERTY_VERSION = "version";
public static final String PROPERTY_LOCATION = "location";
public static final String PROPERTY_GEOLOCATION = "geoLocation";
public static final String PROPERTY_SOFTWARE_VERSION = "softwareVersion";
public static final String PROPERTY_IP_ADDRESS = "ipAddress";
public static final String PROPERTY_REGISTRATION_TIME = "registrationTime";
public static final String PROPERTY_TIME_OF_ACCEPTANCE = "timeOfAcceptance";
public static final String PROPERTY_TIME_OF_DISCOVERY = "timeOfDiscovery";
public static final String PROPERTY_BATTERY_POWERED = "batteryPowered";
public static final String PROPERTY_DEVICE_TYPE = "deviceType";
public static final String PROPERTY_CONFIGURATION_STATE = "configurationState";
public static final String PROPERTY_SHC_TYPE = "controllerType";
public static final String PROPERTY_TIME_ZONE = "timeZone";
public static final String PROPERTY_CURRENT_UTC_OFFSET = "currentUtcOffsetInMinutes";
public static final String PROPERTY_PROTOCOL_ID = "protocolId";
public static final String PROPERTY_BACKEND_CONNECTION_MONITORED = "backendConnectionMonitored";
public static final String PROPERTY_RFCOM_FAILURE_NOTIFICATION = "rfcomFailureNotification";
public static final String PROPERTY_DISPLAY_CURRENT_TEMPERATURE = "displayCurrentTemperature";
public static final String PROPERTY_METER_ID = "meterId";
public static final String PROPERTY_METER_FIRMWARE_VERSION = "meterFirmwareVersion";
// List of main device types
public static final String DEVICE_SHC = "SHC"; // smarthome controller - the bridge
public static final String DEVICE_SHCA = "SHCA"; // smarthome controller version 2
public static final String DEVICE_PSS = "PSS"; // pluggable smart switch
public static final String DEVICE_PSSO = "PSSO"; // pluggable smart switch outdoor
public static final String DEVICE_BT_PSS = "BT-PSS"; // Bluetooth pluggable smart switch
public static final String DEVICE_VARIABLE_ACTUATOR = "VariableActuator";
public static final String DEVICE_RST = "RST"; // radiator mounted smart thermostat
public static final String DEVICE_RST2 = "RST2"; // radiator mounted smart thermostat (newer version)
public static final String DEVICE_WRT = "WRT"; // wall mounted room thermostat
public static final String DEVICE_WDS = "WDS"; // window door sensor
public static final String DEVICE_ISS2 = "ISS2"; // inwall smart switch
public static final String DEVICE_WSD = "WSD"; // wall mounted smoke detector
public static final String DEVICE_WSD2 = "WSD2"; // wall mounted smoke detector
public static final String DEVICE_WMD = "WMD"; // wall mounted motion detector indoor
public static final String DEVICE_WMDO = "WMDO"; // wall mounted motion detector outdoor
public static final String DEVICE_WSC2 = "WSC2"; // wall mounted smart controller (2 buttons)
public static final String DEVICE_BRC8 = "BRC8"; // basic remote controller (8 buttons)
public static final String DEVICE_ISC2 = "ISC2"; // in wall smart controller (2 buttons)
public static final String DEVICE_ISD2 = "ISD2"; // in wall smart dimmer (2 buttons)
public static final String DEVICE_ISR2 = "ISR2"; // in wall smart rollershutter (2 buttons)
public static final String DEVICE_PSD = "PSD"; // pluggable smart dimmer
public static final String DEVICE_ANALOG_METER = "AnalogMeter";
public static final String DEVICE_GENERATION_METER = "GenerationMeter";
public static final String DEVICE_SMART_METER = "SmartMeter";
public static final String DEVICE_TWO_WAY_METER = "TwoWayMeter";
public static final Set<String> SUPPORTED_DEVICES = Set.of(DEVICE_SHC, DEVICE_SHCA, DEVICE_PSS, DEVICE_PSSO,
DEVICE_BT_PSS, DEVICE_VARIABLE_ACTUATOR, DEVICE_RST, DEVICE_RST2, DEVICE_WRT, DEVICE_WDS, DEVICE_ISS2,
DEVICE_WSD, DEVICE_WSD2, DEVICE_WMD, DEVICE_WMDO, DEVICE_WSC2, DEVICE_BRC8, DEVICE_ISC2, DEVICE_ISD2,
DEVICE_ISR2, DEVICE_PSD, DEVICE_ANALOG_METER, DEVICE_GENERATION_METER, DEVICE_SMART_METER,
DEVICE_TWO_WAY_METER);
public static final Set<String> BATTERY_POWERED_DEVICES = Set.of(DEVICE_ISC2, DEVICE_RST, DEVICE_RST2, DEVICE_WRT,
DEVICE_WDS, DEVICE_WSD, DEVICE_WSD2, DEVICE_WMD, DEVICE_WMDO, DEVICE_WSC2, DEVICE_BRC8);
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_BRIDGE = new ThingTypeUID(BINDING_ID, "bridge");
public static final ThingTypeUID THING_TYPE_PSS = new ThingTypeUID(BINDING_ID, DEVICE_PSS);
public static final ThingTypeUID THING_TYPE_PSSO = new ThingTypeUID(BINDING_ID, DEVICE_PSSO);
public static final ThingTypeUID THING_TYPE_BT_PSS = new ThingTypeUID(BINDING_ID, DEVICE_BT_PSS);
public static final ThingTypeUID THING_TYPE_VARIABLE_ACTUATOR = new ThingTypeUID(BINDING_ID,
DEVICE_VARIABLE_ACTUATOR);
public static final ThingTypeUID THING_TYPE_RST = new ThingTypeUID(BINDING_ID, DEVICE_RST);
public static final ThingTypeUID THING_TYPE_RST2 = new ThingTypeUID(BINDING_ID, DEVICE_RST2);
public static final ThingTypeUID THING_TYPE_WRT = new ThingTypeUID(BINDING_ID, DEVICE_WRT);
public static final ThingTypeUID THING_TYPE_WDS = new ThingTypeUID(BINDING_ID, DEVICE_WDS);
public static final ThingTypeUID THING_TYPE_ISS2 = new ThingTypeUID(BINDING_ID, DEVICE_ISS2);
public static final ThingTypeUID THING_TYPE_WSD = new ThingTypeUID(BINDING_ID, DEVICE_WSD);
public static final ThingTypeUID THING_TYPE_WSD2 = new ThingTypeUID(BINDING_ID, DEVICE_WSD2);
public static final ThingTypeUID THING_TYPE_WMD = new ThingTypeUID(BINDING_ID, DEVICE_WMD);
public static final ThingTypeUID THING_TYPE_WMDO = new ThingTypeUID(BINDING_ID, DEVICE_WMDO);
public static final ThingTypeUID THING_TYPE_WSC2 = new ThingTypeUID(BINDING_ID, DEVICE_WSC2);
public static final ThingTypeUID THING_TYPE_BRC8 = new ThingTypeUID(BINDING_ID, DEVICE_BRC8);
public static final ThingTypeUID THING_TYPE_ISC2 = new ThingTypeUID(BINDING_ID, DEVICE_ISC2);
public static final ThingTypeUID THING_TYPE_ISD2 = new ThingTypeUID(BINDING_ID, DEVICE_ISD2);
public static final ThingTypeUID THING_TYPE_ISR2 = new ThingTypeUID(BINDING_ID, DEVICE_ISR2);
public static final ThingTypeUID THING_TYPE_PSD = new ThingTypeUID(BINDING_ID, DEVICE_PSD);
public static final ThingTypeUID THING_TYPE_ANALOG_METER = new ThingTypeUID(BINDING_ID, DEVICE_ANALOG_METER);
public static final ThingTypeUID THING_TYPE_GENERATION_METER = new ThingTypeUID(BINDING_ID,
DEVICE_GENERATION_METER);
public static final ThingTypeUID THING_TYPE_SMART_METER = new ThingTypeUID(BINDING_ID, DEVICE_SMART_METER);
public static final ThingTypeUID THING_TYPE_TWO_WAY_METER = new ThingTypeUID(BINDING_ID, DEVICE_TWO_WAY_METER);
public static final Set<ThingTypeUID> SUPPORTED_DEVICE_THING_TYPES = Set.of(THING_TYPE_PSS, THING_TYPE_PSSO,
THING_TYPE_BT_PSS, THING_TYPE_VARIABLE_ACTUATOR, THING_TYPE_RST, THING_TYPE_RST2, THING_TYPE_WRT,
THING_TYPE_WDS, THING_TYPE_ISS2, THING_TYPE_WSD, THING_TYPE_WSD2, THING_TYPE_WMD, THING_TYPE_WMDO,
THING_TYPE_WSC2, THING_TYPE_BRC8, THING_TYPE_ISC2, THING_TYPE_ISD2, THING_TYPE_ISR2, THING_TYPE_PSD,
THING_TYPE_ANALOG_METER, THING_TYPE_GENERATION_METER, THING_TYPE_SMART_METER, THING_TYPE_TWO_WAY_METER);
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Stream
.concat(Stream.of(THING_TYPE_BRIDGE), SUPPORTED_DEVICE_THING_TYPES.stream()).collect(Collectors.toSet());
// List of all Channel ids
public static final String CHANNEL_SWITCH = "switch";
public static final String CHANNEL_TARGET_TEMPERATURE = "targetTemperature";
public static final String CHANNEL_CURRENT_TEMPERATURE = "currentTemperature";
public static final String CHANNEL_HUMIDITY = "humidity";
public static final String CHANNEL_CONTACT = "contact";
public static final String CHANNEL_SMOKE = "smoke";
public static final String CHANNEL_ALARM = "alarm";
public static final String CHANNEL_MOTION_COUNT = "motionCount";
public static final String CHANNEL_LUMINANCE = "luminance";
public static final String CHANNEL_OPERATION_MODE = "operationMode";
public static final String CHANNEL_FROST_WARNING = "frostWarning";
public static final String CHANNEL_MOLD_WARNING = "moldWarning";
public static final String CHANNEL_WINDOW_REDUCTION_ACTIVE = "windowReductionActive";
public static final String CHANNEL_BUTTON = "button";
public static final String CHANNEL_BUTTON_COUNT = "button%dCount";
public static final String CHANNEL_DIMMER = "dimmer";
public static final String CHANNEL_ROLLERSHUTTER = "rollershutter";
public static final String CHANNEL_BATTERY_LOW = "batteryLow";
public static final String CHANNEL_ENERGY_CONSUMPTION_MONTH_KWH = "energyConsumptionMonthKwh";
public static final String CHANNEL_ABOLUTE_ENERGY_CONSUMPTION = "absoluteEnergyConsumption";
public static final String CHANNEL_ENERGY_CONSUMPTION_MONTH_EURO = "energyConsumptionMonthEuro";
public static final String CHANNEL_ENERGY_CONSUMPTION_DAY_EURO = "energyConsumptionDayEuro";
public static final String CHANNEL_ENERGY_CONSUMPTION_DAY_KWH = "energyConsumptionDayKwh";
public static final String CHANNEL_POWER_CONSUMPTION_WATT = "powerConsumptionWatt";
public static final String CHANNEL_ENERGY_GENERATION_MONTH_KWH = "energyGenerationMonthKwh";
public static final String CHANNEL_TOTAL_ENERGY_GENERATION = "totalEnergyGeneration";
public static final String CHANNEL_ENERGY_GENERATION_MONTH_EURO = "energyGenerationMonthEuro";
public static final String CHANNEL_ENERGY_GENERATION_DAY_EURO = "energyGenerationDayEuro";
public static final String CHANNEL_ENERGY_GENERATION_DAY_KWH = "energyGenerationDayKwh";
public static final String CHANNEL_POWER_GENERATION_WATT = "powerGenerationWatt";
public static final String CHANNEL_ENERGY_MONTH_KWH = "energyMonthKwh";
public static final String CHANNEL_TOTAL_ENERGY = "totalEnergy";
public static final String CHANNEL_ENERGY_MONTH_EURO = "energyMonthEuro";
public static final String CHANNEL_ENERGY_DAY_EURO = "energyDayEuro";
public static final String CHANNEL_ENERGY_DAY_KWH = "energyDayKwh";
public static final String CHANNEL_ENERGY_FEED_MONTH_KWH = "energyFeedMonthKwh";
public static final String CHANNEL_TOTAL_ENERGY_FED = "totalEnergyFed";
public static final String CHANNEL_ENERGY_FEED_MONTH_EURO = "energyFeedMonthEuro";
public static final String CHANNEL_ENERGY_FEED_DAY_EURO = "energyFeedDayEuro";
public static final String CHANNEL_ENERGY_FEED_DAY_KWH = "energyFeedDayKwh";
public static final String CHANNEL_POWER_WATT = "powerWatt";
public static final String CHANNEL_CPU = "cpu";
public static final String CHANNEL_DISK = "disk";
public static final String CHANNEL_MEMORY = "memory";
public static final String CHANNEL_OPERATION_STATUS = "status";
// List of channel parameters
public static final String INVERT_CHANNEL_PARAMETER = "invert";
}

View File

@ -0,0 +1,77 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal;
import static org.openhab.binding.livisismarthome.internal.LivisiBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.livisismarthome.internal.handler.LivisiBridgeHandler;
import org.openhab.binding.livisismarthome.internal.handler.LivisiDeviceHandler;
import org.openhab.core.auth.client.oauth2.OAuthFactory;
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.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link LivisiHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Oliver Kuhl - Initial contribution
* @author Hilbrand Bouwkamp - Refactored to use openHAB http and oauth2 libraries
* @author Sven Strohschein - Renamed from Innogy to Livisi
*/
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.livisismarthome")
@NonNullByDefault
public class LivisiHandlerFactory extends BaseThingHandlerFactory implements ThingHandlerFactory {
private final Logger logger = LoggerFactory.getLogger(LivisiHandlerFactory.class);
private final OAuthFactory oAuthFactory;
private final HttpClient httpClient;
@Activate
public LivisiHandlerFactory(@Reference OAuthFactory oAuthFactory, @Reference HttpClientFactory httpClientFactory) {
this.oAuthFactory = oAuthFactory;
this.httpClient = httpClientFactory.getCommonHttpClient();
}
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES.contains(thingTypeUID);
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (THING_TYPE_BRIDGE.equals(thingTypeUID) || SUPPORTED_DEVICE_THING_TYPES.contains(thingTypeUID)) {
if (THING_TYPE_BRIDGE.equals(thingTypeUID)) {
return new LivisiBridgeHandler((Bridge) thing, oAuthFactory, httpClient);
} else if (SUPPORTED_DEVICE_THING_TYPES.contains(thingTypeUID)) {
return new LivisiDeviceHandler(thing);
}
}
logger.debug("Unsupported thing {}.", thingTypeUID);
return null;
}
}

View File

@ -0,0 +1,189 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal;
import java.io.IOException;
import java.net.URI;
import java.util.concurrent.ExecutionException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.openhab.binding.livisismarthome.internal.client.exception.WebSocketConnectException;
import org.openhab.binding.livisismarthome.internal.listener.EventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link LivisiWebSocket} implements the websocket for receiving constant updates
* from the LIVISI SmartHome web service.
*
* @author Oliver Kuhl - Initial contribution
* @author Sven Strohschein - Renamed from Innogy to Livisi
*/
@NonNullByDefault
@WebSocket
public class LivisiWebSocket {
private final Logger logger = LoggerFactory.getLogger(LivisiWebSocket.class);
private final HttpClient httpClient;
private final EventListener eventListener;
private final URI webSocketURI;
private final int maxIdleTimeout;
private WebSocketClient client;
private @Nullable Session session;
private boolean closing;
/**
* Constructs the {@link LivisiWebSocket}.
*
* @param eventListener the responsible
* {@link org.openhab.binding.livisismarthome.internal.handler.LivisiBridgeHandler}
* @param webSocketURI the {@link URI} of the websocket endpoint
* @param maxIdleTimeout max idle timeout
*/
public LivisiWebSocket(HttpClient httpClient, EventListener eventListener, URI webSocketURI, int maxIdleTimeout) {
this.httpClient = httpClient;
this.eventListener = eventListener;
this.webSocketURI = webSocketURI;
this.maxIdleTimeout = maxIdleTimeout;
this.client = createWebSocketClient();
}
/**
* Starts the {@link LivisiWebSocket}.
*/
public synchronized void start() throws WebSocketConnectException {
if (client.isStopped()) {
client = createWebSocketClient();
startWebSocketClient(client);
}
session = connectWebSocket(session);
}
private Session connectWebSocket(@Nullable Session session) throws WebSocketConnectException {
closeSession(session);
this.session = null;
logger.debug("Connecting to LIVISI SmartHome WebSocket...");
try {
return client.connect(this, webSocketURI).get();
} catch (IOException | InterruptedException | ExecutionException e) {
throw new WebSocketConnectException("The WebSocket couldn't get connected!", e);
}
}
/**
* Stops the {@link LivisiWebSocket}.
*/
public synchronized void stop() {
this.closing = true;
if (isRunning()) {
closeSession(session);
} else {
logger.trace("Stopping websocket ignored - was not running.");
}
session = null;
stopWebSocketClient(client);
client = createWebSocketClient();
}
private void closeSession(@Nullable Session session) {
if (session != null) {
logger.debug("Closing session...");
session.close();
}
}
/**
* Return true, if the websocket is running.
*
* @return true if the websocket is running, otherwise false
*/
public synchronized boolean isRunning() {
return isRunning(session);
}
private boolean isRunning(@Nullable Session session) {
return session != null && session.isOpen();
}
@OnWebSocketConnect
public void onConnect(Session session) {
this.closing = false;
logger.debug("Connected to LIVISI SmartHome webservice.");
logger.trace("LIVISI SmartHome websocket session: {}", session);
}
@OnWebSocketClose
public void onClose(int statusCode, String reason) {
if (statusCode == StatusCode.NORMAL) {
logger.debug("Connection to LIVISI SmartHome webservice was closed normally.");
} else if (!closing) {
// An additional reconnect attempt is only required when the close/stop wasn't executed by the binding.
logger.debug("Connection to LIVISI SmartHome webservice was closed abnormally (code: {}). Reason: {}",
statusCode, reason);
eventListener.connectionClosed();
}
}
@OnWebSocketError
public void onError(Throwable cause) {
logger.debug("LIVISI SmartHome websocket onError() - {}", cause.getMessage());
eventListener.onError(cause);
}
@OnWebSocketMessage
public void onMessage(String msg) {
logger.debug("LIVISI SmartHome websocket onMessage() - {}", msg);
if (closing) {
logger.debug("LIVISI SmartHome websocket onMessage() - ignored, WebSocket is closing...");
} else {
eventListener.onEvent(msg);
}
}
WebSocketClient createWebSocketClient() {
WebSocketClient client = new WebSocketClient(httpClient);
client.setMaxIdleTimeout(maxIdleTimeout);
return client;
}
void startWebSocketClient(WebSocketClient client) throws WebSocketConnectException {
try {
client.start();
} catch (Exception e) {
throw new WebSocketConnectException("Starting WebSocket failed!", e);
}
}
void stopWebSocketClient(WebSocketClient client) {
try {
client.stop();
client.destroy();
} catch (Exception e) {
logger.debug("Stopping WebSocket failed", e);
}
}
}

View File

@ -0,0 +1,54 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
/**
* The {@link GsonOptional} supports non-null-compatible methods to use gson.
*
* @author Sven Strohschein - Initial contribution
*/
@NonNullByDefault
public class GsonOptional {
/**
* date format as used in json in API. Example: 2016-07-11T10:55:52.3863424Z
*/
private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
private final Gson gson;
public GsonOptional() {
gson = new GsonBuilder().setDateFormat(DATE_FORMAT).create();
}
public <T> Optional<T> fromJson(String json, Class<T> clazz) throws JsonSyntaxException {
return Optional.ofNullable(fromJsonNullable(json, clazz));
}
public <T> @Nullable T fromJsonNullable(String json, Class<T> clazz) throws JsonSyntaxException {
return gson.fromJson(json, clazz);
}
public String toJson(Object src) {
return gson.toJson(src);
}
}

View File

@ -0,0 +1,424 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
import org.openhab.binding.livisismarthome.internal.LivisiBindingConstants;
import org.openhab.binding.livisismarthome.internal.client.api.entity.StatusResponseDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.action.ActionDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.action.ShutterActionDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.action.ShutterActionType;
import org.openhab.binding.livisismarthome.internal.client.api.entity.action.StateActionSetterDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.capability.CapabilityDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.capability.CapabilityStateDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.device.DeviceDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.device.DeviceStateDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.device.StateDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.error.ErrorResponseDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.location.LocationDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.message.MessageDTO;
import org.openhab.binding.livisismarthome.internal.client.exception.ApiException;
import org.openhab.binding.livisismarthome.internal.client.exception.AuthenticationException;
import org.openhab.binding.livisismarthome.internal.client.exception.ControllerOfflineException;
import org.openhab.binding.livisismarthome.internal.client.exception.InvalidActionTriggeredException;
import org.openhab.binding.livisismarthome.internal.client.exception.RemoteAccessNotAllowedException;
import org.openhab.binding.livisismarthome.internal.client.exception.ServiceUnavailableException;
import org.openhab.binding.livisismarthome.internal.client.exception.SessionExistsException;
import org.openhab.binding.livisismarthome.internal.client.exception.SessionNotFoundException;
import org.openhab.binding.livisismarthome.internal.handler.LivisiBridgeConfiguration;
import org.openhab.core.auth.client.oauth2.AccessTokenResponse;
import org.openhab.core.auth.client.oauth2.OAuthClientService;
import org.openhab.core.auth.client.oauth2.OAuthException;
import org.openhab.core.auth.client.oauth2.OAuthResponseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonSyntaxException;
/**
* The main client that handles the communication with the LIVISI SmartHome API service.
*
* @author Oliver Kuhl - Initial contribution
* @author Hilbrand Bouwkamp - Refactored to use openHAB http and oauth2 libraries
* @author Sven Strohschein - Renamed from Innogy to Livisi and refactored
*/
@NonNullByDefault
public class LivisiClient {
private final Logger logger = LoggerFactory.getLogger(LivisiClient.class);
private final GsonOptional gson;
private final LivisiBridgeConfiguration bridgeConfiguration;
private final OAuthClientService oAuthService;
private final URLConnectionFactory connectionFactory;
public LivisiClient(final LivisiBridgeConfiguration bridgeConfiguration, final OAuthClientService oAuthService,
final URLConnectionFactory connectionFactory) {
this.bridgeConfiguration = bridgeConfiguration;
this.oAuthService = oAuthService;
this.connectionFactory = connectionFactory;
this.gson = new GsonOptional();
}
/**
* Gets the status
* As the API returns the details of the SmartHome controller (SHC), the config version is returned.
*
* @return config version
*/
public String refreshStatus() throws IOException {
logger.debug("Get LIVISI SmartHome status...");
final Optional<StatusResponseDTO> status = executeGet(URLCreator.createStatusURL(bridgeConfiguration.host),
StatusResponseDTO.class);
if (status.isPresent()) {
String configVersion = status.get().getConfigVersion();
logger.debug("LIVISI SmartHome status loaded. Configuration version is {}.", configVersion);
return configVersion;
}
return "";
}
/**
* Executes a HTTP GET request with default headers and returns data as object of type T.
*
* @param url request URL
* @param clazz type of data to return
* @return response content
*/
private <T> Optional<T> executeGet(final String url, final Class<T> clazz) throws IOException {
HttpURLConnection connection = createBaseRequest(url, HttpMethod.GET);
String responseContent = executeRequest(connection);
return gson.fromJson(responseContent, clazz);
}
/**
* Executes a HTTP GET request with default headers and returns data as List of type T.
*
* @param url request URL
* @param clazz array type of data to return as list
* @return response content (as a List)
*/
private <T> List<T> executeGetList(final String url, final Class<T[]> clazz) throws IOException {
Optional<T[]> objects = executeGet(url, clazz);
if (objects.isPresent()) {
return Arrays.asList(objects.get());
}
return Collections.emptyList();
}
/**
* Executes a HTTP POST request with the given {@link ActionDTO} as content.
*
* @param url request URL
* @param action action to execute
*/
private void executePost(final String url, final ActionDTO action) throws IOException {
final String json = gson.toJson(action);
final byte[] jsonBytes = json.getBytes(StandardCharsets.UTF_8);
logger.debug("Action {} JSON: {}", action.getType(), json);
HttpURLConnection connection = createBaseRequest(url, HttpMethod.POST);
connection.setDoOutput(true);
connection.setRequestProperty(HttpHeader.CONTENT_LENGTH.asString(), String.valueOf(jsonBytes.length));
try (OutputStream outputStream = connection.getOutputStream()) {
outputStream.write(jsonBytes);
}
executeRequest(connection);
}
private String executeRequest(HttpURLConnection connection) throws IOException {
StringBuilder stringBuilder = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
}
}
String responseContent = stringBuilder.toString();
logger.trace("RAW-RESPONSE: {}", responseContent);
handleResponseErrors(connection, responseContent);
return normalizeResponseContent(responseContent);
}
private HttpURLConnection createBaseRequest(String url, HttpMethod httpMethod) throws IOException {
final AccessTokenResponse accessTokenResponse = getAccessTokenResponse();
return connectionFactory.createBaseRequest(url, httpMethod, accessTokenResponse);
}
public AccessTokenResponse getAccessTokenResponse() throws IOException {
try {
@Nullable
final AccessTokenResponse accessTokenResponse = oAuthService.getAccessTokenResponse();
if (accessTokenResponse == null || accessTokenResponse.getAccessToken() == null
|| accessTokenResponse.getAccessToken().isBlank()) {
throw new AuthenticationException("No LIVISI SmartHome access token. Is this thing authorized?");
}
return accessTokenResponse;
} catch (OAuthException | OAuthResponseException e) {
throw new AuthenticationException("Error fetching access token: " + e.getMessage());
}
}
/**
* Handles errors from the {@link org.eclipse.jetty.client.api.ContentResponse} and throws the following errors:
*
* @param connection connection
* @param responseContent response content
* @throws ControllerOfflineException thrown, if the LIVISI SmartHome controller (SHC) is offline.
*/
private void handleResponseErrors(final HttpURLConnection connection, final String responseContent)
throws IOException {
final int status = connection.getResponseCode();
if (HttpStatus.OK_200 == status) {
logger.debug("Statuscode is OK: [{}]", connection.getURL());
} else if (HttpStatus.SERVICE_UNAVAILABLE_503 == status) {
throw new ServiceUnavailableException("LIVISI SmartHome service is unavailable (503).");
} else {
logger.debug("Statuscode {} is NOT OK: [{}]", status, connection.getURL());
String content = normalizeResponseContent(responseContent);
try {
logger.trace("Response error content: {}", content);
final Optional<ErrorResponseDTO> errorOptional = gson.fromJson(content, ErrorResponseDTO.class);
if (errorOptional.isPresent()) {
ErrorResponseDTO error = errorOptional.get();
switch (error.getCode()) {
case ErrorResponseDTO.ERR_SESSION_EXISTS:
throw new SessionExistsException("Session exists: " + error.getDescription());
case ErrorResponseDTO.ERR_SESSION_NOT_FOUND:
throw new SessionNotFoundException("Session not found: " + error.getDescription());
case ErrorResponseDTO.ERR_CONTROLLER_OFFLINE:
throw new ControllerOfflineException("Controller offline: " + error.getDescription());
case ErrorResponseDTO.ERR_REMOTE_ACCESS_NOT_ALLOWED:
throw new RemoteAccessNotAllowedException(
"Remote access not allowed. Access is allowed only from the SHC device network.");
case ErrorResponseDTO.ERR_INVALID_ACTION_TRIGGERED:
throw new InvalidActionTriggeredException(
"Invalid action triggered. Message: " + error.getDescription());
}
throw new ApiException("Unknown error: " + error);
}
} catch (final JsonSyntaxException e) {
throw new ApiException("Invalid JSON syntax in error response: " + content, e);
}
}
}
/**
* Sets a new state of a SwitchActuator.
*/
public void setSwitchActuatorState(final String capabilityId, final boolean state) throws IOException {
executePost(createActionURL(),
new StateActionSetterDTO(capabilityId, CapabilityDTO.TYPE_SWITCHACTUATOR, state));
}
/**
* Sets the dimmer level of a DimmerActuator.
*/
public void setDimmerActuatorState(final String capabilityId, final int dimLevel) throws IOException {
executePost(createActionURL(),
new StateActionSetterDTO(capabilityId, CapabilityDTO.TYPE_DIMMERACTUATOR, dimLevel));
}
/**
* Sets the roller shutter level of a RollerShutterActuator.
*/
public void setRollerShutterActuatorState(final String capabilityId, final int rollerShutterLevel)
throws IOException {
executePost(createActionURL(),
new StateActionSetterDTO(capabilityId, CapabilityDTO.TYPE_ROLLERSHUTTERACTUATOR, rollerShutterLevel));
}
/**
* Starts or stops moving a RollerShutterActuator
*/
public void setRollerShutterAction(final String capabilityId, final ShutterActionType rollerShutterAction)
throws IOException {
executePost(createActionURL(), new ShutterActionDTO(capabilityId, rollerShutterAction));
}
/**
* Sets a new state of a VariableActuator.
*/
public void setVariableActuatorState(final String capabilityId, final boolean state) throws IOException {
executePost(createActionURL(),
new StateActionSetterDTO(capabilityId, CapabilityDTO.TYPE_VARIABLEACTUATOR, state));
}
/**
* Sets the point temperature.
*/
public void setPointTemperatureState(final String capabilityId, final double pointTemperature) throws IOException {
executePost(createActionURL(),
new StateActionSetterDTO(capabilityId, CapabilityDTO.TYPE_THERMOSTATACTUATOR, pointTemperature));
}
/**
* Sets the operation mode to "Auto" or "Manu".
*/
public void setOperationMode(final String capabilityId, final boolean isAutoMode) throws IOException {
executePost(createActionURL(),
new StateActionSetterDTO(capabilityId, CapabilityDTO.TYPE_THERMOSTATACTUATOR, isAutoMode));
}
/**
* Sets the alarm state.
*/
public void setAlarmActuatorState(final String capabilityId, final boolean alarmState) throws IOException {
executePost(createActionURL(),
new StateActionSetterDTO(capabilityId, CapabilityDTO.TYPE_ALARMACTUATOR, alarmState));
}
/**
* Load the device and returns a {@link List} of {@link DeviceDTO}s.
* VariableActuators are returned additionally (independent from the device ids),
* because VariableActuators are everytime available and never have a device state.
*
* @param deviceIds Ids of the devices to return
* @return List of Devices
*/
public List<DeviceDTO> getDevices(Collection<String> deviceIds) throws IOException {
logger.debug("Loading LIVISI SmartHome devices...");
List<DeviceDTO> devices = executeGetList(URLCreator.createDevicesURL(bridgeConfiguration.host),
DeviceDTO[].class);
return devices.stream().filter(d -> isDeviceUsable(d, deviceIds)).collect(Collectors.toList());
}
/**
* Loads the {@link DeviceDTO} with the given deviceId.
*/
public Optional<DeviceDTO> getDeviceById(final String deviceId) throws IOException {
logger.debug("Loading device with id {}...", deviceId);
return executeGet(URLCreator.createDeviceURL(bridgeConfiguration.host, deviceId), DeviceDTO.class);
}
/**
* Loads the states for all {@link DeviceDTO}s.
*/
public List<DeviceStateDTO> getDeviceStates() throws IOException {
logger.debug("Loading device states...");
return executeGetList(URLCreator.createDeviceStatesURL(bridgeConfiguration.host), DeviceStateDTO[].class);
}
/**
* Loads the device state for the given deviceId.
*/
public @Nullable StateDTO getDeviceStateByDeviceId(final String deviceId, final boolean isSHCClassic)
throws IOException {
logger.debug("Loading device states for device id {}...", deviceId);
if (isSHCClassic) {
Optional<DeviceStateDTO> deviceState = executeGet(
URLCreator.createDeviceStateURL(bridgeConfiguration.host, deviceId), DeviceStateDTO.class);
return deviceState.map(DeviceStateDTO::getState).orElse(null);
}
return executeGet(URLCreator.createDeviceStateURL(bridgeConfiguration.host, deviceId), StateDTO.class)
.orElse(null);
}
/**
* Loads the locations and returns a {@link List} of {@link LocationDTO}s.
*
* @return a List of Devices
*/
public List<LocationDTO> getLocations() throws IOException {
logger.debug("Loading locations...");
return executeGetList(URLCreator.createLocationURL(bridgeConfiguration.host), LocationDTO[].class);
}
/**
* Loads and returns a {@link List} of {@link CapabilityDTO}s for the given deviceId.
*
* @param deviceId the id of the {@link DeviceDTO}
* @return capabilities of the device
*/
public List<CapabilityDTO> getCapabilitiesForDevice(final String deviceId) throws IOException {
logger.debug("Loading capabilities for device {}...", deviceId);
return executeGetList(URLCreator.createDeviceCapabilitiesURL(bridgeConfiguration.host, deviceId),
CapabilityDTO[].class);
}
/**
* Loads and returns a {@link List} of all {@link CapabilityDTO}s.
*/
public List<CapabilityDTO> getCapabilities() throws IOException {
logger.debug("Loading capabilities...");
return executeGetList(URLCreator.createCapabilityURL(bridgeConfiguration.host), CapabilityDTO[].class);
}
/**
* Loads and returns a {@link List} of all {@link CapabilityDTO}States.
*/
public List<CapabilityStateDTO> getCapabilityStates() throws IOException {
logger.debug("Loading capability states...");
return executeGetList(URLCreator.createCapabilityStatesURL(bridgeConfiguration.host),
CapabilityStateDTO[].class);
}
/**
* Returns a {@link List} of all {@link MessageDTO}s.
*/
public List<MessageDTO> getMessages() throws IOException {
logger.debug("Loading messages...");
return executeGetList(URLCreator.createMessageURL(bridgeConfiguration.host), MessageDTO[].class);
}
private String createActionURL() {
return URLCreator.createActionURL(bridgeConfiguration.host);
}
/**
* Decides if a (discovered) device is usable (available and supported).
*
* @param device device to check
* @param activeDeviceIds active device id (devices with an according available device state)
* @return true when usable, otherwise false
*/
private static boolean isDeviceUsable(DeviceDTO device, Collection<String> activeDeviceIds) {
return activeDeviceIds.contains(device.getId())
|| LivisiBindingConstants.DEVICE_VARIABLE_ACTUATOR.equals(device.getType());
}
/**
* Normalizes the JSON response content.
* The LIVISI SmartHome local API returns "[]" for missing objects instead of "null". This method fixes
* this issue.
*
* @param responseContent response
* @return normalized response content
*/
private static String normalizeResponseContent(String responseContent) {
return responseContent.replace("[]", "null");
}
}

View File

@ -0,0 +1,54 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.openhab.core.auth.client.oauth2.AccessTokenResponse;
/**
* The {@link URLConnectionFactory} is responsible for creating requests / connections.
* This is useful to avoid real connections in test mode (via replacing it with mocks).
*
* @author Sven Strohschein - Initial contribution
*/
@NonNullByDefault
public class URLConnectionFactory {
public static final String CONTENT_TYPE = "application/json";
public static final int HTTP_REQUEST_TIMEOUT_MILLISECONDS = 10000;
private static final String BEARER = "Bearer ";
public HttpURLConnection createRequest(String url) throws IOException {
return (HttpURLConnection) new URL(url).openConnection();
}
public HttpURLConnection createBaseRequest(String url, HttpMethod httpMethod,
AccessTokenResponse accessTokenResponse) throws IOException {
HttpURLConnection urlConnection = createRequest(url);
urlConnection.setRequestMethod(httpMethod.asString());
urlConnection.setRequestProperty(HttpHeader.ACCEPT.asString(), CONTENT_TYPE);
urlConnection.setRequestProperty(HttpHeader.AUTHORIZATION.asString(),
BEARER + accessTokenResponse.getAccessToken());
urlConnection.setConnectTimeout(HTTP_REQUEST_TIMEOUT_MILLISECONDS);
urlConnection.setReadTimeout(HTTP_REQUEST_TIMEOUT_MILLISECONDS);
return urlConnection;
}
}

View File

@ -0,0 +1,93 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link URLCreator} is responsible for creating all required URLs.
*
* @author Sven Strohschein - Initial contribution
*/
@NonNullByDefault
public final class URLCreator {
private URLCreator() {
}
public static String createTokenURL(String host) {
return createAddress(host) + "/auth/token";
}
public static String createDevicesURL(String host) {
return createAddress(host) + "/device";
}
public static String createDeviceStatesURL(String host) {
return createAddress(host) + "/device/states";
}
public static String createDeviceURL(String host, String deviceId) {
return createAddress(host) + "/device/" + deviceId;
}
public static String createDeviceStateURL(String host, String deviceId) {
return createAddress(host) + "/device/" + deviceId + "/state";
}
public static String createDeviceCapabilitiesURL(String host, String deviceId) {
return createAddress(host) + "/device/" + deviceId + "/capabilities";
}
public static String createCapabilityURL(String host) {
return createAddress(host) + "/capability";
}
public static String createCapabilityStatesURL(String host) {
return createAddress(host) + "/capability/states";
}
public static String createActionURL(String host) {
return createAddress(host) + "/action";
}
public static String createStatusURL(String host) {
return createAddress(host) + "/status";
}
public static String createLocationURL(String host) {
return createAddress(host) + "/location";
}
public static String createMessageURL(String host) {
return createAddress(host) + "/message";
}
public static String createEventsURL(String host, String token, boolean isClassicController) {
final String tokenURLEncoded = URLEncoder.encode(token, StandardCharsets.UTF_8);
final String webSocketPort;
if (isClassicController) {
webSocketPort = "8080";
} else {
webSocketPort = "9090";
}
return "ws://" + host + ':' + webSocketPort + "/events?token=" + tokenURLEncoded;
}
private static String createAddress(String host) {
return "http://" + host + ":8080";
}
}

View File

@ -0,0 +1,41 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Utility class with commonly used methods.
*
* @author Oliver Kuhl - Initial contribution
*
*/
@NonNullByDefault
public final class Util {
private Util() {
}
/**
* Converts an ISO offset date-time string to a {@link ZonedDateTime}
*
* @param dateTimeString date-time string
* @return {@link ZonedDateTime}
*/
public static ZonedDateTime timeStringToDate(String dateTimeString) {
return ZonedDateTime.parse(dateTimeString, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
}
}

View File

@ -0,0 +1,52 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity;
/**
* Defines a {@link PropertyDTO}, that is a basic key/value structure used for several data types in the LIVISI API.
*
* @author Oliver Kuhl - Initial contribution
*/
public class PropertyDTO {
private String name;
private Object value;
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the value
*/
public Object getValue() {
return value;
}
/**
* @param value the value to set
*/
public void setValue(Object value) {
this.value = value;
}
}

View File

@ -0,0 +1,45 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity;
import org.openhab.binding.livisismarthome.internal.client.api.entity.device.GatewayDTO;
/**
* Defines the structure of the status response
*
* @author Oliver Kuhl - Initial contribution
*/
public class StatusResponseDTO {
/**
* The LIVISI SmartHome gateway. Can be null in case there is no registered for the current logged in user.
*/
private GatewayDTO gateway;
/**
* Version of the configuration. Changes each time the configuration was changed via the LIVISI client app.
*/
private String configVersion;
/**
* @return the configuration version
*/
public String getConfigVersion() {
// SHC 2 returns a gateway element with the config version.
if (gateway != null) {
return gateway.getConfigVersion();
}
// SHC 1 (classic) has no gateway element, the configVersion is returned directly within the response object.
return configVersion;
}
}

View File

@ -0,0 +1,118 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.action;
import org.openhab.binding.livisismarthome.internal.client.api.entity.link.LinkDTO;
/**
* Implements the Action structure needed to send JSON actions to the LIVISI backend. They are used to e.g. switch the
* state of a device.
*
* @author Oliver Kuhl - Initial contribution
*/
public class ActionDTO {
private static final String NAMESPACE_CORE_RWE = "core.RWE";
/**
* Specifies the type of the action.
*/
private String type;
/**
* Link to the entity supposed to execute the action.
*/
private String target;
/**
* The product (context) that should handle (execute) the action. Defaults to {@link ActionDTO#NAMESPACE_CORE_RWE}.
*/
private String namespace = NAMESPACE_CORE_RWE;
/**
* Dictionary of functions required for the intended execution of the action.
*/
private ActionParamsDTO params;
/**
* Default constructor, used by serialization.
*/
public ActionDTO() {
// used by serialization
}
/**
* @return the type
*/
public String getType() {
return type;
}
/**
* @param type the type to set
*/
public void setType(String type) {
this.type = type;
}
/**
* @return the link to the target capability
*/
public String getTarget() {
return target;
}
/**
* @param target the link to the target capability to set
*/
public void setTarget(String target) {
this.target = target;
}
/**
* @return the namespace
*/
public String getNamespace() {
return namespace;
}
/**
* @param namespace the namespace to set
*/
public void setNamespace(String namespace) {
this.namespace = namespace;
}
/**
* Sets the link target to the given capability id.
*
* @param capabilityId String with the 32 character long id
*/
public void setTargetCapabilityById(String capabilityId) {
setTarget(LinkDTO.LINK_TYPE_CAPABILITY + capabilityId);
}
/**
* @return the params
*/
public ActionParamsDTO getParams() {
return params;
}
/**
* @param params the params to set
*/
public void setParams(ActionParamsDTO params) {
this.params = params;
}
}

View File

@ -0,0 +1,129 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.action;
/**
* Defines the {@link ActionParamsDTO} data structure needed to pass parameters within an {@link ActionDTO} to the
* Livisi
* SmartHome backend.
*
* @author Oliver Kuhl - Initial contribution
*/
public class ActionParamsDTO {
private BooleanActionParamDTO onState;
private BooleanActionParamDTO value;
private DoubleActionParamDTO pointTemperature;
private IntegerActionParamDTO dimLevel;
private IntegerActionParamDTO shutterLevel;
private StringActionParamDTO operationMode;
private StringActionParamDTO rampDirection;
/**
* @return the onState
*/
public BooleanActionParamDTO getOnState() {
return onState;
}
/**
* @param state the state to set
*/
public void setOnState(BooleanActionParamDTO state) {
this.onState = state;
}
/**
* @return the onState
*/
public BooleanActionParamDTO getValue() {
return value;
}
/**
* @param state the state to set
*/
public void setValue(BooleanActionParamDTO state) {
this.value = state;
}
/**
* @return the pointTemperature
*/
public DoubleActionParamDTO getPointTemperature() {
return pointTemperature;
}
/**
* @param pointTemperature the pointTemperature to set
*/
public void setPointTemperature(DoubleActionParamDTO pointTemperature) {
this.pointTemperature = pointTemperature;
}
/**
* @return the dimLevel
*/
public IntegerActionParamDTO getDimLevel() {
return dimLevel;
}
/**
* @param dimLevel the dimLevel to set
*/
public void setDimLevel(IntegerActionParamDTO dimLevel) {
this.dimLevel = dimLevel;
}
/**
* @return the shutterLevel
*/
public IntegerActionParamDTO getShutterLevel() {
return shutterLevel;
}
/**
* @param shutterLevel the shutterLevel to set
*/
public void setShutterLevel(IntegerActionParamDTO shutterLevel) {
this.shutterLevel = shutterLevel;
}
/**
* @return the operationMode
*/
public StringActionParamDTO getOperationMode() {
return operationMode;
}
/**
* @param operationMode the operationMode to set
*/
public void setOperationMode(StringActionParamDTO operationMode) {
this.operationMode = operationMode;
}
/**
* @return the rampDirection
*/
public StringActionParamDTO getRampDirection() {
return rampDirection;
}
/**
* @param rampDirection the rampDirection to set
*/
public void setRampDirection(StringActionParamDTO rampDirection) {
this.rampDirection = rampDirection;
}
}

View File

@ -0,0 +1,57 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.action;
/**
* Defines the structure of a {@link BooleanActionParamDTO}.
*
* @author Oliver Kuhl - Initial contribution
*/
public class BooleanActionParamDTO {
private String type;
private boolean value;
BooleanActionParamDTO(String type, boolean value) {
this.type = type;
this.value = value;
}
/**
* @return the type
*/
public String getType() {
return type;
}
/**
* @param type the type to set
*/
public void setType(String type) {
this.type = type;
}
/**
* @return the value
*/
public boolean isValue() {
return value;
}
/**
* @param value the value to set
*/
public void setValue(boolean value) {
this.value = value;
}
}

View File

@ -0,0 +1,57 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.action;
/**
* Defines the structure of a {@link DoubleActionParamDTO}.
*
* @author Oliver Kuhl - Initial contribution
*/
public class DoubleActionParamDTO {
private String type;
private double value;
DoubleActionParamDTO(String type, double value) {
this.type = type;
this.value = value;
}
/**
* @return the type
*/
public String getType() {
return type;
}
/**
* @param type the type to set
*/
public void setType(String type) {
this.type = type;
}
/**
* @return the value
*/
public double isValue() {
return value;
}
/**
* @param value the value to set
*/
public void setValue(double value) {
this.value = value;
}
}

View File

@ -0,0 +1,57 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.action;
/**
* Defines the structure of a {@link IntegerActionParamDTO}.
*
* @author Oliver Kuhl - Initial contribution
*/
public class IntegerActionParamDTO {
private String type;
private int value;
IntegerActionParamDTO(String type, int value) {
this.type = type;
this.value = value;
}
/**
* @return the type
*/
public String getType() {
return type;
}
/**
* @param type the type to set
*/
public void setType(String type) {
this.type = type;
}
/**
* @return the value
*/
public int isValue() {
return value;
}
/**
* @param value the value to set
*/
public void setValue(int value) {
this.value = value;
}
}

View File

@ -0,0 +1,51 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.action;
/**
* Special {@link ActionDTO} needed to control shutters.
*
* @author Marco Mans - Initial contribution
*/
public class ShutterActionDTO extends ActionDTO {
private static final String TYPE_STOP_RAMP = "StopRamp";
private static final String TYPE_START_RAMP = "StartRamp";
private static final String DIRECTION_RAMP_UP = "RampUp";
private static final String DIRECTION_RAMP_DOWN = "RampDown";
private static final String CONSTANT = "Constant";
private static final String NAMESPACE_COSIP = "CosipDevices.RWE";
/**
* Describes a Shutteraction
*
* @param capabilityId String of the 32 character capability id
* @param action Which action to perform (UP, DOWN, STOP)
*/
public ShutterActionDTO(String capabilityId, ShutterActionType action) {
setTargetCapabilityById(capabilityId);
setNamespace(NAMESPACE_COSIP);
final ActionParamsDTO params = new ActionParamsDTO();
if (ShutterActionType.STOP.equals(action)) {
setType(TYPE_STOP_RAMP);
} else if (ShutterActionType.UP.equals(action)) {
setType(TYPE_START_RAMP);
params.setRampDirection(new StringActionParamDTO(CONSTANT, DIRECTION_RAMP_UP));
} else if (ShutterActionType.DOWN.equals(action)) {
setType(TYPE_START_RAMP);
params.setRampDirection(new StringActionParamDTO(CONSTANT, DIRECTION_RAMP_DOWN));
}
setParams(params);
}
}

View File

@ -0,0 +1,25 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.action;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* @author Sven Strohschein - Initial contribution
*/
@NonNullByDefault
public enum ShutterActionType {
UP,
DOWN,
STOP
}

View File

@ -0,0 +1,97 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.action;
import org.openhab.binding.livisismarthome.internal.client.api.entity.capability.CapabilityDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.capability.CapabilityStateDTO;
/**
* Special {@link ActionDTO} needed to set a state of a device.
*
* @author Oliver Kuhl - Initial contribution
*/
public class StateActionSetterDTO extends ActionDTO {
private static final String CONSTANT = "Constant";
private static final String ACTION_TYPE_SETSTATE = "SetState";
/**
* Constructs a new {@link StateActionSetterDTO}.
*
* @param capabilityId String of the 32 character capability id
* @param capabilityType the type of the {@link CapabilityDTO}, {@link CapabilityDTO#TYPE_SWITCHACTUATOR} or
* {@link CapabilityDTO#TYPE_VARIABLEACTUATOR}
* @param state the new state as boolean (true=on, false=off)
*/
public StateActionSetterDTO(String capabilityId, String capabilityType, boolean state) {
setType(ACTION_TYPE_SETSTATE);
setTargetCapabilityById(capabilityId);
final ActionParamsDTO params = new ActionParamsDTO();
if (CapabilityDTO.TYPE_SWITCHACTUATOR.equals(capabilityType)) {
params.setOnState(new BooleanActionParamDTO(CONSTANT, state));
} else if (CapabilityDTO.TYPE_VARIABLEACTUATOR.equals(capabilityType)) {
params.setValue(new BooleanActionParamDTO(CONSTANT, state));
} else if (CapabilityDTO.TYPE_ALARMACTUATOR.equals(capabilityType)) {
params.setOnState(new BooleanActionParamDTO(CONSTANT, state));
} else if (CapabilityDTO.TYPE_THERMOSTATACTUATOR.equals(capabilityType)) {
final String operationMode;
if (state) {
operationMode = CapabilityStateDTO.STATE_VALUE_OPERATION_MODE_AUTO;
} else {
operationMode = CapabilityStateDTO.STATE_VALUE_OPERATION_MODE_MANUAL;
}
params.setOperationMode(new StringActionParamDTO(CONSTANT, operationMode));
}
setParams(params);
}
/**
* Constructs a new {@link StateActionSetterDTO}.
*
* @param capabilityId String of the 32 character capability id
* @param capabilityType the type of the {@link CapabilityDTO}, {@link CapabilityDTO#TYPE_THERMOSTATACTUATOR}
* @param newValue the new double value
*/
public StateActionSetterDTO(String capabilityId, String capabilityType, double newValue) {
setType(ACTION_TYPE_SETSTATE);
setTargetCapabilityById(capabilityId);
final ActionParamsDTO params = new ActionParamsDTO();
if (CapabilityDTO.TYPE_THERMOSTATACTUATOR.equals(capabilityType)) {
params.setPointTemperature(new DoubleActionParamDTO(CONSTANT, newValue));
}
setParams(params);
}
/**
* Constructs a new {@link StateActionSetterDTO}.
*
* @param capabilityId String of the 32 character capability id
* @param capabilityType the type of the {@link CapabilityDTO}, {@link CapabilityDTO#TYPE_DIMMERACTUATOR}
* @param newValue the new int value
*/
public StateActionSetterDTO(String capabilityId, String capabilityType, int newValue) {
setType(ACTION_TYPE_SETSTATE);
setTargetCapabilityById(capabilityId);
final ActionParamsDTO params = new ActionParamsDTO();
if (CapabilityDTO.TYPE_DIMMERACTUATOR.equals(capabilityType)) {
params.setDimLevel(new IntegerActionParamDTO(CONSTANT, newValue));
} else if (CapabilityDTO.TYPE_ROLLERSHUTTERACTUATOR.equals(capabilityType)) {
params.setShutterLevel(new IntegerActionParamDTO(CONSTANT, newValue));
}
setParams(params);
}
}

View File

@ -0,0 +1,57 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.action;
/**
* Defines the structure of a {@link StringActionParamDTO}.
*
* @author Oliver Kuhl - Initial contribution
*/
public class StringActionParamDTO {
private String type;
private String value;
StringActionParamDTO(String type, String value) {
this.type = type;
this.value = value;
}
/**
* @return the type
*/
public String getType() {
return type;
}
/**
* @param type the type to set
*/
public void setType(String type) {
this.type = type;
}
/**
* @return the value
*/
public String isValue() {
return value;
}
/**
* @param value the value to set
*/
public void setValue(String value) {
this.value = value;
}
}

View File

@ -0,0 +1,639 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.capability;
/**
* Holds the Capability configuration.
*
* @author Oliver Kuhl - Initial contribution
*
*/
public class CapabilityConfigDTO {
/**
* Name of the capability
*/
private String name;
/**
* Specifies if the activity logging is enabled
*/
private Boolean activityLogActive;
/**
* Specifies if the activity logging is enabled
*/
private Integer pushButtons;
/**
* The valve index
*/
private Integer valveIndex;
/**
* The valve type
*/
private String valveType;
/**
* The valve control mode: Heating or Cooling
*/
private String controlMode;
/**
* Dimmer: Programmed on the device as maximum/minimum and not used for UI representation
*/
private Integer technicalMaxValue;
/**
* Dimmer: Programmed on the device as maximum/minimum and not used for UI representation
*/
private Integer technicalMinValue;
/**
* Rollershutter: How long it takes for the shutter to open completely when it's completely closed (in tenth of
* second)
*/
private Integer timeFullUp;
/**
* Rollershutter: How long it takes for the shutter to close completely when it's completely open (in tenth of
* second)
*/
private Integer timeFullDown;
/**
* Rollershutter: Flag indicating the ISR is in the calibration mode or not.
*/
private Boolean isCalibrating;
/**
* Switchactuator:
* "different types of current sensing behavior the ISS can have:
* Enabled - Factory default value, current sensing is enabled; (default)
* DisabledNormal - Current sensing disabled, uses output 1;
* DisabledReversed - Current sensing disabled, uses output 2"
*/
private String sensingBehavior;
/**
* Thermostatactuator: The max temperature
*/
private Double maxTemperature;
/**
* Thermostatactuator: The min temperature
*/
private Double minTemperature;
/**
* Thermostatactuator: Indicating whether the device is locked
*/
private Boolean childLock;
/**
* Thermostatactuator: The window open temperature
*/
private Double windowOpenTemperature;
/**
* Thermostatactuator: default PointTemperature
*/
private String vRCCSetPoint;
/**
* Temperaturesensor: Indicating whether the device has freeze protection activated
*/
private Boolean isFreezeProtectionActivated;
/**
* Temperaturesensor: The freeze protection temperature, default 6 °C
*/
private Double freezeProtection;
/**
* Temperaturesensor: default Temperature
*/
private String vRCCTemperature;
/**
* HumiditySensor: Indicating whether the device has mold protection activated
*/
private Boolean isMoldProtectionActivated;
/**
* HumiditySensor: The humidity mold protection
*/
private Double humidityMoldProtection;
/**
* HumiditySensor: default Humidity
*/
private String vRCCHumidity;
/**
* SirenActuator: Alarm Sound Id
*/
private String alarmSoundId;
/**
* SirenActuator: Notification Sound Id
*/
private String notificationSoundId;
/**
* SirenActuator: Feedback Sound Id
*/
private String feedbackSoundId;
/**
* RoomSetPoint/RoomTemperature/RoomHumidity: List of capability ids, which are linked to the VRCC
*/
private String underlyingCapabilityIds;
/**
* WindowsDoorSensor: Time before the changed status is sent after the window/door is opened (in seconds)
*/
private Integer eventFilterTime;
/**
* Medion ThermostatActuator: Specifies the temperature threshold that will denote a window open event. 0 = window
* reduction disabled 1-12 = 1/12 °C, 2/12 °C,, 12/12 °C
*/
private Integer windowOpenThreshold;
/**
* Medion ThermostatActuator: Duration in minutes for how long after the threshold was overstepped the valve will be
* closed (target temperature = OFF). After the set time, the temperature will jump back to the previous set target
* temperature.
*/
private Integer windowOpenTimer;
/**
* Medion MotionDetectionSensor sensitivityControl
*/
private Integer sensitivityControl;
/**
* Medion WindowDoorShockSensor: shockDetectorThreshold
*/
private Integer shockDetectorThreshold;
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(final String name) {
this.name = name;
}
/**
* @return the activityLogActive
*/
public Boolean getActivityLogActive() {
return activityLogActive;
}
/**
* @param activityLogActive the activityLogActive to set
*/
public void setActivityLogActive(final Boolean activityLogActive) {
this.activityLogActive = activityLogActive;
}
/**
* @return the pushButtons
*/
public Integer getPushButtons() {
return pushButtons;
}
/**
* @param pushButtons the pushButtons to set
*/
public void setPushButtons(final Integer pushButtons) {
this.pushButtons = pushButtons;
}
/**
* @return the valveIndex
*/
public Integer getValveIndex() {
return valveIndex;
}
/**
* @param valveIndex the valveIndex to set
*/
public void setValveIndex(final Integer valveIndex) {
this.valveIndex = valveIndex;
}
/**
* @return the valveType
*/
public String getValveType() {
return valveType;
}
/**
* @param valveType the valveType to set
*/
public void setValveType(final String valveType) {
this.valveType = valveType;
}
/**
* @return the controlMode
*/
public String getControlMode() {
return controlMode;
}
/**
* @param controlMode the controlMode to set
*/
public void setControlMode(final String controlMode) {
this.controlMode = controlMode;
}
/**
* @return the technicalMaxValue
*/
public Integer getTechnicalMaxValue() {
return technicalMaxValue;
}
/**
* @param technicalMaxValue the technicalMaxValue to set
*/
public void setTechnicalMaxValue(final Integer technicalMaxValue) {
this.technicalMaxValue = technicalMaxValue;
}
/**
* @return the technicalMinValue
*/
public Integer getTechnicalMinValue() {
return technicalMinValue;
}
/**
* @param technicalMinValue the technicalMinValue to set
*/
public void setTechnicalMinValue(final Integer technicalMinValue) {
this.technicalMinValue = technicalMinValue;
}
/**
* @return the timeFullUp
*/
public Integer getTimeFullUp() {
return timeFullUp;
}
/**
* @param timeFullUp the timeFullUp to set
*/
public void setTimeFullUp(final Integer timeFullUp) {
this.timeFullUp = timeFullUp;
}
/**
* @return the timeFullDown
*/
public Integer getTimeFullDown() {
return timeFullDown;
}
/**
* @param timeFullDown the timeFullDown to set
*/
public void setTimeFullDown(final Integer timeFullDown) {
this.timeFullDown = timeFullDown;
}
/**
* @return the isCalibrating
*/
public Boolean getIsCalibrating() {
return isCalibrating;
}
/**
* @param isCalibrating the isCalibrating to set
*/
public void setIsCalibrating(final Boolean isCalibrating) {
this.isCalibrating = isCalibrating;
}
/**
* @return the sensingBehavior
*/
public String getSensingBehavior() {
return sensingBehavior;
}
/**
* @param sensingBehavior the sensingBehavior to set
*/
public void setSensingBehavior(final String sensingBehavior) {
this.sensingBehavior = sensingBehavior;
}
/**
* @return the maxTemperature
*/
public Double getMaxTemperature() {
return maxTemperature;
}
/**
* @param maxTemperature the maxTemperature to set
*/
public void setMaxTemperature(final Double maxTemperature) {
this.maxTemperature = maxTemperature;
}
/**
* @return the minTemperature
*/
public Double getMinTemperature() {
return minTemperature;
}
/**
* @param minTemperature the minTemperature to set
*/
public void setMinTemperature(final Double minTemperature) {
this.minTemperature = minTemperature;
}
/**
* @return the childLock
*/
public Boolean getChildLock() {
return childLock;
}
/**
* @param childLock the childLock to set
*/
public void setChildLock(final Boolean childLock) {
this.childLock = childLock;
}
/**
* @return the windowOpenTemperature
*/
public Double getWindowOpenTemperature() {
return windowOpenTemperature;
}
/**
* @param windowOpenTemperature the windowOpenTemperature to set
*/
public void setWindowOpenTemperature(final Double windowOpenTemperature) {
this.windowOpenTemperature = windowOpenTemperature;
}
/**
* @return the vRCCSetPoint
*/
public String getvRCCSetPoint() {
return vRCCSetPoint;
}
/**
* @param vRCCSetPoint the vRCCSetPoint to set
*/
public void setvRCCSetPoint(final String vRCCSetPoint) {
this.vRCCSetPoint = vRCCSetPoint;
}
/**
* @return the isFreezeProtectionActivated
*/
public Boolean getIsFreezeProtectionActivated() {
return isFreezeProtectionActivated;
}
/**
* @param isFreezeProtectionActivated the isFreezeProtectionActivated to set
*/
public void setIsFreezeProtectionActivated(final Boolean isFreezeProtectionActivated) {
this.isFreezeProtectionActivated = isFreezeProtectionActivated;
}
/**
* @return the freezeProtection
*/
public Double getFreezeProtection() {
return freezeProtection;
}
/**
* @param freezeProtection the freezeProtection to set
*/
public void setFreezeProtection(final Double freezeProtection) {
this.freezeProtection = freezeProtection;
}
/**
* @return the vRCCTemperature
*/
public String getvRCCTemperature() {
return vRCCTemperature;
}
/**
* @param vRCCTemperature the vRCCTemperature to set
*/
public void setvRCCTemperature(final String vRCCTemperature) {
this.vRCCTemperature = vRCCTemperature;
}
/**
* @return the isMoldProtectionActivated
*/
public Boolean getIsMoldProtectionActivated() {
return isMoldProtectionActivated;
}
/**
* @param isMoldProtectionActivated the isMoldProtectionActivated to set
*/
public void setIsMoldProtectionActivated(final Boolean isMoldProtectionActivated) {
this.isMoldProtectionActivated = isMoldProtectionActivated;
}
/**
* @return the humidityMoldProtection
*/
public Double getHumidityMoldProtection() {
return humidityMoldProtection;
}
/**
* @param humidityMoldProtection the humidityMoldProtection to set
*/
public void setHumidityMoldProtection(final Double humidityMoldProtection) {
this.humidityMoldProtection = humidityMoldProtection;
}
/**
* @return the vRCCHumidity
*/
public String getvRCCHumidity() {
return vRCCHumidity;
}
/**
* @param vRCCHumidity the vRCCHumidity to set
*/
public void setvRCCHumidity(final String vRCCHumidity) {
this.vRCCHumidity = vRCCHumidity;
}
/**
* @return the alarmSoundId
*/
public String getAlarmSoundId() {
return alarmSoundId;
}
/**
* @param alarmSoundId the alarmSoundId to set
*/
public void setAlarmSoundId(final String alarmSoundId) {
this.alarmSoundId = alarmSoundId;
}
/**
* @return the notificationSoundId
*/
public String getNotificationSoundId() {
return notificationSoundId;
}
/**
* @param notificationSoundId the notificationSoundId to set
*/
public void setNotificationSoundId(final String notificationSoundId) {
this.notificationSoundId = notificationSoundId;
}
/**
* @return the feedbackSoundId
*/
public String getFeedbackSoundId() {
return feedbackSoundId;
}
/**
* @param feedbackSoundId the feedbackSoundId to set
*/
public void setFeedbackSoundId(final String feedbackSoundId) {
this.feedbackSoundId = feedbackSoundId;
}
/**
* @return the underlyingCapabilityIds
*/
public String getUnderlyingCapabilityIds() {
return underlyingCapabilityIds;
}
/**
* @param underlyingCapabilityIds the underlyingCapabilityIds to set
*/
public void setUnderlyingCapabilityIds(final String underlyingCapabilityIds) {
this.underlyingCapabilityIds = underlyingCapabilityIds;
}
/**
* @return the eventFilterTime
*/
public Integer getEventFilterTime() {
return eventFilterTime;
}
/**
* @param eventFilterTime the eventFilterTime to set
*/
public void setEventFilterTime(final Integer eventFilterTime) {
this.eventFilterTime = eventFilterTime;
}
/**
* @return the windowOpenThreshold
*/
public Integer getWindowOpenThreshold() {
return windowOpenThreshold;
}
/**
* @param windowOpenThreshold the windowOpenThreshold to set
*/
public void setWindowOpenThreshold(final Integer windowOpenThreshold) {
this.windowOpenThreshold = windowOpenThreshold;
}
/**
* @return the windowOpenTimer
*/
public Integer getWindowOpenTimer() {
return windowOpenTimer;
}
/**
* @param windowOpenTimer the windowOpenTimer to set
*/
public void setWindowOpenTimer(final Integer windowOpenTimer) {
this.windowOpenTimer = windowOpenTimer;
}
/**
* @return the sensitivityControl
*/
public Integer getSensitivityControl() {
return sensitivityControl;
}
/**
* @param sensitivityControl the sensitivityControl to set
*/
public void setSensitivityControl(final Integer sensitivityControl) {
this.sensitivityControl = sensitivityControl;
}
/**
* @return the shockDetectorThreshold
*/
public Integer getShockDetectorThreshold() {
return shockDetectorThreshold;
}
/**
* @param shockDetectorThreshold the shockDetectorThreshold to set
*/
public void setShockDetectorThreshold(final Integer shockDetectorThreshold) {
this.shockDetectorThreshold = shockDetectorThreshold;
}
}

View File

@ -0,0 +1,331 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.capability;
/**
* Defines the structure of a {@link CapabilityDTO}. A capability is a specific functionality of a device like a
* temperature sensor.
*
* @author Oliver Kuhl - Initial contribution
*/
public class CapabilityDTO {
/** capability types */
public static final String TYPE_SWITCHACTUATOR = "SwitchActuator";
public static final String TYPE_VARIABLEACTUATOR = "BooleanStateActuator";
public static final String TYPE_THERMOSTATACTUATOR = "ThermostatActuator";
public static final String TYPE_TEMPERATURESENSOR = "TemperatureSensor";
public static final String TYPE_HUMIDITYSENSOR = "HumiditySensor";
public static final String TYPE_WINDOWDOORSENSOR = "WindowDoorSensor";
public static final String TYPE_SMOKEDETECTORSENSOR = "SmokeDetectorSensor";
public static final String TYPE_ALARMACTUATOR = "AlarmActuator";
public static final String TYPE_MOTIONDETECTIONSENSOR = "MotionDetectionSensor";
public static final String TYPE_LUMINANCESENSOR = "LuminanceSensor";
public static final String TYPE_PUSHBUTTONSENSOR = "PushButtonSensor";
public static final String TYPE_DIMMERACTUATOR = "DimmerActuator";
public static final String TYPE_ROLLERSHUTTERACTUATOR = "RollerShutterActuator";
public static final String TYPE_ENERGYCONSUMPTIONSENSOR = "EnergyConsumptionSensor";
public static final String TYPE_POWERCONSUMPTIONSENSOR = "PowerConsumptionSensor";
public static final String TYPE_GENERATIONMETERENERGYSENSOR = "GenerationMeterEnergySensor";
public static final String TYPE_GENERATIONMETERPOWERCONSUMPTIONSENSOR = "GenerationMeterPowerConsumptionSensor";
public static final String TYPE_TWOWAYMETERENERGYCONSUMPTIONSENSOR = "TwoWayMeterEnergyConsumptionSensor";
public static final String TYPE_TWOWAYMETERENERGYFEEDSENSOR = "TwoWayMeterEnergyFeedSensor";
public static final String TYPE_TWOWAYMETERPOWERCONSUMPTIONSENSOR = "TwoWayMeterPowerConsumptionSensor";
/**
* Unique id for the Capability.
*/
private String id;
/**
* Type of the capability must be unique per device, since the device links to the capability via the type.
*/
private String type;
/**
* Contains the link to the parent device, which offers the capability.
*/
private String device;
/**
* This represents a container of all configuration properties.
*/
private CapabilityConfigDTO config;
private CapabilityStateDTO capabilityState;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getDeviceLink() {
return device;
}
public void setDeviceLink(String deviceLink) {
this.device = deviceLink;
}
public CapabilityConfigDTO getConfig() {
return config;
}
public void setConfig(CapabilityConfigDTO config) {
this.config = config;
}
/**
* Returns the {@link CapabilityStateDTO}. Only available, if capability has a state. Better check with
* {@link CapabilityDTO#hasState()} first!
*
* @return the capabilityState or null
*/
public CapabilityStateDTO getCapabilityState() {
return capabilityState;
}
/**
* @param capabilityState the capabilityState to set
*/
public void setCapabilityState(CapabilityStateDTO capabilityState) {
this.capabilityState = capabilityState;
}
/**
* Returns, if the capability has a state. Not all capabilities have a state.
*
* @return true if the capability has a state, otherwise false
*/
public boolean hasState() {
return (capabilityState != null) && (capabilityState.getState() != null);
}
/**
* Returns the name of the {@link CapabilityDTO}.
*
* @return capability name
*/
public String getName() {
return getConfig().getName();
}
/**
* Returns, if the activity log is active for the {@link CapabilityDTO}.
*
* @return boolean or null, if the {@link CapabilityDTO} does not have this property.
*/
public boolean getActivityLogActive() {
return getConfig().getActivityLogActive();
}
/**
* Returns the number of pushbuttons for the {@link CapabilityDTO}.
*
* @return int or null, if the {@link CapabilityDTO} does not have this property.
*/
public int getPushButtons() {
return getConfig().getPushButtons();
}
/**
* Returns true, if the {@link CapabilityDTO} is of type VariableActuator.
*
* @return true if it is a VariableActuator, otherwise false
*/
public boolean isTypeVariableActuator() {
return TYPE_VARIABLEACTUATOR.equals(getType());
}
/**
* Returns true, if the {@link CapabilityDTO} is of type SwitchActuator.
*
* @return true if it is a SwitchActuator, otherwise false
*/
public boolean isTypeSwitchActuator() {
return TYPE_SWITCHACTUATOR.equals(getType());
}
/**
* Returns true, if the {@link CapabilityDTO} is of type ThermostatActuator.
*
* @return true if it is a SwitchActuator, otherwise false
*/
public boolean isTypeThermostatActuator() {
return TYPE_THERMOSTATACTUATOR.equals(getType());
}
/**
* Returns true, if the {@link CapabilityDTO} is of type TemperatureSensor.
*
* @return true if it is a TemperatureSensor, otherwise false
*/
public boolean isTypeTemperatureSensor() {
return TYPE_TEMPERATURESENSOR.equals(getType());
}
/**
* Returns true, if the {@link CapabilityDTO} is of type HumiditySensor.
*
* @return true if it is a HumiditySensor, otherwise false
*/
public boolean isTypeHumiditySensor() {
return TYPE_HUMIDITYSENSOR.equals(getType());
}
/**
* Returns true, if the {@link CapabilityDTO} is of type WindowDoorSensor.
*
* @return true if it is a WindowDoorSensor, otherwise false
*/
public boolean isTypeWindowDoorSensor() {
return TYPE_WINDOWDOORSENSOR.equals(getType());
}
/**
* Returns true, if the {@link CapabilityDTO} is of type SmokeDetectorSensor.
*
* @return true if it is a SmokeDetector, otherwise false
*/
public boolean isTypeSmokeDetectorSensor() {
return TYPE_SMOKEDETECTORSENSOR.equals(getType());
}
/**
* Returns true, if the {@link CapabilityDTO} is of type AlarmActuator.
*
* @return true if it is an AlarmActuator, otherwise false
*/
public boolean isTypeAlarmActuator() {
return TYPE_ALARMACTUATOR.equals(getType());
}
/**
* Returns true, if the {@link CapabilityDTO} is of type MotionDetectionSensor.
*
* @return true if it is a MotionDetectionSensor, otherwise false
*/
public boolean isTypeMotionDetectionSensor() {
return TYPE_MOTIONDETECTIONSENSOR.equals(getType());
}
/**
* Returns true, if the {@link CapabilityDTO} is of type LuminanceSensor.
*
* @return true if it is a LuminanceSensor, otherwise false
*/
public boolean isTypeLuminanceSensor() {
return TYPE_LUMINANCESENSOR.equals(getType());
}
/**
* Returns true, if the {@link CapabilityDTO} is of type PushButtonSensor.
*
* @return true if it is a PushButtonSensor, otherwise false
*/
public boolean isTypePushButtonSensor() {
return TYPE_PUSHBUTTONSENSOR.equals(getType());
}
/**
* Returns true, if the {@link CapabilityDTO} is of type DimmerActuator.
*
* @return true if it is a DimmerActuator, otherwise false
*/
public boolean isTypeDimmerActuator() {
return TYPE_DIMMERACTUATOR.equals(getType());
}
/**
* Returns true, if the {@link CapabilityDTO} is of type RollerShutterActuator.
*
* @return true if it is a RollerShutterActuator, otherwise false
*/
public boolean isTypeRollerShutterActuator() {
return TYPE_ROLLERSHUTTERACTUATOR.equals(getType());
}
/**
* Returns true, if the {@link CapabilityDTO} is of type EnergyConsumptionSensor.
*
* @return true if it is a EnergyConsumptionSensor, otherwise false
*/
public boolean isTypeEnergyConsumptionSensor() {
return TYPE_ENERGYCONSUMPTIONSENSOR.equals(getType());
}
/**
* Returns true, if the {@link CapabilityDTO} is of type PowerConsumptionSensor.
*
* @return true if it is a PowerConsumptionSensor, otherwise false
*/
public boolean isTypePowerConsumptionSensor() {
return TYPE_POWERCONSUMPTIONSENSOR.equals(getType());
}
/**
* Returns true, if the {@link CapabilityDTO} is of type GenerationMeterEnergySensor.
*
* @return true if it is a GenerationMeterEnergySensor, otherwise false
*/
public boolean isTypeGenerationMeterEnergySensor() {
return TYPE_GENERATIONMETERENERGYSENSOR.equals(getType());
}
/**
* Returns true, if the {@link CapabilityDTO} is of type GenerationMeterPowerConsumptionSensor.
*
* @return true if it is a GenerationMeterPowerConsumptionSensor, otherwise false
*/
public boolean isTypeGenerationMeterPowerConsumptionSensor() {
return TYPE_GENERATIONMETERPOWERCONSUMPTIONSENSOR.equals(getType());
}
/**
* Returns true, if the {@link CapabilityDTO} is of type TwoWayMeterEnergyConsumptionSensor.
*
* @return true if it is a TwoWayMeterEnergyConsumptionSensor, otherwise false
*/
public boolean isTypeTwoWayMeterEnergyConsumptionSensor() {
return TYPE_TWOWAYMETERENERGYCONSUMPTIONSENSOR.equals(getType());
}
/**
* Returns true, if the {@link CapabilityDTO} is of type TwoWayMeterEnergyFeedSensor.
*
* @return true if it is a TwoWayMeterEnergyFeedSensor, otherwise false
*/
public boolean isTypeTwoWayMeterEnergyFeedSensor() {
return TYPE_TWOWAYMETERENERGYFEEDSENSOR.equals(getType());
}
/**
* Returns true, if the {@link CapabilityDTO} is of type TwoWayMeterPowerConsumptionSensor.
*
* @return true if it is a TwoWayMeterPowerConsumptionSensor, otherwise false
*/
public boolean isTypeTwoWayMeterPowerConsumptionSensor() {
return TYPE_TWOWAYMETERPOWERCONSUMPTIONSENSOR.equals(getType());
}
}

View File

@ -0,0 +1,413 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.capability;
/**
* Defines the {@link CapabilityStateDTO}, that holds the state of a {@link CapabilityDTO}, e.g. a temperature.
*
* @author Oliver Kuhl - Initial contribution
*/
public class CapabilityStateDTO {
public static final String STATE_VALUE_OPERATION_MODE_AUTO = "Auto";
public static final String STATE_VALUE_OPERATION_MODE_MANUAL = "Manu";
/**
* id of the {@link CapabilityDTO}
*/
private String id;
/**
* class containing all states
*/
private StateDTO state;
public CapabilityStateDTO() {
state = new StateDTO();
}
/**
* @return the id
*/
public String getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(final String id) {
this.id = id;
}
/**
* @return the state
*/
public StateDTO getState() {
return state;
}
/**
* @param state the state to set
*/
public void setState(final StateDTO state) {
this.state = state;
}
public Boolean getVariableActuatorState() {
return getState().getValueState().getValue();
}
public void setVariableActuatorState(final Boolean on) {
getState().getValueState().setValue(on);
}
public Boolean getSwitchActuatorState() {
return getState().getOnState().getValue();
}
public void setSwitchActuatorState(final Boolean on) {
getState().getOnState().setValue(on);
}
public Double getTemperatureSensorTemperatureState() {
return getState().getTemperatureState().getValue();
}
public void setTemperatureSensorTemperatureState(final Double temperature) {
getState().getTemperatureState().setValue(temperature);
}
public Boolean getTemperatureSensorFrostWarningState() {
return getState().getFrostWarningState().getValue();
}
public void setTemperatureSensorFrostWarningState(final Boolean frostWarning) {
getState().getFrostWarningState().setValue(frostWarning);
}
public Double getThermostatActuatorPointTemperatureState() {
return getState().getPointTemperatureState().getValue();
}
public void setThermostatActuatorPointTemperatureState(final Double pointTemperature) {
getState().getPointTemperatureState().setValue(pointTemperature);
}
public String getThermostatActuatorOperationModeState() {
return getState().getOperationModeState().getValue();
}
public void setThermostatActuatorOperationModeState(final String operationMode) {
if (STATE_VALUE_OPERATION_MODE_MANUAL.equals(operationMode)) {
getState().getOperationModeState().setValue(STATE_VALUE_OPERATION_MODE_MANUAL);
} else {
getState().getOperationModeState().setValue(STATE_VALUE_OPERATION_MODE_AUTO);
}
}
public Boolean getThermostatActuatorWindowReductionActiveState() {
return getState().getWindowReductionActiveState().getValue();
}
public void setThermostatActuatorWindowReductionActiveState(final Boolean windowReductionActive) {
getState().getWindowReductionActiveState().setValue(windowReductionActive);
}
public Double getHumiditySensorHumidityState() {
return getState().getHumidityState().getValue();
}
public void setHumiditySensorHumidityState(final Double humidity) {
getState().getHumidityState().setValue(humidity);
}
public Boolean getHumiditySensorMoldWarningState() {
return getState().getMoldWarningState().getValue();
}
public void setHumiditySensorMoldWarningState(final Boolean moldWarning) {
getState().getMoldWarningState().setValue(moldWarning);
}
public Boolean getWindowDoorSensorState() {
return getState().getIsOpenState().getValue();
}
public void setWindowDoorSensorState(final Boolean open) {
getState().getIsOpenState().setValue(open);
}
public Boolean getSmokeDetectorSensorState() {
return getState().getIsSmokeAlarmState().getValue();
}
public void setSmokeDetectorSensorState(final Boolean on) {
getState().getIsSmokeAlarmState().setValue(on);
}
public Boolean getAlarmActuatorState() {
return getState().getOnState().getValue();
}
public void setAlarmActuatorState(final Boolean on) {
getState().getOnState().setValue(on);
}
public Integer getMotionDetectionSensorState() {
return getState().getMotionDetectedCountState().getValue();
}
public void setMotionDetectionSensorState(final Integer numberOfMotions) {
getState().getMotionDetectedCountState().setValue(numberOfMotions);
}
public Double getLuminanceSensorState() {
return getState().getLuminanceState().getValue();
}
public void setLuminanceSensorState(final Double luminance) {
getState().getLuminanceState().setValue(luminance);
}
public Integer getPushButtonSensorCounterState() {
return getState().getLastKeyPressCounterState().getValue();
}
public void setPushButtonSensorCounterState(final Integer numberOfPresses) {
getState().getLastKeyPressCounterState().setValue(numberOfPresses);
}
public Integer getPushButtonSensorButtonIndexState() {
return getState().getLastPressedButtonIndex().getValue();
}
public void setPushButtonSensorButtonIndexState(final Integer buttonIndex) {
getState().getLastPressedButtonIndex().setValue(buttonIndex);
}
public String getPushButtonSensorButtonIndexType() {
return getState().getLastKeyPressType().getValue();
}
public void setPushButtonSensorButtonIndexType(String lastKeyPressType) {
getState().getLastKeyPressType().setValue(lastKeyPressType);
}
public Integer getDimmerActuatorState() {
return getState().getDimLevelState().getValue();
}
public void setDimmerActuatorState(final Integer DimLevel) {
getState().getDimLevelState().setValue(DimLevel);
}
public Integer getRollerShutterActuatorState() {
return getState().getShutterLevelState().getValue();
}
public void setRollerShutterActuatorState(final Integer rollerShutterLevel) {
getState().getShutterLevelState().setValue(rollerShutterLevel);
}
// ENERGY CONSUMPTION SENSOR
public Double getEnergyConsumptionSensorEnergyConsumptionMonthKWhState() {
return getState().getEnergyConsumptionMonthKWhState().getValue();
}
public void setEnergyConsumptionSensorEnergyConsumptionMonthKWhState(final Double state) {
getState().getEnergyConsumptionMonthKWhState().setValue(state);
}
public Double getEnergyConsumptionSensorAbsoluteEnergyConsumptionState() {
return getState().getAbsoluteEnergyConsumptionState().getValue();
}
public void setEnergyConsumptionSensorAbsoluteEnergyConsumptionState(final Double state) {
getState().getAbsoluteEnergyConsumptionState().setValue(state);
}
public Double getEnergyConsumptionSensorEnergyConsumptionMonthEuroState() {
return getState().getEnergyConsumptionMonthEuroState().getValue();
}
public void setEnergyConsumptionSensorEnergyConsumptionMonthEuroState(final Double state) {
getState().getEnergyConsumptionMonthEuroState().setValue(state);
}
public Double getEnergyConsumptionSensorEnergyConsumptionDayEuroState() {
return getState().getEnergyConsumptionDayEuroState().getValue();
}
public void setEnergyConsumptionSensorEnergyConsumptionDayEuroState(final Double state) {
getState().getEnergyConsumptionDayEuroState().setValue(state);
}
public Double getEnergyConsumptionSensorEnergyConsumptionDayKWhState() {
return getState().getEnergyConsumptionDayKWhState().getValue();
}
public void setEnergyConsumptionSensorEnergyConsumptionDayKWhState(final Double state) {
getState().getEnergyConsumptionDayKWhState().setValue(state);
}
// POWER CONSUMPTION SENSOR
public Double getPowerConsumptionSensorPowerConsumptionWattState() {
return getState().getPowerConsumptionWattState().getValue();
}
public void setPowerConsumptionSensorPowerConsumptionWattState(final Double state) {
getState().getPowerConsumptionWattState().setValue(state);
}
// GENERATION METER ENGERY SENSOR
public Double getGenerationMeterEnergySensorEnergyPerMonthInKWhState() {
return getState().getEnergyPerMonthInKWhState().getValue();
}
public void setGenerationMeterEnergySensorEnergyPerMonthInKWhState(final Double state) {
getState().getEnergyPerMonthInKWhState().setValue(state);
}
public Double getGenerationMeterEnergySensorTotalEnergyState() {
return getState().getTotalEnergyState().getValue();
}
public void setGenerationMeterEnergySensorTotalEnergyState(final Double state) {
getState().getTotalEnergyState().setValue(state);
}
public Double getGenerationMeterEnergySensorEnergyPerMonthInEuroState() {
return getState().getEnergyPerMonthInEuroState().getValue();
}
public void setGenerationMeterEnergySensorEnergyPerMonthInEuroState(final Double state) {
getState().getEnergyPerMonthInEuroState().setValue(state);
}
public Double getGenerationMeterEnergySensorEnergyPerDayInEuroState() {
return getState().getEnergyPerDayInEuroState().getValue();
}
public void setGenerationMeterEnergySensorEnergyPerDayInEuroState(final Double state) {
getState().getEnergyPerDayInEuroState().setValue(state);
}
public Double getGenerationMeterEnergySensorEnergyPerDayInKWhState() {
return getState().getEnergyPerDayInKWhState().getValue();
}
public void setGenerationMeterEnergySensorEnergyPerDayInKWhState(final Double state) {
getState().getEnergyPerDayInKWhState().setValue(state);
}
// GENERATION METER POWER CONSUMPTION SENSOR
public Double getGenerationMeterPowerConsumptionSensorPowerInWattState() {
return getState().getPowerInWattState().getValue();
}
public void setGenerationMeterPowerConsumptionSensorPowerInWattState(final Double state) {
getState().getPowerInWattState().setValue(state);
}
// TWO WAY METER ENERGY CONSUMPTION SENSOR
public Double getTwoWayMeterEnergyConsumptionSensorEnergyPerMonthInKWhState() {
return getState().getEnergyPerMonthInKWhState().getValue();
}
public void setTwoWayMeterEnergyConsumptionSensorEnergyPerMonthInKWhState(final Double state) {
getState().getEnergyPerMonthInKWhState().setValue(state);
}
public Double getTwoWayMeterEnergyConsumptionSensorTotalEnergyState() {
return getState().getTotalEnergyState().getValue();
}
public void setTwoWayMeterEnergyConsumptionSensorTotalEnergyState(final Double state) {
getState().getTotalEnergyState().setValue(state);
}
public Double getTwoWayMeterEnergyConsumptionSensorEnergyPerMonthInEuroState() {
return getState().getEnergyPerMonthInEuroState().getValue();
}
public void setTwoWayMeterEnergyConsumptionSensorEnergyPerMonthInEuroState(final Double state) {
getState().getEnergyPerMonthInEuroState().setValue(state);
}
public Double getTwoWayMeterEnergyConsumptionSensorEnergyPerDayInEuroState() {
return getState().getEnergyPerDayInEuroState().getValue();
}
public void setTwoWayMeterEnergyConsumptionSensorEnergyPerDayInEuroState(final Double state) {
getState().getEnergyPerDayInEuroState().setValue(state);
}
public Double getTwoWayMeterEnergyConsumptionSensorEnergyPerDayInKWhState() {
return getState().getEnergyPerDayInKWhState().getValue();
}
public void setTwoWayMeterEnergyConsumptionSensorEnergyPerDayInKWhState(final Double state) {
getState().getEnergyPerDayInKWhState().setValue(state);
}
// TWO WAY METER ENERGY FEED SENSOR
public Double getTwoWayMeterEnergyFeedSensorEnergyPerMonthInKWhState() {
return getState().getEnergyPerMonthInKWhState().getValue();
}
public void setTwoWayMeterEnergyFeedSensorEnergyPerMonthInKWhState(final Double state) {
getState().getEnergyPerMonthInKWhState().setValue(state);
}
public Double getTwoWayMeterEnergyFeedSensorTotalEnergyState() {
return getState().getTotalEnergyState().getValue();
}
public void setTwoWayMeterEnergyFeedSensorTotalEnergyState(final Double state) {
getState().getTotalEnergyState().setValue(state);
}
public Double getTwoWayMeterEnergyFeedSensorEnergyPerMonthInEuroState() {
return getState().getEnergyPerMonthInEuroState().getValue();
}
public void setTwoWayMeterEnergyFeedSensorEnergyPerMonthInEuroState(final Double state) {
getState().getEnergyPerMonthInEuroState().setValue(state);
}
public Double getTwoWayMeterEnergyFeedSensorEnergyPerDayInEuroState() {
return getState().getEnergyPerDayInEuroState().getValue();
}
public void setTwoWayMeterEnergyFeedSensorEnergyPerDayInEuroState(final Double state) {
getState().getEnergyPerDayInEuroState().setValue(state);
}
public Double getTwoWayMeterEnergyFeedSensorEnergyPerDayInKWhState() {
return getState().getEnergyPerDayInKWhState().getValue();
}
public void setTwoWayMeterEnergyFeedSensorEnergyPerDayInKWhState(final Double state) {
getState().getEnergyPerDayInKWhState().setValue(state);
}
// TWO WAY METER POWER CONSUMPTION SENSOR
public Double getTwoWayMeterPowerConsumptionSensorPowerInWattState() {
return getState().getPowerInWattState().getValue();
}
public void setTwoWayMeterPowerConsumptionSensorPowerInWattState(final Double state) {
getState().getPowerInWattState().setValue(state);
}
}

View File

@ -0,0 +1,803 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.capability;
import org.openhab.binding.livisismarthome.internal.client.api.entity.state.BooleanStateDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.state.DateTimeStateDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.state.DoubleStateDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.state.IntegerStateDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.state.StringStateDTO;
import com.google.gson.annotations.SerializedName;
/**
* Holds the Capability state.
*
* @author Oliver Kuhl - Initial contribution
*
*/
public class StateDTO {
@SerializedName("absoluteEnergyConsumption")
private DoubleStateDTO absoluteEnergyConsumptionState;
@SerializedName("activeChannel")
private StringStateDTO activeChannelState;
@SerializedName("dimLevel")
private IntegerStateDTO dimLevelState;
@SerializedName("energyConsumptionDayEuro")
private DoubleStateDTO energyConsumptionDayEuroState;
@SerializedName("energyConsumptionDayKWh")
private DoubleStateDTO energyConsumptionDayKWhState;
@SerializedName("energyConsumptionMonthEuro")
private DoubleStateDTO energyConsumptionMonthEuroState;
@SerializedName("energyConsumptionMonthKWh")
private DoubleStateDTO energyConsumptionMonthKWhState;
@SerializedName("energyPerDayInEuro")
private DoubleStateDTO energyPerDayInEuroState;
@SerializedName("energyPerDayInKWh")
private DoubleStateDTO energyPerDayInKWhState;
@SerializedName("energyPerMonthInEuro")
private DoubleStateDTO energyPerMonthInEuroState;
@SerializedName("energyPerMonthInKWh")
private DoubleStateDTO energyPerMonthInKWhState;
@SerializedName("frostWarning")
private BooleanStateDTO frostWarningState;
@SerializedName("humidity")
private DoubleStateDTO humidityState;
@SerializedName("isDay")
private BooleanStateDTO isDayState;
@SerializedName("isOn")
private BooleanStateDTO isOnState;
@SerializedName("isOpen")
private BooleanStateDTO isOpenState;
@SerializedName("isSmokeAlarm")
private BooleanStateDTO isSmokeAlarmState;
@SerializedName("lastKeyPressCounter")
private IntegerStateDTO lastKeyPressCounterState;
@SerializedName("lastPressedButtonIndex")
private IntegerStateDTO lastPressedButtonIndex;
private StringStateDTO lastPressedButtonIndexState;
@SerializedName("luminance")
private DoubleStateDTO luminanceState;
@SerializedName("moldWarning")
private BooleanStateDTO moldWarningState;
@SerializedName("motionDetectedCount")
private IntegerStateDTO motionDetectedCountState;
@SerializedName("nextSunrise")
private DateTimeStateDTO nextSunrise;
@SerializedName("nextSunset")
private DateTimeStateDTO nextSunsetState;
@SerializedName("nextTimeEvent")
private DateTimeStateDTO nextTimeEventState;
@SerializedName("onState")
private BooleanStateDTO onState;
@SerializedName("operationMode")
private StringStateDTO operationModeState;
@SerializedName("pointTemperature")
private DoubleStateDTO pointTemperatureState;
@SerializedName("powerConsumptionWatt")
private DoubleStateDTO powerConsumptionWattState;
@SerializedName("powerInWatt")
private DoubleStateDTO powerInWattState;
@SerializedName("shutterLevel")
private IntegerStateDTO shutterLevelState;
@SerializedName("supplyValueInCubicMetterPerDay")
private DoubleStateDTO supplyValueInCubicMetterPerDayState;
@SerializedName("supplyValueInCubicMetterPerMonth")
private DoubleStateDTO supplyValueInCubicMetterPerMonthState;
@SerializedName("supplyValueInCurrencyPerDay")
private DoubleStateDTO supplyValueInCurrencyPerDayState;
@SerializedName("supplyValueInCurrencyPerMonth")
private DoubleStateDTO supplyValueInCurrencyPerMonthState;
@SerializedName("supplyValueInLitrePerDay")
private DoubleStateDTO supplyValueInLitrePerDayState;
@SerializedName("supplyValueInLitrePerMonth")
private DoubleStateDTO supplyValueInLitrePerMonthState;
@SerializedName("temperature")
private DoubleStateDTO temperatureState;
@SerializedName("totalEnergy")
private DoubleStateDTO totalEnergyState;
@SerializedName("value")
private BooleanStateDTO valueState;
@SerializedName("valvePosition")
private BooleanStateDTO valvePositionState;
@SerializedName("windowReductionActive")
private BooleanStateDTO windowReductionActiveState;
public StateDTO() {
absoluteEnergyConsumptionState = new DoubleStateDTO();
activeChannelState = new StringStateDTO();
dimLevelState = new IntegerStateDTO();
energyConsumptionDayEuroState = new DoubleStateDTO();
energyConsumptionDayKWhState = new DoubleStateDTO();
energyConsumptionMonthEuroState = new DoubleStateDTO();
energyConsumptionMonthKWhState = new DoubleStateDTO();
energyPerDayInEuroState = new DoubleStateDTO();
energyPerDayInKWhState = new DoubleStateDTO();
energyPerMonthInEuroState = new DoubleStateDTO();
energyPerMonthInKWhState = new DoubleStateDTO();
frostWarningState = new BooleanStateDTO();
humidityState = new DoubleStateDTO();
isDayState = new BooleanStateDTO();
isOnState = new BooleanStateDTO();
isOpenState = new BooleanStateDTO();
isSmokeAlarmState = new BooleanStateDTO();
lastKeyPressCounterState = new IntegerStateDTO();
lastPressedButtonIndex = new IntegerStateDTO();
lastPressedButtonIndexState = new StringStateDTO();
luminanceState = new DoubleStateDTO();
moldWarningState = new BooleanStateDTO();
motionDetectedCountState = new IntegerStateDTO();
nextSunrise = new DateTimeStateDTO();
nextSunsetState = new DateTimeStateDTO();
nextTimeEventState = new DateTimeStateDTO();
onState = new BooleanStateDTO();
operationModeState = new StringStateDTO();
pointTemperatureState = new DoubleStateDTO();
powerConsumptionWattState = new DoubleStateDTO();
powerInWattState = new DoubleStateDTO();
shutterLevelState = new IntegerStateDTO();
supplyValueInCubicMetterPerDayState = new DoubleStateDTO();
supplyValueInCubicMetterPerMonthState = new DoubleStateDTO();
supplyValueInCurrencyPerDayState = new DoubleStateDTO();
supplyValueInCurrencyPerMonthState = new DoubleStateDTO();
supplyValueInLitrePerDayState = new DoubleStateDTO();
supplyValueInLitrePerMonthState = new DoubleStateDTO();
temperatureState = new DoubleStateDTO();
totalEnergyState = new DoubleStateDTO();
valueState = new BooleanStateDTO();
valvePositionState = new BooleanStateDTO();
windowReductionActiveState = new BooleanStateDTO();
}
/**
* @return the absoluteEnergyConsumptionState
*/
public DoubleStateDTO getAbsoluteEnergyConsumptionState() {
return absoluteEnergyConsumptionState;
}
/**
* @param state the absoluteEnergyConsumptionState to set
*/
public void setAbsoluteEnergyConsumptionState(DoubleStateDTO state) {
this.absoluteEnergyConsumptionState = state;
}
/**
* @return the activeChannelState
*/
public StringStateDTO getActiveChannelState() {
return activeChannelState;
}
/**
* @param state the activeChannelState to set
*/
public void setActiveChannelState(StringStateDTO state) {
this.activeChannelState = state;
}
/**
* @return the dimLevelState
*/
public IntegerStateDTO getDimLevelState() {
return dimLevelState;
}
/**
* @param state the dimLevelState to set
*/
public void setDimLevelState(IntegerStateDTO state) {
this.dimLevelState = state;
}
/**
* @return the energyConsumptionDayEuroState
*/
public DoubleStateDTO getEnergyConsumptionDayEuroState() {
return energyConsumptionDayEuroState;
}
/**
* @param state the energyConsumptionDayEuroState to set
*/
public void setEnergyConsumptionDayEuroState(DoubleStateDTO state) {
this.energyConsumptionDayEuroState = state;
}
/**
* @return the energyConsumptionDayKWhState
*/
public DoubleStateDTO getEnergyConsumptionDayKWhState() {
return energyConsumptionDayKWhState;
}
/**
* @param state the energyConsumptionDayKWhState to set
*/
public void setEnergyConsumptionDayKWhState(DoubleStateDTO state) {
this.energyConsumptionDayKWhState = state;
}
/**
* @return the energyConsumptionMonthEuroState
*/
public DoubleStateDTO getEnergyConsumptionMonthEuroState() {
return energyConsumptionMonthEuroState;
}
/**
* @param state the energyConsumptionMonthEuroState to set
*/
public void setEnergyConsumptionMonthEuroState(DoubleStateDTO state) {
this.energyConsumptionMonthEuroState = state;
}
/**
* @return the energyConsumptionMonthKWhState
*/
public DoubleStateDTO getEnergyConsumptionMonthKWhState() {
return energyConsumptionMonthKWhState;
}
/**
* @param state the energyConsumptionMonthKWhState to set
*/
public void setEnergyConsumptionMonthKWhState(DoubleStateDTO state) {
this.energyConsumptionMonthKWhState = state;
}
/**
* @return the energyPerDayInEuroState
*/
public DoubleStateDTO getEnergyPerDayInEuroState() {
return energyPerDayInEuroState;
}
/**
* @param state the energyPerDayInEuroState to set
*/
public void setEnergyPerDayInEuroState(DoubleStateDTO state) {
this.energyPerDayInEuroState = state;
}
/**
* @return the energyPerDayInKWhState
*/
public DoubleStateDTO getEnergyPerDayInKWhState() {
return energyPerDayInKWhState;
}
/**
* @param state the energyPerDayInKWhState to set
*/
public void setEnergyPerDayInKWhState(DoubleStateDTO state) {
this.energyPerDayInKWhState = state;
}
/**
* @return the energyPerMonthInEuroState
*/
public DoubleStateDTO getEnergyPerMonthInEuroState() {
return energyPerMonthInEuroState;
}
/**
* @param state the energyPerMonthInEuroState to set
*/
public void setEnergyPerMonthInEuroState(DoubleStateDTO state) {
this.energyPerMonthInEuroState = state;
}
/**
* @return the energyPerMonthInKWhState
*/
public DoubleStateDTO getEnergyPerMonthInKWhState() {
return energyPerMonthInKWhState;
}
/**
* @param state the energyPerMonthInKWhState to set
*/
public void setEnergyPerMonthInKWhState(DoubleStateDTO state) {
this.energyPerMonthInKWhState = state;
}
/**
* @return the frostWarningState
*/
public BooleanStateDTO getFrostWarningState() {
return frostWarningState;
}
/**
* @param state the frostWarningState to set
*/
public void setFrostWarningState(BooleanStateDTO state) {
this.frostWarningState = state;
}
/**
* @return the humidityState
*/
public DoubleStateDTO getHumidityState() {
return humidityState;
}
/**
* @param state the humidityState to set
*/
public void setHumidityState(DoubleStateDTO state) {
this.humidityState = state;
}
/**
* @return the isDayState
*/
public BooleanStateDTO getIsDayState() {
return isDayState;
}
/**
* @param state the isDayState to set
*/
public void setIsDayState(BooleanStateDTO state) {
this.isDayState = state;
}
/**
* @return the isOnState
*/
public BooleanStateDTO getIsOnState() {
return isOnState;
}
/**
* @param state the isOnState to set
*/
public void setIsOnState(BooleanStateDTO state) {
this.isOnState = state;
}
/**
* @return the isOpenState
*/
public BooleanStateDTO getIsOpenState() {
return isOpenState;
}
/**
* @param state the isOpenState to set
*/
public void setIsOpenState(BooleanStateDTO state) {
this.isOpenState = state;
}
/**
* @return the isSmokeAlarmState
*/
public BooleanStateDTO getIsSmokeAlarmState() {
return isSmokeAlarmState;
}
/**
* @param state the isSmokeAlarmState to set
*/
public void setIsSmokeAlarmState(BooleanStateDTO state) {
this.isSmokeAlarmState = state;
}
/**
* @return the lastKeyPressCounterState
*/
public IntegerStateDTO getLastKeyPressCounterState() {
return lastKeyPressCounterState;
}
/**
* @param state the lastKeyPressCounterState to set
*/
public void setLastKeyPressCounterState(IntegerStateDTO state) {
this.lastKeyPressCounterState = state;
}
/**
* @return the lastPressedButtonIndex
*/
public IntegerStateDTO getLastPressedButtonIndex() {
return lastPressedButtonIndex;
}
/**
* @param state the lastPressedButtonIndex to set
*/
public void setLastPressedButtonIndex(IntegerStateDTO state) {
this.lastPressedButtonIndex = state;
}
public StringStateDTO getLastKeyPressType() {
if (lastPressedButtonIndexState == null) {
lastPressedButtonIndexState = new StringStateDTO();
}
return lastPressedButtonIndexState;
}
public void setLastKeyPressType(StringStateDTO lastPressedButtonIndexState) {
this.lastPressedButtonIndexState = lastPressedButtonIndexState;
}
/**
* @return the luminanceState
*/
public DoubleStateDTO getLuminanceState() {
return luminanceState;
}
/**
* @param state the luminanceState to set
*/
public void setLuminanceState(DoubleStateDTO state) {
this.luminanceState = state;
}
/**
* @return the moldWarningState
*/
public BooleanStateDTO getMoldWarningState() {
return moldWarningState;
}
/**
* @param state the moldWarningState to set
*/
public void setMoldWarningState(BooleanStateDTO state) {
this.moldWarningState = state;
}
/**
* @return the motionDetectedCountState
*/
public IntegerStateDTO getMotionDetectedCountState() {
return motionDetectedCountState;
}
/**
* @param state the motionDetectedCountState to set
*/
public void setMotionDetectedCountState(IntegerStateDTO state) {
this.motionDetectedCountState = state;
}
/**
* @return the nextSunrise
*/
public DateTimeStateDTO getNextSunrise() {
return nextSunrise;
}
/**
* @param state the nextSunrise to set
*/
public void setNextSunrise(DateTimeStateDTO state) {
this.nextSunrise = state;
}
/**
* @return the nextSunsetState
*/
public DateTimeStateDTO getNextSunsetState() {
return nextSunsetState;
}
/**
* @param state the nextSunsetState to set
*/
public void setNextSunsetState(DateTimeStateDTO state) {
this.nextSunsetState = state;
}
/**
* @return the nextTimeEventState
*/
public DateTimeStateDTO getNextTimeEventState() {
return nextTimeEventState;
}
/**
* @param state the nextTimeEventState to set
*/
public void setNextTimeEventState(DateTimeStateDTO state) {
this.nextTimeEventState = state;
}
/**
* @return the onState
*/
public BooleanStateDTO getOnState() {
return onState;
}
/**
* @param state the onState to set
*/
public void setOnState(BooleanStateDTO state) {
this.onState = state;
}
/**
* @return the operationModeState
*/
public StringStateDTO getOperationModeState() {
return operationModeState;
}
/**
* @param state the operationModeState to set
*/
public void setOperationModeState(StringStateDTO state) {
this.operationModeState = state;
}
/**
* @return the pointTemperatureState
*/
public DoubleStateDTO getPointTemperatureState() {
return pointTemperatureState;
}
/**
* @param state the pointTemperatureState to set
*/
public void setPointTemperatureState(DoubleStateDTO state) {
this.pointTemperatureState = state;
}
/**
* @return the powerConsumptionWattState
*/
public DoubleStateDTO getPowerConsumptionWattState() {
return powerConsumptionWattState;
}
/**
* @param state the powerConsumptionWattState to set
*/
public void setPowerConsumptionWattState(DoubleStateDTO state) {
this.powerConsumptionWattState = state;
}
/**
* @return the powerInWattState
*/
public DoubleStateDTO getPowerInWattState() {
return powerInWattState;
}
/**
* @param state the powerInWattState to set
*/
public void setPowerInWattState(DoubleStateDTO state) {
this.powerInWattState = state;
}
/**
* @return the shutterLevelState
*/
public IntegerStateDTO getShutterLevelState() {
return shutterLevelState;
}
/**
* @param state the shutterLevelState to set
*/
public void setShutterLevelState(IntegerStateDTO state) {
this.shutterLevelState = state;
}
/**
* @return the supplyValueInCubicMetterPerDayState
*/
public DoubleStateDTO getSupplyValueInCubicMetterPerDayState() {
return supplyValueInCubicMetterPerDayState;
}
/**
* @param state the supplyValueInCubicMetterPerDayState to set
*/
public void setSupplyValueInCubicMetterPerDayState(DoubleStateDTO state) {
this.supplyValueInCubicMetterPerDayState = state;
}
/**
* @return the supplyValueInCubicMetterPerMonthState
*/
public DoubleStateDTO getSupplyValueInCubicMetterPerMonthState() {
return supplyValueInCubicMetterPerMonthState;
}
/**
* @param state the supplyValueInCubicMetterPerMonthState to set
*/
public void setSupplyValueInCubicMetterPerMonthState(DoubleStateDTO state) {
this.supplyValueInCubicMetterPerMonthState = state;
}
/**
* @return the supplyValueInCurrencyPerDayState
*/
public DoubleStateDTO getSupplyValueInCurrencyPerDayState() {
return supplyValueInCurrencyPerDayState;
}
/**
* @param state the supplyValueInCurrencyPerDayState to set
*/
public void setSupplyValueInCurrencyPerDayState(DoubleStateDTO state) {
this.supplyValueInCurrencyPerDayState = state;
}
/**
* @return the supplyValueInCurrencyPerMonthState
*/
public DoubleStateDTO getSupplyValueInCurrencyPerMonthState() {
return supplyValueInCurrencyPerMonthState;
}
/**
* @param state the supplyValueInCurrencyPerMonthState to set
*/
public void setSupplyValueInCurrencyPerMonthState(DoubleStateDTO state) {
this.supplyValueInCurrencyPerMonthState = state;
}
/**
* @return the supplyValueInLitrePerDayState
*/
public DoubleStateDTO getSupplyValueInLitrePerDayState() {
return supplyValueInLitrePerDayState;
}
/**
* @param state the supplyValueInLitrePerDayState to set
*/
public void setSupplyValueInLitrePerDayState(DoubleStateDTO state) {
this.supplyValueInLitrePerDayState = state;
}
/**
* @return the supplyValueInLitrePerMonthState
*/
public DoubleStateDTO getSupplyValueInLitrePerMonthState() {
return supplyValueInLitrePerMonthState;
}
/**
* @param state the supplyValueInLitrePerMonthState to set
*/
public void setSupplyValueInLitrePerMonthState(DoubleStateDTO state) {
this.supplyValueInLitrePerMonthState = state;
}
/**
* @return the temperatureState
*/
public DoubleStateDTO getTemperatureState() {
return temperatureState;
}
/**
* @param state the temperatureState to set
*/
public void setTemperatureState(DoubleStateDTO state) {
this.temperatureState = state;
}
/**
* @return the totalEnergyState
*/
public DoubleStateDTO getTotalEnergyState() {
return totalEnergyState;
}
/**
* @param state the totalEnergyState to set
*/
public void setTotalEnergyState(DoubleStateDTO state) {
this.totalEnergyState = state;
}
/**
* @return the valueState
*/
public BooleanStateDTO getValueState() {
return valueState;
}
/**
* @param state the valueState to set
*/
public void setValueState(BooleanStateDTO state) {
this.valueState = state;
}
/**
* @return the valvePositionState
*/
public BooleanStateDTO getValvePositionState() {
return valvePositionState;
}
/**
* @param state the valvePositionState to set
*/
public void setValvePositionState(BooleanStateDTO state) {
this.valvePositionState = state;
}
/**
* @return the windowReductionActiveState
*/
public BooleanStateDTO getWindowReductionActiveState() {
return windowReductionActiveState;
}
/**
* @param state the windowReductionActiveState to set
*/
public void setWindowReductionActiveState(BooleanStateDTO state) {
this.windowReductionActiveState = state;
}
}

View File

@ -0,0 +1,390 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.device;
import java.time.ZonedDateTime;
import org.openhab.binding.livisismarthome.internal.client.Util;
import com.google.gson.annotations.SerializedName;
/**
* Holds the configuration of the Device.
*
* @author Oliver Kuhl - Initial contribution
*
*/
public class DeviceConfigDTO {
private String name;
private String protocolId;
private String timeOfAcceptance;
private String timeOfDiscovery;
private String hardwareVersion;
private String softwareVersion;
private String firmwareVersion;
private String hostName;
private boolean activityLogEnabled;
private String configurationState;
@SerializedName("IPAddress")
private String ipAddress;
@SerializedName("MACAddress")
private String macAddress;
private String registrationTime;
private String timeZone;
private String shcType;
private String geoLocation;
private Double currentUTCOffset;
private Boolean backendConnectionMonitored;
@SerializedName("RFCommFailureNotification")
private Boolean rfCommFailureNotification;
private String displayCurrentTemperature;
private String underlyingDeviceIds;
private String meterId;
private String meterFirmwareVersion;
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the protocolId
*/
public String getProtocolId() {
return protocolId;
}
/**
* @param protocolId the protocolId to set
*/
public void setProtocolId(String protocolId) {
this.protocolId = protocolId;
}
/**
* Returns the time, when the {@link DeviceDTO} was added to the SHC configuration.
*
* @return time of acceptance
*/
public ZonedDateTime getTimeOfAcceptance() {
if (timeOfAcceptance == null) {
return null;
}
return Util.timeStringToDate(timeOfAcceptance);
}
/**
* @param timeOfAcceptance the timeOfAcceptance to set
*/
public void setTimeOfAcceptance(String timeOfAcceptance) {
this.timeOfAcceptance = timeOfAcceptance;
}
/**
* Returns the time, when the {@link DeviceDTO} was discovered by the SHC.
*
* @return time of discovery
*/
public ZonedDateTime getTimeOfDiscovery() {
if (timeOfDiscovery == null) {
return null;
}
return Util.timeStringToDate(timeOfDiscovery);
}
/**
* @param timeOfDiscovery the timeOfDiscovery to set
*/
public void setTimeOfDiscovery(String timeOfDiscovery) {
this.timeOfDiscovery = timeOfDiscovery;
}
/**
* @return the hardwareVersion
*/
public String getHardwareVersion() {
return hardwareVersion;
}
/**
* @param hardwareVersion the hardwareVersion to set
*/
public void setHardwareVersion(String hardwareVersion) {
this.hardwareVersion = hardwareVersion;
}
/**
* @return the softwareVersion
*/
public String getSoftwareVersion() {
return softwareVersion;
}
/**
* @param softwareVersion the softwareVersion to set
*/
public void setSoftwareVersion(String softwareVersion) {
this.softwareVersion = softwareVersion;
}
/**
* @return the firmwareVersion
*/
public String getFirmwareVersion() {
return firmwareVersion;
}
/**
* @param firmwareVersion the firmwareVersion to set
*/
public void setFirmwareVersion(String firmwareVersion) {
this.firmwareVersion = firmwareVersion;
}
/**
* @return the hostName
*/
public String getHostName() {
return hostName;
}
/**
* @param hostName the hostName to set
*/
public void setHostName(String hostName) {
this.hostName = hostName;
}
/**
* @return the activityLogEnabled
*/
public boolean isActivityLogEnabled() {
return activityLogEnabled;
}
/**
* @param activityLogEnabled the activityLogEnabled to set
*/
public void setActivityLogEnabled(boolean activityLogEnabled) {
this.activityLogEnabled = activityLogEnabled;
}
/**
* @return the configurationState
*/
public String getConfigurationState() {
return configurationState;
}
/**
* @param configurationState the configurationState to set
*/
public void setConfigurationState(String configurationState) {
this.configurationState = configurationState;
}
/**
* @return the iPAddress
*/
public String getIPAddress() {
return ipAddress;
}
/**
* @param ipAddress the ipAddress to set
*/
public void setIPAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
/**
* @return the mACAddress
*/
public String getMACAddress() {
return macAddress;
}
/**
* @param mACAddress the mACAddress to set
*/
public void setMACAddress(String mACAddress) {
this.macAddress = mACAddress;
}
/**
* @return the registrationTime
*/
public ZonedDateTime getRegistrationTime() {
if (registrationTime == null) {
return null;
}
return Util.timeStringToDate(registrationTime);
}
/**
* @param registrationTime the registrationTime to set
*/
public void setRegistrationTime(String registrationTime) {
this.registrationTime = registrationTime;
}
/**
* @return the timeZone
*/
public String getTimeZone() {
return timeZone;
}
/**
* @param timeZone the timeZone to set
*/
public void setTimeZone(String timeZone) {
this.timeZone = timeZone;
}
/**
* @return the shcType
*/
public String getShcType() {
return shcType;
}
/**
* @param shcType the shcType to set
*/
public void setShcType(String shcType) {
this.shcType = shcType;
}
/**
* @return the geoLocation
*/
public String getGeoLocation() {
return geoLocation;
}
/**
* @param geoLocation the geoLocation to set
*/
public void setGeoLocation(String geoLocation) {
this.geoLocation = geoLocation;
}
/**
* @return the currentUTCOffset
*/
public Double getCurrentUTCOffset() {
return currentUTCOffset;
}
/**
* @param currentUTCOffset the currentUTCOffset to set
*/
public void setCurrentUTCOffset(Double currentUTCOffset) {
this.currentUTCOffset = currentUTCOffset;
}
/**
* @return the backendConnectionMonitored
*/
public Boolean getBackendConnectionMonitored() {
return backendConnectionMonitored;
}
/**
* @param backendConnectionMonitored the backendConnectionMonitored to set
*/
public void setBackendConnectionMonitored(Boolean backendConnectionMonitored) {
this.backendConnectionMonitored = backendConnectionMonitored;
}
/**
* @return the rFCommFailureNotification
*/
public Boolean getRFCommFailureNotification() {
return rfCommFailureNotification;
}
/**
* @param rFCommFailureNotification the rFCommFailureNotification to set
*/
public void setRFCommFailureNotification(Boolean rFCommFailureNotification) {
rfCommFailureNotification = rFCommFailureNotification;
}
/**
* @return the displayCurrentTemperature
*/
public String getDisplayCurrentTemperature() {
return displayCurrentTemperature;
}
/**
* @param displayCurrentTemperature the displayCurrentTemperature to set
*/
public void setDisplayCurrentTemperature(String displayCurrentTemperature) {
this.displayCurrentTemperature = displayCurrentTemperature;
}
/**
* @return the underlyingDeviceIds
*/
public String getUnderlyingDeviceIds() {
return underlyingDeviceIds;
}
/**
* @param underlyingDeviceIds the underlyingDeviceIds to set
*/
public void setUnderlyingDeviceIds(String underlyingDeviceIds) {
this.underlyingDeviceIds = underlyingDeviceIds;
}
/**
* @return the meterId
*/
public String getMeterId() {
return meterId;
}
/**
* @param meterId the meterId to set
*/
public void setMeterId(String meterId) {
this.meterId = meterId;
}
/**
* @return the meterFirmwareVersion
*/
public String getMeterFirmwareVersion() {
return meterFirmwareVersion;
}
/**
* @param meterFirmwareVersion the meterFirmwareVersion to set
*/
public void setMeterFirmwareVersion(String meterFirmwareVersion) {
this.meterFirmwareVersion = meterFirmwareVersion;
}
}

View File

@ -0,0 +1,523 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.device;
import static org.openhab.binding.livisismarthome.internal.LivisiBindingConstants.*;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.eclipse.jdt.annotation.NonNull;
import org.openhab.binding.livisismarthome.internal.client.api.entity.capability.CapabilityDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.location.LocationDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.message.MessageDTO;
import com.google.gson.annotations.SerializedName;
/**
* Defines the structure of a {@link DeviceDTO}.
*
* @author Oliver Kuhl - Initial contribution
*/
public class DeviceDTO {
private static final String PROTOCOL_ID_COSIP = "Cosip";
private static final String PROTOCOL_ID_VIRTUAL = "Virtual";
private static final String PROTOCOL_ID_WMBUS = "wMBus";
/**
* Unique id for the device, always available in model.
*/
private String id;
/**
* Identifier of the manufacturer, always available in model
*/
private String manufacturer;
/**
* Version number of the device for the domain model.
*
* If the functionality of the device changes, the version must
* be increased to indicate that there are new or changed attributes
* of the device. Always available in model.
*/
private String version;
/**
* Defines the product, which is used as an identifier for selecting the
* right add-in to support the functionality of the device.
* Remark: one add-in can support multiple devices, e.g.
* core.RWE, which supports all RWE hardware devices (also referred to as core devices).
* Always available in model.
*/
private String product;
/**
* Device number or id like SGTIN given by the manufacturer. Optional.
*/
@SerializedName("serialnumber")
private String serialNumber;
/**
* Specifies the type of the device, which is defined by the manufacturer. The triple of device type, manufacturer
* and the version must be unique.
* Always available in model.
*/
private String type;
private DeviceConfigDTO config;
private List<String> capabilities;
private Map<String, CapabilityDTO> capabilityMap;
private DeviceStateDTO deviceState;
/*
* The tag container can contain any number of properties for grouping of the devices in the client, e.g. category
* of device like security related. The tags can be freely chosen by the client and will not be considered by the
* system for any business logic.
*
* Optional.
*
* @Key("tags")
* private List<Property> tagList;
*/
/**
* The location contains the link to the location of the device. Optional.
*/
@SerializedName("location")
private String locationLink;
private transient LocationDTO location;
private List<MessageDTO> messageList;
private boolean lowBattery;
/**
* Stores, if the {@link DeviceDTO} is battery powered.
*/
private boolean batteryPowered = false;
/**
* @return the id
*/
public String getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(String id) {
this.id = id;
}
/**
* @return the manufacturer
*/
public String getManufacturer() {
return manufacturer;
}
/**
* @param manufacturer the manufacturer to set
*/
public void setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
/**
* @return the version
*/
public String getVersion() {
return version;
}
/**
* @param version the version to set
*/
public void setVersion(String version) {
this.version = version;
}
/**
* @return the product
*/
public String getProduct() {
return product;
}
/**
* @param product the product to set
*/
public void setProduct(String product) {
this.product = product;
}
/**
* @return the serialnumber
*/
public String getSerialNumber() {
return serialNumber;
}
/**
* @param serialNumber the serialnumber to set
*/
public void setSerialNumber(String serialNumber) {
this.serialNumber = serialNumber;
}
/**
* Returns true, if the {@link DeviceDTO} has a serial number.
*
* @return true if the device has serial number, otherwise false
*/
public boolean hasSerialNumber() {
return serialNumber != null && !serialNumber.isEmpty();
}
/**
* @return the type
*/
public String getType() {
return type;
}
/**
* @param type the type to set
*/
public void setType(String type) {
this.type = type;
}
/**
* @return the config
*/
public DeviceConfigDTO getConfig() {
return config;
}
/**
* @param config the config to set
*/
public void setConfig(DeviceConfigDTO config) {
this.config = config;
}
/**
* Returns the {@link DeviceStateDTO}. Only available, if device has a state. Better check with
* {@link DeviceDTO#hasDeviceState()} first!
*
* @return the entityState or null
*/
public DeviceStateDTO getDeviceState() {
return deviceState;
}
/**
* @param deviceState the deviceState to set
*/
public void setDeviceState(DeviceStateDTO deviceState) {
this.deviceState = deviceState;
}
/**
* Returns, if the {@link DeviceDTO} has a state. Not all {@link DeviceDTO}s have a state.
*
* @return true if the device has a device state, otherwise false
*/
public boolean hasDeviceState() {
return deviceState != null;
}
/**
* @return the capabilityList
*/
public List<String> getCapabilities() {
return Objects.requireNonNullElse(capabilities, Collections.emptyList());
}
/**
* @param capabilityList the capabilityList to set
*/
public void setCapabilities(List<String> capabilityList) {
this.capabilities = capabilityList;
}
/**
* @param capabilityMap the capabilityMap to set
*/
public void setCapabilityMap(Map<String, CapabilityDTO> capabilityMap) {
this.capabilityMap = capabilityMap;
}
/**
* @return the capabilityMap
*/
public Map<String, CapabilityDTO> getCapabilityMap() {
if (capabilityMap != null) {
return capabilityMap;
}
return Collections.emptyMap();
}
/**
* Returns the {@link CapabilityDTO} with the given id.
*
* @param id capability id
* @return capability
*/
public CapabilityDTO getCapabilityWithId(String id) {
return this.capabilityMap.get(id);
}
/**
* @return the locationLink
*/
public String getLocationLink() {
return locationLink;
}
/**
* @param locationLink the locationList to set
*/
public void setLocation(String locationLink) {
this.locationLink = locationLink;
}
/**
* Returns the id of the {@link LocationDTO}
*
* @return location id
*/
public String getLocationId() {
if (locationLink != null) {
return locationLink.replace("/location/", "");
}
return null;
}
/**
* Returns the {@link LocationDTO} of the {@link DeviceDTO}. Better check with {@link DeviceDTO#hasLocation()}
* first, as not
* all devices have one.
*
* @return the location
*/
public LocationDTO getLocation() {
return location;
}
/**
* @param location the location to set
*/
public void setLocation(LocationDTO location) {
this.location = location;
}
/**
* Returns, if the {@link DeviceDTO} has a {@link LocationDTO}. Not all devices have a {@link LocationDTO}...
*
* @return boolean true, if a {@link LocationDTO} is set, else false
*/
public boolean hasLocation() {
return location != null;
}
public @NonNull String getLocationName() {
LocationDTO location = getLocation();
if (location != null && location.getName() != null) {
return location.getName();
}
return "<none>";
}
/**
* @return the messageList
*/
public List<MessageDTO> getMessageList() {
if (messageList != null) {
return messageList;
}
return Collections.emptyList();
}
/**
* @param messageList the messageList to set
*/
public void setMessageList(List<MessageDTO> messageList) {
this.messageList = messageList;
applyMessageList(messageList);
}
private void applyMessageList(List<MessageDTO> messageList) {
if (messageList != null && !messageList.isEmpty()) {
boolean isUnreachableMessageFound = false;
boolean isLowBatteryMessageFound = false;
for (final MessageDTO message : messageList) {
switch (message.getType()) {
case MessageDTO.TYPE_DEVICE_UNREACHABLE:
isUnreachableMessageFound = true;
break;
case MessageDTO.TYPE_DEVICE_LOW_BATTERY:
isLowBatteryMessageFound = true;
break;
}
}
if (isUnreachableMessageFound) {
setReachable(false); // overwrite only when there is a corresponding message (to keep the state of the
// API in other cases)
}
if (isLowBatteryMessageFound) {
setLowBattery(true); // overwrite only when there is a corresponding message (to keep the state of the
// API in other cases)
}
}
}
/**
* Sets if the {@link DeviceDTO} is reachable;
*
* @param isReachable reachable (boolean)
*/
private void setReachable(boolean isReachable) {
if (getDeviceState().hasIsReachableState()) {
getDeviceState().setReachable(isReachable);
}
}
/**
* Returns if the {@link DeviceDTO} is reachable.
*
* @return reachable (boolean)
*/
public Boolean isReachable() {
if (hasDeviceState() && getDeviceState().hasIsReachableState()) {
return getDeviceState().isReachable();
}
return null;
}
/**
* Sets the low battery state for the {@link DeviceDTO}.
*
* @param isBatteryLow true if the battery is low, otherwise false
*/
public void setLowBattery(boolean isBatteryLow) {
this.lowBattery = isBatteryLow;
}
/**
* Returns true if the {@link DeviceDTO} has a low battery warning. Only available on battery devices.
*
* @return true if the battery is low, otherwise false
*/
public boolean hasLowBattery() {
return lowBattery;
}
/**
* Returns true, if the {@link DeviceDTO} is battery powered.
*
* @return true if the device is battery powered, otherwise false
*/
public boolean isBatteryPowered() {
return batteryPowered;
}
/**
* Sets if the device is battery powered.
*
* @param isBatteryPowerd true if the device is battery powered, otherwise false
*/
public void setIsBatteryPowered(boolean isBatteryPowerd) {
batteryPowered = isBatteryPowerd;
}
/**
* Returns true, if the {@link DeviceDTO} has {@link MessageDTO}s.
*
* @return true if messages accoring the device are available, otherwise false
*/
public boolean hasMessages() {
return (messageList != null && !messageList.isEmpty());
}
/**
* Returns true if the device is a SmartHomeController (SHC).
*
* @return true if the device is a SmartHomeController (SHC) otherwise false
*/
public boolean isController() {
return isClassicController() || DEVICE_SHCA.equals(type);
}
/**
* Returns true if the device is a classic controller (SHC, before Gen 2.).
*
* @return true if it is a classic controller, otherwise false
*/
public boolean isClassicController() {
return DEVICE_SHC.equals(type);
}
/**
* Returns true, if the {@link DeviceDTO} is a virtual device (e.g. a VariableActuator).
*
* @return true if it is a virtual device, otherwise false
*/
public boolean isVirtualDevice() {
return PROTOCOL_ID_VIRTUAL.equals(getConfig().getProtocolId());
}
/**
* Returns true, if the {@link DeviceDTO} is a radio device.
*
* @return true if it is a radio device, otherwise false
*/
public boolean isRadioDevice() {
return isCoSipDevice() || isWMBusDevice();
}
/**
* Returns true, if the {@link DeviceDTO} is a CoSip device.
*
* @return true if it is a CoSip device, otherwise false
*/
public boolean isCoSipDevice() {
return PROTOCOL_ID_COSIP.equals(getConfig().getProtocolId());
}
/**
* Returns true, if the {@link DeviceDTO} is a W-Mbus device.
*
* @return true if it is a W-Mbus device, otherwise false
*/
public boolean isWMBusDevice() {
return PROTOCOL_ID_WMBUS.equals(getConfig().getProtocolId());
}
@Override
public String toString() {
return "Device [" + "id=" + getId() + " manufacturer=" + getManufacturer() + " version=" + getVersion()
+ " product=" + getProduct() + " serialnumber=" + getSerialNumber() + " type=" + getType() + " name="
+ getConfig().getName() + "]";
}
}

View File

@ -0,0 +1,150 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.device;
import java.util.HashMap;
import org.openhab.binding.livisismarthome.internal.client.api.entity.PropertyDTO;
/**
* Defines the {@link DeviceStateDTO}, e.g. if the device is reachable.
*
* @author Oliver Kuhl - Initial contribution
*/
public class DeviceStateDTO {
private static final String DEVICE_UPDATE_STATE_UPTODATE = "UpToDate";
private String id;
private StateDTO state;
private HashMap<String, PropertyDTO> stateMap;
public DeviceStateDTO() {
state = new StateDTO();
stateMap = new HashMap<>();
}
/**
* @return the id
*/
public String getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(String id) {
this.id = id;
}
/**
* @return the state
*/
public StateDTO getState() {
return state;
}
/**
* @param state the state to set
*/
public void setState(StateDTO state) {
this.state = state;
}
/**
* Returns true if the device is reachable, false otherwise.
*
* @return true or false for "reachable" {@link DeviceDTO}s, else null.
*/
public Boolean isReachable() {
return getState().getIsReachable().getValue();
}
/**
* Returns if the {@link StateDTO} "isReachable" is available for the current {@link DeviceDTO}.
*
* @return true if the reachable state is available, otherwise false
*/
public Boolean hasIsReachableState() {
return getState().getIsReachable() != null;
}
/**
* Sets if the {@link DeviceDTO} is reachable.
*
* @param isReachable reachable (boolean)
*/
public void setReachable(boolean isReachable) {
getState().getIsReachable().setValue(isReachable);
}
/**
* Returns the configuration state of the device.
*
* @return the configuration state
*/
public String getDeviceConfigurationState() {
return getState().getDeviceConfigurationState().getValue();
}
/**
* Returns the device inclusion state.
*
* @return the device inclusion state
*/
public String getDeviceInclusionState() {
return getState().getDeviceInclusionState().getValue();
}
/**
* @return the stateMap
*/
public HashMap<String, PropertyDTO> getStateMap() {
return stateMap;
}
/**
* @param stateMap the stateMap to set
*/
public void setStateMap(HashMap<String, PropertyDTO> stateMap) {
this.stateMap = stateMap;
}
/**
* Return the update state of the {@link DeviceDTO}.
*
* @return the update state
*/
public String getDeviceUpdateState() {
return getState().getUpdateState().getValue();
}
/**
* Returns true if the {@link DeviceDTO} is up to date.
*
* @return true, if the deviceUpdateState is "UpToDate"
*/
public Boolean deviceIsUpToDate() {
return DEVICE_UPDATE_STATE_UPTODATE.equals(getDeviceUpdateState());
}
/**
* Returns the firmware version of the {@link DeviceDTO}.
*
* @return the firmware version
*/
public String getFirmwareVersion() {
return getState().getFirmwareVersion().getValue();
}
}

View File

@ -0,0 +1,40 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.device;
/**
* Defines the {@link GatewayDTO} structure.
*
* @author Oliver Kuhl - Initial contribution
*/
public class GatewayDTO {
/**
* Version of the configuration. Changes each time the configuration was changed via the LIVISI client app.
*/
private String configVersion;
/**
* @return the configuration version
*/
public String getConfigVersion() {
return configVersion;
}
/**
* @param configVersion the config version to set
*/
public void setConfigVersion(String configVersion) {
this.configVersion = configVersion;
}
}

View File

@ -0,0 +1,473 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.device;
import org.openhab.binding.livisismarthome.internal.client.api.entity.state.BooleanStateDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.state.DateTimeStateDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.state.DoubleStateDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.state.IntegerStateDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.state.StringStateDTO;
import com.google.gson.annotations.SerializedName;
/**
* Holds the state of the Device.
*
* @author Oliver Kuhl - Initial contribution
*
*/
public class StateDTO {
/** Standard device states */
@SerializedName("deviceInclusionState")
private StringStateDTO deviceInclusionState;
@SerializedName("deviceConfigurationState")
private StringStateDTO deviceConfigurationState;
private BooleanStateDTO isReachable;
private StringStateDTO updateState;
private StringStateDTO firmwareVersion;
@SerializedName("WHRating")
private DoubleStateDTO wHRating;
/** SHC device states */
// Removed updateAvailable because it is different between version 1 and 2 devices and not used anyway
// Related to openhab-addons #6613
// private StringState updateAvailable
private DateTimeStateDTO lastReboot;
private DoubleStateDTO memoryLoad;
@SerializedName("CPULoad")
private DoubleStateDTO cpuLoad;
@SerializedName("LBDongleAttached")
private BooleanStateDTO lBDongleAttached;
@SerializedName("MBusDongleAttached")
private BooleanStateDTO mBusDongleAttached;
private IntegerStateDTO configVersion;
@SerializedName("OSState")
private StringStateDTO osState;
private IntegerStateDTO wifiSignalStrength;
private StringStateDTO ethIpAddress;
private StringStateDTO wifiIpAddress;
private StringStateDTO ethMacAddress;
private StringStateDTO wifiMacAddress;
private StringStateDTO inUseAdapter;
private BooleanStateDTO discoveryActive;
private StringStateDTO operationStatus;
private DoubleStateDTO currentUtcOffset;
private DoubleStateDTO cpuUsage;
private DoubleStateDTO diskUsage;
private DoubleStateDTO memoryUsage;
public StateDTO() {
deviceInclusionState = new StringStateDTO();
deviceConfigurationState = new StringStateDTO();
isReachable = new BooleanStateDTO();
updateState = new StringStateDTO();
firmwareVersion = new StringStateDTO();
wHRating = new DoubleStateDTO();
lastReboot = new DateTimeStateDTO();
memoryLoad = new DoubleStateDTO();
cpuLoad = new DoubleStateDTO();
lBDongleAttached = new BooleanStateDTO();
mBusDongleAttached = new BooleanStateDTO();
configVersion = new IntegerStateDTO();
osState = new StringStateDTO();
wifiSignalStrength = new IntegerStateDTO();
ethIpAddress = new StringStateDTO();
wifiIpAddress = new StringStateDTO();
ethMacAddress = new StringStateDTO();
wifiMacAddress = new StringStateDTO();
inUseAdapter = new StringStateDTO();
discoveryActive = new BooleanStateDTO();
operationStatus = new StringStateDTO();
currentUtcOffset = new DoubleStateDTO();
cpuUsage = new DoubleStateDTO();
diskUsage = new DoubleStateDTO();
memoryUsage = new DoubleStateDTO();
}
/**
* @return the deviceInclusionState
*/
public StringStateDTO getDeviceInclusionState() {
return deviceInclusionState;
}
/**
* @param deviceInclusionState the deviceInclusionState to set
*/
public void setDeviceInclusionState(StringStateDTO deviceInclusionState) {
this.deviceInclusionState = deviceInclusionState;
}
/**
* @return the deviceConfigurationState
*/
public StringStateDTO getDeviceConfigurationState() {
return deviceConfigurationState;
}
/**
* @param deviceConfigurationState the deviceConfigurationState to set
*/
public void setDeviceConfigurationState(StringStateDTO deviceConfigurationState) {
this.deviceConfigurationState = deviceConfigurationState;
}
/**
* @return the isReachable
*/
public BooleanStateDTO getIsReachable() {
return isReachable;
}
/**
* @param isReachable the isReachable to set
*/
public void setIsReachable(BooleanStateDTO isReachable) {
this.isReachable = isReachable;
}
/**
* @return the updateState
*/
public StringStateDTO getUpdateState() {
return updateState;
}
/**
* @param updateState the updateState to set
*/
public void setUpdateState(StringStateDTO updateState) {
this.updateState = updateState;
}
/**
* @return the firmwareVersion
*/
public StringStateDTO getFirmwareVersion() {
return firmwareVersion;
}
/**
* @param firmwareVersion the firmwareVersion to set
*/
public void setFirmwareVersion(StringStateDTO firmwareVersion) {
this.firmwareVersion = firmwareVersion;
}
/**
* @return the wHRating
*/
public DoubleStateDTO getWHRating() {
return wHRating;
}
/**
* @param wHRating the wHRating to set
*/
public void setWHRating(DoubleStateDTO wHRating) {
this.wHRating = wHRating;
}
/**
* @return the lastReboot
*/
public DateTimeStateDTO getLastReboot() {
return lastReboot;
}
/**
* @param lastReboot the lastReboot to set
*/
public void setLastReboot(DateTimeStateDTO lastReboot) {
this.lastReboot = lastReboot;
}
/**
* @return the memoryLoad
*/
public DoubleStateDTO getMemoryLoad() {
return memoryLoad;
}
/**
* @param memoryLoad the memoryLoad to set
*/
public void setMemoryLoad(DoubleStateDTO memoryLoad) {
this.memoryLoad = memoryLoad;
}
/**
* @return the cPULoad
*/
public DoubleStateDTO getCPULoad() {
return cpuLoad;
}
/**
* @param cpuLoad the cPULoad to set
*/
public void setCPULoad(DoubleStateDTO cpuLoad) {
this.cpuLoad = cpuLoad;
}
/**
* @return the lBDongleAttached
*/
public BooleanStateDTO getLBDongleAttached() {
return lBDongleAttached;
}
/**
* @param lBDongleAttached the lBDongleAttached to set
*/
public void setLBDongleAttached(BooleanStateDTO lBDongleAttached) {
this.lBDongleAttached = lBDongleAttached;
}
/**
* @return the mBusDongleAttached
*/
public BooleanStateDTO getMBusDongleAttached() {
return mBusDongleAttached;
}
/**
* @param mBusDongleAttached the mBusDongleAttached to set
*/
public void setMBusDongleAttached(BooleanStateDTO mBusDongleAttached) {
this.mBusDongleAttached = mBusDongleAttached;
}
/**
* @return the configVersion
*/
public IntegerStateDTO getConfigVersion() {
return configVersion;
}
/**
* @param configVersion the configVersion to set
*/
public void setConfigVersion(IntegerStateDTO configVersion) {
this.configVersion = configVersion;
}
/**
* @return the oSState
*/
public StringStateDTO getOSState() {
return osState;
}
/**
* @param osState the oSState to set
*/
public void setOSState(StringStateDTO osState) {
this.osState = osState;
}
/**
* @return the wifiSignalStrength
*/
public IntegerStateDTO getWifiSignalStrength() {
return wifiSignalStrength;
}
/**
* @param wifiSignalStrength the wifiSignalStrength to set
*/
public void setWifiSignalStrength(IntegerStateDTO wifiSignalStrength) {
this.wifiSignalStrength = wifiSignalStrength;
}
/**
* @return the ethIpAddress
*/
public StringStateDTO getEthIpAddress() {
return ethIpAddress;
}
/**
* @param ethIpAddress the ethIpAddress to set
*/
public void setEthIpAddress(StringStateDTO ethIpAddress) {
this.ethIpAddress = ethIpAddress;
}
/**
* @return the wifiIpAddress
*/
public StringStateDTO getWifiIpAddress() {
return wifiIpAddress;
}
/**
* @param wifiIpAddress the wifiIpAddress to set
*/
public void setWifiIpAddress(StringStateDTO wifiIpAddress) {
this.wifiIpAddress = wifiIpAddress;
}
/**
* @return the ethMacAddress
*/
public StringStateDTO getEthMacAddress() {
return ethMacAddress;
}
/**
* @param ethMacAddress the ethMacAddress to set
*/
public void setEthMacAddress(StringStateDTO ethMacAddress) {
this.ethMacAddress = ethMacAddress;
}
/**
* @return the wifiMacAddress
*/
public StringStateDTO getWifiMacAddress() {
return wifiMacAddress;
}
/**
* @param wifiMacAddress the wifiMacAddress to set
*/
public void setWifiMacAddress(StringStateDTO wifiMacAddress) {
this.wifiMacAddress = wifiMacAddress;
}
/**
* @return the inUseAdapter
*/
public StringStateDTO getInUseAdapter() {
return inUseAdapter;
}
/**
* @param inUseAdapter the inUseAdapter to set
*/
public void setInUseAdapter(StringStateDTO inUseAdapter) {
this.inUseAdapter = inUseAdapter;
}
/**
* @return the discoveryActive
*/
public BooleanStateDTO getDiscoveryActive() {
return discoveryActive;
}
/**
* @param discoveryActive the discoveryActive to set
*/
public void setDiscoveryActive(BooleanStateDTO discoveryActive) {
this.discoveryActive = discoveryActive;
}
/**
* @return the operationStatus
*/
public StringStateDTO getOperationStatus() {
return operationStatus;
}
/**
* @param operationStatus the operationStatus to set
*/
public void setOperationStatus(StringStateDTO operationStatus) {
this.operationStatus = operationStatus;
}
/**
* @return the operationStatus
*/
public StringStateDTO getOperationStatus(boolean isSHCClassic) {
if (isSHCClassic) {
return getOSState();
}
return getOperationStatus();
}
/**
* @return the currentUtcOffset
*/
public DoubleStateDTO getCurrentUtcOffset() {
return currentUtcOffset;
}
/**
* @param currentUtcOffset the currentUtcOffset to set
*/
public void setCurrentUtcOffset(DoubleStateDTO currentUtcOffset) {
this.currentUtcOffset = currentUtcOffset;
}
/**
* @return the cpuUsage
*/
public DoubleStateDTO getCpuUsage() {
return cpuUsage;
}
/**
* @param cpuUsage the cpuUsage to set
*/
public void setCpuUsage(DoubleStateDTO cpuUsage) {
this.cpuUsage = cpuUsage;
}
public DoubleStateDTO getCpuUsage(boolean isSHCClassic) {
if (isSHCClassic) {
return getCPULoad();
}
return getCpuUsage();
}
/**
* @return the diskUsage
*/
public DoubleStateDTO getDiskUsage() {
return diskUsage;
}
/**
* @param diskUsage the diskUsage to set
*/
public void setDiskUsage(DoubleStateDTO diskUsage) {
this.diskUsage = diskUsage;
}
/**
* @return the memoryUsage
*/
public DoubleStateDTO getMemoryUsage() {
return memoryUsage;
}
/**
* @param memoryUsage the memoryUsage to set
*/
public void setMemoryUsage(DoubleStateDTO memoryUsage) {
this.memoryUsage = memoryUsage;
}
/**
* @return the memoryUsage
*/
public DoubleStateDTO getMemoryUsage(boolean isSHCClassic) {
if (isSHCClassic) {
return getMemoryLoad();
}
return getMemoryUsage();
}
}

View File

@ -0,0 +1,141 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.error;
import java.util.List;
import com.google.gson.annotations.SerializedName;
/**
* Error response object from the LIVISI SmartHome api.
*
* @author Oliver Kuhl - Initial contribution
*/
public class ErrorResponseDTO {
// General errors
public static final int ERR_UNKNOWN = 1000;
public static final int ERR_SERVICE_UNAVAILABLE = 1001;
public static final int ERR_SERVICE_TIMEOUT = 1002;
public static final int ERR_INTERNAL_API_ERROR = 1003;
public static final int ERR_INVALID_SHC_OPERATION = 1004;
public static final int ERR_MISSING_ARGUMENT_OR_WRONG_VALUE = 1005;
public static final int ERR_SERVICE_TOO_BUSY = 1006;
// Authentication and authorization errors
public static final int ERR_UNKNOWN_AUTHENTICATION_ERROR = 2000;
public static final int ERR_ACCESS_NOT_ALLOWED = 2001;
public static final int ERR_INVALID_TOKEN_REQUEST = 2002;
public static final int ERR_INVALID_CLIENT_CREDENTIALS = 2003;
public static final int ERR_INVALID_TOKEN_SIGNATURE = 2004;
public static final int ERR_SESSION_INITIALIZATION_FAILED = 2005;
public static final int ERR_SESSION_EXISTS = 2006;
public static final int ERR_TOKEN_EXPIRED = 2007;
public static final int ERR_LOGIN_FROM_DIFFERENT_CLIENT = 2008;
public static final int ERR_INVALID_USER_CREDENTIALS = 2009;
public static final int ERR_REMOTE_ACCESS_NOT_ALLOWED = 2010;
public static final int ERR_INSUFFICIENT_PERMISSIONS = 2011;
public static final int ERR_SESSION_NOT_FOUND = 2012;
public static final int ERR_ACCOUNT_TEMPORARY_LOCKED = 2013;
// Entities
public static final int ERR_ENTITY_DOES_NOT_EXIST = 3000;
public static final int ERR_INVALID_REQUEST_CONTENT = 3001;
public static final int ERR_NO_CHANGE_PERFORMED = 3002;
public static final int ERR_ENTITY_ALREADY_EXISTS = 3003;
public static final int ERR_INVALID_INTERACTION = 3004;
// Products
public static final int ERR_PREMIUM_SERVICE_CANNOT_BE_ENABLED_DIRECTLY = 3500;
public static final int ERR_CANNOT_REMOVE_A_PRODUCT_THAT_WAS_PAID = 3501;
// Actions
public static final int ERR_INVALID_ACTION_TRIGGERED = 4000;
public static final int ERR_INVALID_PARAMETER = 4001;
public static final int ERR_TRIGGER_ACTION_NOT_ALLOWED = 4002;
public static final int ERR_UNSUPPORTED_ACTION_TYPE = 4003;
// Configuration
public static final int ERR_ERROR_UPDATING_CONFIG = 5000;
public static final int ERR_CONFIG_LOCKED_BY_OTHER_PROCESS = 5001;
public static final int ERR_COMMUNICATION_WITH_SHC_FAILED = 5002;
public static final int ERR_LATEST_TERMS_AND_CONDITIONS_NOT_ACCEPTED_BY_USER = 5003;
public static final int ERR_ONE_SHC_ALREADY_REGISTERED = 5004;
public static final int ERR_USER_HAS_NO_REGISTERED_SHC = 5005;
public static final int ERR_CONTROLLER_OFFLINE = 5006;
public static final int ERR_REGISTRATION_FAILURE = 5009;
// Smart codes
public static final int ERR_SMARTCODE_REQUEST_NOT_ALLOWED = 6000;
public static final int ERR_SMARTCODE_CANNOT_BE_REDEEMED = 6001;
public static final int ERR_RESTRICTED_ACCESS = 6002;
@SerializedName("errorcode")
private int code;
@SerializedName("description")
private String description;
@SerializedName("messages")
private List<String> messages;
/**
* @return the error code
*/
public int getCode() {
return code;
}
/**
* @param code the error code to set
*/
public void setCode(int code) {
this.code = code;
}
/**
* @return the description
*/
public String getDescription() {
return description;
}
/**
* @param description the description to set
*/
public void setDescription(String description) {
this.description = description;
}
/**
* @return the messages
*/
public List<String> getMessages() {
return messages;
}
/**
* @param messages the messages to set
*/
public void setMessages(List<String> messages) {
this.messages = messages;
}
@Override
public String toString() {
String stringRepresentation = "ErrorResponse [code=" + code + ", description=" + description;
if (messages != null) {
stringRepresentation += ", messages=" + messages.toString();
}
stringRepresentation += "]";
return stringRepresentation;
}
}

View File

@ -0,0 +1,142 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.event;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author Oliver Kuhl - Initial contribution
*/
public class BaseEventDTO {
public static final String TYPE_STATE_CHANGED = "StateChanged";// "device/SHC.RWE/1.0/event/StateChanged";
public static final String TYPE_NEW_MESSAGE_RECEIVED = "NewMessageReceived"; // "device/SHC.RWE/1.0/event/NewMessageReceived";
public static final String TYPE_MESSAGE_CREATED = "MessageCreated";
public static final String TYPE_MESSAGE_DELETED = "MessageDeleted"; // "device/SHC.RWE/1.0/event/MessageDeleted";
public static final String TYPE_DISCONNECT = "Disconnect"; // "/event/Disconnect";
public static final String TYPE_CONFIGURATION_CHANGED = "ConfigurationChanged"; // "device/SHC.RWE/1.0/event/ConfigChanged";
public static final String TYPE_CONTROLLER_CONNECTIVITY_CHANGED = "/event/ControllerConnectivityChanged"; // "device/SHC.RWE/1.0/event/ControllerConnectivityChanged";
public static final String TYPE_BUTTON_PRESSED = "ButtonPressed";
public static final Set<String> SUPPORTED_EVENT_TYPES = Collections
.unmodifiableSet(Stream.of(TYPE_STATE_CHANGED, TYPE_NEW_MESSAGE_RECEIVED, TYPE_MESSAGE_CREATED,
TYPE_MESSAGE_DELETED, TYPE_DISCONNECT, TYPE_CONFIGURATION_CHANGED,
TYPE_CONTROLLER_CONNECTIVITY_CHANGED, TYPE_BUTTON_PRESSED).collect(Collectors.toSet()));
/**
* The event sequence number the gateway keeps track and adds a sequence number to each event for the client to
* identify order and missing events
*/
private Integer sequenceNumber;
/**
* Specifies the type of the event. The type must be the full path to uniquely reference the event definition.
* Always available.
*/
private String type;
/**
* Date and time when the event occurred in the system. Always available.
*/
private String timestamp;
/**
* @return the sequenceNumber
*/
public Integer getSequenceNumber() {
return sequenceNumber;
}
/**
* @return the timestamp
*/
public String getTimestamp() {
return timestamp;
}
/**
* @return the type
*/
public String getType() {
return type;
}
/**
* @param sequenceNumber the sequenceNumber to set
*/
public void setSequenceNumber(Integer sequenceNumber) {
this.sequenceNumber = sequenceNumber;
}
/**
* @param timestamp the timestamp to set
*/
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
/**
* @param type the type to set
*/
public void setType(String type) {
this.type = type;
}
/**
* Returns true, if the {@link EventDTO} is a ConfigChanged event.
*
* @return true if it is a ConfigChanged event, otherwise false
*/
public boolean isConfigChangedEvent() {
return TYPE_CONFIGURATION_CHANGED.equals(getType());
}
/**
* Returns true, if the {@link EventDTO} is a Disconnect event.
*
* @return true if it is a Disconnect event, otherwise false
*/
public boolean isDisconnectedEvent() {
return TYPE_DISCONNECT.equals(getType());
}
/**
* Returns true, if the {@link EventDTO} is a MessageDeletedEvent.
*
* @return true if it is a MessageDeleted event, otherwise false
*/
public boolean isMessageDeletedEvent() {
return TYPE_MESSAGE_DELETED.equals(getType());
}
/**
* Returns true, if the {@link EventDTO} is a NewMessageReceivedEvent.
*
* @return true if it is a MessageReceived event, otherwise false
*/
public boolean isNewMessageReceivedEvent() {
return TYPE_NEW_MESSAGE_RECEIVED.equals(getType());
}
/**
* Returns true, if the {@link EventDTO} is a StateChangedEvent.
*
* @return true if it is a StateChanged event, otherwise false
*/
public boolean isStateChangedEvent() {
return TYPE_STATE_CHANGED.equals(getType());
}
}

View File

@ -0,0 +1,204 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.event;
import org.openhab.binding.livisismarthome.internal.client.api.entity.link.LinkDTO;
/**
* Defines the {@link EventDTO}, which is sent by the LIVISI websocket to inform the clients about changes.
*
* @author Oliver Kuhl - Initial contribution
*/
public class EventDTO extends BaseEventDTO {
/**
* Reference to the associated entity (instance or metadata) for the given event. Always available.
*/
private String source;
/**
* The product (context) that generated the event.
*/
private String namespace;
/**
* This container includes only properties, e.g. for the changed state properties. If there is other data than
* properties to be transported, the data container will be used.
* Optional.
*/
private EventPropertiesDTO properties;
/**
* Data for the event, The data container can contain any type of entity dependent on the event type. For example,
* the DeviceFound events contains the entire Device entity rather than selected properties.
* Optional.
*/
private EventDataDTO data;
/**
* @return the link to the source
*/
public String getSource() {
return source;
}
/**
* @param source the link to the source to set
*/
public void setSource(String source) {
this.source = source;
}
/**
* @return the namespace
*/
public String getNamespace() {
return namespace;
}
/**
* @param namespace the namespace to set
*/
public void setNamespace(String namespace) {
this.namespace = namespace;
}
/**
* @return the properties
*/
public EventPropertiesDTO getProperties() {
return properties;
}
/**
* @param properties the properties to set
*/
public void setProperties(EventPropertiesDTO properties) {
this.properties = properties;
}
/**
* @return the dataList
*/
public EventDataDTO getData() {
return data;
}
/**
* @param data the data to set
*/
public void setData(EventDataDTO data) {
this.data = data;
}
/**
* Returns the id of the link or null, if there is no link or the link does not have an id.
*
* @return String the id of the link or null
*/
public String getSourceId() {
final String linkType = getSourceLinkType();
if (linkType != null && !LinkDTO.LINK_TYPE_UNKNOWN.equals(linkType)
&& !LinkDTO.LINK_TYPE_SHC.equals(linkType)) {
if (source != null) {
String sourceId = source.replace(linkType, "");
sourceId = sourceId.replace("-", "");
return sourceId;
}
}
return null;
}
/**
* Returns the Type of the {@link LinkDTO} in the {@link EventDTO}.
*
* @return link type
*/
public String getSourceLinkType() {
if (source != null) {
return LinkDTO.getLinkType(source);
}
return null;
}
/**
* Returns true, if the {@link LinkDTO} points to a
* {@link org.openhab.binding.livisismarthome.internal.client.api.entity.capability.CapabilityDTO}.
*
* @return true if the link points to a capability, otherwise false
*/
public Boolean isLinkedtoCapability() {
return source != null && LinkDTO.isTypeCapability(source);
}
/**
* Returns true, if the {@link LinkDTO} points to a
* {@link org.openhab.binding.livisismarthome.internal.client.api.entity.device.DeviceDTO}.
*
* @return true if the link points to a device, otherwise false
*/
public Boolean isLinkedtoDevice() {
return source != null && LinkDTO.isTypeDevice(source);
}
/**
* Returns true, if the {@link LinkDTO} points to a
* {@link org.openhab.binding.livisismarthome.internal.client.api.entity.message.MessageDTO}.
*
* @return true if the link points to a message, otherwise false
*/
public Boolean isLinkedtoMessage() {
return source != null && LinkDTO.isTypeMessage(source);
}
/**
* Returns true, if the {@link LinkDTO} points to the SHC
* {@link org.openhab.binding.livisismarthome.internal.client.api.entity.device.DeviceDTO}.
*
* @return true if the link points to a SHC bridge device, otherwise false
*/
public Boolean isLinkedtoSHC() {
return source != null && LinkDTO.isTypeSHC(source);
}
/**
* Returns true, if it is a button pressed event. Otherwise false.
* It is a button pressed event when button index is set (LastPressedButtonIndex is set too).
*
* @return true if it is a button pressed event, otherwise false
*/
public boolean isButtonPressedEvent() {
final Integer buttonIndex = getProperties().getKeyPressButtonIndex();
return buttonIndex != null;
}
/**
* Returns the configurationVersion or null, if this
* {@link org.openhab.binding.livisismarthome.internal.client.api.entity.PropertyDTO} is not available in the event.
*
* @return configuration version
*/
public Integer getConfigurationVersion() {
return getData().getConfigVersion();
}
/**
* Returns the isConnected {@link org.openhab.binding.livisismarthome.internal.client.api.entity.PropertyDTO} value.
* Only available for event of type ControllerConnectivityChanged
*
* @return {@link Boolean} or <code>null</code>, if not available
*/
public Boolean getIsConnected() {
return getProperties().getIsConnected();
}
}

View File

@ -0,0 +1,45 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.event;
/**
* @author Oliver Kuhl - Initial contribution
*
*/
public class EventDataDTO {
private Integer configVersion;
private String id;
/**
* @return the configVersion
*/
public Integer getConfigVersion() {
return configVersion;
}
/**
* @param configVersion the configVersion to set
*/
public void setConfigVersion(Integer configVersion) {
this.configVersion = configVersion;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}

View File

@ -0,0 +1,641 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.event;
import com.google.gson.annotations.SerializedName;
/**
* @author Oliver Kuhl - Initial contribution
*/
public class EventPropertiesDTO {
/** SHC Properties **/
private Integer configVersion;
private Boolean isConnected;
/** Writable capability properties **/
private Integer dimLevel;
private Boolean onState;
private String operationMode;
private String operationStatus;
private Double pointTemperature;
private Integer shutterLevel;
private Boolean value;
/** readable capability properties **/
private Double absoluteEnergyConsumption;
private Double energyConsumptionDayEuro;
private Double energyConsumptionDayKWh;
private Double energyConsumptionMonthEuro;
private Double energyConsumptionMonthKWh;
private Double energyPerDayInEuro;
private Double energyPerDayInKWh;
private Double energyPerMonthInEuro;
private Double energyPerMonthInKWh;
private Boolean frostWarning;
private Double humidity;
private Boolean isReachable;
private Boolean isOpen;
private Boolean isSmokeAlarm;
@SerializedName("type")
private String keyPressType;
@SerializedName("index")
private Integer keyPressButtonIndex;
private Integer keyPressCounter;
@SerializedName("lastPressedButtonIndex")
private Integer lastKeyPressButtonIndex;
private Integer lastKeyPressCounter;
private Double luminance;
private Boolean moldWarning;
private Integer motionDetectedCount;
private Double powerConsumptionWatt;
private Double powerInWatt;
private Double temperature;
private Double totalEnergy;
private Boolean windowReductionActive;
private Double cpuUsage;
private Double diskUsage;
private Double memoryUsage;
@SerializedName("CPULoad")
private Double cpuLoad;
private Double memoryLoad;
@SerializedName("OSState")
private String osState;
/**
* @return the configurationVersion
*/
public Integer getConfigVersion() {
return configVersion;
}
/**
* @param configVersion the configurationVersion to set
*/
public void setConfigVersion(final Integer configVersion) {
this.configVersion = configVersion;
}
/**
* @return the isConnected
*/
public Boolean getIsConnected() {
return isConnected;
}
/**
* @param isConnected the isConnected to set
*/
public void setIsConnected(final Boolean isConnected) {
this.isConnected = isConnected;
}
/**
* @return the dimLevel
*/
public Integer getDimLevel() {
return dimLevel;
}
/**
* @param dimLevel the dimLevel to set
*/
public void setDimLevel(final Integer dimLevel) {
this.dimLevel = dimLevel;
}
/**
* @return the onState
*/
public Boolean getOnState() {
return onState;
}
/**
* @param onState the onState to set
*/
public void setOnState(final Boolean onState) {
this.onState = onState;
}
/**
* @return the operationMode
*/
public String getOperationMode() {
return operationMode;
}
/**
* @param operationMode the operationMode to set
*/
public void setOperationMode(final String operationMode) {
this.operationMode = operationMode;
}
/**
* @return the operationStatus
*/
public String getOperationStatus() {
return operationStatus;
}
/**
* @param operationStatus the operationStatus to set
*/
public void setOperationStatus(final String operationStatus) {
this.operationStatus = operationStatus;
}
/**
* @return the pointTemperature
*/
public Double getPointTemperature() {
return pointTemperature;
}
/**
* @param pointTemperature the pointTemperature to set
*/
public void setPointTemperature(final Double pointTemperature) {
this.pointTemperature = pointTemperature;
}
/**
* @return the shutterLevel
*/
public Integer getShutterLevel() {
return shutterLevel;
}
/**
* @param shutterLevel the shutterLevel to set
*/
public void setShutterLevel(final Integer shutterLevel) {
this.shutterLevel = shutterLevel;
}
/**
* @return the value
*/
public Boolean getValue() {
return value;
}
/**
* @param value the value to set
*/
public void setValue(final Boolean value) {
this.value = value;
}
/**
* @return the absoluteEnergyConsumption
*/
public Double getAbsoluteEnergyConsumption() {
return absoluteEnergyConsumption;
}
/**
* @param absoluteEnergyConsumption the absoluteEnergyConsumption to set
*/
public void setAbsoluteEnergyConsumption(final Double absoluteEnergyConsumption) {
this.absoluteEnergyConsumption = absoluteEnergyConsumption;
}
/**
* @return the energyConsumptionDayEuro
*/
public Double getEnergyConsumptionDayEuro() {
return energyConsumptionDayEuro;
}
/**
* @param energyConsumptionDayEuro the energyConsumptionDayEuro to set
*/
public void setEnergyConsumptionDayEuro(final Double energyConsumptionDayEuro) {
this.energyConsumptionDayEuro = energyConsumptionDayEuro;
}
/**
* @return the energyConsumptionDayKWh
*/
public Double getEnergyConsumptionDayKWh() {
return energyConsumptionDayKWh;
}
/**
* @param energyConsumptionDayKWh the energyConsumptionDayKWh to set
*/
public void setEnergyConsumptionDayKWh(final Double energyConsumptionDayKWh) {
this.energyConsumptionDayKWh = energyConsumptionDayKWh;
}
/**
* @return the energyConsumptionMonthEuro
*/
public Double getEnergyConsumptionMonthEuro() {
return energyConsumptionMonthEuro;
}
/**
* @param energyConsumptionMonthEuro the energyConsumptionMonthEuro to set
*/
public void setEnergyConsumptionMonthEuro(final Double energyConsumptionMonthEuro) {
this.energyConsumptionMonthEuro = energyConsumptionMonthEuro;
}
/**
* @return the energyConsumptionMonthKWh
*/
public Double getEnergyConsumptionMonthKWh() {
return energyConsumptionMonthKWh;
}
/**
* @param energyConsumptionMonthKWh the energyConsumptionMonthKWh to set
*/
public void setEnergyConsumptionMonthKWh(final Double energyConsumptionMonthKWh) {
this.energyConsumptionMonthKWh = energyConsumptionMonthKWh;
}
/**
* @return the energyPerDayInEuro
*/
public Double getEnergyPerDayInEuro() {
return energyPerDayInEuro;
}
/**
* @param energyPerDayInEuro the energyPerDayInEuro to set
*/
public void setEnergyPerDayInEuro(final Double energyPerDayInEuro) {
this.energyPerDayInEuro = energyPerDayInEuro;
}
/**
* @return the energyPerDayInKWh
*/
public Double getEnergyPerDayInKWh() {
return energyPerDayInKWh;
}
/**
* @param energyPerDayInKWh the energyPerDayInKWh to set
*/
public void setEnergyPerDayInKWh(final Double energyPerDayInKWh) {
this.energyPerDayInKWh = energyPerDayInKWh;
}
/**
* @return the energyPerMonthInEuro
*/
public Double getEnergyPerMonthInEuro() {
return energyPerMonthInEuro;
}
/**
* @param energyPerMonthInEuro the energyPerMonthInEuro to set
*/
public void setEnergyPerMonthInEuro(final Double energyPerMonthInEuro) {
this.energyPerMonthInEuro = energyPerMonthInEuro;
}
/**
* @return the energyPerMonthInKWh
*/
public Double getEnergyPerMonthInKWh() {
return energyPerMonthInKWh;
}
/**
* @param energyPerMonthInKWh the energyPerMonthInKWh to set
*/
public void setEnergyPerMonthInKWh(final Double energyPerMonthInKWh) {
this.energyPerMonthInKWh = energyPerMonthInKWh;
}
/**
* @return the frostWarning
*/
public Boolean getFrostWarning() {
return frostWarning;
}
/**
* @param frostWarning the frostWarning to set
*/
public void setFrostWarning(final Boolean frostWarning) {
this.frostWarning = frostWarning;
}
/**
* @return the humidity
*/
public Double getHumidity() {
return humidity;
}
/**
* @param humidity the humidity to set
*/
public void setHumidity(final Double humidity) {
this.humidity = humidity;
}
/**
* @return if the device is reachable
*/
public Boolean getReachable() {
return isReachable;
}
/**
* @param reachable if the device is reachable
*/
public void setReachable(Boolean reachable) {
isReachable = reachable;
}
/**
* @return the isOpen
*/
public Boolean getIsOpen() {
return isOpen;
}
/**
* @param isOpen the isOpen to set
*/
public void setIsOpen(final Boolean isOpen) {
this.isOpen = isOpen;
}
/**
* @return the isSmokeAlarm
*/
public Boolean getIsSmokeAlarm() {
return isSmokeAlarm;
}
/**
* @param isSmokeAlarm the isSmokeAlarm to set
*/
public void setIsSmokeAlarm(final Boolean isSmokeAlarm) {
this.isSmokeAlarm = isSmokeAlarm;
}
public String getKeyPressType() {
return keyPressType;
}
public void setKeyPressType(final String keyPressType) {
this.keyPressType = keyPressType;
}
public Integer getKeyPressButtonIndex() {
return keyPressButtonIndex;
}
public void setKeyPressButtonIndex(final Integer keyPressButtonIndex) {
this.keyPressButtonIndex = keyPressButtonIndex;
}
public Integer getKeyPressCounter() {
return keyPressCounter;
}
public void setKeyPressCounter(final Integer keyPressCounter) {
this.keyPressCounter = keyPressCounter;
}
public Integer getLastKeyPressButtonIndex() {
return lastKeyPressButtonIndex;
}
public void setLastKeyPressButtonIndex(final Integer lastKeyPressButtonIndex) {
this.lastKeyPressButtonIndex = lastKeyPressButtonIndex;
}
public Integer getLastKeyPressCounter() {
return lastKeyPressCounter;
}
public void setLastKeyPressCounter(final Integer lastKeyPressCounter) {
this.lastKeyPressCounter = lastKeyPressCounter;
}
/**
* @return the luminance
*/
public Double getLuminance() {
return luminance;
}
/**
* @param luminance the luminance to set
*/
public void setLuminance(final Double luminance) {
this.luminance = luminance;
}
/**
* @return the moldWarning
*/
public Boolean getMoldWarning() {
return moldWarning;
}
/**
* @param moldWarning the moldWarning to set
*/
public void setMoldWarning(final Boolean moldWarning) {
this.moldWarning = moldWarning;
}
/**
* @return the motionDetectedCount
*/
public Integer getMotionDetectedCount() {
return motionDetectedCount;
}
/**
* @param motionDetectedCount the motionDetectedCount to set
*/
public void setMotionDetectedCount(final Integer motionDetectedCount) {
this.motionDetectedCount = motionDetectedCount;
}
/**
* @return the powerConsumptionWatt
*/
public Double getPowerConsumptionWatt() {
return powerConsumptionWatt;
}
/**
* @param powerConsumptionWatt the powerConsumptionWatt to set
*/
public void setPowerConsumptionWatt(final Double powerConsumptionWatt) {
this.powerConsumptionWatt = powerConsumptionWatt;
}
/**
* @return the powerInWatt
*/
public Double getPowerInWatt() {
return powerInWatt;
}
/**
* @param powerInWatt the powerInWatt to set
*/
public void setPowerInWatt(final Double powerInWatt) {
this.powerInWatt = powerInWatt;
}
/**
* @return the temperature
*/
public Double getTemperature() {
return temperature;
}
/**
* @param temperature the temperature to set
*/
public void setTemperature(final Double temperature) {
this.temperature = temperature;
}
/**
* @return the totalEnergy
*/
public Double getTotalEnergy() {
return totalEnergy;
}
/**
* @param totalEnergy the totalEnergy to set
*/
public void setTotalEnergy(final Double totalEnergy) {
this.totalEnergy = totalEnergy;
}
/**
* @return the windowReductionActive
*/
public Boolean getWindowReductionActive() {
return windowReductionActive;
}
/**
* @param windowReductionActive the windowReductionActive to set
*/
public void setWindowReductionActive(final Boolean windowReductionActive) {
this.windowReductionActive = windowReductionActive;
}
/**
* @param cpuUsage the cpuUsage to set
*/
public void setCpuUsage(final Double cpuUsage) {
this.cpuUsage = cpuUsage;
}
/**
* @return the cpuUsage
*/
public Double getCpuUsage() {
return cpuUsage;
}
/**
* @param diskUsage the diskUsage to set
*/
public void setDiskUsage(final Double diskUsage) {
this.diskUsage = diskUsage;
}
/**
* @return the diskUsage
*/
public Double getDiskUsage() {
return diskUsage;
}
/**
* @param memoryUsage the memoryUsage to set
*/
public void setMemoryUsage(final Double memoryUsage) {
this.memoryUsage = memoryUsage;
}
/**
* @return the memoryUsage
*/
public Double getMemoryUsage() {
return memoryUsage;
}
public Double getCPULoad() {
return cpuLoad;
}
public void setCPULoad(Double cpuLoad) {
this.cpuLoad = cpuLoad;
}
public Double getCpuUsage(boolean isSHCClassic) {
if (isSHCClassic) {
return getCPULoad();
}
return getCpuUsage();
}
public Double getMemoryLoad() {
return memoryLoad;
}
public void setMemoryLoad(Double memoryLoad) {
this.memoryLoad = memoryLoad;
}
/**
* @return the memoryUsage
*/
public Double getMemoryUsage(boolean isSHCClassic) {
if (isSHCClassic) {
return getMemoryLoad();
}
return getMemoryUsage();
}
public String getOSState() {
return osState;
}
public void setOSState(String osState) {
this.osState = osState;
}
/**
* @return the operationStatus
*/
public String getOperationStatus(boolean isSHCClassic) {
if (isSHCClassic) {
return getOSState();
}
return getOperationStatus();
}
}

View File

@ -0,0 +1,115 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.event;
import org.openhab.binding.livisismarthome.internal.client.api.entity.link.LinkDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.message.MessageDTO;
/**
* Defines the {@link EventDTO}, which is sent by the LIVISI websocket to inform the clients about changes.
*
* @author Oliver Kuhl - Initial contribution
*/
public class MessageEventDTO extends BaseEventDTO {
/**
* Reference to the associated entity (instance or metadata) for the given event. Always available.
*/
private String source;
/**
* The product (context) that generated the event.
*/
private String namespace;
/**
* Data for the event, The data container can contain any type of entity dependent on the event type. For example,
* the DeviceFound events contains the entire Device entity rather than selected properties.
* Optional.
*/
private MessageDTO data;
/**
* @return the link to the source
*/
public String getSource() {
return source;
}
/**
* @param source the link to the source to set
*/
public void setSource(String source) {
this.source = source;
}
/**
* @return the namespace
*/
public String getNamespace() {
return namespace;
}
/**
* @param namespace the namespace to set
*/
public void setNamespace(String namespace) {
this.namespace = namespace;
}
/**
* @return the dataList
*/
public MessageDTO getData() {
return data;
}
/**
* @param data the data to set
*/
public void setData(MessageDTO data) {
this.data = data;
}
public MessageDTO getMessage() {
return data;
}
/**
* Returns the id of the link or null, if there is no link or the link does not have an id.
*
* @return String the id of the link or null
*/
public String getSourceId() {
if (source != null) {
final String linkType = getSourceLinkType();
if (linkType != null && !LinkDTO.LINK_TYPE_UNKNOWN.equals(linkType)
&& !LinkDTO.LINK_TYPE_SHC.equals(linkType)) {
return source.replace(linkType, "");
}
}
return null;
}
/**
* Returns the Type of the {@link LinkDTO} in the {@link EventDTO}.
*
* @return type of the {@link LinkDTO}
*/
private String getSourceLinkType() {
if (source != null) {
return LinkDTO.getLinkType(source);
}
return null;
}
}

View File

@ -0,0 +1,113 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.link;
/**
* Defines the data structure for a {@link LinkDTO}. This is the basic component used to link different data types in
* the
* LIVISI API.
*
* @author Oliver Kuhl - Initial contribution
*/
public class LinkDTO {
public static final String LINK_TYPE_CAPABILITY = "/capability/";
public static final String LINK_TYPE_DEVICE = "/device/";
public static final String LINK_TYPE_MESSAGE = "/message/";
public static final String LINK_TYPE_SHC = "/desc/device/SHC.RWE/";
public static final String LINK_TYPE_UNKNOWN = "unknown";
/**
* Returns the Type of the {@link LinkDTO}.
*
* @return {@link #LINK_TYPE_CAPABILITY},{@link #LINK_TYPE_DEVICE}, {@link #LINK_TYPE_MESSAGE},
* {@link #LINK_TYPE_SHC} or {@link #LINK_TYPE_UNKNOWN}
*/
public static String getLinkType(String link) {
if (link.startsWith(LINK_TYPE_CAPABILITY)) {
return LINK_TYPE_CAPABILITY;
} else if (link.startsWith(LINK_TYPE_DEVICE)) {
return LINK_TYPE_DEVICE;
} else if (link.startsWith(LINK_TYPE_MESSAGE)) {
return LINK_TYPE_MESSAGE;
} else if (link.startsWith(LINK_TYPE_SHC)) {
return LINK_TYPE_SHC;
} else {
return LINK_TYPE_UNKNOWN;
}
}
/**
* Returns the id of the {@link LinkDTO} or null, if the link does not have an id or even no value.
*
* @return String the id of the link or null
*/
public static String getId(String link) {
if (link != null) {
final String linkType = getLinkType(link);
if (linkType != null && !LinkDTO.LINK_TYPE_UNKNOWN.equals(linkType)
&& !LinkDTO.LINK_TYPE_SHC.equals(linkType)) {
return link.replace(linkType, "");
}
}
return null;
}
/**
* Returns true, if the {@link LinkDTO} points to a
* {@link org.openhab.binding.livisismarthome.internal.client.api.entity.capability.CapabilityDTO}.
*
* @return true if the link points to a capability, otherwise false
*/
public static boolean isTypeCapability(String link) {
return LINK_TYPE_CAPABILITY.equals(LinkDTO.getLinkType(link));
}
/**
* Returns true, if the {@link LinkDTO} points to a
* {@link org.openhab.binding.livisismarthome.internal.client.api.entity.device.DeviceDTO}.
*
* @return true if the link points to a device, otherwise false
*/
public static boolean isTypeDevice(String link) {
return LINK_TYPE_DEVICE.equals(LinkDTO.getLinkType(link));
}
/**
* Returns true, if the {@link LinkDTO} points to a
* {@link org.openhab.binding.livisismarthome.internal.client.api.entity.message.MessageDTO}.
*
* @return true if the link points to a message, otherwise false
*/
public static boolean isTypeMessage(String link) {
return LINK_TYPE_MESSAGE.equals(LinkDTO.getLinkType(link));
}
/**
* Returns true, if the {@link LinkDTO} points to a SHC.
*
* @return true if the link points to a SHC bridge device, otherwise false
*/
public static boolean isTypeSHC(String link) {
return LINK_TYPE_SHC.equals(LinkDTO.getLinkType(link));
}
/**
* Returns true, if the {@link LinkDTO} points to something unknown.
*
* @return true if the link points to something unknown, otherwise false
*/
public static boolean isTypeUnknown(String link) {
return LINK_TYPE_UNKNOWN.equals(LinkDTO.getLinkType(link));
}
}

View File

@ -0,0 +1,59 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.location;
/**
* Defines the structure of the configuration of a {@link LocationDTO}.
*
* @author Oliver Kuhl - Initial contribution
*/
public class LocationConfigDTO {
/**
* Name of the {@link LocationDTO}
*/
private String name;
/**
* Type of the {@link LocationDTO}
*/
private String type;
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the type
*/
public String getType() {
return type;
}
/**
* @param type the type to set
*/
public void setType(String type) {
this.type = type;
}
}

View File

@ -0,0 +1,73 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.location;
/**
* Defines a {@link LocationDTO} structure.
*
* @author Oliver Kuhl - Initial contribution
*/
public class LocationDTO {
/**
* Identifier of the location must be unique.
*/
private String id;
/**
* Configuration properties of the {@link LocationDTO}.
*/
private LocationConfigDTO config;
/**
* @return the id
*/
public String getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(String id) {
this.id = id;
}
/**
* @return the config
*/
public LocationConfigDTO getConfig() {
return config;
}
/**
* @param config the config to set
*/
public void setConfig(LocationConfigDTO config) {
this.config = config;
}
/**
* @return the location name
*/
public String getName() {
return getConfig().getName();
}
/**
* @return the location type
*/
public String getType() {
return getConfig().getType();
}
}

View File

@ -0,0 +1,210 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.message;
import java.util.List;
import com.google.gson.annotations.SerializedName;
/**
* Defines the structure of a {@link MessageDTO}. Messages are part of the LIVISI SmartHome system and besides other
* things
* are used
* to raise battery warnings.
*
* @author Oliver Kuhl - Initial contribution
*/
public class MessageDTO {
/** device related messages */
public static final String TYPE_DEVICE_UNREACHABLE = "DeviceUnreachable";
public static final String TYPE_DEVICE_LOW_BATTERY = "DeviceLowBattery";
/**
* Identifier of the message must be unique.
*/
private String id;
/**
* Specifies the type of the message.
*/
private String type;
/**
* Defines whether the message has been viewed by a user.
*/
@SerializedName("read")
private boolean isRead;
/**
* Defines whether it is an alert or a message, default is message.
*/
@SerializedName("class")
private String messageClass;
/**
* Timestamp when the message was created.
*
* Optional.
*/
private String timestamp;
/**
* Reference to the underlying devices, which the message relates to.
*
* Optional.
*/
private List<String> devices;
/**
* Container for all parameters of the message. The parameters are contained in Property entities.
*
* Optional.
*/
private MessagePropertiesDTO properties;
/**
* The product (context) that generated the message.
*/
private String namespace;
/**
* @return the id
*/
public String getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(String id) {
this.id = id;
}
/**
* @return the type
*/
public String getType() {
return type;
}
/**
* @param type the type to set
*/
public void setType(String type) {
this.type = type;
}
/**
* @return the messageClass
*/
public String getMessageClass() {
return messageClass;
}
/**
* @param messageClass the messageClass to set
*/
public void setMessageClass(String messageClass) {
this.messageClass = messageClass;
}
/**
* @return the timestamp
*/
public String getTimestamp() {
return timestamp;
}
/**
* @param timestamp the timestamp to set
*/
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
/**
* @return the isRead
*/
public boolean isRead() {
return isRead;
}
/**
* @param isRead the isRead to set
*/
public void setRead(boolean isRead) {
this.isRead = isRead;
}
/**
* @return the devices
*/
public List<String> getDevices() {
return devices;
}
/**
* @param devices the devices to set
*/
public void setDevices(List<String> devices) {
this.devices = devices;
}
/**
* @return the dataPropertyList
*/
public MessagePropertiesDTO getProperties() {
return properties;
}
/**
* @param properties the dataPropertyList to set
*/
public void setProperties(MessagePropertiesDTO properties) {
this.properties = properties;
}
/**
* @return the namespace
*/
public String getNamespace() {
return namespace;
}
/**
* @param namespace the namespace to set
*/
public void setNamespace(String namespace) {
this.namespace = namespace;
}
/**
* Returns true, if the message is of type "DeviceUnreachable".
*
* @return true if the message is of type "DeviceUnreachable", otherwise false
*/
public boolean isTypeDeviceUnreachable() {
return TYPE_DEVICE_UNREACHABLE.equals(type);
}
/**
* Returns true, if the message is of type "DeviceLowBattery".
*
* @return true if the message is of type "DeviceLowBattery", otherwise false
*/
public boolean isTypeDeviceLowBattery() {
return TYPE_DEVICE_LOW_BATTERY.equals(type);
}
}

View File

@ -0,0 +1,79 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.message;
/**
* @author Oliver Kuhl - Initial contribution
*
*/
public class MessagePropertiesDTO {
/**
* Name of the referenced {@link org.openhab.binding.livisismarthome.internal.client.api.entity.device.DeviceDTO}
*/
private String deviceName;
/**
* Serialnumber of the referenced
* {@link org.openhab.binding.livisismarthome.internal.client.api.entity.device.DeviceDTO}
*/
private String serialNumber;
/**
* Locationname of the referenced
* {@link org.openhab.binding.livisismarthome.internal.client.api.entity.device.DeviceDTO}
*/
private String locationName;
/**
* @return the deviceName
*/
public String getDeviceName() {
return deviceName;
}
/**
* @param deviceName the deviceName to set
*/
public void setDeviceName(String deviceName) {
this.deviceName = deviceName;
}
/**
* @return the serialNumber
*/
public String getSerialNumber() {
return serialNumber;
}
/**
* @param serialNumber the serialNumber to set
*/
public void setSerialNumber(String serialNumber) {
this.serialNumber = serialNumber;
}
/**
* @return the locationName
*/
public String getLocationName() {
return locationName;
}
/**
* @param locationName the locationName to set
*/
public void setLocationName(String locationName) {
this.locationName = locationName;
}
}

View File

@ -0,0 +1,35 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.state;
/**
* @author Oliver Kuhl - Initial contribution
*/
public abstract class BaseStateDTO {
private String lastChanged;
/**
* @return the lastChanged
*/
public String getLastChanged() {
return lastChanged;
}
/**
* @param lastChanged the lastChanged to set
*/
public void setLastChanged(String lastChanged) {
this.lastChanged = lastChanged;
}
}

View File

@ -0,0 +1,35 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.state;
/**
* @author Oliver Kuhl - Initial contribution
*/
public class BooleanStateDTO extends BaseStateDTO {
private Boolean value;
/**
* @return the value
*/
public Boolean getValue() {
return value;
}
/**
* @param value the value to set
*/
public void setValue(Boolean value) {
this.value = value;
}
}

View File

@ -0,0 +1,20 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.state;
/**
* @author Oliver Kuhl - Initial contribution
*/
public class DateTimeStateDTO extends StringStateDTO {
}

View File

@ -0,0 +1,35 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.state;
/**
* @author Oliver Kuhl - Initial contribution
*/
public class DoubleStateDTO extends BaseStateDTO {
private Double value;
/**
* @return the value
*/
public Double getValue() {
return value;
}
/**
* @param value the value to set
*/
public void setValue(Double value) {
this.value = value;
}
}

View File

@ -0,0 +1,35 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.state;
/**
* @author Oliver Kuhl - Initial contribution
*/
public class IntegerStateDTO extends BaseStateDTO {
private Integer value;
/**
* @return the value
*/
public Integer getValue() {
return value;
}
/**
* @param value the value to set
*/
public void setValue(Integer value) {
this.value = value;
}
}

View File

@ -0,0 +1,35 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.api.entity.state;
/**
* @author Oliver Kuhl - Initial contribution
*/
public class StringStateDTO extends BaseStateDTO {
private String value;
/**
* @return the value
*/
public String getValue() {
return value;
}
/**
* @param value the value to set
*/
public void setValue(String value) {
this.value = value;
}
}

View File

@ -0,0 +1,36 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.exception;
import java.io.IOException;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Thrown, when the LIVISI SmartHome Client API returns an unknown error.
*
* @author Oliver Kuhl - Initial contribution
*/
@NonNullByDefault
public class ApiException extends IOException {
private static final long serialVersionUID = -3581569381976159265L;
public ApiException(String message) {
super(message);
}
public ApiException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -0,0 +1,31 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.exception;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Thrown, if an authentication error is given.
*
* @author Hilbrand Bouwkamp - Initial contribution
*
*/
@NonNullByDefault
public class AuthenticationException extends ApiException {
private static final long serialVersionUID = 720872317620845246L;
public AuthenticationException(String message) {
super(message);
}
}

View File

@ -0,0 +1,33 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.exception;
import java.io.IOException;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Thrown, if the LIVISI SmartHome controller (SHC) is offline.
*
* @author Oliver Kuhl - Initial contribution
*
*/
@NonNullByDefault
public class ControllerOfflineException extends IOException {
private static final long serialVersionUID = 2851756294511651529L;
public ControllerOfflineException(String message) {
super(message);
}
}

View File

@ -0,0 +1,31 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.exception;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Thrown, if an action was called with invalid parameters.
*
* @author Oliver Kuhl - Initial contribution
*
*/
@NonNullByDefault
public class InvalidActionTriggeredException extends ApiException {
private static final long serialVersionUID = 5320848072133493770L;
public InvalidActionTriggeredException(String message) {
super(message);
}
}

View File

@ -0,0 +1,31 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.exception;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Thrown, when the authorization fails with a "remote access not allowed" error.
*
* @author Oliver Kuhl - Initial contribution
*
*/
@NonNullByDefault
public class RemoteAccessNotAllowedException extends ApiException {
private static final long serialVersionUID = 3399664327165581656L;
public RemoteAccessNotAllowedException(String message) {
super(message);
}
}

View File

@ -0,0 +1,31 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.exception;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Thrown, if the LIVISI service is unavailable (HTTP response 503).
*
* @author Oliver Kuhl - Initial contribution
*
*/
@NonNullByDefault
public class ServiceUnavailableException extends ApiException {
private static final long serialVersionUID = -9148687420729079329L;
public ServiceUnavailableException(String message) {
super(message);
}
}

View File

@ -0,0 +1,31 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.exception;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Thrown, when a session already exists while initializing a new session.
*
* @author Oliver Kuhl - Initial contribution
*
*/
@NonNullByDefault
public class SessionExistsException extends ApiException {
private static final long serialVersionUID = -5497104376650832564L;
public SessionExistsException(String message) {
super(message);
}
}

View File

@ -0,0 +1,31 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.exception;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Thrown, if the session is not initialized or disconnected.
*
* @author Oliver Kuhl - Initial contribution
*
*/
@NonNullByDefault
public class SessionNotFoundException extends ApiException {
private static final long serialVersionUID = -2621323485648025577L;
public SessionNotFoundException(String message) {
super(message);
}
}

View File

@ -0,0 +1,32 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.client.exception;
import java.io.IOException;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Thrown, if the WebSocket couldn't get started / connected.
*
* @author Sven Strohschein - Initial contribution
*/
@NonNullByDefault
public class WebSocketConnectException extends IOException {
private static final long serialVersionUID = -5594715669510573378L;
public WebSocketConnectException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -0,0 +1,172 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.discovery;
import static org.openhab.binding.livisismarthome.internal.LivisiBindingConstants.PROPERTY_ID;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.livisismarthome.internal.LivisiBindingConstants;
import org.openhab.binding.livisismarthome.internal.client.api.entity.device.DeviceDTO;
import org.openhab.binding.livisismarthome.internal.handler.LivisiBridgeHandler;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link LivisiDeviceDiscoveryService} is responsible for discovering new devices.
*
* @author Oliver Kuhl - Initial contribution
* @author Sven Strohschein - Renamed from Innogy to Livisi
*/
@NonNullByDefault
public class LivisiDeviceDiscoveryService extends AbstractDiscoveryService
implements DiscoveryService, ThingHandlerService {
private static final int SEARCH_TIME_SECONDS = 60;
private final Logger logger = LoggerFactory.getLogger(LivisiDeviceDiscoveryService.class);
private @Nullable LivisiBridgeHandler bridgeHandler;
/**
* Construct an {@link LivisiDeviceDiscoveryService}.
*/
public LivisiDeviceDiscoveryService() {
super(SEARCH_TIME_SECONDS);
}
/**
* Deactivates the {@link LivisiDeviceDiscoveryService} by unregistering it as
* {@link org.openhab.binding.livisismarthome.internal.listener.DeviceStatusListener} on the
* {@link LivisiBridgeHandler}. Older discovery results will be removed.
*
* @see org.openhab.core.config.discovery.AbstractDiscoveryService#deactivate()
*/
@Override
public void deactivate() {
removeOlderResults(new Date().getTime());
}
@Override
public Set<ThingTypeUID> getSupportedThingTypes() {
return LivisiBindingConstants.SUPPORTED_DEVICE_THING_TYPES;
}
@Override
protected void startScan() {
logger.debug("SCAN for new LIVISI SmartHome devices started...");
final LivisiBridgeHandler bridgeHandlerNonNullable = bridgeHandler;
if (bridgeHandlerNonNullable != null) {
for (final DeviceDTO d : bridgeHandlerNonNullable.loadDevices()) {
onDeviceAdded(d);
}
}
}
@Override
protected synchronized void stopScan() {
super.stopScan();
removeOlderResults(getTimestampOfLastScan());
}
public void onDeviceAdded(DeviceDTO device) {
final LivisiBridgeHandler bridgeHandlerNonNullable = bridgeHandler;
if (bridgeHandlerNonNullable != null) {
final ThingUID bridgeUID = bridgeHandlerNonNullable.getThing().getUID();
final Optional<ThingUID> thingUID = getThingUID(bridgeUID, device);
final Optional<ThingTypeUID> thingTypeUID = getThingTypeUID(device);
if (thingUID.isPresent() && thingTypeUID.isPresent()) {
String name = device.getConfig().getName();
if (name.isEmpty()) {
name = device.getSerialNumber();
}
final Map<String, Object> properties = new HashMap<>();
properties.put(PROPERTY_ID, device.getId());
final String label;
if (device.hasLocation()) {
label = device.getType() + ": " + name + " (" + device.getLocation().getName() + ")";
} else {
label = device.getType() + ": " + name;
}
final DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID.get())
.withThingType(thingTypeUID.get()).withProperties(properties).withBridge(bridgeUID)
.withRepresentationProperty(PROPERTY_ID).withLabel(label).build();
thingDiscovered(discoveryResult);
} else {
logger.debug("Discovered unsupported device of type '{}' and name '{}' with id {}", device.getType(),
device.getConfig().getName(), device.getId());
}
}
}
/**
* Returns the {@link ThingUID} for the given {@link DeviceDTO} or empty, if the device type is not available.
*
* @param bridgeUID bridge
* @param device device
* @return {@link ThingUID} for the given {@link DeviceDTO} or empty
*/
private Optional<ThingUID> getThingUID(ThingUID bridgeUID, DeviceDTO device) {
final Optional<ThingTypeUID> thingTypeUID = getThingTypeUID(device);
if (thingTypeUID.isPresent() && getSupportedThingTypes().contains(thingTypeUID.get())) {
return Optional.of(new ThingUID(thingTypeUID.get(), bridgeUID, device.getId()));
}
return Optional.empty();
}
/**
* Returns a {@link ThingTypeUID} for the given {@link DeviceDTO} or empty, if the device type is not available.
*
* @param device device
* @return {@link ThingTypeUID} for the given {@link DeviceDTO} or empty
*/
private Optional<ThingTypeUID> getThingTypeUID(DeviceDTO device) {
final String thingTypeId = device.getType();
if (thingTypeId != null) {
return Optional.of(new ThingTypeUID(LivisiBindingConstants.BINDING_ID, thingTypeId));
}
return Optional.empty();
}
@Override
public void setThingHandler(@Nullable ThingHandler handler) {
if (handler instanceof LivisiBridgeHandler) {
bridgeHandler = (LivisiBridgeHandler) handler;
}
}
@Override
public @Nullable ThingHandler getThingHandler() {
return bridgeHandler;
}
}

View File

@ -0,0 +1,27 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* @author Hilbrand Bouwkamp - Initial contribution
* @author Sven Strohschein - Renamed from Innogy to Livisi
*/
@NonNullByDefault
public class LivisiBridgeConfiguration {
public String host = "";
public String password = "";
public int webSocketIdleTimeout = 900;
}

View File

@ -0,0 +1,924 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.handler;
import static org.openhab.binding.livisismarthome.internal.LivisiBindingConstants.*;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.livisismarthome.internal.LivisiBindingConstants;
import org.openhab.binding.livisismarthome.internal.LivisiWebSocket;
import org.openhab.binding.livisismarthome.internal.client.GsonOptional;
import org.openhab.binding.livisismarthome.internal.client.LivisiClient;
import org.openhab.binding.livisismarthome.internal.client.URLConnectionFactory;
import org.openhab.binding.livisismarthome.internal.client.URLCreator;
import org.openhab.binding.livisismarthome.internal.client.api.entity.action.ShutterActionType;
import org.openhab.binding.livisismarthome.internal.client.api.entity.capability.CapabilityDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.device.DeviceConfigDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.device.DeviceDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.device.DeviceStateDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.event.BaseEventDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.event.EventDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.event.MessageEventDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.link.LinkDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.message.MessageDTO;
import org.openhab.binding.livisismarthome.internal.client.exception.ApiException;
import org.openhab.binding.livisismarthome.internal.client.exception.AuthenticationException;
import org.openhab.binding.livisismarthome.internal.client.exception.ControllerOfflineException;
import org.openhab.binding.livisismarthome.internal.client.exception.InvalidActionTriggeredException;
import org.openhab.binding.livisismarthome.internal.client.exception.RemoteAccessNotAllowedException;
import org.openhab.binding.livisismarthome.internal.client.exception.SessionExistsException;
import org.openhab.binding.livisismarthome.internal.discovery.LivisiDeviceDiscoveryService;
import org.openhab.binding.livisismarthome.internal.listener.DeviceStatusListener;
import org.openhab.binding.livisismarthome.internal.listener.EventListener;
import org.openhab.binding.livisismarthome.internal.manager.DeviceStructureManager;
import org.openhab.binding.livisismarthome.internal.manager.FullDeviceManager;
import org.openhab.core.auth.client.oauth2.AccessTokenRefreshListener;
import org.openhab.core.auth.client.oauth2.AccessTokenResponse;
import org.openhab.core.auth.client.oauth2.OAuthClientService;
import org.openhab.core.auth.client.oauth2.OAuthException;
import org.openhab.core.auth.client.oauth2.OAuthFactory;
import org.openhab.core.auth.client.oauth2.OAuthResponseException;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link LivisiBridgeHandler} is responsible for handling the LIVISI SmartHome controller including the connection
* to the LIVISI SmartHome backend for all communications with the LIVISI SmartHome {@link DeviceDTO}s.
* <p/>
* It implements the {@link AccessTokenRefreshListener} to handle updates of the oauth2 tokens and the
* {@link EventListener} to handle {@link EventDTO}s, that are received by the {@link LivisiWebSocket}.
* <p/>
* The {@link DeviceDTO}s are organized by the {@link DeviceStructureManager}, which is also responsible for the
* connection
* to the LIVISI SmartHome webservice via the {@link LivisiClient}.
*
* @author Oliver Kuhl - Initial contribution
* @author Hilbrand Bouwkamp - Refactored to use openHAB http and oauth2 libraries
* @author Sven Strohschein - Renamed from Innogy to Livisi
*/
@NonNullByDefault
public class LivisiBridgeHandler extends BaseBridgeHandler
implements AccessTokenRefreshListener, EventListener, DeviceStatusListener {
private final Logger logger = LoggerFactory.getLogger(LivisiBridgeHandler.class);
private final GsonOptional gson = new GsonOptional();
private final Object lock = new Object();
private final Map<String, DeviceStatusListener> deviceStatusListeners;
private final OAuthFactory oAuthFactory;
private final HttpClient httpClient;
private @NonNullByDefault({}) LivisiClient client;
private @Nullable LivisiWebSocket webSocket;
private @NonNullByDefault({}) DeviceStructureManager deviceStructMan;
private @Nullable String bridgeId;
private @Nullable ScheduledFuture<?> reInitJob;
private @Nullable ScheduledFuture<?> bridgeRefreshJob;
private @NonNullByDefault({}) LivisiBridgeConfiguration bridgeConfiguration;
private @NonNullByDefault({}) OAuthClientService oAuthService;
private String configVersion = "";
/**
* Constructs a new {@link LivisiBridgeHandler}.
*
* @param bridge Bridge thing to be used by this handler
* @param oAuthFactory Factory class to get OAuth2 service
* @param httpClient httpclient instance
*/
public LivisiBridgeHandler(final Bridge bridge, final OAuthFactory oAuthFactory, final HttpClient httpClient) {
super(bridge);
this.oAuthFactory = oAuthFactory;
this.httpClient = httpClient;
deviceStatusListeners = new ConcurrentHashMap<>();
}
@Override
public void handleCommand(final ChannelUID channelUID, final Command command) {
// not needed
}
@Override
public Collection<Class<? extends ThingHandlerService>> getServices() {
return Collections.singleton(LivisiDeviceDiscoveryService.class);
}
@Override
public void initialize() {
logger.debug("Initializing LIVISI SmartHome BridgeHandler...");
bridgeConfiguration = getConfigAs(LivisiBridgeConfiguration.class);
updateStatus(ThingStatus.UNKNOWN);
initializeClient();
}
/**
* Initializes the services and LivisiClient.
*/
private void initializeClient() {
String tokenURL = URLCreator.createTokenURL(bridgeConfiguration.host);
oAuthService = oAuthFactory.createOAuthClientService(thing.getUID().getAsString(), tokenURL, tokenURL,
"clientId", "clientPass", null, true);
client = createClient(oAuthService);
deviceStructMan = new DeviceStructureManager(createFullDeviceManager(client));
oAuthService.addAccessTokenRefreshListener(this);
getScheduler().schedule(() -> {
try {
requestAccessToken();
scheduleRestartClient(false);
} catch (IOException | OAuthException | OAuthResponseException e) {
logger.debug("Error fetching access tokens. Please check your credentials. Detail: {}", e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/error.connect");
}
}, 0, TimeUnit.SECONDS);
}
/**
* Initializes the client and connects to the LIVISI SmartHome service via Client API. Based on the provided
* configuration while constructing {@link LivisiClient}, the given oauth2 access and refresh tokens are
* used or - if not yet available - new tokens are fetched from the service using the provided auth code.
*/
private void startClient() {
logger.debug("Initializing LIVISI SmartHome client...");
boolean isSuccessfullyRefreshed = refreshDevices();
if (isSuccessfullyRefreshed) {
Optional<DeviceDTO> bridgeDeviceOptional = getBridgeDevice();
if (bridgeDeviceOptional.isPresent()) {
DeviceDTO bridgeDevice = bridgeDeviceOptional.get();
bridgeId = bridgeDevice.getId();
setBridgeProperties(bridgeDevice);
registerDeviceStatusListener(bridgeDevice.getId(), this);
onDeviceStateChanged(bridgeDevice); // initialize channels
scheduleBridgeRefreshJob(bridgeDevice);
startWebSocket(bridgeDevice);
} else {
logger.debug("Failed to get bridge device, re-scheduling startClient.");
scheduleRestartClient(true);
}
}
}
private boolean refreshDevices() {
try {
configVersion = client.refreshStatus();
deviceStructMan.refreshDevices();
return true;
} catch (IOException e) {
if (handleClientException(e)) {
// If exception could not be handled properly it's no use to continue so we won't continue start
logger.debug("Error initializing LIVISI SmartHome client.", e);
}
}
return false;
}
/**
* Start the websocket connection for receiving permanent update {@link EventDTO}s from the LIVISI API.
*/
private void startWebSocket(DeviceDTO bridgeDevice) {
try {
stopWebSocket();
logger.debug("Starting LIVISI SmartHome websocket.");
webSocket = createAndStartWebSocket(bridgeDevice);
updateStatus(ThingStatus.ONLINE);
} catch (final IOException e) {
logger.warn("Error starting websocket.", e);
handleClientException(e);
}
}
private void stopWebSocket() {
LivisiWebSocket webSocket = this.webSocket;
if (webSocket != null && webSocket.isRunning()) {
logger.debug("Stopping LIVISI SmartHome websocket.");
webSocket.stop();
this.webSocket = null;
}
}
@Nullable
LivisiWebSocket createAndStartWebSocket(DeviceDTO bridgeDevice) throws IOException {
final Optional<String> accessToken = getAccessToken(client);
if (accessToken.isEmpty()) {
return null;
}
final String webSocketUrl = URLCreator.createEventsURL(bridgeConfiguration.host, accessToken.get(),
bridgeDevice.isClassicController());
logger.debug("WebSocket URL: {}...{}", webSocketUrl.substring(0, 70),
webSocketUrl.substring(webSocketUrl.length() - 10));
LivisiWebSocket webSocket = new LivisiWebSocket(httpClient, this, URI.create(webSocketUrl),
bridgeConfiguration.webSocketIdleTimeout * 1000);
webSocket.start();
return webSocket;
}
private static Optional<String> getAccessToken(LivisiClient client) throws IOException {
return Optional.of(client.getAccessTokenResponse().getAccessToken());
}
@Override
public void onAccessTokenResponse(final AccessTokenResponse credential) {
scheduleRestartClient(true);
}
/**
* Schedules a re-initialization in the given future.
*
* @param delayed when it is scheduled delayed, it starts with a delay of
* {@link org.openhab.binding.livisismarthome.internal.LivisiBindingConstants#REINITIALIZE_DELAY_SECONDS}
* seconds,
* otherwise it starts directly
*/
private synchronized void scheduleRestartClient(final boolean delayed) {
final ScheduledFuture<?> reInitJobLocal = this.reInitJob;
if (reInitJobLocal == null || !isAlreadyScheduled(reInitJobLocal)) {
long delaySeconds = 0;
if (delayed) {
delaySeconds = REINITIALIZE_DELAY_SECONDS;
}
logger.debug("Scheduling reinitialize in {} delaySeconds.", delaySeconds);
this.reInitJob = getScheduler().schedule(this::startClient, delaySeconds, TimeUnit.SECONDS);
}
}
/**
* Starts a refresh job for the bridge channels, because the SHC 1 (classic) doesn't send events
* for cpu, memory, disc or operation state changes.
* The refresh job is only executed for SHC 1 (classic) bridges, newer bridges like SHC 2 do send events.
*/
private void scheduleBridgeRefreshJob(DeviceDTO bridgeDevice) {
if (bridgeDevice.isClassicController()) {
final ScheduledFuture<?> bridgeRefreshJobLocal = this.bridgeRefreshJob;
if (bridgeRefreshJobLocal == null || !isAlreadyScheduled(bridgeRefreshJobLocal)) {
logger.debug("Scheduling bridge refresh job with an interval of {} seconds.", BRIDGE_REFRESH_SECONDS);
this.bridgeRefreshJob = getScheduler().scheduleWithFixedDelay(() -> {
logger.debug("Refreshing bridge");
refreshBridgeState();
onDeviceStateChanged(bridgeDevice);
}, BRIDGE_REFRESH_SECONDS, BRIDGE_REFRESH_SECONDS, TimeUnit.SECONDS);
}
}
}
private void setBridgeProperties(final DeviceDTO bridgeDevice) {
final DeviceConfigDTO config = bridgeDevice.getConfig();
logger.debug("Setting Bridge Device Properties for Bridge of type '{}' with ID '{}'", config.getName(),
bridgeDevice.getId());
final Map<String, String> properties = editProperties();
setPropertyIfPresent(Thing.PROPERTY_VENDOR, bridgeDevice.getManufacturer(), properties);
setPropertyIfPresent(Thing.PROPERTY_SERIAL_NUMBER, bridgeDevice.getSerialNumber(), properties);
setPropertyIfPresent(PROPERTY_ID, bridgeDevice.getId(), properties);
setPropertyIfPresent(Thing.PROPERTY_FIRMWARE_VERSION, config.getFirmwareVersion(), properties);
setPropertyIfPresent(Thing.PROPERTY_HARDWARE_VERSION, config.getHardwareVersion(), properties);
setPropertyIfPresent(PROPERTY_SOFTWARE_VERSION, config.getSoftwareVersion(), properties);
setPropertyIfPresent(PROPERTY_IP_ADDRESS, config.getIPAddress(), properties);
setPropertyIfPresent(Thing.PROPERTY_MAC_ADDRESS, config.getMACAddress(), properties);
if (config.getRegistrationTime() != null) {
properties.put(PROPERTY_REGISTRATION_TIME,
config.getRegistrationTime().format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)));
}
setPropertyIfPresent(PROPERTY_CONFIGURATION_STATE, config.getConfigurationState(), properties);
setPropertyIfPresent(PROPERTY_SHC_TYPE, bridgeDevice.getType(), properties);
setPropertyIfPresent(PROPERTY_TIME_ZONE, config.getTimeZone(), properties);
setPropertyIfPresent(PROPERTY_PROTOCOL_ID, config.getProtocolId(), properties);
setPropertyIfPresent(PROPERTY_GEOLOCATION, config.getGeoLocation(), properties);
setPropertyIfPresent(PROPERTY_CURRENT_UTC_OFFSET, config.getCurrentUTCOffset(), properties);
setPropertyIfPresent(PROPERTY_BACKEND_CONNECTION_MONITORED, config.getBackendConnectionMonitored(), properties);
setPropertyIfPresent(PROPERTY_RFCOM_FAILURE_NOTIFICATION, config.getRFCommFailureNotification(), properties);
updateProperties(properties);
}
private void setPropertyIfPresent(final String key, final @Nullable Object data,
final Map<String, String> properties) {
if (data != null) {
properties.put(key, data.toString());
}
}
@Override
public void dispose() {
logger.debug("Disposing LIVISI SmartHome bridge handler '{}'", getThing().getUID().getId());
unregisterDeviceStatusListener(bridgeId);
cancelJobs();
stopWebSocket();
client = null;
deviceStructMan = null;
super.dispose();
logger.debug("LIVISI SmartHome bridge handler shut down.");
}
private synchronized void cancelJobs() {
if (cancelJob(reInitJob)) {
reInitJob = null;
}
if (cancelJob(bridgeRefreshJob)) {
bridgeRefreshJob = null;
}
}
private static boolean cancelJob(@Nullable ScheduledFuture<?> job) {
if (job != null) {
job.cancel(true);
return true;
}
return false;
}
/**
* Registers a {@link DeviceStatusListener}.
*
* @param deviceStatusListener listener
*/
public void registerDeviceStatusListener(final String deviceId, final DeviceStatusListener deviceStatusListener) {
deviceStatusListeners.putIfAbsent(deviceId, deviceStatusListener);
}
/**
* Unregisters a {@link DeviceStatusListener}.
*
* @param deviceId id of the device to which the listener is registered
*/
public void unregisterDeviceStatusListener(@Nullable final String deviceId) {
if (deviceId != null) {
deviceStatusListeners.remove(deviceId);
}
}
/**
* Loads a Collection of {@link DeviceDTO}s from the bridge and returns them.
*
* @return a Collection of {@link DeviceDTO}s
*/
public Collection<DeviceDTO> loadDevices() {
return deviceStructMan.getDeviceList();
}
public boolean isSHCClassic() {
return getBridgeDevice().filter(DeviceDTO::isClassicController).isPresent();
}
/**
* Returns the bridge {@link DeviceDTO}.
*
* @return bridge {@link DeviceDTO}
*/
private Optional<DeviceDTO> getBridgeDevice() {
return deviceStructMan.getBridgeDevice();
}
/**
* Returns the {@link DeviceDTO} with the given deviceId.
*
* @param deviceId device id
* @return {@link DeviceDTO} or null, if it does not exist or no {@link DeviceStructureManager} is available
*/
public Optional<DeviceDTO> getDeviceById(final String deviceId) {
return deviceStructMan.getDeviceById(deviceId);
}
private void refreshBridgeState() {
Optional<DeviceDTO> bridgeOptional = getBridgeDevice();
if (bridgeOptional.isPresent()) {
try {
DeviceDTO bridgeDevice = bridgeOptional.get();
DeviceStateDTO deviceState = new DeviceStateDTO();
deviceState.setId(bridgeDevice.getId());
deviceState.setState(client.getDeviceStateByDeviceId(bridgeDevice.getId(), isSHCClassic()));
bridgeDevice.setDeviceState(deviceState);
} catch (IOException e) {
logger.debug("Exception occurred on reloading bridge", e);
}
}
}
/**
* Refreshes the {@link DeviceDTO} with the given id, by reloading the full device from the LIVISI webservice.
*
* @param deviceId device id
* @return the {@link DeviceDTO} or null, if it does not exist or no {@link DeviceStructureManager} is available
*/
public Optional<DeviceDTO> refreshDevice(final String deviceId) {
try {
return deviceStructMan.refreshDevice(deviceId, isSHCClassic());
} catch (IOException e) {
handleClientException(e);
}
return Optional.empty();
}
@Override
public void onDeviceStateChanged(final DeviceDTO bridgeDevice) {
synchronized (this.lock) {
// DEVICE STATES
if (bridgeDevice.hasDeviceState()) {
final boolean isSHCClassic = bridgeDevice.isClassicController();
final Double cpuUsage = bridgeDevice.getDeviceState().getState().getCpuUsage(isSHCClassic).getValue();
if (cpuUsage != null) {
logger.debug("-> CPU usage state: {}", cpuUsage);
updateState(CHANNEL_CPU, QuantityType.valueOf(cpuUsage, Units.PERCENT));
}
final Double diskUsage = bridgeDevice.getDeviceState().getState().getDiskUsage().getValue();
if (diskUsage != null) {
logger.debug("-> Disk usage state: {}", diskUsage);
updateState(CHANNEL_DISK, QuantityType.valueOf(diskUsage, Units.PERCENT));
}
final Double memoryUsage = bridgeDevice.getDeviceState().getState().getMemoryUsage(isSHCClassic)
.getValue();
if (memoryUsage != null) {
logger.debug("-> Memory usage state: {}", memoryUsage);
updateState(CHANNEL_MEMORY, QuantityType.valueOf(memoryUsage, Units.PERCENT));
}
String operationStatus = bridgeDevice.getDeviceState().getState().getOperationStatus(isSHCClassic)
.getValue();
if (operationStatus != null) {
logger.debug("-> Operation status: {}", operationStatus);
updateState(CHANNEL_OPERATION_STATUS, new StringType(operationStatus.toUpperCase()));
}
}
}
}
@Override
public void onDeviceStateChanged(final DeviceDTO bridgeDevice, final EventDTO event) {
synchronized (this.lock) {
if (event.isLinkedtoDevice()) {
final boolean isSHCClassic = bridgeDevice.isClassicController();
bridgeDevice.getDeviceState().getState().getOperationStatus(isSHCClassic)
.setValue(event.getProperties().getOperationStatus(isSHCClassic));
bridgeDevice.getDeviceState().getState().getCpuUsage(isSHCClassic)
.setValue(event.getProperties().getCpuUsage(isSHCClassic));
bridgeDevice.getDeviceState().getState().getDiskUsage().setValue(event.getProperties().getDiskUsage());
bridgeDevice.getDeviceState().getState().getMemoryUsage(isSHCClassic)
.setValue(event.getProperties().getMemoryUsage(isSHCClassic));
onDeviceStateChanged(bridgeDevice);
}
}
}
@Override
public void onEvent(final String msg) {
logger.trace("onEvent called. Msg: {}", msg);
try {
final Optional<EventDTO> eventOptional = parseEvent(msg);
if (eventOptional.isPresent()) {
EventDTO event = eventOptional.get();
switch (event.getType()) {
case BaseEventDTO.TYPE_STATE_CHANGED:
case BaseEventDTO.TYPE_BUTTON_PRESSED:
handleStateChangedEvent(event);
break;
case BaseEventDTO.TYPE_DISCONNECT:
logger.debug("Websocket disconnected.");
scheduleRestartClient(true);
break;
case BaseEventDTO.TYPE_CONFIGURATION_CHANGED:
handleConfigurationChangedEvent(event);
break;
case BaseEventDTO.TYPE_CONTROLLER_CONNECTIVITY_CHANGED:
handleControllerConnectivityChangedEvent(event);
break;
case BaseEventDTO.TYPE_NEW_MESSAGE_RECEIVED:
case BaseEventDTO.TYPE_MESSAGE_CREATED:
final Optional<MessageEventDTO> messageEvent = gson.fromJson(msg, MessageEventDTO.class);
if (messageEvent.isPresent()) {
handleNewMessageReceivedEvent(Objects.requireNonNull(messageEvent.get()));
}
break;
case BaseEventDTO.TYPE_MESSAGE_DELETED:
handleMessageDeletedEvent(event);
break;
default:
logger.debug("Unsupported event type {}.", event.getType());
break;
}
}
} catch (IOException | RuntimeException e) {
logger.debug("Error with Event: {}", e.getMessage(), e);
handleClientException(e);
}
}
@Override
public void onError(final Throwable cause) {
if (cause instanceof Exception) {
handleClientException((Exception) cause);
}
}
/**
* Handles the event that occurs, when the state of a device (like reachability) or a capability (like a temperature
* value) has changed.
*
* @param event event
*/
private void handleStateChangedEvent(final EventDTO event) throws IOException {
// CAPABILITY
if (event.isLinkedtoCapability()) {
logger.trace("Event is linked to capability");
final Optional<DeviceDTO> device = deviceStructMan.getDeviceByCapabilityId(event.getSourceId());
notifyDeviceStatusListeners(device, event);
// DEVICE
} else if (event.isLinkedtoDevice()) {
logger.trace("Event is linked to device");
final String sourceId = event.getSourceId();
final Optional<DeviceDTO> bridgeDevice = deviceStructMan.getBridgeDevice();
final Optional<DeviceDTO> device;
if (bridgeDevice.isPresent() && !sourceId.equals(bridgeDevice.get().getId())) {
device = deviceStructMan.refreshDevice(sourceId, isSHCClassic());
} else {
device = deviceStructMan.getDeviceById(sourceId);
}
notifyDeviceStatusListeners(device, event);
} else {
logger.debug("link type {} not supported (yet?)", event.getSourceLinkType());
}
}
/**
* Handles the event that occurs, when the connectivity of the bridge has changed.
*
* @param event event
*/
private void handleControllerConnectivityChangedEvent(final EventDTO event) throws IOException {
final Boolean connected = event.getIsConnected();
if (connected != null) {
final ThingStatus thingStatus;
if (connected) {
deviceStructMan.refreshDevices();
thingStatus = ThingStatus.ONLINE;
updateStatus(thingStatus);
} else {
thingStatus = ThingStatus.OFFLINE;
}
logger.debug("SmartHome Controller connectivity changed to {} by {} event.", thingStatus,
BaseEventDTO.TYPE_CONTROLLER_CONNECTIVITY_CHANGED);
} else {
logger.debug("isConnected property missing in {} event (returned null)!",
BaseEventDTO.TYPE_CONTROLLER_CONNECTIVITY_CHANGED);
}
}
/**
* Handles the event that occurs, when a new message was received. Currently only handles low battery messages.
*
* @param event event
*/
private void handleNewMessageReceivedEvent(final MessageEventDTO event) throws IOException {
final MessageDTO message = event.getMessage();
if (logger.isTraceEnabled()) {
logger.trace("Message: {}", gson.toJson(message));
logger.trace("Messagetype: {}", message.getType());
}
if (MessageDTO.TYPE_DEVICE_LOW_BATTERY.equals(message.getType()) && message.getDevices() != null) {
for (final String link : message.getDevices()) {
final Optional<DeviceDTO> device = deviceStructMan.refreshDevice(LinkDTO.getId(link), isSHCClassic());
notifyDeviceStatusListener(event.getSourceId(), device);
}
} else {
logger.debug("Message received event not yet implemented for Messagetype {}.", message.getType());
}
}
/**
* Handle the event that occurs, when a message was deleted. In case of a low battery message this means, that the
* device is back to normal. Currently, only messages linked to devices are handled by refreshing the device data
* and informing the {@link LivisiDeviceHandler} about the changed device.
*
* @param event event
*/
private void handleMessageDeletedEvent(final EventDTO event) throws IOException {
final String messageId = event.getData().getId();
logger.debug("handleMessageDeletedEvent with messageId '{}'", messageId);
Optional<DeviceDTO> device = deviceStructMan.getDeviceWithMessageId(messageId);
if (device.isPresent()) {
String id = device.get().getId();
Optional<DeviceDTO> deviceRefreshed = deviceStructMan.refreshDevice(id, isSHCClassic());
notifyDeviceStatusListener(event.getSourceId(), deviceRefreshed);
} else {
logger.debug("No device found with message id {}.", messageId);
}
}
private void handleConfigurationChangedEvent(EventDTO event) {
if (configVersion.equals(event.getConfigurationVersion().toString())) {
logger.debug("Ignored configuration changed event with version '{}' as current version is '{}' the same.",
event.getConfigurationVersion(), configVersion);
} else {
logger.info("Configuration changed from version {} to {}. Restarting LIVISI SmartHome binding...",
configVersion, event.getConfigurationVersion());
scheduleRestartClient(false);
}
}
private void notifyDeviceStatusListener(String deviceId, Optional<DeviceDTO> device) {
if (device.isPresent()) {
DeviceStatusListener deviceStatusListener = deviceStatusListeners.get(device.get().getId());
if (deviceStatusListener != null) {
deviceStatusListener.onDeviceStateChanged(device.get());
} else {
logger.debug("No device status listener registered for device {}.", deviceId);
}
} else {
logger.debug("Unknown/unsupported device {}.", deviceId);
}
}
private void notifyDeviceStatusListeners(Optional<DeviceDTO> device, EventDTO event) {
String sourceId = event.getSourceId();
if (device.isPresent()) {
DeviceStatusListener deviceStatusListener = deviceStatusListeners.get(device.get().getId());
if (deviceStatusListener != null) {
deviceStatusListener.onDeviceStateChanged(device.get(), event);
} else {
logger.debug("No device status listener registered for device / capability {}.", sourceId);
}
} else {
logger.debug("Unknown/unsupported device / capability {}.", sourceId);
}
}
@Override
public void connectionClosed() {
scheduleRestartClient(true);
}
/**
* Sends the command to switch the {@link DeviceDTO} with the given id to the new state. Is called by the
* {@link LivisiDeviceHandler} for switch devices like the VariableActuator, PSS, PSSO or ISS2.
*
* @param deviceId device id
* @param state state (boolean)
*/
public void commandSwitchDevice(final String deviceId, final boolean state) {
// VariableActuator
Optional<DeviceDTO> device = deviceStructMan.getDeviceById(deviceId);
if (device.isPresent()) {
final String deviceType = device.get().getType();
if (DEVICE_VARIABLE_ACTUATOR.equals(deviceType)) {
executeCommand(deviceId, CapabilityDTO.TYPE_VARIABLEACTUATOR,
(capabilityId) -> client.setVariableActuatorState(capabilityId, state));
// PSS / PSSO / ISS2 / BT-PSS
} else if (DEVICE_PSS.equals(deviceType) || DEVICE_PSSO.equals(deviceType) || DEVICE_ISS2.equals(deviceType)
|| DEVICE_BT_PSS.equals((deviceType))) {
executeCommand(deviceId, CapabilityDTO.TYPE_SWITCHACTUATOR,
(capabilityId) -> client.setSwitchActuatorState(capabilityId, state));
}
} else {
logger.debug("No device with id {} could get found!", deviceId);
}
}
/**
* Sends the command to update the point temperature of the {@link DeviceDTO} with the given deviceId. Is called by
* the
* {@link LivisiDeviceHandler} for thermostat {@link DeviceDTO}s like RST or WRT.
*
* @param deviceId device id
* @param pointTemperature point temperature
*/
public void commandUpdatePointTemperature(final String deviceId, final double pointTemperature) {
executeCommand(deviceId, CapabilityDTO.TYPE_THERMOSTATACTUATOR,
(capabilityId) -> client.setPointTemperatureState(capabilityId, pointTemperature));
}
/**
* Sends the command to turn the alarm of the {@link DeviceDTO} with the given id on or off. Is called by the
* {@link LivisiDeviceHandler} for smoke detector {@link DeviceDTO}s like WSD or WSD2.
*
* @param deviceId device id
* @param alarmState alarm state (boolean)
*/
public void commandSwitchAlarm(final String deviceId, final boolean alarmState) {
executeCommand(deviceId, CapabilityDTO.TYPE_ALARMACTUATOR,
(capabilityId) -> client.setAlarmActuatorState(capabilityId, alarmState));
}
/**
* Sends the command to set the operation mode of the {@link DeviceDTO} with the given deviceId to auto (or manual,
* if
* false). Is called by the {@link LivisiDeviceHandler} for thermostat {@link DeviceDTO}s like RST.
*
* @param deviceId device id
* @param isAutoMode true activates the automatic mode, false the manual mode.
*/
public void commandSetOperationMode(final String deviceId, final boolean isAutoMode) {
executeCommand(deviceId, CapabilityDTO.TYPE_THERMOSTATACTUATOR,
(capabilityId) -> client.setOperationMode(capabilityId, isAutoMode));
}
/**
* Sends the command to set the dimm level of the {@link DeviceDTO} with the given id. Is called by the
* {@link LivisiDeviceHandler} for {@link DeviceDTO}s like ISD2 or PSD.
*
* @param deviceId device id
* @param dimLevel dim level
*/
public void commandSetDimLevel(final String deviceId, final int dimLevel) {
executeCommand(deviceId, CapabilityDTO.TYPE_DIMMERACTUATOR,
(capabilityId) -> client.setDimmerActuatorState(capabilityId, dimLevel));
}
/**
* Sends the command to set the rollershutter level of the {@link DeviceDTO} with the given id. Is called by the
* {@link LivisiDeviceHandler} for {@link DeviceDTO}s like ISR2.
*
* @param deviceId device id
* @param rollerShutterLevel roller shutter level
*/
public void commandSetRollerShutterLevel(final String deviceId, final int rollerShutterLevel) {
executeCommand(deviceId, CapabilityDTO.TYPE_ROLLERSHUTTERACTUATOR,
(capabilityId) -> client.setRollerShutterActuatorState(capabilityId, rollerShutterLevel));
}
/**
* Sends the command to start or stop moving the rollershutter (ISR2) in a specified direction
*
* @param deviceId device id
* @param action action
*/
public void commandSetRollerShutterStop(final String deviceId, final ShutterActionType action) {
executeCommand(deviceId, CapabilityDTO.TYPE_ROLLERSHUTTERACTUATOR,
(capabilityId) -> client.setRollerShutterAction(capabilityId, action));
}
private void executeCommand(final String deviceId, final String capabilityType,
final CommandExecutor commandExecutor) {
try {
final Optional<String> capabilityId = deviceStructMan.getCapabilityId(deviceId, capabilityType);
if (capabilityId.isPresent()) {
commandExecutor.executeCommand(capabilityId.get());
}
} catch (IOException e) {
handleClientException(e);
}
}
ScheduledExecutorService getScheduler() {
return scheduler;
}
FullDeviceManager createFullDeviceManager(LivisiClient client) {
return new FullDeviceManager(client);
}
LivisiClient createClient(final OAuthClientService oAuthService) {
return new LivisiClient(bridgeConfiguration, oAuthService, new URLConnectionFactory());
}
/**
* Handles all Exceptions of the client communication. For minor "errors" like an already existing session, it
* returns true to inform the binding to continue running. In other cases it may e.g. schedule a reinitialization of
* the binding.
*
* @param e the Exception
* @return boolean true, if binding should continue.
*/
private boolean handleClientException(final Exception e) {
boolean isReinitialize = true;
if (e instanceof SessionExistsException) {
logger.debug("Session already exists. Continuing...");
isReinitialize = false;
} else if (e instanceof InvalidActionTriggeredException) {
logger.debug("Error triggering action: {}", e.getMessage());
isReinitialize = false;
} else if (e instanceof RemoteAccessNotAllowedException) {
// Remote access not allowed (usually by IP address change)
logger.debug("Remote access not allowed. Dropping access token and reinitializing binding...");
refreshAccessToken();
} else if (e instanceof ControllerOfflineException) {
logger.debug("LIVISI SmartHome Controller is offline.");
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
} else if (e instanceof AuthenticationException) {
logger.debug("OAuthenticaton error, refreshing tokens: {}", e.getMessage());
refreshAccessToken();
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
} else if (e instanceof ApiException) {
logger.warn("Unexpected API error: {}", e.getMessage());
logger.debug("Unexpected API error", e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
} else if (e instanceof TimeoutException) {
logger.debug("WebSocket timeout: {}", e.getMessage());
} else if (e instanceof SocketTimeoutException) {
logger.debug("Socket timeout: {}", e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
} else if (e instanceof IOException) {
logger.debug("IOException occurred", e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
} else if (e instanceof InterruptedException) {
isReinitialize = false;
Thread.currentThread().interrupt();
} else if (e instanceof ExecutionException) {
logger.debug("ExecutionException occurred", e);
updateStatus(ThingStatus.OFFLINE);
} else {
logger.debug("Unknown exception", e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, e.getMessage());
}
if (isReinitialize) {
scheduleRestartClient(true);
}
return isReinitialize;
}
private void refreshAccessToken() {
try {
requestAccessToken();
} catch (IOException | OAuthException | OAuthResponseException e) {
logger.debug("Could not refresh tokens", e);
}
}
private void requestAccessToken() throws OAuthException, IOException, OAuthResponseException {
oAuthService.getAccessTokenByResourceOwnerPasswordCredentials(LivisiBindingConstants.USERNAME,
bridgeConfiguration.password, null);
}
private Optional<EventDTO> parseEvent(final String msg) {
final Optional<BaseEventDTO> baseEventOptional = gson.fromJson(msg, BaseEventDTO.class);
if (baseEventOptional.isPresent()) {
BaseEventDTO baseEvent = baseEventOptional.get();
logger.debug("Event no {} found. Type: {}", baseEvent.getSequenceNumber(), baseEvent.getType());
if (BaseEventDTO.SUPPORTED_EVENT_TYPES.contains(baseEvent.getType())) {
return gson.fromJson(msg, EventDTO.class);
}
logger.debug("Event type {} not supported. Skipping...", baseEvent.getType());
}
return Optional.empty();
}
/**
* Checks if the job is already (re-)scheduled.
*
* @param job job to check
* @return true, when the job is already (re-)scheduled, otherwise false
*/
private static boolean isAlreadyScheduled(ScheduledFuture<?> job) {
return job.getDelay(TimeUnit.SECONDS) > 0;
}
@FunctionalInterface
private interface CommandExecutor {
void executeCommand(String capabilityId) throws IOException;
}
}

View File

@ -0,0 +1,41 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.listener;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.livisismarthome.internal.client.api.entity.device.DeviceDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.event.EventDTO;
/**
* The {@link DeviceStatusListener} is called, when {@link DeviceDTO}s are added, removed or changed.
*
* @author Oliver Kuhl - Initial contribution
*/
@NonNullByDefault
public interface DeviceStatusListener {
/**
* This method is called whenever the state of the given {@link DeviceDTO} has changed.
*
* @param device The device which received the state update.
*/
void onDeviceStateChanged(DeviceDTO device);
/**
* This method is called whenever the state of a {@link DeviceDTO} is changed by the given {@link EventDTO}.
*
* @param device device
* @param event event
*/
void onDeviceStateChanged(DeviceDTO device, EventDTO event);
}

View File

@ -0,0 +1,46 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.listener;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link EventListener} is called by the {@link org.openhab.binding.livisismarthome.internal.LivisiWebSocket} on
* new Events and if the {@link org.openhab.binding.livisismarthome.internal.LivisiWebSocket}
* closed the connection.
*
* @author Oliver Kuhl - Initial contribution
*/
@NonNullByDefault
public interface EventListener {
/**
* This method is called, whenever a new event comes from the LIVISI SmartHome service (like a device change for
* example).
*
* @param msg message
*/
void onEvent(String msg);
/**
* This method is called when the LIVISI SmartHome websocket services throws an onError.
*
* @param cause cause / throwable
*/
void onError(Throwable cause);
/**
* This method is called, when the evenRunner stops abnormally (statuscode <> 1000).
*/
void connectionClosed();
}

View File

@ -0,0 +1,229 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.manager;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.livisismarthome.internal.LivisiBindingConstants;
import org.openhab.binding.livisismarthome.internal.client.api.entity.capability.CapabilityDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.device.DeviceDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.link.LinkDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.message.MessageDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Manages the structure of the {@link DeviceDTO}s and the calls to the
* {@link org.openhab.binding.livisismarthome.internal.client.LivisiClient} to load the {@link DeviceDTO}
* data from the LIVISI SmartHome web service.
*
* @author Oliver Kuhl - Initial contribution
*
*/
@NonNullByDefault
public class DeviceStructureManager {
private final Logger logger = LoggerFactory.getLogger(DeviceStructureManager.class);
private final FullDeviceManager deviceManager;
private final Map<String, DeviceDTO> deviceMap;
private final Map<String, DeviceDTO> capabilityIdToDeviceMap;
private String bridgeDeviceId = "";
/**
* Constructs the {@link DeviceStructureManager}.
*
* @param deviceManager the {@link FullDeviceManager}
*/
public DeviceStructureManager(FullDeviceManager deviceManager) {
this.deviceManager = deviceManager;
deviceMap = Collections.synchronizedMap(new HashMap<>());
capabilityIdToDeviceMap = new ConcurrentHashMap<>();
}
/**
* Returns the {@link #deviceMap}, a map with the device id and the device.
*
* @return map of device id and device
*/
public Map<String, DeviceDTO> getDeviceMap() {
return deviceMap;
}
/**
* Loads all device data from the bridge and stores the {@link DeviceDTO}s and their states in the
* {@link DeviceStructureManager}.
*/
public void refreshDevices() throws IOException {
deviceMap.clear();
capabilityIdToDeviceMap.clear();
List<DeviceDTO> devices = deviceManager.getFullDevices();
for (DeviceDTO d : devices) {
handleRefreshedDevice(d);
}
}
/**
* Refreshs the {@link DeviceDTO} with the given id and stores it in the {@link DeviceStructureManager}.
*
* @param deviceId device id
*/
public Optional<DeviceDTO> refreshDevice(final String deviceId, final boolean isSHCClassic) throws IOException {
logger.trace("Refreshing Device with id '{}'", deviceId);
Optional<DeviceDTO> device = deviceManager.getFullDeviceById(deviceId, isSHCClassic);
device.ifPresent(this::handleRefreshedDevice);
return device;
}
/**
* Stores the newly refreshed {@link DeviceDTO} in the {@link DeviceStructureManager} structure and logs the
* {@link DeviceDTO}s details and state, if the debug logging is enabled.
*
* @param d the {@link DeviceDTO}
*/
private void handleRefreshedDevice(DeviceDTO d) {
if (LivisiBindingConstants.SUPPORTED_DEVICES.contains(d.getType())) {
addDeviceToStructure(d);
if (d.isController()) {
bridgeDeviceId = d.getId();
}
} else {
logger.debug("Device {}:'{}' by {} ({}) ignored - UNSUPPORTED.", d.getType(), d.getConfig().getName(),
d.getManufacturer(), d.getId());
logger.debug("====================================");
}
}
/**
* Adds the {@link DeviceDTO} to the structure.
*
* @param device device
*/
private void addDeviceToStructure(DeviceDTO device) {
if (device.getId() != null) {
getDeviceMap().put(device.getId(), device);
}
for (String capability : device.getCapabilities()) {
capabilityIdToDeviceMap.put(LinkDTO.getId(capability), device);
}
logDeviceLoaded(device);
}
/**
* Returns the {@link DeviceDTO} with the given id.
*
* @param id device id
* @return the {@link DeviceDTO} or null, if it does not exist
*/
public Optional<DeviceDTO> getDeviceById(String id) {
logger.debug("getDeviceById {}:{}", id, getDeviceMap().containsKey(id));
return Optional.ofNullable(getDeviceMap().get(id));
}
/**
* Returns the {@link DeviceDTO}, that provides the given capability.
*
* @param capabilityId capability id
* @return {@link DeviceDTO} or null
*/
public Optional<DeviceDTO> getDeviceByCapabilityId(String capabilityId) {
return Optional.ofNullable(capabilityIdToDeviceMap.get(capabilityId));
}
/**
* Returns the bridge {@link DeviceDTO}.
*
* @return bridge device
*/
public Optional<DeviceDTO> getBridgeDevice() {
return Optional.ofNullable(getDeviceMap().get(bridgeDeviceId));
}
/**
* Returns a {@link Collection} of all {@link DeviceDTO}s handled by the {@link DeviceStructureManager}.
*
* @return devices
*/
public Collection<DeviceDTO> getDeviceList() {
return Collections.unmodifiableCollection(getDeviceMap().values());
}
/**
* Returns the {@link DeviceDTO}, that has the {@link MessageDTO} with the given messageId.
*
* @param messageId the id of the {@link MessageDTO}
* @return the {@link DeviceDTO} or null if none found
*/
public Optional<DeviceDTO> getDeviceWithMessageId(String messageId) {
logger.trace("Getting Device with MessageId '{}'", messageId);
for (DeviceDTO d : getDeviceMap().values()) {
if (d.hasMessages()) {
for (MessageDTO m : d.getMessageList()) {
if (messageId.equals(m.getId())) {
return Optional.of(d);
}
}
}
}
return Optional.empty();
}
/**
* Returns the id of the {@link CapabilityDTO} for {@link DeviceDTO} with the given id and the given capabilityType.
*
* @param deviceId device id
* @param capabilityType capability type
* @return the id of the found {@link CapabilityDTO} or null
*/
public Optional<String> getCapabilityId(String deviceId, String capabilityType) {
DeviceDTO device = getDeviceMap().get(deviceId);
if (device != null) {
for (CapabilityDTO c : device.getCapabilityMap().values()) {
if (c.getType().equals(capabilityType)) {
return Optional.of(c.getId());
}
}
}
return Optional.empty();
}
private void logDeviceLoaded(DeviceDTO device) {
if (logger.isDebugEnabled()) {
String location = device.getLocationName();
logger.debug("Device {}:'{}@{}' by {} ({}) loaded.", device.getType(), device.getConfig().getName(),
location, device.getManufacturer(), device.getId());
for (CapabilityDTO c : device.getCapabilityMap().values()) {
logger.debug("> CAP: {}/{} ({})", c.getType(), c.getName(), c.getId());
if (device.isRadioDevice() && device.isReachable() != null && !device.isReachable()) {
logger.debug(">> CAP-State: unknown (device NOT REACHABLE).");
} else {
if (!c.hasState()) {
logger.debug(">> CAP-State: unknown (NULL)");
}
}
}
logger.debug("====================================");
}
}
}

View File

@ -0,0 +1,229 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal.manager;
import static org.openhab.binding.livisismarthome.internal.LivisiBindingConstants.BATTERY_POWERED_DEVICES;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.livisismarthome.internal.client.LivisiClient;
import org.openhab.binding.livisismarthome.internal.client.api.entity.capability.CapabilityDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.capability.CapabilityStateDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.device.DeviceDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.device.DeviceStateDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.link.LinkDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.location.LocationDTO;
import org.openhab.binding.livisismarthome.internal.client.api.entity.message.MessageDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Sven Strohschein - Initial contribution
*
* (created by refactoring the LivisiClient class)
*/
@NonNullByDefault
public class FullDeviceManager {
private final Logger logger = LoggerFactory.getLogger(FullDeviceManager.class);
private final LivisiClient client;
public FullDeviceManager(LivisiClient client) {
this.client = client;
}
/**
* Returns a {@link List} of all {@link DeviceDTO}s with the full configuration details, {@link CapabilityDTO}s and
* states. Calling this may take a while...
*/
public List<DeviceDTO> getFullDevices() throws IOException {
final Map<String, LocationDTO> locationMap = createLocationMap(client);
final Map<String, CapabilityDTO> capabilityMap = createCapabilityMap(client);
final Map<String, DeviceStateDTO> deviceStateMap = createDeviceStateMap(client);
final Map<String, List<MessageDTO>> messageMap = createMessageMap(client);
final List<DeviceDTO> deviceList = client.getDevices(deviceStateMap.keySet());
for (final DeviceDTO device : deviceList) {
final String deviceId = device.getId();
initializeDevice(device, deviceStateMap.get(deviceId), locationMap, capabilityMap,
getMessageList(device, messageMap));
}
return deviceList;
}
/**
* Returns the {@link DeviceDTO} with the given deviceId with full configuration details, {@link CapabilityDTO}s and
* states. Calling this may take a little bit longer...
*/
public Optional<DeviceDTO> getFullDeviceById(final String deviceId, final boolean isSHCClassic) throws IOException {
final Map<String, LocationDTO> locationMap = createLocationMap(client);
final Map<String, CapabilityDTO> capabilityMap = createCapabilityMap(deviceId, client);
final List<MessageDTO> messageMap = createMessageMap(deviceId, client);
final Optional<DeviceDTO> device = client.getDeviceById(deviceId);
if (device.isPresent()) {
final DeviceStateDTO deviceState = new DeviceStateDTO();
deviceState.setId(deviceId);
deviceState.setState(client.getDeviceStateByDeviceId(deviceId, isSHCClassic));
initializeDevice(device.get(), deviceState, locationMap, capabilityMap, messageMap);
}
return device;
}
private void initializeDevice(DeviceDTO device, @Nullable DeviceStateDTO deviceState,
Map<String, LocationDTO> locationMap, Map<String, CapabilityDTO> capabilityMap,
List<MessageDTO> messageList) {
device.setDeviceState(deviceState);
if (isBatteryPowered(device)) {
device.setIsBatteryPowered(true);
}
device.setLocation(locationMap.get(device.getLocationId()));
device.setCapabilityMap(createDeviceCapabilityMap(device, capabilityMap));
device.setMessageList(messageList);
}
private static boolean isBatteryPowered(DeviceDTO device) {
return BATTERY_POWERED_DEVICES.contains(device.getType());
}
private List<MessageDTO> getMessageList(DeviceDTO device, Map<String, List<MessageDTO>> messageMap) {
return Objects.requireNonNullElse(messageMap.get(device.getId()), Collections.emptyList());
}
private static Map<String, LocationDTO> createLocationMap(LivisiClient client) throws IOException {
final List<LocationDTO> locationList = client.getLocations();
final Map<String, LocationDTO> locationMap = new HashMap<>(locationList.size());
for (final LocationDTO location : locationList) {
locationMap.put(location.getId(), location);
}
return locationMap;
}
private static Map<String, CapabilityStateDTO> createCapabilityStateMap(LivisiClient client) throws IOException {
final List<CapabilityStateDTO> capabilityStateList = client.getCapabilityStates();
final Map<String, CapabilityStateDTO> capabilityStateMap = new HashMap<>(capabilityStateList.size());
for (final CapabilityStateDTO capabilityState : capabilityStateList) {
capabilityStateMap.put(capabilityState.getId(), capabilityState);
}
return capabilityStateMap;
}
private static Map<String, CapabilityDTO> createCapabilityMap(LivisiClient client) throws IOException {
final Map<String, CapabilityStateDTO> capabilityStateMap = createCapabilityStateMap(client);
final List<CapabilityDTO> capabilityList = client.getCapabilities();
return initializeCapabilities(capabilityStateMap, capabilityList);
}
private static Map<String, CapabilityDTO> createCapabilityMap(String deviceId, LivisiClient client)
throws IOException {
final Map<String, CapabilityStateDTO> capabilityStateMap = createCapabilityStateMap(client);
final List<CapabilityDTO> capabilityList = client.getCapabilitiesForDevice(deviceId);
return initializeCapabilities(capabilityStateMap, capabilityList);
}
private static Map<String, CapabilityDTO> initializeCapabilities(Map<String, CapabilityStateDTO> capabilityStateMap,
List<CapabilityDTO> capabilityList) {
final Map<String, CapabilityDTO> capabilityMap = new HashMap<>(capabilityList.size());
for (final CapabilityDTO capability : capabilityList) {
String capabilityId = capability.getId();
CapabilityStateDTO capabilityState = capabilityStateMap.get(capabilityId);
capability.setCapabilityState(capabilityState);
capabilityMap.put(capabilityId, capability);
}
return capabilityMap;
}
private static Map<String, CapabilityDTO> createDeviceCapabilityMap(DeviceDTO device,
Map<String, CapabilityDTO> capabilityMap) {
final HashMap<String, CapabilityDTO> deviceCapabilityMap = new HashMap<>();
for (final String capabilityValue : device.getCapabilities()) {
final CapabilityDTO capability = capabilityMap.get(LinkDTO.getId(capabilityValue));
if (capability != null) {
final String capabilityId = capability.getId();
deviceCapabilityMap.put(capabilityId, capability);
}
}
return deviceCapabilityMap;
}
private static Map<String, DeviceStateDTO> createDeviceStateMap(LivisiClient client) throws IOException {
final List<DeviceStateDTO> deviceStateList = client.getDeviceStates();
final Map<String, DeviceStateDTO> deviceStateMap = new HashMap<>(deviceStateList.size());
for (final DeviceStateDTO deviceState : deviceStateList) {
deviceStateMap.put(deviceState.getId(), deviceState);
}
return deviceStateMap;
}
private List<MessageDTO> createMessageMap(String deviceId, LivisiClient client) throws IOException {
final List<MessageDTO> messages = client.getMessages();
final List<MessageDTO> messageList = new ArrayList<>();
final String deviceIdPath = "/device/" + deviceId;
for (final MessageDTO message : messages) {
logger.trace("Message Type {} with ID {}", message.getType(), message.getId());
if (message.getDevices() != null && !message.getDevices().isEmpty()) {
for (final String li : message.getDevices()) {
if (deviceIdPath.equals(li)) {
messageList.add(message);
}
}
}
}
return messageList;
}
private static Map<String, List<MessageDTO>> createMessageMap(LivisiClient client) throws IOException {
final List<MessageDTO> messageList = client.getMessages();
final Map<String, List<MessageDTO>> deviceMessageMap = new HashMap<>();
for (final MessageDTO message : messageList) {
if (message.getDevices() != null && !message.getDevices().isEmpty()) {
final String deviceId = message.getDevices().get(0).replace("/device/", "");
// could get optimized with computeIfAbsent, but the non-null checks doesn't understand that and
// produces compiler warnings...
List<MessageDTO> ml = deviceMessageMap.get(deviceId);
if (ml == null) {
ml = new ArrayList<>();
deviceMessageMap.put(deviceId, ml);
}
ml.add(message);
}
}
return deviceMessageMap;
}
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="livisismarthome" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
<name>LIVISI SmartHome Binding</name>
<description>The LIVISI SmartHome binding integrates your LIVISI SmartHome system.</description>
</binding:binding>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<config-description:config-descriptions
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0
https://openhab.org/schemas/config-description-1.0.0.xsd">
<config-description uri="thing-type:livisismarthome:config">
<parameter name="id" type="text" required="true">
<label>ID</label>
<description>The identifier uniquely identifies this device.</description>
</parameter>
</config-description>
</config-description:config-descriptions>

View File

@ -0,0 +1,161 @@
# binding
binding.livisismarthome.name = LIVISI SmartHome Binding
binding.livisismarthome.description = The LIVISI SmartHome binding integrates your LIVISI SmartHome system.
# common messages
error.connect = Can't connect to LIVISI SmartHome service! Please check your credentials.
error.notReachable = Device not reachable
error.deviceNotFound = Device not found in LIVISI SmartHome config. Was it removed?
error.deviceIdUnknown = Unknown device id
error.bridgeHandlerMissing = The bridge or bridge handler is missing. Isn't it configured at the thing?
# thing types
thing-type.livisismarthome.AnalogMeter.label = Analog Meter
thing-type.livisismarthome.AnalogMeter.description = The Analog Meter from the EnergyControl product.
thing-type.livisismarthome.BRC8.label = Basic Remote Controller (BRC8)
thing-type.livisismarthome.BRC8.description = A battery powered remote controller with eight push buttons.
thing-type.livisismarthome.BT-PSS.label = Bluetooth Pluggable Smart Switch (BT-PSS)
thing-type.livisismarthome.BT-PSS.description = A pluggable switch that can be switched on and off and which can measure the current energy consumption.
thing-type.livisismarthome.GenerationMeter.label = Generation Meter
thing-type.livisismarthome.GenerationMeter.description = The Generation Meter from the PowerControlSolar product, that measures the generated energy.
thing-type.livisismarthome.ISC2.label = In Wall Smart Controller (ISC2)
thing-type.livisismarthome.ISC2.description = A smart controller with two push buttons.
thing-type.livisismarthome.ISD2.label = In Wall Smart Dimmer (ISD2)
thing-type.livisismarthome.ISD2.description = An in wall dimmer with push buttons.
thing-type.livisismarthome.ISR2.label = In Wall Smart Roller Shutter (ISR2)
thing-type.livisismarthome.ISR2.description = An in wall rollershutter with two push buttons.
thing-type.livisismarthome.ISS2.label = In Wall Smart Switch (ISS2)
thing-type.livisismarthome.ISS2.description = An in wall switch with push buttons that can be switched on and off.
thing-type.livisismarthome.PSD.label = Pluggable Smart Dimmer (PSD)
thing-type.livisismarthome.PSD.description = A pluggable dimmer.
thing-type.livisismarthome.PSS.label = Pluggable Smart Switch (PSS)
thing-type.livisismarthome.PSS.description = A pluggable switch that can be switched on and off.
thing-type.livisismarthome.PSSO.label = Pluggable Smart Switch Outdoor (PSSO)
thing-type.livisismarthome.PSSO.description = A pluggable outdoor switch that can be switched on and off.
thing-type.livisismarthome.RST.label = Radiator Mounted Smart Thermostat (RST)
thing-type.livisismarthome.RST.description = A thermostat, that supports setting the temperature and measuring the current temperature and humidity.
thing-type.livisismarthome.RST2.label = Radiator Mounted Smart Thermostat (RST2)
thing-type.livisismarthome.RST2.description = A thermostat, that supports setting the temperature and measuring the current temperature and humidity (2 battery version since 2018)
thing-type.livisismarthome.SmartMeter.label = Smart Meter
thing-type.livisismarthome.SmartMeter.description = The Smart Meter from the PowerControl product.
thing-type.livisismarthome.TwoWayMeter.label = Two-Way-Meter
thing-type.livisismarthome.TwoWayMeter.description = The Two-Way-Meter from the PowerControlSolar product.
thing-type.livisismarthome.VariableActuator.label = Variable Actuator
thing-type.livisismarthome.VariableActuator.description = A variable from the LIVISI SmartHome System that can be switched on and off.
thing-type.livisismarthome.WDS.label = Wall Mounted Door/Window Sensor (WDS)
thing-type.livisismarthome.WDS.description = A window/door sensor, that provides the open/close state.
thing-type.livisismarthome.WMD.label = Wall Mounted Motion Detector Indoor (WMD)
thing-type.livisismarthome.WMD.description = A battery powered motion detector, that also measures luminance.
thing-type.livisismarthome.WMDO.label = Wall Mounted Motion Detector Outdoor (WMDO)
thing-type.livisismarthome.WMDO.description = A battery powered motion detector for outdoors, that also measures luminance.
thing-type.livisismarthome.WRT.label = Wall Mounted Room Thermostat (WRT)
thing-type.livisismarthome.WRT.description = A wall thermostat, that supports setting the temperature and measuring the current temperature and humidity.
thing-type.livisismarthome.WSC2.label = Wall Mounted Smart Controller (WSC2)
thing-type.livisismarthome.WSC2.description = A battery powered smart controller with two push buttons.
thing-type.livisismarthome.WSD.label = Wall Mounted Smoke Detector (WSD)
thing-type.livisismarthome.WSD.description = A battery powered smoke detector sensor with integrated alarm (first version).
thing-type.livisismarthome.WSD2.label = Wall Mounted Smoke Detector (WSD2)
thing-type.livisismarthome.WSD2.description = A battery powered smoke detector sensor with integrated alarm (2nd version with long-life battery).
thing-type.livisismarthome.bridge.label = LIVISI SmartHome Controller
thing-type.livisismarthome.bridge.description = The LIVISI SmartHome Controller (SHC) is the bridge for the LIVISI SmartHome System.
# thing types config
thing-type.config.livisismarthome.bridge.group.advanced.label = Advanced Configuration
thing-type.config.livisismarthome.bridge.group.advanced.description = Advanced parameters, for special tweaking only.
thing-type.config.livisismarthome.bridge.group.connection.label = Connection
thing-type.config.livisismarthome.bridge.group.connection.description = Parameters for connecting to LIVISI SmartHome Controller (SHC)
thing-type.config.livisismarthome.bridge.webSocketIdleTimeout.label = WebSocket Idle Timeout in Seconds
thing-type.config.livisismarthome.bridge.webSocketIdleTimeout.description = The WebSocket is the connection to the LIVISI service that listens to status updates. If no data is received over the websocket connection for the given time, the websocket will reconnect. 0 will disable the idle timeout. Default is 900 seconds (15 minutes).
thing-type.config.livisismarthome.config.id.label = ID
thing-type.config.livisismarthome.config.id.description = The identifier uniquely identifies this device.
# channel types
channel-type.livisismarthome.absoluteEnergyConsumption.label = Total Consumption
channel-type.livisismarthome.absoluteEnergyConsumption.description = The absolute Energy consumption
channel-type.livisismarthome.alarmActuator.label = Alarm
channel-type.livisismarthome.alarmActuator.description = Switches the alarm on/off
channel-type.livisismarthome.booleanStateActuator.label = Switch
channel-type.livisismarthome.booleanStateActuator.description = Switches the state on/off
channel-type.livisismarthome.cpuUsage.label = CPU Usage
channel-type.livisismarthome.cpuUsage.description = The CPU usage of SHC
channel-type.livisismarthome.dimmerActuator.label = Dimmer
channel-type.livisismarthome.dimmerActuator.description = Dimms the connected light (percent)
channel-type.livisismarthome.diskUsage.label = Disk Usage
channel-type.livisismarthome.diskUsage.description = The disk usage of SHC
channel-type.livisismarthome.energyConsumptionDayEuro.label = Consumption Costs (day)
channel-type.livisismarthome.energyConsumptionDayEuro.description = The energy consumption per day (Euro)
channel-type.livisismarthome.energyConsumptionDayKwh.label = Consumption (day)
channel-type.livisismarthome.energyConsumptionDayKwh.description = The energy consumption per day (kWh)
channel-type.livisismarthome.energyConsumptionMonthEuro.label = Consumption Costs (month)
channel-type.livisismarthome.energyConsumptionMonthEuro.description = The energy consumption per month (Euro)
channel-type.livisismarthome.energyConsumptionMonthKwh.label = Consumption (month)
channel-type.livisismarthome.energyConsumptionMonthKwh.description = The energy consumption per month (kWh)
channel-type.livisismarthome.energyFeedDayEuro.label = Feed Income (day)
channel-type.livisismarthome.energyFeedDayEuro.description = The energy feed per day (Euro)
channel-type.livisismarthome.energyFeedDayKwh.label = Feed (day)
channel-type.livisismarthome.energyFeedDayKwh.description = The energy feed per day (kWh)
channel-type.livisismarthome.energyFeedMonthEuro.label = Feed Income (month)
channel-type.livisismarthome.energyFeedMonthEuro.description = The energy feed per month (Euro)
channel-type.livisismarthome.energyFeedMonthKwh.label = Feed (month)
channel-type.livisismarthome.energyFeedMonthKwh.description = The energy feed per month (kWh)
channel-type.livisismarthome.energyGenerationDayEuro.label = Generation Value (day)
channel-type.livisismarthome.energyGenerationDayEuro.description = The energy generation per day (Euro)
channel-type.livisismarthome.energyGenerationDayKwh.label = Generation (day)
channel-type.livisismarthome.energyGenerationDayKwh.description = The energy generation per day (kWh)
channel-type.livisismarthome.energyGenerationMonthEuro.label = Generation Value (month)
channel-type.livisismarthome.energyGenerationMonthEuro.description = The energy generation per month (Euro)
channel-type.livisismarthome.energyGenerationMonthKwh.label = Generation (month)
channel-type.livisismarthome.energyGenerationMonthKwh.description = The energy generation per month (kWh)
channel-type.livisismarthome.humiditySensorHumidity.label = Actual Humidity
channel-type.livisismarthome.humiditySensorHumidity.description = Actual measured room humidity (percent)
channel-type.livisismarthome.humiditySensorMoldWarning.label = Mold Warning
channel-type.livisismarthome.humiditySensorMoldWarning.description = Active, if humidity is over a threshold (configured in LIVISI app)
channel-type.livisismarthome.luminanceSensor.label = Luminance
channel-type.livisismarthome.luminanceSensor.description = Shows the detected luminance (percent)
channel-type.livisismarthome.memoryUsage.label = Memory Usage
channel-type.livisismarthome.memoryUsage.description = The memory usage of SHC (percent)
channel-type.livisismarthome.motionDetectionSensor.label = Motion Count
channel-type.livisismarthome.motionDetectionSensor.description = The count of detected motions
channel-type.livisismarthome.operationStatus.label = Operation Status
channel-type.livisismarthome.operationStatus.description = The operation status of SHC-A
channel-type.livisismarthome.powerConsumptionWatt.label = Current Power Consumption
channel-type.livisismarthome.powerConsumptionWatt.description = The current power consumption (Watt)
channel-type.livisismarthome.powerGenerationWatt.label = Current Power Generation
channel-type.livisismarthome.powerGenerationWatt.description = The current power generation (Watt)
channel-type.livisismarthome.pushButtonCounter.label = Button Pushed Count
channel-type.livisismarthome.pushButtonCounter.description = The count of button pushes.
channel-type.livisismarthome.rollerShutterActuator.label = Blinds Position
channel-type.livisismarthome.rollerShutterActuator.description = Controls the blinds (percent)
channel-type.livisismarthome.smokeDetectorSensor.label = Smoke
channel-type.livisismarthome.smokeDetectorSensor.description = Shows if smoke was detected (on/off)
channel-type.livisismarthome.switchActuator.label = Switch
channel-type.livisismarthome.switchActuator.description = Switches the current (on/off)
channel-type.livisismarthome.temperatureSensorFrostWarning.label = Frost Warning
channel-type.livisismarthome.temperatureSensorFrostWarning.description = Warns, if temperature drop below a threshold (configured in LIVISI app)
channel-type.livisismarthome.temperatureSensorTemperature.label = Actual Temperature
channel-type.livisismarthome.temperatureSensorTemperature.description = Actual measured room temperature
channel-type.livisismarthome.thermostatActuatorOperationMode.label = Operation Mode
channel-type.livisismarthome.thermostatActuatorOperationMode.description = Thermostat operation mode (manual/auto)
channel-type.livisismarthome.thermostatActuatorOperationMode.state.option.Auto = auto
channel-type.livisismarthome.thermostatActuatorOperationMode.state.option.Manu = manual
channel-type.livisismarthome.thermostatActuatorPointTemperature.label = Target Temperature
channel-type.livisismarthome.thermostatActuatorPointTemperature.description = Thermostat target temperature (6°C to 30°C)
channel-type.livisismarthome.thermostatActuatorWindowReductionActive.label = Window Reduction Active
channel-type.livisismarthome.thermostatActuatorWindowReductionActive.description = Thermostat temperature reduced, if window is open.
channel-type.livisismarthome.totalEnergyConsumption.label = Total Consumption
channel-type.livisismarthome.totalEnergyConsumption.description = The total Energy consumption
channel-type.livisismarthome.totalEnergyFed.label = Total Fed
channel-type.livisismarthome.totalEnergyFed.description = The total Energy fed
channel-type.livisismarthome.totalEnergyGeneration.label = Total Generation
channel-type.livisismarthome.totalEnergyGeneration.description = The total Energy generation
channel-type.livisismarthome.windowDoorSensor.label = Contact
channel-type.livisismarthome.windowDoorSensor.description = Shows the open/close state
# channel types config
channel-type.config.livisismarthome.RollerShutterActuator.invert.label = Invert Position
channel-type.config.livisismarthome.RollerShutterActuator.invert.description = By default the LIVISI value for OpenHAB is inverted so that "top" in LIVISI is also "top" in OpenHAB. If this is not desired, this inversion can be canceled again by activating this option.

View File

@ -0,0 +1,164 @@
# binding
binding.livisismarthome.name = LIVISI SmartHome Binding
binding.livisismarthome.description = Das LIVISI SmartHome Binding verbindet dein LIVISI SmartHome System mit openHAB.
# common messages
error.connect = Konnte keine Verbindung zum LIVISI SmartHome - Service herstellen! Bitte überprüfen Sie die Zugangsdaten.
error.notReachable = Gerät nicht erreichbar
error.deviceNotFound = Das Gerät wurde nicht in der LIVISI SmartHome Konfiguration gefunden. Wurde es entfernt?
error.deviceIdUnknown = Unbekannte device id
error.bridgeHandlerMissing = Das Bridge-Thing oder der Bridge-Handler wurden nicht gefunden. Ist die Bridge nicht am Gerät konfiguriert?
# thing types
thing-type.livisismarthome.bridge.label = LIVISI SmartHome Zentrale
thing-type.livisismarthome.bridge.description = Der LIVISI SmartHome Controller (SHC) ist die Zentrale für das LIVISI SmartHome System.
thing-type.livisismarthome.AnalogMeter.label = Analoger Zähler (Analog Meter)
thing-type.livisismarthome.AnalogMeter.description = Ein konventioneller Zähler / Ferraris-Zähler
thing-type.livisismarthome.BT-PSS.label = Zwischenstecker (Bluetooth) (BT-PSS)
thing-type.livisismarthome.BT-PSS.description = Ein Zwischenstecker von Medion zum Schalten mit Energieverbrauchsmessung
thing-type.livisismarthome.BRC8.label = Funkfernbedienung (BRC8)
thing-type.livisismarthome.BRC8.description = Eine batteriebetriebene Fernbedienung mit 8 Tasten.
thing-type.livisismarthome.GenerationMeter.label = Erzeugungs-Zähler (Generation Meter)
thing-type.livisismarthome.GenerationMeter.description = Ein Erzeugungs-Zähler (für PV-Anlagen)
thing-type.livisismarthome.ISC2.label = Unterputzsender (ISC2)
thing-type.livisismarthome.ISC2.description = Ein batteriebetriebener Unterputzsender mit zwei Tasten.
thing-type.livisismarthome.ISD2.label = Unterputzdimmer (ISD2)
thing-type.livisismarthome.ISD2.description = Ein Unterputzdimmer mit zwei Tasten.
thing-type.livisismarthome.ISR2.label = Unterputz Rollladensteuerung (ISR2)
thing-type.livisismarthome.ISR2.description = Eine Unterputz Rollladensteuerung mit zwei Tasten.
thing-type.livisismarthome.ISS2.label = Unterputz Lichtschalter (ISS2)
thing-type.livisismarthome.ISS2.description = Ein Unterputz Lichtschalter mit zwei Tasten.
thing-type.livisismarthome.PSD.label = Zwischenstecker dimmbar (PSD)
thing-type.livisismarthome.PSD.description = Ein dimmbarer Zwischenstecker.
thing-type.livisismarthome.PSS.label = Zwischenstecker innen (PSS)
thing-type.livisismarthome.PSS.description = Ein Zwischenstecker für innen, der ein- und ausgeschaltet werden kann.
thing-type.livisismarthome.PSSO.label = Zwischenstecker außen (PSSO)
thing-type.livisismarthome.PSSO.description = Ein Zwischenstecker für den Außenbereich, der ein- und ausgeschaltet werden kann.
thing-type.livisismarthome.RST.label = Heizkörperthermostat (RST)
thing-type.livisismarthome.RST.description = Das Thermostat unterstützt das Einstellen der Temperatur sowie das Messen der aktuellen Temperatur und Luftfeuchtigkeit.
thing-type.livisismarthome.RST2.label = Heizkörperthermostat (RST2)
thing-type.livisismarthome.RST2.description = Das Thermostat unterstützt das Einstellen der Temperatur sowie das Messen der aktuellen Temperatur und Luftfeuchtigkeit (Version mit 2 Batterien seit 2018).
thing-type.livisismarthome.SmartMeter.label = Elektronischer Zähler (Smart Meter)
thing-type.livisismarthome.SmartMeter.description = Ein elektronischer Zähler
thing-type.livisismarthome.TwoWayMeter.label = Zweiwege-Zähler (Two-Way-Meter)
thing-type.livisismarthome.TwoWayMeter.description = Ein Zweiwege-Zähler für PV-Anlagen mit Einspeisung ins öffentliche Netz
thing-type.livisismarthome.VariableActuator.label = Zustandsvariable
thing-type.livisismarthome.VariableActuator.description = Eine Zustandsvariable des LIVISI SmartHome Systems, die ein- oder ausgeschaltet werden kann.
thing-type.livisismarthome.WDS.label = Fenster-/Türkontakt (WDS)
thing-type.livisismarthome.WDS.description = Ein Fenster-/Türkontakt, der offen oder geschlossen anzeigt.
thing-type.livisismarthome.WMD.label = Bewegungsmelder (WMD)
thing-type.livisismarthome.WMD.description = Ein batteriebetriebener Bewegungsmelder, der zusätzlich die Helligkeit misst.
thing-type.livisismarthome.WMDO.label = Bewegungsmelder außen (WMDO)
thing-type.livisismarthome.WMDO.description = Ein batteriebetriebener Bewegungsmelder für den Außenbereich, der zusätzlich die Helligkeit misst.
thing-type.livisismarthome.WRT.label = Raumthermostat (WRT)
thing-type.livisismarthome.WRT.description = Ein Raumthermostat zur Wandbefestigung, das das Einstellen der Temperatur sowie das Messen der aktuellen Temperatur und Luftfeuchtigkeit unterstützt.
thing-type.livisismarthome.WSC2.label = Wandsender (WSC2)
thing-type.livisismarthome.WSC2.description = Ein batteriebetriebener Wandsender mit zwei Tasten.
thing-type.livisismarthome.WSD.label = Rauchmelder (WSD)
thing-type.livisismarthome.WSD.description = Ein batteriebetriebener Rauchmelder mit integriertem Alarm (erste Version).
thing-type.livisismarthome.WSD2.label = Rauchmelder (WSD2)
thing-type.livisismarthome.WSD2.description = Ein batteriebetriebener Rauchmelder mit integriertem Alarm (zweite Version mit long-life Batterie).
# thing types config
thing-type.config.livisismarthome.bridge.group.advanced.label = Erweiterte Konfiguration
thing-type.config.livisismarthome.bridge.group.advanced.description = Erweiterte Parameter für spezielle Anpassungen.
thing-type.config.livisismarthome.bridge.group.connection.label = Verbindung
thing-type.config.livisismarthome.bridge.group.connection.description = Parameter zur Verbindung mit dem LIVISI SmartHome Controller (SHC)
thing-type.config.livisismarthome.bridge.webSocketIdleTimeout.label = WebSocket idle timeout in Sekunden
thing-type.config.livisismarthome.bridge.webSocketIdleTimeout.description = Der WebSocket hält die Verbindung zum LIVISI Webservice und wartet auf Statusaktualisierungen. Wenn für die angegebene Dauer keine Daten über den WebSocket empfangen werden, wird die Verbindung neu aufgebaut. 0 deaktiviert den idle timeout. Standard ist 900 Sekunden (15 Minuten).
thing-type.config.livisismarthome.bridge.host.label = Host
thing-type.config.livisismarthome.bridge.host.description = Der Hostname oder die lokale IP-Adresse der LIVISI SmartHome Zentrale (SHC)
thing-type.config.livisismarthome.bridge.password.label = Passwort
thing-type.config.livisismarthome.bridge.password.description = Das Passwort für den Zugriff auf die lokale API der LIVISI Smarthome Zentrale (SHC)
thing-type.config.livisismarthome.config.id.label = ID
thing-type.config.livisismarthome.config.id.description = ID zur eindeutigen Geräte-Identifizierung
# channel types
channel-type.livisismarthome.absoluteEnergyConsumption.label = Gesamtverbrauch
channel-type.livisismarthome.absoluteEnergyConsumption.description = Gesamtenergieverbrauch (kWh)
channel-type.livisismarthome.alarmActuator.label = Alarmton
channel-type.livisismarthome.alarmActuator.description = Schaltet den Alarmton (an/aus)
channel-type.livisismarthome.booleanStateActuator.label = Status
channel-type.livisismarthome.booleanStateActuator.description = Schaltet den Zustand (an/aus)
channel-type.livisismarthome.cpuUsage.label = CPU-Last
channel-type.livisismarthome.cpuUsage.description = CPU-Last des SHC (in Prozent)
channel-type.livisismarthome.dimmerActuator.label = Dimmer
channel-type.livisismarthome.dimmerActuator.description = Dimmt das verbundene Licht (in Prozent)
channel-type.livisismarthome.diskUsage.label = Festplatten-Belegung
channel-type.livisismarthome.diskUsage.description = Festplatte des SHC belegt (in Prozent)
channel-type.livisismarthome.energyConsumptionDayEuro.label = Verbrauchkosten pro Tag
channel-type.livisismarthome.energyConsumptionDayEuro.description = Energieverbrauchskosten pro Tag (Euro)
channel-type.livisismarthome.energyConsumptionDayKwh.label = Verbrauch pro Tag
channel-type.livisismarthome.energyConsumptionDayKwh.description = Energieverbrauch pro Tag (kWh)
channel-type.livisismarthome.energyConsumptionMonthEuro.label = Verbrauchskosten pro Monat
channel-type.livisismarthome.energyConsumptionMonthEuro.description = Energieverbrauchskosten pro Monat (Euro)
channel-type.livisismarthome.energyConsumptionMonthKwh.label = Verbrauch pro Monat
channel-type.livisismarthome.energyConsumptionMonthKwh.description = Energieverbrauch pro Monat (kWh)
channel-type.livisismarthome.energyFeedDayEuro.label = Einspeise-Vergütung pro Tag
channel-type.livisismarthome.energyFeedDayEuro.description = Einspeise-Vergütung pro Tag (Euro)
channel-type.livisismarthome.energyFeedDayKwh.label = Einspeisung pro Tag
channel-type.livisismarthome.energyFeedDayKwh.description = Energie-Einspeisung pro Tag (kWh)
channel-type.livisismarthome.energyFeedMonthEuro.label = Einspeise-Vergütung pro Monat
channel-type.livisismarthome.energyFeedMonthEuro.description = Einspeise-Vergütung pro Monat (Euro)
channel-type.livisismarthome.energyFeedMonthKwh.label = Einspeisung pro Monat
channel-type.livisismarthome.energyFeedMonthKwh.description = Energie-Einspeisung pro Monat (kWh)
channel-type.livisismarthome.energyGenerationDayEuro.label = Erzeugungswert pro Tag
channel-type.livisismarthome.energyGenerationDayEuro.description = Energie-Erzeugungswert pro Tag (Euro)
channel-type.livisismarthome.energyGenerationDayKwh.label = Erzeugung pro Tag
channel-type.livisismarthome.energyGenerationDayKwh.description = Energie-Erzeugung pro Tag (kWh)
channel-type.livisismarthome.energyGenerationMonthEuro.label = Erzeugungswert pro Monat
channel-type.livisismarthome.energyGenerationMonthEuro.description = Energie-Erzeugungswert pro Monat (Euro)
channel-type.livisismarthome.energyGenerationMonthKwh.label = Erzeugung pro Monat
channel-type.livisismarthome.energyGenerationMonthKwh.description = Energie-Erzeugung pro Monat (kWh)
channel-type.livisismarthome.humiditySensorHumidity.label = Luftfeuchtigkeit
channel-type.livisismarthome.humiditySensorHumidity.description = Aktuell gemessene Luftfeuchtigkeit (in Prozent)
channel-type.livisismarthome.humiditySensorMoldWarning.label = Schimmelwarnung
channel-type.livisismarthome.humiditySensorMoldWarning.description = Warnt bei überschreiten der in der LIVISI-App konfigurierten maximalen Feuchtigkeit (an/aus)
channel-type.livisismarthome.luminanceSensor.label = Helligkeit
channel-type.livisismarthome.luminanceSensor.description = Gemessene Helligkeit (in Prozent)
channel-type.livisismarthome.memoryUsage.label = Hauptspeicher-Belegung
channel-type.livisismarthome.memoryUsage.description = Hauptspeicher des SHC belegt (in Prozent)
channel-type.livisismarthome.motionDetectionSensor.label = Bewegungszähler
channel-type.livisismarthome.motionDetectionSensor.description = Anzahl der erkannten Bewegungen
channel-type.livisismarthome.operationStatus.label = Betriebssstatus
channel-type.livisismarthome.operationStatus.description = Betriebsstatus des SHC
channel-type.livisismarthome.powerConsumptionWatt.label = Aktueller Verbrauch
channel-type.livisismarthome.powerConsumptionWatt.description = Aktueller Energieverbrauch (Watt)
channel-type.livisismarthome.powerGenerationWatt.label = Aktuelle Erzeugung
channel-type.livisismarthome.powerGenerationWatt.description = Aktuelle Energieerzeuzung (Watt)
channel-type.livisismarthome.pushButtonCounter.label = Tastendruck-Zähler
channel-type.livisismarthome.pushButtonCounter.description = Anzahl der Tastenbetätigungen
channel-type.livisismarthome.rollerShutterActuator.label = Rollladenposition
channel-type.livisismarthome.rollerShutterActuator.description = Steuert die Rollladen (in Prozent)
channel-type.livisismarthome.smokeDetectorSensor.label = Rauchalarm
channel-type.livisismarthome.smokeDetectorSensor.description = Meldet bei Raucherkennung (an/aus)
channel-type.livisismarthome.switchActuator.label = Schalter
channel-type.livisismarthome.switchActuator.description = Schaltet den Strom (an/aus)
channel-type.livisismarthome.thermostatActuatorOperationMode.label = Betriebsmodus
channel-type.livisismarthome.thermostatActuatorOperationMode.description = Betriebsmodus des Thermostats (manuell/automatisch)
channel-type.livisismarthome.thermostatActuatorPointTemperature.label = Solltemperatur
channel-type.livisismarthome.thermostatActuatorPointTemperature.description = Temperaturvorgabe für das Thermostat (6°C - 30°C)
channel-type.livisismarthome.thermostatActuatorWindowReductionActive.label = Fensterabsenkung aktiv
channel-type.livisismarthome.thermostatActuatorWindowReductionActive.description = Absenkung der Solltemperatur bei offenem Fenster (an/aus)
channel-type.livisismarthome.temperatureSensorFrostWarning.label = Frostwarnung
channel-type.livisismarthome.temperatureSensorFrostWarning.description = Warnt beim Unterschreiten der in der LIVISI-App konfigurierten Mindesttemperatur (an/aus)
channel-type.livisismarthome.temperatureSensorTemperature.label = Aktuelle Temperatur
channel-type.livisismarthome.temperatureSensorTemperature.description = Aktuell gemessene Raumtemperatur (°C)
channel-type.livisismarthome.totalEnergyConsumption.label = Gesamtverbrauch
channel-type.livisismarthome.totalEnergyConsumption.description = Energie-Gesamtverbrauch (kWh)
channel-type.livisismarthome.totalEnergyFed.label = Gesamteinspeisung
channel-type.livisismarthome.totalEnergyFed.description = Energie-Gesamteinspeisung (kWh)
channel-type.livisismarthome.totalEnergyGeneration.label = Gesamterzeugung
channel-type.livisismarthome.totalEnergyGeneration.description = Energie-Gesamterzeugung (kWh)
channel-type.livisismarthome.windowDoorSensor.label = Tür/Fensterstatus
channel-type.livisismarthome.windowDoorSensor.description = Zeigt den Status (offen/geschlossen)
# channel types config
channel-type.config.livisismarthome.RollerShutterActuator.invert.label = Invertierte Position
channel-type.config.livisismarthome.RollerShutterActuator.invert.description = Standardmäßig wird der LIVISI-Wert für OpenHAB invertiert, damit "Oben" in LIVISI auch "Oben" in OpenHAB ist. Wenn das nicht gewünscht wird, kann diese Invertierung durch Aktivieren dieser Option wieder aufgehoben werden.

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="AnalogMeter">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Analog Meter</label>
<description>The Analog Meter from the LIVISI EnergyControl product.</description>
<channels>
<channel id="absoluteEnergyConsumption" typeId="absoluteEnergyConsumption"/>
<channel id="energyConsumptionDayKwh" typeId="energyConsumptionDayKwh"/>
<channel id="energyConsumptionDayEuro" typeId="energyConsumptionDayEuro"/>
<channel id="energyConsumptionMonthKwh" typeId="energyConsumptionMonthKwh"/>
<channel id="energyConsumptionMonthEuro" typeId="energyConsumptionMonthEuro"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:livisismarthome:config"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="BRC8">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Basic Remote Controller (BRC8)</label>
<description>A battery powered remote controller with eight push buttons.</description>
<channels>
<channel id="button1" typeId="system.button"/>
<channel id="button2" typeId="system.button"/>
<channel id="button3" typeId="system.button"/>
<channel id="button4" typeId="system.button"/>
<channel id="button5" typeId="system.button"/>
<channel id="button6" typeId="system.button"/>
<channel id="button7" typeId="system.button"/>
<channel id="button8" typeId="system.button"/>
<channel id="button1Count" typeId="pushButtonCounter"/>
<channel id="button2Count" typeId="pushButtonCounter"/>
<channel id="button3Count" typeId="pushButtonCounter"/>
<channel id="button4Count" typeId="pushButtonCounter"/>
<channel id="button5Count" typeId="pushButtonCounter"/>
<channel id="button6Count" typeId="pushButtonCounter"/>
<channel id="button7Count" typeId="pushButtonCounter"/>
<channel id="button8Count" typeId="pushButtonCounter"/>
<channel id="batteryLow" typeId="system.low-battery"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:livisismarthome:config"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="BT-PSS">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Bluetooth Pluggable Smart Switch (BT-PSS)</label>
<description>A pluggable switch that can be switched on and off and which can measure the current energy consumption.</description>
<channels>
<channel id="switch" typeId="switchActuator"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:livisismarthome:config"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="GenerationMeter">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Generation Meter</label>
<description>The Generation Meter from the LIVISI PowerControlSolar product, that measures the generated energy.</description>
<channels>
<channel id="powerGenerationWatt" typeId="powerGenerationWatt"/>
<channel id="totalEnergyGeneration" typeId="totalEnergyGeneration"/>
<channel id="energyGenerationDayKwh" typeId="energyGenerationDayKwh"/>
<channel id="energyGenerationDayEuro" typeId="energyGenerationDayEuro"/>
<channel id="energyGenerationMonthKwh" typeId="energyGenerationMonthKwh"/>
<channel id="energyGenerationMonthEuro" typeId="energyGenerationMonthEuro"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:livisismarthome:config"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="ISC2">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>In Wall Smart Controller (ISC2)</label>
<description>A smart controller with two push buttons.</description>
<channels>
<channel id="button1" typeId="system.button"/>
<channel id="button2" typeId="system.button"/>
<channel id="button1Count" typeId="pushButtonCounter"/>
<channel id="button2Count" typeId="pushButtonCounter"/>
<channel id="batteryLow" typeId="system.low-battery"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:livisismarthome:config"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="ISD2">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>In Wall Smart Dimmer (ISD2)</label>
<description>An in wall dimmer with push buttons.</description>
<channels>
<channel id="dimmer" typeId="dimmerActuator"/>
<channel id="button1" typeId="system.button"/>
<channel id="button2" typeId="system.button"/>
<channel id="button1Count" typeId="pushButtonCounter"/>
<channel id="button2Count" typeId="pushButtonCounter"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:livisismarthome:config"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="ISR2">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>In Wall Smart Roller Shutter (ISR2)</label>
<description>An in wall rollershutter with two push buttons.</description>
<channels>
<channel id="rollershutter" typeId="rollershutterActuator"/>
<channel id="button1" typeId="system.button"/>
<channel id="button2" typeId="system.button"/>
<channel id="button1Count" typeId="pushButtonCounter"/>
<channel id="button2Count" typeId="pushButtonCounter"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:livisismarthome:config"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="ISS2">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>In Wall Smart Switch (ISS2)</label>
<description>An in wall switch with push buttons that can be switched on and off.</description>
<channels>
<channel id="switch" typeId="switchActuator"/>
<channel id="button1" typeId="system.button"/>
<channel id="button2" typeId="system.button"/>
<channel id="button1Count" typeId="pushButtonCounter"/>
<channel id="button2Count" typeId="pushButtonCounter"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:livisismarthome:config"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="PSD">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Pluggable Smart Dimmer (PSD)</label>
<description>A pluggable dimmer.</description>
<channels>
<channel id="dimmer" typeId="dimmerActuator"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:livisismarthome:config"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="PSS">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Pluggable Smart Switch (PSS)</label>
<description>A pluggable switch that can be switched on and off.</description>
<channels>
<channel id="switch" typeId="switchActuator"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:livisismarthome:config"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="PSSO">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Pluggable Smart Switch Outdoor (PSSO)</label>
<description>A pluggable outdoor switch that can be switched on and off.</description>
<channels>
<channel id="switch" typeId="switchActuator"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:livisismarthome:config"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="RST">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Radiator Mounted Smart Thermostat (RST)</label>
<description>A thermostat, that supports setting the temperature and measuring the current temperature and humidity.</description>
<channels>
<channel id="targetTemperature" typeId="thermostatActuatorPointTemperature"/>
<channel id="currentTemperature" typeId="temperatureSensorTemperature"/>
<channel id="frostWarning" typeId="temperatureSensorFrostWarning"/>
<channel id="humidity" typeId="humiditySensorHumidity"/>
<channel id="moldWarning" typeId="humiditySensorMoldWarning"/>
<channel id="operationMode" typeId="thermostatActuatorOperationMode"/>
<channel id="windowReductionActive" typeId="thermostatActuatorWindowReductionActive"/>
<channel id="batteryLow" typeId="system.low-battery"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:livisismarthome:config"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="RST2">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Radiator Mounted Smart Thermostat (RST2)</label>
<description>A thermostat, that supports setting the temperature and measuring the current temperature and humidity (2
battery version since 2018)</description>
<channels>
<channel id="targetTemperature" typeId="thermostatActuatorPointTemperature"/>
<channel id="currentTemperature" typeId="temperatureSensorTemperature"/>
<channel id="frostWarning" typeId="temperatureSensorFrostWarning"/>
<channel id="humidity" typeId="humiditySensorHumidity"/>
<channel id="moldWarning" typeId="humiditySensorMoldWarning"/>
<channel id="operationMode" typeId="thermostatActuatorOperationMode"/>
<channel id="windowReductionActive" typeId="thermostatActuatorWindowReductionActive"/>
<channel id="batteryLow" typeId="system.low-battery"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:livisismarthome:config"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="SmartMeter">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Smart Meter</label>
<description>The Smart Meter from the LIVISI PowerControl product.</description>
<channels>
<channel id="powerConsumptionWatt" typeId="powerConsumptionWatt"/>
<channel id="absoluteEnergyConsumption" typeId="absoluteEnergyConsumption"/>
<channel id="energyConsumptionDayKwh" typeId="energyConsumptionDayKwh"/>
<channel id="energyConsumptionDayEuro" typeId="energyConsumptionDayEuro"/>
<channel id="energyConsumptionMonthKwh" typeId="energyConsumptionMonthKwh"/>
<channel id="energyConsumptionMonthEuro" typeId="energyConsumptionMonthEuro"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:livisismarthome:config"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="TwoWayMeter">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Two-Way-Meter</label>
<description>The Two-Way-Meter from the LIVISI PowerControlSolar product.</description>
<channels>
<channel id="powerWatt" typeId="powerConsumptionWatt"/>
<channel id="totalEnergy" typeId="totalEnergyConsumption"/>
<channel id="energyDayKwh" typeId="energyConsumptionDayKwh"/>
<channel id="energyDayEuro" typeId="energyConsumptionDayEuro"/>
<channel id="energyMonthKwh" typeId="energyConsumptionMonthKwh"/>
<channel id="energyMonthEuro" typeId="energyConsumptionMonthEuro"/>
<channel id="totalEnergyFed" typeId="totalEnergyFed"/>
<channel id="energyFeedDayKwh" typeId="energyFeedDayKwh"/>
<channel id="energyFeedDayEuro" typeId="energyFeedDayEuro"/>
<channel id="energyFeedMonthKwh" typeId="energyFeedMonthKwh"/>
<channel id="energyFeedMonthEuro" typeId="energyFeedMonthEuro"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:livisismarthome:config"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="VariableActuator">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Variable Actuator</label>
<description>A variable from the LIVISI SmartHome system that can be switched on and off.</description>
<channels>
<channel id="switch" typeId="booleanStateActuator"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:livisismarthome:config"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="WDS">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Wall Mounted Door/Window Sensor (WDS)</label>
<description>A window/door sensor, that provides the open/close state.</description>
<channels>
<channel id="contact" typeId="windowDoorSensor"/>
<channel id="batteryLow" typeId="system.low-battery"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:livisismarthome:config"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="WMD">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Wall Mounted Motion Detector Indoor (WMD)</label>
<description>A battery powered motion detector, that also measures luminance.</description>
<channels>
<channel id="motionCount" typeId="motionDetectionSensor"/>
<channel id="luminance" typeId="luminanceSensor"/>
<channel id="batteryLow" typeId="system.low-battery"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:livisismarthome:config"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="WMDO">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Wall Mounted Motion Detector Outdoor (WMDO)</label>
<description>A battery powered motion detector for outdoors, that also measures luminance.</description>
<channels>
<channel id="motionCount" typeId="motionDetectionSensor"/>
<channel id="luminance" typeId="luminanceSensor"/>
<channel id="batteryLow" typeId="system.low-battery"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:livisismarthome:config"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="WRT">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Wall Mounted Room Thermostat (WRT)</label>
<description>A wall thermostat, that supports setting the temperature and measuring the current temperature and
humidity.</description>
<channels>
<channel id="targetTemperature" typeId="thermostatActuatorPointTemperature"/>
<channel id="currentTemperature" typeId="temperatureSensorTemperature"/>
<channel id="frostWarning" typeId="temperatureSensorFrostWarning"/>
<channel id="humidity" typeId="humiditySensorHumidity"/>
<channel id="moldWarning" typeId="humiditySensorMoldWarning"/>
<channel id="operationMode" typeId="thermostatActuatorOperationMode"/>
<channel id="windowReductionActive" typeId="thermostatActuatorWindowReductionActive"/>
<channel id="batteryLow" typeId="system.low-battery"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:livisismarthome:config"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="WSC2">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Wall Mounted Smart Controller (WSC2)</label>
<description>A battery powered smart controller with two push buttons.</description>
<channels>
<channel id="button1" typeId="system.button"/>
<channel id="button2" typeId="system.button"/>
<channel id="button1Count" typeId="pushButtonCounter"/>
<channel id="button2Count" typeId="pushButtonCounter"/>
<channel id="batteryLow" typeId="system.low-battery"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:livisismarthome:config"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="WSD">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Wall Mounted Smoke Detector (WSD)</label>
<description>A battery powered smoke detector sensor with integrated alarm (first version).</description>
<channels>
<channel id="smoke" typeId="smokeDetectorSensor"/>
<channel id="alarm" typeId="alarmActuator"/>
<channel id="batteryLow" typeId="system.low-battery"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:livisismarthome:config"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="WSD2">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Wall Mounted Smoke Detector (WSD2)</label>
<description>A battery powered smoke detector sensor with integrated alarm (2nd version with long-life battery).</description>
<channels>
<channel id="smoke" typeId="smokeDetectorSensor"/>
<channel id="alarm" typeId="alarmActuator"/>
<channel id="batteryLow" typeId="system.low-battery"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:livisismarthome:config"/>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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="bridge">
<label>LIVISI SmartHome Controller</label>
<description>The LIVISI SmartHome Controller (SHC) is the bridge for the LIVISI SmartHome System.</description>
<channels>
<channel id="status" typeId="operationStatus"/>
<channel id="cpu" typeId="cpuUsage"/>
<channel id="disk" typeId="diskUsage"/>
<channel id="memory" typeId="memoryUsage"/>
</channels>
<representation-property>id</representation-property>
<config-description>
<parameter-group name="connection">
<label>Connection</label>
<description>Parameters for connecting to LIVISI SmartHome Controller (SHC)</description>
</parameter-group>
<parameter-group name="advanced">
<label>Advanced Configuration</label>
<description>Advanced parameters, for special tweaking only.</description>
<advanced>true</advanced>
</parameter-group>
<parameter name="host" type="text" required="true" groupName="connection">
<label>Host</label>
<description>The hostname or local IP address of the LIVISI SmartHome Controller (SHC)</description>
</parameter>
<parameter name="password" type="text" required="true" groupName="connection">
<label>Password</label>
<description>Password for the local API of LIVISI SmartHome</description>
<context>password</context>
</parameter>
<parameter name="webSocketIdleTimeout" type="integer" min="0" max="3600" unit="s" groupName="advanced">
<unitLabel>seconds</unitLabel>
<label>WebSocket Idle Timeout in Seconds</label>
<description>The WebSocket is the connection to the LIVISI service that listens to status updates. If no data is
received over the WebSocket connection for the given time, the WebSocket will reconnect. 0 will disable the idle
timeout. Default is 900 seconds (15 minutes).</description>
<default>900</default>
<advanced>true</advanced>
</parameter>
</config-description>
</bridge-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,368 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="livisismarthome"
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">
<!-- Switch Channel -->
<channel-type id="switchActuator">
<item-type>Switch</item-type>
<label>Switch</label>
<description>Switches the current on/off</description>
<category>Switch</category>
</channel-type>
<!-- Dimmer Channel -->
<channel-type id="dimmerActuator">
<item-type>Dimmer</item-type>
<label>Dimmer</label>
<description>Dims the connected light</description>
<category>Lightbulb</category>
</channel-type>
<!-- RollerShutter Channel -->
<channel-type id="rollershutterActuator">
<item-type>Rollershutter</item-type>
<label>Blinds Position</label>
<description>Controls the blinds</description>
<category>Blinds</category>
<config-description>
<parameter name="invert" type="boolean">
<label>Invert Position</label>
<description>When invert is true than 0 on LIVISI is UP and 100 is DOWN</description>
</parameter>
</config-description>
</channel-type>
<!-- BooleanSwitch Channel -->
<channel-type id="booleanStateActuator">
<item-type>Switch</item-type>
<label>State</label>
<description>Switches the state on/off</description>
<category>Switch</category>
</channel-type>
<!-- ThermostatActuator -->
<channel-type id="thermostatActuatorPointTemperature">
<item-type>Number:Temperature</item-type>
<label>Target Temperature</label>
<description>Thermostat target temperature</description>
<category>Temperature</category>
<tags>
<tag>Setpoint</tag>
<tag>Temperature</tag>
</tags>
<state min="6" max="30" step="0.5" pattern="%.1f %unit%" readOnly="false"/>
</channel-type>
<channel-type id="thermostatActuatorOperationMode" advanced="true">
<item-type>String</item-type>
<label>Operation Mode</label>
<description>Thermostat operation mode (manual/auto)</description>
<category>Settings</category>
<state>
<options>
<option value="Auto">Auto</option>
<option value="Manu">Manual</option>
</options>
</state>
</channel-type>
<channel-type id="thermostatActuatorWindowReductionActive" advanced="true">
<item-type>Switch</item-type>
<label>Window Reduction Active</label>
<description>Thermostat temperature reduced, if window is open.</description>
<category>Temperature</category>
<state readOnly="true"/>
</channel-type>
<!-- TemperatureSensor -->
<channel-type id="temperatureSensorTemperature">
<item-type>Number:Temperature</item-type>
<label>Actual Temperature</label>
<description>Actual measured room temperature</description>
<category>Temperature</category>
<tags>
<tag>Measurement</tag>
<tag>Temperature</tag>
</tags>
<state pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="temperatureSensorFrostWarning" advanced="true">
<item-type>Switch</item-type>
<label>Frost Warning</label>
<description>Warns, if temperature drop below a threshold (configured in LIVISI app)</description>
<category>Temperature</category>
<state readOnly="true"/>
</channel-type>
<!-- HumiditySensor -->
<channel-type id="humiditySensorHumidity">
<item-type>Number:Dimensionless</item-type>
<label>Actual Humidity</label>
<description>Actual measured room humidity</description>
<category>Humidity</category>
<tags>
<tag>Measurement</tag>
<tag>Humidity</tag>
</tags>
<state readOnly="true" min="0" max="100" pattern="%.1f%%"/>
</channel-type>
<channel-type id="humiditySensorMoldWarning" advanced="true">
<item-type>Switch</item-type>
<label>Mold Warning</label>
<description>Active, if humidity is over a threshold (configured in LIVISI app)</description>
<category>Humidity</category>
<state readOnly="true"/>
</channel-type>
<!-- WindowDoorSensor Channel -->
<channel-type id="windowDoorSensor">
<item-type>Contact</item-type>
<label>Contact</label>
<description>Shows the open/close state</description>
<category>Contact</category>
<state readOnly="true"/>
</channel-type>
<!-- SmokeDetectorSensor Channel -->
<channel-type id="smokeDetectorSensor">
<item-type>Switch</item-type>
<label>Smoke</label>
<description>Shows if smoke was detected</description>
<category>Smoke</category>
<state readOnly="true"/>
</channel-type>
<!-- AlarmActuator Channel -->
<channel-type id="alarmActuator">
<item-type>Switch</item-type>
<label>Alarm</label>
<description>Switches the alarm on/off</description>
<category>Alarm</category>
</channel-type>
<!-- MotionDetectionSensor Channel -->
<channel-type id="motionDetectionSensor">
<item-type>Number</item-type>
<label>Motion Count</label>
<description>The count of detected motions</description>
<category>Motion</category>
<state readOnly="true"/>
</channel-type>
<!-- LuminanceSensor Channel -->
<channel-type id="luminanceSensor">
<item-type>Number:Dimensionless</item-type>
<label>Luminance</label>
<description>Shows the detected luminance in percent</description>
<category>Sun</category>
<state readOnly="true" min="0" max="100" pattern="%d%%"/>
</channel-type>
<!-- PushButtonCounter Channel -->
<channel-type id="pushButtonCounter" advanced="true">
<item-type>Number</item-type>
<label>Button Pushed Count</label>
<description>The count of button pushes.</description>
<category>Count</category>
<state readOnly="true"/>
</channel-type>
<!-- EnergyConsumptionMonthKWh -->
<channel-type id="energyConsumptionMonthKwh" advanced="true">
<item-type>Number:Energy</item-type>
<label>Consumption (month)</label>
<description>The energy consumption per month in kWh</description>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<!-- AbsoluteEnergyConsumption -->
<channel-type id="absoluteEnergyConsumption">
<item-type>Number:Energy</item-type>
<label>Total Consumption</label>
<description>The absolute energy consumption</description>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<!-- EnergyConsumptionMonthEuro -->
<channel-type id="energyConsumptionMonthEuro" advanced="true">
<item-type>Number</item-type>
<label>Consumption Costs (month)</label>
<description>The energy consumption per month in Euro</description>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<!-- EnergyConsumptionDayEuro -->
<channel-type id="energyConsumptionDayEuro">
<item-type>Number</item-type>
<label>Consumption Costs (day)</label>
<description>The energy consumption per day in Euro</description>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<!-- EnergyConsumptionDayKWh -->
<channel-type id="energyConsumptionDayKwh">
<item-type>Number:Energy</item-type>
<label>Consumption (day)</label>
<description>The energy consumption per day in kWh</description>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<!-- PowerConsumptionWatt -->
<channel-type id="powerConsumptionWatt">
<item-type>Number:Power</item-type>
<label>Current Power Consumption</label>
<description>The current power consumption in Watt</description>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<!-- EnergyGenerationMonthKWh -->
<channel-type id="energyGenerationMonthKwh" advanced="true">
<item-type>Number:Energy</item-type>
<label>Generation (month)</label>
<description>The energy generation per month in kWh</description>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<!-- TotalEnergyGeneration -->
<channel-type id="totalEnergyGeneration">
<item-type>Number:Energy</item-type>
<label>Total Generation</label>
<description>The total energy generation</description>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<!-- EnergyGenerationMonthEuro -->
<channel-type id="energyGenerationMonthEuro" advanced="true">
<item-type>Number</item-type>
<label>Generation Value (month)</label>
<description>The energy generation per month in Euro</description>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<!-- EnergyGenerationDayEuro -->
<channel-type id="energyGenerationDayEuro">
<item-type>Number</item-type>
<label>Generation Value (day)</label>
<description>The energy generation per day in Euro</description>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<!-- EnergyGenerationDayKWh -->
<channel-type id="energyGenerationDayKwh">
<item-type>Number:Energy</item-type>
<label>Generation (day)</label>
<description>The energy generation per day in kWh</description>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<!-- PowerGenerationWatt -->
<channel-type id="powerGenerationWatt">
<item-type>Number:Power</item-type>
<label>Current Power Generation</label>
<description>The current power generation in Watt</description>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<!-- TotalEnergyConsumption -->
<channel-type id="totalEnergyConsumption">
<item-type>Number:Energy</item-type>
<label>Total Consumption</label>
<description>The total energy consumption</description>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<!-- EnergyFeedMonthKWh -->
<channel-type id="energyFeedMonthKwh" advanced="true">
<item-type>Number:Energy</item-type>
<label>Feed (month)</label>
<description>The energy feed per month in kWh</description>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<!-- TotalEnergyFeed -->
<channel-type id="totalEnergyFed">
<item-type>Number:Energy</item-type>
<label>Total Fed</label>
<description>The total energy fed</description>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<!-- EnergyFeedMonthEuro -->
<channel-type id="energyFeedMonthEuro" advanced="true">
<item-type>Number</item-type>
<label>Feed Income (month)</label>
<description>The energy feed per month in Euro</description>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<!-- EnergyFeedDayEuro -->
<channel-type id="energyFeedDayEuro">
<item-type>Number</item-type>
<label>Feed Income (day)</label>
<description>The energy feed per day in Euro</description>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<!-- EnergyFeedDayKWh -->
<channel-type id="energyFeedDayKwh">
<item-type>Number:Energy</item-type>
<label>Feed (day)</label>
<description>The energy feed per day in kWh</description>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<!-- CPUUsage -->
<channel-type id="cpuUsage">
<item-type>Number:Dimensionless</item-type>
<label>CPU Usage</label>
<description>The CPU usage of the SHC in percent</description>
<category>Line</category>
<state readOnly="true" min="0" max="100" pattern="%d%%"/>
</channel-type>
<!-- DiskUsage -->
<channel-type id="diskUsage">
<item-type>Number:Dimensionless</item-type>
<label>Disk Usage</label>
<description>The disk usage of the SHC</description>
<category>Line</category>
<state readOnly="true" min="0" max="100" pattern="%d%%"/>
</channel-type>
<!-- MemoryUsage -->
<channel-type id="memoryUsage">
<item-type>Number:Dimensionless</item-type>
<label>Memory Usage</label>
<description>The memory usage of the SHC in percent</description>
<category>Line</category>
<state readOnly="true" min="0" max="100" pattern="%d%%"/>
</channel-type>
<!-- OperationStatus -->
<channel-type id="operationStatus">
<item-type>String</item-type>
<label>Status</label>
<description>The operation status of SHC-A</description>
<category>Settings</category>
<state readOnly="true"/>
</channel-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,259 @@
/**
* Copyright (c) 2010-2022 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.livisismarthome.internal;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import java.net.URI;
import java.util.concurrent.Future;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openhab.binding.livisismarthome.internal.listener.EventListener;
/**
* @author Sven Strohschein - Initial contribution
*/
@NonNullByDefault
public class LivisiWebSocketTest {
private @NonNullByDefault({}) LivisiWebSocketAccessible webSocket;
private @NonNullByDefault({}) EventListenerDummy eventListener;
private @NonNullByDefault({}) WebSocketClient webSocketClientMock;
private @NonNullByDefault({}) Session sessionMock;
@BeforeEach
@SuppressWarnings("unchecked")
public void before() throws Exception {
sessionMock = mock(Session.class);
Future<Session> futureMock = mock(Future.class);
when(futureMock.get()).thenReturn(sessionMock);
webSocketClientMock = mock(WebSocketClient.class);
when(webSocketClientMock.connect(any(), any())).thenReturn(futureMock);
HttpClient httpClientMock = mock(HttpClient.class);
eventListener = new EventListenerDummy();
webSocket = new LivisiWebSocketAccessible(httpClientMock, eventListener, new URI(""), 1000);
}
@Test
public void testStart() throws Exception {
startWebSocket();
assertTrue(webSocket.isRunning());
}
@Test
public void testStop() throws Exception {
startWebSocket();
webSocket.stop();
assertFalse(webSocket.isRunning());
}
@Test
public void testOnCloseAfterStop() throws Exception {
startWebSocket();
assertFalse(eventListener.isOnEventCalled());
assertFalse(eventListener.isOnErrorCalled());
assertFalse(eventListener.isConnectionClosedCalled());
webSocket.stop();
webSocket.onClose(StatusCode.ABNORMAL, "Test");
assertFalse(eventListener.isOnEventCalled());
assertFalse(eventListener.isOnErrorCalled());
// stop() itself causes a (abnormal) close event, that shouldn't get noticed
// (otherwise it would cause a reconnect event which would lead to an infinite loop ...)
assertFalse(eventListener.isConnectionClosedCalled());
}
@Test
public void testOnCloseAfterRestart() throws Exception {
startWebSocket();
assertFalse(eventListener.isOnEventCalled());
assertFalse(eventListener.isOnErrorCalled());
assertFalse(eventListener.isConnectionClosedCalled());
webSocket.stop();
webSocket.onClose(StatusCode.ABNORMAL, "Test");
assertFalse(eventListener.isOnEventCalled());
assertFalse(eventListener.isOnErrorCalled());
// stop() itself causes a (abnormal) close event, that shouldn't get noticed
// (otherwise it would cause a reconnect event which would lead to an infinite loop ...)
assertFalse(eventListener.isConnectionClosedCalled());
startWebSocket();
webSocket.onClose(StatusCode.ABNORMAL, "Test");
assertFalse(eventListener.isOnEventCalled());
assertFalse(eventListener.isOnErrorCalled());
// A close event after a restart of the web socket should get recognized again
assertTrue(eventListener.isConnectionClosedCalled());
}
@Test
public void testOnCloseAbnormal() throws Exception {
startWebSocket();
assertFalse(eventListener.isOnEventCalled());
assertFalse(eventListener.isOnErrorCalled());
assertFalse(eventListener.isConnectionClosedCalled());
webSocket.onClose(StatusCode.ABNORMAL, "Test");
assertFalse(eventListener.isOnEventCalled());
assertFalse(eventListener.isOnErrorCalled());
assertTrue(eventListener.isConnectionClosedCalled());
}
@Test
public void testOnCloseNormal() throws Exception {
startWebSocket();
assertFalse(eventListener.isOnEventCalled());
assertFalse(eventListener.isOnErrorCalled());
assertFalse(eventListener.isConnectionClosedCalled());
webSocket.onClose(StatusCode.NORMAL, "Test");
assertFalse(eventListener.isOnEventCalled());
assertFalse(eventListener.isOnErrorCalled());
// Nothing should get noticed when a normal close is executed (for example by stopping OpenHAB)
assertFalse(eventListener.isConnectionClosedCalled());
}
@Test
public void testOnMessage() throws Exception {
startWebSocket();
assertFalse(eventListener.isOnEventCalled());
assertFalse(eventListener.isOnErrorCalled());
assertFalse(eventListener.isConnectionClosedCalled());
webSocket.onMessage("Test-Message");
assertTrue(eventListener.isOnEventCalled());
assertFalse(eventListener.isOnErrorCalled());
assertFalse(eventListener.isConnectionClosedCalled());
}
@Test
public void testOnMessageAfterStop() throws Exception {
startWebSocket();
assertFalse(eventListener.isOnEventCalled());
assertFalse(eventListener.isOnErrorCalled());
assertFalse(eventListener.isConnectionClosedCalled());
webSocket.stop();
webSocket.onClose(StatusCode.ABNORMAL, "Test");
webSocket.onMessage("Test-Message");
assertFalse(eventListener.isOnEventCalled());
assertFalse(eventListener.isOnErrorCalled());
assertFalse(eventListener.isConnectionClosedCalled());
}
@Test
public void testOnError() throws Exception {
startWebSocket();
assertFalse(eventListener.isOnEventCalled());
assertFalse(eventListener.isOnErrorCalled());
assertFalse(eventListener.isConnectionClosedCalled());
webSocket.onError(new RuntimeException("Test-Exception"));
assertFalse(eventListener.isOnEventCalled());
assertTrue(eventListener.isOnErrorCalled());
assertFalse(eventListener.isConnectionClosedCalled());
}
private void startWebSocket() throws Exception {
webSocket.start();
when(sessionMock.isOpen()).thenReturn(true);
webSocket.onConnect(sessionMock);
}
private class LivisiWebSocketAccessible extends LivisiWebSocket {
private LivisiWebSocketAccessible(HttpClient httpClient, EventListener eventListener, URI webSocketURI,
int maxIdleTimeout) {
super(httpClient, eventListener, webSocketURI, maxIdleTimeout);
}
@Override
WebSocketClient createWebSocketClient() {
return webSocketClientMock;
}
@Override
void startWebSocketClient(WebSocketClient client) {
}
@Override
void stopWebSocketClient(WebSocketClient client) {
}
}
private static class EventListenerDummy implements EventListener {
private boolean isOnEventCalled;
private boolean isOnErrorCalled;
private boolean isConnectionClosedCalled;
@Override
public void onEvent(String msg) {
isOnEventCalled = true;
}
@Override
public void onError(Throwable cause) {
isOnErrorCalled = true;
}
@Override
public void connectionClosed() {
isConnectionClosedCalled = true;
}
public boolean isOnEventCalled() {
return isOnEventCalled;
}
public boolean isOnErrorCalled() {
return isOnErrorCalled;
}
public boolean isConnectionClosedCalled() {
return isConnectionClosedCalled;
}
}
}

Some files were not shown because too many files have changed in this diff Show More