[imperihome] Remove imperihome addon (#15014)

Signed-off-by: Holger Friedrich <mail@holger-friedrich.de>
pull/15019/head
Holger Friedrich 2023-05-23 07:38:21 +02:00 committed by GitHub
parent d8376aa6d0
commit ac04a4e71d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
74 changed files with 0 additions and 4822 deletions

View File

@ -388,7 +388,6 @@
/bundles/org.openhab.binding.zway/ @pathec
/bundles/org.openhab.io.homekit/ @andylintner @ccutrer @yfre
/bundles/org.openhab.io.hueemulation/ @davidgraeff @digitaldan
/bundles/org.openhab.io.imperihome/ @pdegeus
/bundles/org.openhab.io.metrics/ @pravussum
/bundles/org.openhab.io.neeo/ @tmrobert8
/bundles/org.openhab.io.openhabcloud/ @kaikreuzer

View File

@ -1931,11 +1931,6 @@
<artifactId>org.openhab.io.hueemulation</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.io.imperihome</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.io.metrics</artifactId>

View File

@ -1,13 +0,0 @@
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

@ -1,511 +0,0 @@
# ImperiHome integration service
This IO service exposes openHAB Items to the Evertygo [ImperiHome](https://imperihome.com/) dashboard app for Android and iOS.
It creates a REST service at _/imperihome/iss_ that implements the [ImperiHome Standard System API](http://dev.evertygo.com/api/iss) (ISS).
## Installation
The ImperiHome integration service can be installed through the "Misc" add-ons category in the UI.
## Configuration
### openHAB Add-on
To configure the ImperiHome integration add-on in openHAB, create a _imperihome.cfg_ file in the _conf/services_ directory.
The following configuration options can be used:
**System ID**
The ImperiHome integration service identifies itself to ImperiHome using a system ID.
By default the unique identifier of your openHAB installation is used. To override the ID, use the _system.id_ configuration option.
```
system.id=my-openhab-123
```
_Warning_: the system ID can not contain the underscore character (&lowbar;).
**Root URL**
Root URL of your openHAB installation.
Should point to the openHAB welcome page
This option is currently only required when using the custom icon tag.
```
openhab.rootUrl=http://myserver.example.org:7070/
```
### ImperiHome
ImperiHome must be configured to connect to your openHAB instance.
Start ImperiHome, open the menu and go to My Systems.
Add a new system (+) and choose 'ImperiHome Standard System' as the object type.
Now enter the URL to your openHAB instance as Local URL, followed by _/imperihome/iss_.
For example, if your openHAB instance is running at _<http://192.168.1.10:8080/>_, the Local URL would be _<http://192.168.1.10:8080/imperihome/iss>_.
If you have port forwarding or similar set up to access your openHAB from the internet, you can also fill the Remote URL in the same way.
For example: _<http://my-openhab-url.dyndns.org:8080/imperihome/iss>_.
_Warning_: this service provides no authentication mechanism, so anyone could use the API to control your system when accessible from the internet.
Add a secure proxy or use the openHAB Cloud proxy to protect your system ([more information](https://www.openhab.org/docs/installation/security.html)).
Click Next to let ImperiHome validate the URL.
After validation succeeded the system is added and you can continue to configure your Items for use in ImperiHome.
## Device Tagging
This service uses Item tags to determine how to expose your Items to ImperiHome.
All tags are formatted like this:
```
iss:<tagtype>:<value>
```
For example:
```
iss:room:Kitchen
```
If you have defined your Items in _.items_ files, tags can be added using:
```
[ "mytag" ]
```
syntax (after the _(Groups)_ and before the _{channel}_).
### Tag: _type_
Specifies the device type to expose to ImperiHome.
Take a look at [Device types](#deviceTypes) below for the supported device types and how to configure them.
If no type is specified, this service will try to auto-detect the type from the Item, based on supported value types (OnOff for a switch, HSB for color light) and Item name.
_Required_: no<br>
_Default_: auto-detect<br>
Example:
```
iss:type:DevSwitch
```
### Tag: _room_
Specifies the room the device will show up in in ImperiHome.
_Required_: no<br>
_Default_: 'No Room'<br>
_Example_:
```
iss:room:Kitchen
```
### Tag: _label_
Sets the device label in ImperiHome.
If no label is specified, the Item label is used if available.
Otherwise the Item name will be used.
_Required_: no<br>
_Default_: Item label or name<br>
_Example_:
```
iss:label:Kitchen light
```
### Tag: _mapping_
Sets the mapping for an ImperiHome MultiSwitch device, just like an openHAB sitemap mapping does.
In the example below, 'All off', 'Relax' and 'Reading' will be visible in ImperiHome.
Clicking one of the options will send a 0, 1 or 2 value command to the openHAB item.
_Required_: only for MultiSwitch device<br>
_Default_: none<br>
_Example_:
```
iss:mapping:0=All off,1=Relax,2=Reading
```
### Tag: _link_
Links two devices together, using the value from the linked device as an additional value in the device containing the link tag.
See [Device links](#deviceLinks) for details.
_Required_: no<br>
_Default_: none<br>
_Example_:
```
iss:link:energy:Kitchen_Current_Consumption
```
### Tag: _unit_
Sets the unit for devices with a numeric value, such as _DevTemperature_ and _DevGenericSensor_.
The unit is only used to tell ImperiHome what to display; no conversion is performed.
_Required_: no<br>
_Default_: none<br>
_Example_:
```
iss:unit:°C
```
### Tag: _invert_
Inverts the state of on/off devices such as switches and dimmers.
_Required_: no<br>
_Default_: false<br>
_Example_:
```
iss:invert:true
```
### Tag: _icon_
Sets a custom icon to be shown in ImperiHome.
You can use all icon names that are also available for use in your sitemaps, including custom icons.
To use this tag you must set the openHAB root URL in your [configuration](#configuration).
_Required_: no<br>
_Default_: none<br>
_Example_:
```
iss:icon:sofa
```
<a name="deviceTypes"></a>
## Device types
The following table lists the ImperiHome API device types that you can use in a _iss:type_ tag.
Not all device types are currently supported.
For those that are supported, the Item types you can use them on are listed.
<table>
<tr>
<th>Device</th>
<th>Description</th>
<th>Supported</th>
<th>Item types</th>
<th>Link types</th>
</tr>
<tr>
<td>DevCamera</td>
<td>MJPEG IP Camera</td>
<td>No</td>
<td></td>
<td>-</td>
</tr>
<tr>
<td>DevCO2</td>
<td>CO2 sensor</td>
<td>Yes</td>
<td>Number</td>
<td>-</td>
</tr>
<tr>
<td>DevCO2Alert</td>
<td>CO2 Alert sensor</td>
<td>Yes</td>
<td>Contact, Number, String<sup>(1)</sup>, Switch</td>
<td>-</td>
</tr>
<tr>
<td>DevDimmer</td>
<td>Dimmable light</td>
<td>Yes</td>
<td>Dimmer, Number</td>
<td>energy</td>
</tr>
<tr>
<td>DevDoor</td>
<td>Door / window security sensor</td>
<td>Yes</td>
<td>Contact, Number, String<sup>(1)</sup>, Switch</td>
<td>-</td>
</tr>
<tr>
<td>DevElectricity</td>
<td>Electricity consumption sensor</td>
<td>Yes</td>
<td>Number</td>
<td>kwh, watt</td>
</tr>
<tr>
<td>DevFlood</td>
<td>Flood security sensor</td>
<td>Yes</td>
<td>Contact, Number, String<sup>(1)</sup>, Switch</td>
<td>-</td>
</tr>
<tr>
<td>DevGenericSensor</td>
<td>Generic sensor (any value)</td>
<td>Yes</td>
<td>Number, String</td>
<td>-</td>
</tr>
<tr>
<td>DevHygrometry</td>
<td>Hygro sensor</td>
<td>Yes</td>
<td>Number</td>
<td>-</td>
</tr>
<tr>
<td>DevLock</td>
<td>Door lock</td>
<td>Yes</td>
<td>Contact, Switch</td>
<td>-</td>
</tr>
<tr>
<td>DevLuminosity</td>
<td>Luminance sensor</td>
<td>Yes</td>
<td>Number</td>
<td>-</td>
</tr>
<tr>
<td>DevMotion</td>
<td>Motion security sensor</td>
<td>Yes</td>
<td>Contact, Number, String<sup>(1)</sup>, Switch</td>
<td>-</td>
</tr>
<tr>
<td>DevMultiSwitch</td>
<td>Multiple choice actuator</td>
<td>Yes</td>
<td>Number</td>
<td>-</td>
</tr>
<tr>
<td>DevNoise</td>
<td>Noise sensor</td>
<td>Yes</td>
<td>Number</td>
<td>-</td>
</tr>
<tr>
<td>DevPlayer</td>
<td>Audio/Video player</td>
<td>No</td>
<td></td>
<td>-</td>
</tr>
<tr>
<td>DevPlaylist</td>
<td>Audio/Video playlist</td>
<td>No</td>
<td></td>
<td>-</td>
</tr>
<tr>
<td>DevPressure</td>
<td>Pressure sensor</td>
<td>Yes</td>
<td>Number</td>
<td>-</td>
</tr>
<tr>
<td>DevRain</td>
<td>Rain sensor</td>
<td>Yes</td>
<td>Number</td>
<td>accum</td>
</tr>
<tr>
<td>DevRGBLight</td>
<td>RGB(W) Light (dimmable)</td>
<td>Yes</td>
<td>Color</td>
<td>energy</td>
</tr>
<tr>
<td>DevScene</td>
<td>Scene (launchable)</td>
<td>Yes</td>
<td>Switch, Number</td>
<td>-</td>
</tr>
<tr>
<td>DevShutter</td>
<td>Shutter actuator</td>
<td>Yes</td>
<td>Dimmer, Number</td>
<td>-</td>
</tr>
<tr>
<td>DevSmoke</td>
<td>Smoke security sensor</td>
<td>Yes</td>
<td>Contact, Number, String<sup>(1)</sup>, Switch</td>
<td>-</td>
</tr>
<tr>
<td>DevSwitch</td>
<td>Standard on/off switch</td>
<td>Yes</td>
<td>Switch</td>
<td>energy</td>
</tr>
<tr>
<td>DevTemperature</td>
<td>Temperature sensor</td>
<td>Yes</td>
<td>Number</td>
<td>-</td>
</tr>
<tr>
<td>DevTempHygro</td>
<td>Temperature and Hygrometry combined sensor</td>
<td>Yes</td>
<td>Number</td>
<td>hygro, temp</td>
</tr>
<tr>
<td>DevThermostat</td>
<td>Thermostat <sup>(2)</sup></td>
<td>Yes</td>
<td>Number</td>
<td>curmode, curtemp</td>
</tr>
<tr>
<td>DevUV</td>
<td>UV sensor</td>
<td>Yes</td>
<td>Number</td>
<td>-</td>
</tr>
<tr>
<td>DevWind</td>
<td>Wind sensor</td>
<td>Yes</td>
<td>Number</td>
<td>direction</td>
</tr>
</table>
<sup>(1)</sup> When using a String Item for trippable devices, any non-empty value other than 'ok' will set the device to tripped. This makes it compatible with the Nest Protect binding.
<sup>(2)</sup> Thermostat devices require additional tags. See [Thermostat](#thermostat) for details.
<a name="deviceLinks"></a>
## Device links
Some devices can be linked to another device.
This allows you to create combined devices reporting multiple values, or reporting the energy consumption with a switch device.
The _link_ tag refers to the name of the Item it should link to.
The item must be an ImperiHome device itself, so it must have at least one _iss_ tag.
### Switch energy consumption
ImperiHome allows you to show the current energy consumption for a _DevDimmer_, _DevRGBLight_ and _DevSwitch_.
This example links the _MyLightEnergy_ Number Item to the _MyLight_ Switch Item, so the _DevSwitch_ device will also report the energy consumption value to ImperiHome:
```
Switch MyLight "My Light" ["iss:type:DevSwitch", "iss:link:energy:MyLight_Energy"] { channel="zwave:device:1:node14:switch_binary1" }
Number MyLightEnergy "My Light Usage [%.1f W]" ["iss:type:DevElectricity"] { channel="zwave:device:1:node14:meter_watts1" }
```
### Total energy consumption
The _DevElectricity_ devices main value is the current consumption in Watts.
To add the total consumption in KWh, link your electricity device to a generic sensor device containing the total energy consumption value:
```
Number MyLight_Energy "My Light Usage [%.1f W]" ["iss:type:DevElectricity", "iss:link:kwh:MyLight_Total_Energy"] { channel="zwave:device:1:node14:meter_watts1" }
Number MyLight_Total_Energy "My Light Total usage [%.1f KWh]" ["iss:type:DevGenericSensor", "iss:unit:KWh"] { channel="zwave:device:1:node14:sensor_power1" }
```
### TempHygro
ImperiHome recognizes the special _DevTempHygro_ device, combining a temperature and hydrometry sensor.
You can create such a device by linking either from a temperature Item to a hygro Item:
```
Number MyTemp "Temperature [%.1f °C]" ["iss:type:DevTempHygro", "iss:link:hygro:MyHum"] { channel="zwave:device:1:node8:sensor_temperature" }
Number MyHum "Humidity [%d%%]" ["iss:type:DevHygrometry"] { channel="zwave:device:1:node8:sensor_relhumidity" }
```
or vise versa:
```
Number MyTemp "Temperature [%.1f °C]" ["iss:type:DevTemperature"] { channel="zwave:device:1:node8:sensor_temperature" }
Number MyHum "Humidity [%d%%]" ["iss:type:DevTempHygro", "iss:link:temp:MyTemp"] { channel="zwave:device:1:node8:sensor_relhumidity" }
```
### Rain accumulation
The _DevRain_ devices main value is the current instant rain value (default in mm per hour).
To add the total rain accumulation value, link your rain device to a generic sensor device:
```
Number RainCurrent "Rain current [%.1f mm/h]" ["iss:type:DevRain", "iss:link:accum:RainAccumulation"] { channel="..." }
Number RainAccumulation "Rain accumulation [%.1f mm]" ["iss:type:DevGenericSensor", "iss:unit:mm"] { channel="..." }
```
### Wind direction
The _DevWind_ devices main value is the current wind speed (default in km per hour).
To add the wind direction value (default in degrees), link your wind device to a generic sensor device:
```
Number WindSpeed "Wind speed [%.1f km/h]" ["iss:type:DevWind", "iss:link:direction:WindDirection"] { channel="..." }
Number WindDirection "Wind direction [%d deg]" ["iss:type:DevGenericSensor", "iss:unit:deg"] { channel="..." }
```
<a name="thermostat"></a>
### Thermostat
The _DevThermostat_ combines a setpoint, current temperature and mode in one ImperiHome device.
To accomplish this using openHAB items, it uses a _curtemp_ and _curmode_ link and a few additional tags.
```
Number Thermos_Setpoint "Thermostat" ["iss:room:Test", "iss:type:DevThermostat", "iss:step:0.5", "iss:minVal:15", "iss:maxVal:24", "iss:modes:Home,Away,Comfort,Sleeping", "iss:link:curmode:Thermos_Mode", "iss:link:curtemp:Thermos_Temp"] { channel="..." }
Number Thermos_Temp "Thermos temp" ["iss:room:Test", "iss:type:DevTemperature", "iss:unit:K"] { channel="..." }
String Thermos_Mode "Thermos mode" ["iss:room:Test", "iss:type:DevGenericSensor"] { channel="..." }
```
The main _DevThermostat_ device must be the Item holding the setpoint.
Using tags, this device specifies the minimum and maximum setpoint value, the setpoint step and the available modes.
The two links specify what Items contain the current temperature and current mode.
If you want to use a custom unit, set the _unit_ tag on the current temperature device.
### Shutter stopper
The _DevShutter_ device of ImperiHome support a 'stop' action.
To use this, link a Switch item to your shutter item, like so:
```
Dimmer MyShutter "Shutter" ["iss:room:Test", "iss:type:DevShutter", "iss:link:stopper:MyShutterStop"] { channel="..." }
Switch MyShutterStop "Stop shutter" ["iss:room:Test", "iss:type:DevSwitch"] { channel="..." }
```
Implement a Rule listening for the ON command on the switch to handle the stop action yourself.
## Items example
```
Color LVR_Billy "Billy" <colorlight> (Lights) ["iss:room:Living room", "iss:type:DevRGBLight"] { channel="hue:0210:001122334455:bulb1:color" }
Switch LVR_TallLamp "Tall lamp" (Lights) ["iss:room:Living room", "iss:type:DevSwitch", "iss:invert:true"] { channel="zwave:device:1:node3:switch_binary" }
Dimmer LVR_DinnerTable "Dinner table" (Lights) ["iss:room:Living room", "iss:type:DevDimmer"] { channel="zwave:device:1:node13:switch_dimmer" }
Number ENT_Entrance_Current "Entrance usage [%.1f W]" (Wattage) ["iss:room:Entrance", "iss:type:DevElectricity", "iss:unit:Watt"] { channel="zwave:device:1:node14:meter_watts1" }
Number ENT_Temperature "Entrance temperature [%.1f °C]" (Temperature) ["iss:room:Entrance", "iss:type:DevTempHygro", "iss:link:hygro:ENT_Humidity"] { channel="zwave:device:1:node8:sensor_temperature" }
Number ENT_Luminance "Entrance light [%d lm]" (Luminance) ["iss:room:Entrance", "iss:type:DevLuminosity", "iss:unit:lux"] { channel="zwave:device:1:node8:sensor_luminance" }
Number ENT_Humidity "Entrance humidity [%d%%]" (Humidity) ["iss:room:Entrance", "iss:type:DevHygrometry"] { channel="zwave:device:1:node8:sensor_relhumidity" }
```

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
<version>4.0.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.io.imperihome</artifactId>
<name>openHAB Add-ons :: Bundles :: IO :: ImperiHome Integration Service</name>
</project>

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.io.imperihome-${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-misc-imperihome" description="ImperiHome Integration" version="${project.version}">
<feature>openhab-runtime-base</feature>
<feature>openhab-core-model-item</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.io.imperihome/${project.version}</bundle>
</feature>
</features>

View File

@ -1,248 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal;
import java.io.IOException;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.openhab.core.config.core.ConfigurableService;
import org.openhab.core.events.EventPublisher;
import org.openhab.core.items.ItemRegistry;
import org.openhab.core.persistence.PersistenceServiceRegistry;
import org.openhab.io.imperihome.internal.action.ActionRegistry;
import org.openhab.io.imperihome.internal.handler.DeviceActionHandler;
import org.openhab.io.imperihome.internal.handler.DeviceHistoryHandler;
import org.openhab.io.imperihome.internal.handler.DevicesListHandler;
import org.openhab.io.imperihome.internal.handler.RoomListHandler;
import org.openhab.io.imperihome.internal.handler.SystemHandler;
import org.openhab.io.imperihome.internal.io.DeviceParametersSerializer;
import org.openhab.io.imperihome.internal.io.DeviceTypeSerializer;
import org.openhab.io.imperihome.internal.io.ParamTypeSerializer;
import org.openhab.io.imperihome.internal.model.device.DeviceType;
import org.openhab.io.imperihome.internal.model.param.DeviceParameters;
import org.openhab.io.imperihome.internal.model.param.ParamType;
import org.openhab.io.imperihome.internal.processor.DeviceRegistry;
import org.openhab.io.imperihome.internal.processor.ItemProcessor;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.http.HttpService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
/**
* Main OSGi service and HTTP servlet for ImperiHome integration.
*
* @author Pepijn de Geus - Initial contribution
*/
@Component(service = HttpServlet.class, configurationPid = "org.openhab.imperihome", //
property = Constants.SERVICE_PID + "=org.openhab.imperihome")
@ConfigurableService(category = "io", label = "ImperiHome Integration", description_uri = "io:imperihome")
public class ImperiHomeApiServlet extends HttpServlet {
private static final long serialVersionUID = -1966364789075448441L;
private static final String PATH = "/imperihome/iss";
private static final String APPLICATION_JSON = "application/json";
private static final String CHARSET = "utf-8";
private static final Pattern URL_PATTERN_SYSTEM = Pattern.compile(PATH + "/system$", Pattern.CASE_INSENSITIVE);
private static final Pattern URL_PATTERN_ROOMS = Pattern.compile(PATH + "/rooms$", Pattern.CASE_INSENSITIVE);
private static final Pattern URL_PATTERN_DEVICES = Pattern.compile(PATH + "/devices$", Pattern.CASE_INSENSITIVE);
private static final Pattern URL_PATTERN_DEVICE_ACTION = Pattern
.compile(PATH + "/devices/(.+?)/action/(.+?)(?:/(.*?))?$", Pattern.CASE_INSENSITIVE);
private static final Pattern URL_PATTERN_DEVICE_HISTORY = Pattern
.compile(PATH + "/devices/(.+?)/(.+?)/histo/(.+?)/(.+?)$", Pattern.CASE_INSENSITIVE);
private final Logger logger = LoggerFactory.getLogger(ImperiHomeApiServlet.class);
private final Gson gson;
private final ImperiHomeConfig imperiHomeConfig;
private HttpService httpService;
private ItemRegistry itemRegistry;
private PersistenceServiceRegistry persistenceServiceRegistry;
private EventPublisher eventPublisher;
private ItemProcessor itemProcessor;
private DevicesListHandler devicesListHandler;
private RoomListHandler roomListHandler;
private SystemHandler systemHandler;
private DeviceRegistry deviceRegistry;
private DeviceActionHandler deviceActionHandler;
private DeviceHistoryHandler deviceHistoryHandler;
private ActionRegistry actionRegistry;
/**
* Default constructor.
*/
public ImperiHomeApiServlet() {
imperiHomeConfig = new ImperiHomeConfig();
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(DeviceType.class, new DeviceTypeSerializer());
gsonBuilder.registerTypeAdapter(ParamType.class, new ParamTypeSerializer());
gsonBuilder.registerTypeAdapter(DeviceParameters.class, new DeviceParametersSerializer());
gson = gsonBuilder.create();
}
/**
* OSGi activation callback.
*
* @param config Service config.
*/
@Activate
protected void activate(Map<String, Object> config) {
modified(config);
systemHandler = new SystemHandler(imperiHomeConfig);
deviceRegistry = new DeviceRegistry();
actionRegistry = new ActionRegistry(eventPublisher, deviceRegistry);
itemProcessor = new ItemProcessor(itemRegistry, deviceRegistry, actionRegistry, imperiHomeConfig);
roomListHandler = new RoomListHandler(deviceRegistry);
devicesListHandler = new DevicesListHandler(deviceRegistry);
deviceActionHandler = new DeviceActionHandler(deviceRegistry);
deviceHistoryHandler = new DeviceHistoryHandler(deviceRegistry, persistenceServiceRegistry);
try {
Dictionary<String, String> servletParams = new Hashtable<>();
httpService.registerServlet(PATH, this, servletParams, httpService.createDefaultHttpContext());
logger.info("Started ImperiHome integration service at " + PATH);
} catch (Exception e) {
logger.error("Could not start ImperiHome integration service: {}", e.getMessage(), e);
}
}
/**
* OSGi config modification callback.
*
* @param config Service config.
*/
@Modified
protected void modified(Map<String, Object> config) {
imperiHomeConfig.update(config);
}
/**
* OSGi deactivation callback.
*/
@Deactivate
protected void deactivate() {
try {
httpService.unregister(PATH);
} catch (IllegalArgumentException ignored) {
}
itemProcessor.destroy();
systemHandler = null;
deviceRegistry = null;
itemProcessor = null;
roomListHandler = null;
devicesListHandler = null;
deviceActionHandler = null;
deviceHistoryHandler = null;
logger.info("ImperiHome integration service stopped");
}
@Reference(policy = ReferencePolicy.DYNAMIC)
protected void setItemRegistry(ItemRegistry itemRegistry) {
this.itemRegistry = itemRegistry;
}
protected void unsetItemRegistry(ItemRegistry itemRegistry) {
this.itemRegistry = null;
}
@Reference
protected void setEventPublisher(EventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
protected void unsetEventPublisher(EventPublisher eventPublisher) {
this.eventPublisher = null;
}
@Reference
protected void setHttpService(HttpService httpService) {
this.httpService = httpService;
}
protected void unsetHttpService(HttpService httpService) {
this.httpService = null;
}
@Reference
protected void setPersistenceServiceRegistry(PersistenceServiceRegistry persistenceServiceRegistry) {
this.persistenceServiceRegistry = persistenceServiceRegistry;
}
protected void unsetPersistenceServiceRegistry(PersistenceServiceRegistry persistenceServiceRegistry) {
this.persistenceServiceRegistry = null;
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String path = req.getRequestURI();
logger.debug("{}: {} {}", req.getRemoteAddr(), req.getMethod(), path);
setHeaders(resp);
Object response = null;
Matcher actionMatcher = URL_PATTERN_DEVICE_ACTION.matcher(path);
Matcher historyMatcher = URL_PATTERN_DEVICE_HISTORY.matcher(path);
if (URL_PATTERN_ROOMS.matcher(path).matches()) {
response = roomListHandler.handle(req);
} else if (URL_PATTERN_DEVICES.matcher(path).matches()) {
response = devicesListHandler.handle(req);
} else if (actionMatcher.matches()) {
deviceActionHandler.handle(req, actionMatcher);
} else if (historyMatcher.matches()) {
response = deviceHistoryHandler.handle(req, historyMatcher);
} else if (URL_PATTERN_SYSTEM.matcher(path).matches()) {
response = systemHandler.handle(req);
} else {
logger.warn("Unrecognized request: {}", path);
}
resp.getWriter().write(gson.toJson(response));
}
private void setHeaders(HttpServletResponse response) {
response.setCharacterEncoding(CHARSET);
response.setContentType(APPLICATION_JSON);
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
}
}

View File

@ -1,59 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal;
import java.util.Map;
import org.openhab.core.id.InstanceUUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Configuration parser and container.
*
* @author Pepijn de Geus - Initial contribution
*/
public class ImperiHomeConfig {
private final Logger logger = LoggerFactory.getLogger(ImperiHomeConfig.class);
private String systemId;
private String rootUrl;
public void update(Map<String, Object> config) {
Object cSystemId = config.get("system.id");
if (cSystemId == null || cSystemId.toString().isEmpty()) {
systemId = InstanceUUID.get();
} else {
systemId = cSystemId.toString();
}
Object rootUrlObj = config.get("openhab.rootUrl");
if (rootUrlObj != null) {
rootUrl = String.valueOf(rootUrlObj);
if (!rootUrl.endsWith("/")) {
rootUrl += "/";
}
}
logger.info("Configuration updated");
}
public String getSystemId() {
return systemId;
}
public String getRootUrl() {
return rootUrl;
}
}

View File

@ -1,55 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.action;
import org.openhab.core.events.EventPublisher;
import org.openhab.core.items.Item;
import org.openhab.io.imperihome.internal.model.device.AbstractDevice;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Abstract action, called through the API by ImperiHome clients.
*
* @author Pepijn de Geus - Initial contribution
*/
public abstract class Action {
protected final transient Logger logger = LoggerFactory.getLogger(getClass());
protected static final String COMMAND_SOURCE = "imperihome";
protected final EventPublisher eventPublisher;
protected Action(EventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
/**
* Indicates if this action can be performed on the given Item.
*
* @param device
* @param item Item to check compatibility with.
* @return True if the Item is supported.
*/
public abstract boolean supports(AbstractDevice device, Item item);
/**
* Perform this action on the given Item.
*
* @param device
* @param item Item to perform action on.
* @param value Action parameter value.
*/
public abstract void perform(AbstractDevice device, Item item, String value);
}

View File

@ -1,44 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.action;
import java.util.HashMap;
import java.util.Map;
import org.openhab.core.events.EventPublisher;
import org.openhab.io.imperihome.internal.processor.DeviceRegistry;
/**
* Action registry. Maps ImperiHome API action name to {@link Action} implementation.
*
* @author Pepijn de Geus - Initial contribution
*/
public class ActionRegistry {
private final Map<String, Action> actions = new HashMap<>();
public ActionRegistry(EventPublisher eventPublisher, DeviceRegistry deviceRegistry) {
actions.put("setStatus", new SetStatusAction(eventPublisher));
actions.put("setColor", new SetColorAction(eventPublisher));
actions.put("setLevel", new SetLevelAction(eventPublisher));
actions.put("setChoice", new SetChoiceAction(eventPublisher));
actions.put("setMode", new SetModeAction(eventPublisher, deviceRegistry));
actions.put("setSetPoint", new SetSetPointAction(eventPublisher));
actions.put("launchScene", new LaunchSceneAction(eventPublisher));
actions.put("stopShutter", new StopShutterAction(eventPublisher, deviceRegistry));
}
public Action get(String action) {
return actions.get(action);
}
}

View File

@ -1,58 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.action;
import java.util.List;
import org.openhab.core.events.EventPublisher;
import org.openhab.core.items.Item;
import org.openhab.core.items.events.ItemCommandEvent;
import org.openhab.core.items.events.ItemEventFactory;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.types.Command;
import org.openhab.io.imperihome.internal.model.device.AbstractDevice;
/**
* Action performed on a DevScene. Sends an {@link OnOffType#ON} or {@link DecimalType} 1 to the Item.
*
* @author Pepijn de Geus - Initial contribution
*/
public class LaunchSceneAction extends Action {
public LaunchSceneAction(EventPublisher eventPublisher) {
super(eventPublisher);
}
@Override
public boolean supports(AbstractDevice device, Item item) {
List<Class<? extends Command>> acceptedCommandTypes = item.getAcceptedCommandTypes();
return acceptedCommandTypes.contains(OnOffType.class) || acceptedCommandTypes.contains(DecimalType.class);
}
@Override
public void perform(AbstractDevice device, Item item, String value) {
ItemCommandEvent event = null;
List<Class<? extends Command>> acceptedCommandTypes = item.getAcceptedCommandTypes();
if (acceptedCommandTypes.contains(OnOffType.class)) {
event = ItemEventFactory.createCommandEvent(item.getName(), OnOffType.ON, COMMAND_SOURCE);
} else if (acceptedCommandTypes.contains(DecimalType.class)) {
event = ItemEventFactory.createCommandEvent(item.getName(), new DecimalType(1), COMMAND_SOURCE);
}
if (event != null) {
eventPublisher.post(event);
}
}
}

View File

@ -1,63 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.action;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import org.openhab.core.events.EventPublisher;
import org.openhab.core.items.Item;
import org.openhab.core.items.events.ItemCommandEvent;
import org.openhab.core.items.events.ItemEventFactory;
import org.openhab.core.library.types.DecimalType;
import org.openhab.io.imperihome.internal.model.device.AbstractDevice;
/**
* Action setting a choice from a selection list, e.g. MultiSwitch.
*
* @author Pepijn de Geus - Initial contribution
*/
public class SetChoiceAction extends Action {
public SetChoiceAction(EventPublisher eventPublisher) {
super(eventPublisher);
}
@Override
public boolean supports(AbstractDevice device, Item item) {
Map<String, String> mapping = device.getMapping();
return mapping != null && !mapping.isEmpty() && item.getAcceptedCommandTypes().contains(DecimalType.class);
}
@Override
public void perform(AbstractDevice device, Item item, String value) {
String newValue = null;
for (Entry<String, String> entry : device.getMapping().entrySet()) {
if (Objects.equals(entry.getValue(), value)) {
newValue = entry.getKey();
break;
}
}
if (newValue == null) {
logger.warn("Could not find selection '{}' in mapping {} of device {}", value, device.getMapping(), device);
return;
}
ItemCommandEvent event = ItemEventFactory.createCommandEvent(item.getName(), new DecimalType(newValue),
COMMAND_SOURCE);
eventPublisher.post(event);
}
}

View File

@ -1,60 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.action;
import org.openhab.core.events.EventPublisher;
import org.openhab.core.items.Item;
import org.openhab.core.items.events.ItemCommandEvent;
import org.openhab.core.items.events.ItemEventFactory;
import org.openhab.core.library.types.HSBType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.io.imperihome.internal.model.device.AbstractDevice;
/**
* Items setting RGB color value.
*
* @author Pepijn de Geus - Initial contribution
*/
public class SetColorAction extends Action {
public SetColorAction(EventPublisher eventPublisher) {
super(eventPublisher);
}
@Override
public boolean supports(AbstractDevice device, Item item) {
return item.getAcceptedCommandTypes().contains(HSBType.class);
}
@Override
public void perform(AbstractDevice device, Item item, String value) {
if (value == null || value.length() != 8) {
logger.error("Invalid parameter: '{}'. Format must be 'aarrggbb'.", value);
return;
}
int r = Integer.parseInt(value.substring(2, 4), 16);
int g = Integer.parseInt(value.substring(4, 6), 16);
int b = Integer.parseInt(value.substring(6, 8), 16);
ItemCommandEvent event;
if (r == 0 && g == 0 && b == 0) {
event = ItemEventFactory.createCommandEvent(item.getName(), OnOffType.OFF, COMMAND_SOURCE);
} else {
HSBType hsbValue = HSBType.fromRGB(r, g, b);
event = ItemEventFactory.createCommandEvent(item.getName(), hsbValue, COMMAND_SOURCE);
}
eventPublisher.post(event);
}
}

View File

@ -1,44 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.action;
import org.openhab.core.events.EventPublisher;
import org.openhab.core.items.Item;
import org.openhab.core.items.events.ItemCommandEvent;
import org.openhab.core.items.events.ItemEventFactory;
import org.openhab.core.library.types.PercentType;
import org.openhab.io.imperihome.internal.model.device.AbstractDevice;
/**
* Action setting percentage level, e.g. dimmer.
*
* @author Pepijn de Geus - Initial contribution
*/
public class SetLevelAction extends Action {
public SetLevelAction(EventPublisher eventPublisher) {
super(eventPublisher);
}
@Override
public boolean supports(AbstractDevice device, Item item) {
return item.getAcceptedCommandTypes().contains(PercentType.class);
}
@Override
public void perform(AbstractDevice device, Item item, String value) {
ItemCommandEvent event = ItemEventFactory.createCommandEvent(item.getName(), new PercentType(value),
COMMAND_SOURCE);
eventPublisher.post(event);
}
}

View File

@ -1,64 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.action;
import org.openhab.core.events.EventPublisher;
import org.openhab.core.items.Item;
import org.openhab.core.items.events.ItemCommandEvent;
import org.openhab.core.items.events.ItemEventFactory;
import org.openhab.core.library.types.StringType;
import org.openhab.io.imperihome.internal.model.device.AbstractDevice;
import org.openhab.io.imperihome.internal.model.device.DeviceType;
import org.openhab.io.imperihome.internal.processor.DeviceRegistry;
import org.openhab.io.imperihome.internal.processor.ItemProcessor;
/**
* Action setting a thermostat mode.
*
* @author Pepijn de Geus - Initial contribution
*/
public class SetModeAction extends Action {
private final DeviceRegistry deviceRegistry;
public SetModeAction(EventPublisher eventPublisher, DeviceRegistry deviceRegistry) {
super(eventPublisher);
this.deviceRegistry = deviceRegistry;
}
@Override
public boolean supports(AbstractDevice device, Item item) {
if (device.getType() != DeviceType.THERMOSTAT) {
return false;
}
String curmode = device.getLinks().get("curmode");
return curmode != null && !curmode.isBlank();
}
@Override
public void perform(AbstractDevice device, Item item, String value) {
String modeDeviceName = device.getLinks().get("curmode");
AbstractDevice modeDevice = deviceRegistry.getDevice(ItemProcessor.getDeviceId(modeDeviceName));
if (modeDevice == null) {
logger.error("Couldn't resolve linked CurMode device '{}', make sure the Item has iss tags",
modeDeviceName);
return;
}
Item modeItem = modeDevice.getItem();
ItemCommandEvent event = ItemEventFactory.createCommandEvent(modeItem.getName(), new StringType(value),
COMMAND_SOURCE);
eventPublisher.post(event);
}
}

View File

@ -1,64 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.action;
import java.util.List;
import org.openhab.core.events.EventPublisher;
import org.openhab.core.items.Item;
import org.openhab.core.items.events.ItemCommandEvent;
import org.openhab.core.items.events.ItemEventFactory;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.types.Command;
import org.openhab.io.imperihome.internal.model.device.AbstractDevice;
import org.openhab.io.imperihome.internal.model.device.DeviceType;
/**
* Action setting a thermostat setpoint.
*
* @author Pepijn de Geus - Initial contribution
*/
public class SetSetPointAction extends Action {
public SetSetPointAction(EventPublisher eventPublisher) {
super(eventPublisher);
}
@Override
public boolean supports(AbstractDevice device, Item item) {
if (device.getType() != DeviceType.THERMOSTAT) {
return false;
}
List<Class<? extends Command>> acceptedCommandTypes = item.getAcceptedCommandTypes();
return acceptedCommandTypes.contains(DecimalType.class) || acceptedCommandTypes.contains(StringType.class);
}
@Override
public void perform(AbstractDevice device, Item item, String value) {
List<Class<? extends Command>> acceptedCommandTypes = item.getAcceptedCommandTypes();
Command command;
if (acceptedCommandTypes.contains(DecimalType.class)) {
command = new DecimalType(value);
} else if (acceptedCommandTypes.contains(StringType.class)) {
command = new StringType(value);
} else {
logger.error("Item {} doesn't support Decimal or String type", item);
return;
}
ItemCommandEvent event = ItemEventFactory.createCommandEvent(item.getName(), command, COMMAND_SOURCE);
eventPublisher.post(event);
}
}

View File

@ -1,50 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.action;
import java.util.Objects;
import org.openhab.core.events.EventPublisher;
import org.openhab.core.items.Item;
import org.openhab.core.items.events.ItemCommandEvent;
import org.openhab.core.items.events.ItemEventFactory;
import org.openhab.core.library.types.OnOffType;
import org.openhab.io.imperihome.internal.model.device.AbstractDevice;
/**
* Action setting device status to 1 or 0.
*
* @author Pepijn de Geus - Initial contribution
*/
public class SetStatusAction extends Action {
public SetStatusAction(EventPublisher eventPublisher) {
super(eventPublisher);
}
@Override
public boolean supports(AbstractDevice device, Item item) {
return item.getAcceptedCommandTypes().contains(OnOffType.class);
}
@Override
public void perform(AbstractDevice device, Item item, String value) {
OnOffType cmdValue = OnOffType.OFF;
if (Objects.equals("1", value)) {
cmdValue = OnOffType.ON;
}
ItemCommandEvent event = ItemEventFactory.createCommandEvent(item.getName(), cmdValue, COMMAND_SOURCE);
eventPublisher.post(event);
}
}

View File

@ -1,60 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.action;
import org.openhab.core.events.EventPublisher;
import org.openhab.core.items.Item;
import org.openhab.core.items.events.ItemCommandEvent;
import org.openhab.core.items.events.ItemEventFactory;
import org.openhab.core.library.types.OnOffType;
import org.openhab.io.imperihome.internal.model.device.AbstractDevice;
import org.openhab.io.imperihome.internal.model.device.DeviceType;
import org.openhab.io.imperihome.internal.processor.DeviceRegistry;
import org.openhab.io.imperihome.internal.processor.ItemProcessor;
/**
* Action to stop a shutter. Actually just sends an ON command to a linked switch device, to be handled by rules.
*
* @author Pepijn de Geus - Initial contribution
*/
public class StopShutterAction extends Action {
private final DeviceRegistry deviceRegistry;
public StopShutterAction(EventPublisher eventPublisher, DeviceRegistry deviceRegistry) {
super(eventPublisher);
this.deviceRegistry = deviceRegistry;
}
@Override
public boolean supports(AbstractDevice device, Item item) {
String stopper = device.getLinks().get("stopper");
return device.getType() == DeviceType.SHUTTER && stopper != null && !stopper.isBlank();
}
@Override
public void perform(AbstractDevice device, Item item, String value) {
String modeDeviceName = device.getLinks().get("stopper");
AbstractDevice modeDevice = deviceRegistry.getDevice(ItemProcessor.getDeviceId(modeDeviceName));
if (modeDevice == null) {
logger.error("Couldn't resolve linked Stopper device '{}', make sure the Item has iss tags",
modeDeviceName);
return;
}
Item modeItem = modeDevice.getItem();
ItemCommandEvent event = ItemEventFactory.createCommandEvent(modeItem.getName(), OnOffType.ON, COMMAND_SOURCE);
eventPublisher.post(event);
}
}

View File

@ -1,61 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.handler;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.regex.Matcher;
import javax.servlet.http.HttpServletRequest;
import org.openhab.io.imperihome.internal.model.device.AbstractDevice;
import org.openhab.io.imperihome.internal.processor.DeviceRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Device action request handler.
*
* @author Pepijn de Geus - Initial contribution
*/
public class DeviceActionHandler {
private final Logger logger = LoggerFactory.getLogger(DeviceActionHandler.class);
private final DeviceRegistry deviceRegistry;
public DeviceActionHandler(DeviceRegistry deviceRegistry) {
this.deviceRegistry = deviceRegistry;
}
public void handle(HttpServletRequest req, Matcher urlMatcher) {
String deviceId, action, value;
deviceId = URLDecoder.decode(urlMatcher.group(1), StandardCharsets.UTF_8);
action = URLDecoder.decode(urlMatcher.group(2), StandardCharsets.UTF_8);
if (urlMatcher.group(3) == null) {
value = null;
} else {
value = URLDecoder.decode(urlMatcher.group(3), StandardCharsets.UTF_8);
}
logger.debug("Action request for device {}: [{}] [{}]", deviceId, action, value);
AbstractDevice device = deviceRegistry.getDevice(deviceId);
if (device == null) {
logger.warn("Received action request for unknown device: {}", urlMatcher.group(0));
} else {
device.performAction(action, value);
}
}
}

View File

@ -1,123 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.handler;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import javax.servlet.http.HttpServletRequest;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.persistence.FilterCriteria;
import org.openhab.core.persistence.HistoricItem;
import org.openhab.core.persistence.PersistenceService;
import org.openhab.core.persistence.PersistenceServiceRegistry;
import org.openhab.core.persistence.QueryablePersistenceService;
import org.openhab.core.types.State;
import org.openhab.io.imperihome.internal.model.HistoryItem;
import org.openhab.io.imperihome.internal.model.HistoryList;
import org.openhab.io.imperihome.internal.model.device.AbstractDevice;
import org.openhab.io.imperihome.internal.processor.DeviceRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Device history request handler.
*
* @author Pepijn de Geus - Initial contribution
*/
public class DeviceHistoryHandler {
private final Logger logger = LoggerFactory.getLogger(DeviceHistoryHandler.class);
private final DeviceRegistry deviceRegistry;
private final PersistenceServiceRegistry persistenceServiceRegistry;
public DeviceHistoryHandler(DeviceRegistry deviceRegistry, PersistenceServiceRegistry persistenceServiceRegistry) {
this.deviceRegistry = deviceRegistry;
this.persistenceServiceRegistry = persistenceServiceRegistry;
}
public HistoryList handle(HttpServletRequest req, Matcher urlMatcher) {
String deviceId, field;
long start, end;
try {
deviceId = URLDecoder.decode(urlMatcher.group(1), StandardCharsets.UTF_8);
field = URLDecoder.decode(urlMatcher.group(2), StandardCharsets.UTF_8);
start = Long.parseLong(urlMatcher.group(3));
end = Long.parseLong(urlMatcher.group(4));
} catch (NumberFormatException e) {
throw new RuntimeException("Could not decode request params", e);
}
logger.debug("History request for device {}, field {}: {}-{}", deviceId, field, start, end);
AbstractDevice device = deviceRegistry.getDevice(deviceId);
if (device == null) {
logger.warn("Received history request for unknown device: {}", urlMatcher.group(0));
return null;
}
PersistenceService persistence = persistenceServiceRegistry.getDefault();
if (persistence == null) {
logger.warn("Could not retrieve default persistence service; can't serve history request");
return null;
}
if (!(persistence instanceof QueryablePersistenceService)) {
logger.warn("Default persistence service is not queryable; can't serve history request");
return null;
}
return serveHistory(device, (QueryablePersistenceService) persistence, start, end);
}
private HistoryList serveHistory(AbstractDevice device, QueryablePersistenceService persistence, long start,
long end) {
logger.info("Querying persistence for history of Item {}, from {} to {}", device.getItemName(), start, end);
FilterCriteria criteria = new FilterCriteria().setItemName(device.getItemName())
.setBeginDate(ZonedDateTime.ofInstant(Instant.ofEpochMilli(start), ZoneId.systemDefault()))
.setEndDate(ZonedDateTime.ofInstant(Instant.ofEpochMilli(end), ZoneId.systemDefault()));
List<HistoryItem> resultItems = new LinkedList<>();
Iterable<HistoricItem> historicItems = persistence.query(criteria);
Iterator<HistoricItem> iterator = historicItems.iterator();
if (!iterator.hasNext()) {
logger.info("Persistence returned no results for history query");
} else {
while (iterator.hasNext()) {
HistoricItem historicItem = iterator.next();
State state = historicItem.getState();
if (state instanceof DecimalType) {
Number value = ((DecimalType) state).toBigDecimal();
resultItems.add(new HistoryItem(historicItem.getTimestamp().toInstant().toEpochMilli(), value));
}
}
if (resultItems.isEmpty()) {
logger.warn(
"Persistence returned results for history query, but could not be interpreted as DecimalTypes");
}
}
return new HistoryList(resultItems);
}
}

View File

@ -1,53 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.handler;
import java.util.Collection;
import javax.servlet.http.HttpServletRequest;
import org.openhab.io.imperihome.internal.model.device.AbstractDevice;
import org.openhab.io.imperihome.internal.model.device.DeviceList;
import org.openhab.io.imperihome.internal.processor.DeviceRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Device list request handler.
*
* @author Pepijn de Geus - Initial contribution
*/
public class DevicesListHandler {
private final Logger logger = LoggerFactory.getLogger(DevicesListHandler.class);
private final DeviceRegistry deviceRegistry;
public DevicesListHandler(DeviceRegistry deviceRegistry) {
this.deviceRegistry = deviceRegistry;
}
public DeviceList handle(HttpServletRequest req) {
DeviceList response = new DeviceList();
Collection<AbstractDevice> devices = deviceRegistry.getDevices().values();
for (AbstractDevice device : devices) {
device.updateParams();
}
response.setDevices(devices);
logger.debug("Device list response: {}", response);
return response;
}
}

View File

@ -1,38 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.handler;
import javax.servlet.http.HttpServletRequest;
import org.openhab.io.imperihome.internal.model.RoomList;
import org.openhab.io.imperihome.internal.processor.DeviceRegistry;
/**
* Rooms list request handler.
*
* @author Pepijn de Geus - Initial contribution
*/
public class RoomListHandler {
private final DeviceRegistry deviceRegistry;
public RoomListHandler(DeviceRegistry deviceRegistry) {
this.deviceRegistry = deviceRegistry;
}
public RoomList handle(HttpServletRequest req) {
RoomList response = new RoomList();
response.setRooms(deviceRegistry.getRooms());
return response;
}
}

View File

@ -1,39 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.handler;
import javax.servlet.http.HttpServletRequest;
import org.openhab.io.imperihome.internal.ImperiHomeConfig;
import org.openhab.io.imperihome.internal.model.System;
/**
* System data request handler.
*
* @author Pepijn de Geus - Initial contribution
*/
public class SystemHandler {
private ImperiHomeConfig config;
public SystemHandler(ImperiHomeConfig imperiHomeConfig) {
config = imperiHomeConfig;
}
public System handle(HttpServletRequest req) {
System system = new System();
system.setId(config.getSystemId());
system.setApiVersion(1);
return system;
}
}

View File

@ -1,41 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.io;
import java.lang.reflect.Type;
import org.openhab.io.imperihome.internal.model.param.DeviceParam;
import org.openhab.io.imperihome.internal.model.param.DeviceParameters;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
/**
* Serializer for {@link DeviceParameters}.
*
* @author Pepijn de Geus - Initial contribution
*/
public class DeviceParametersSerializer implements JsonSerializer<DeviceParameters> {
@Override
public JsonElement serialize(DeviceParameters params, Type type,
JsonSerializationContext jsonSerializationContext) {
JsonArray result = new JsonArray();
for (DeviceParam param : params.values()) {
result.add(jsonSerializationContext.serialize(param));
}
return result;
}
}

View File

@ -1,35 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.io;
import java.lang.reflect.Type;
import org.openhab.io.imperihome.internal.model.device.DeviceType;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
/**
* Serializer for {@link DeviceType}.
*
* @author Pepijn de Geus - Initial contribution
*/
public class DeviceTypeSerializer implements JsonSerializer<DeviceType> {
@Override
public JsonElement serialize(DeviceType deviceType, Type type, JsonSerializationContext jsonSerializationContext) {
return new JsonPrimitive(deviceType.getApiString());
}
}

View File

@ -1,35 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.io;
import java.lang.reflect.Type;
import org.openhab.io.imperihome.internal.model.param.ParamType;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
/**
* Serializer for {@link ParamType}.
*
* @author Pepijn de Geus - Initial contribution
*/
public class ParamTypeSerializer implements JsonSerializer<ParamType> {
@Override
public JsonElement serialize(ParamType paramType, Type type, JsonSerializationContext jsonSerializationContext) {
return new JsonPrimitive(paramType.getApiString());
}
}

View File

@ -1,51 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model;
import java.util.Date;
/**
* History item data object.
*
* @author Pepijn de Geus - Initial contribution
*/
public class HistoryItem {
private long date;
private Number value;
public HistoryItem(Date date, Number value) {
this(date.getTime(), value);
}
public HistoryItem(long date, Number value) {
this.date = date;
this.value = value;
}
public long getDate() {
return date;
}
public void setDate(long date) {
this.date = date;
}
public Number getValue() {
return value;
}
public void setValue(Number value) {
this.value = value;
}
}

View File

@ -1,42 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model;
import java.util.LinkedList;
import java.util.List;
/**
* History list data object.
*
* @author Pepijn de Geus - Initial contribution
*/
public class HistoryList {
private List<HistoryItem> values;
public HistoryList() {
this(new LinkedList<>());
}
public HistoryList(List<HistoryItem> resultItems) {
this.values = resultItems;
}
public List<HistoryItem> getValues() {
return values;
}
public void setValues(List<HistoryItem> values) {
this.values = values;
}
}

View File

@ -1,64 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model;
/**
* Room data object.
*
* @author Pepijn de Geus - Initial contribution
*/
public class Room {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Room)) {
return false;
}
Room room = (Room) o;
return id != null ? id.equals(room.id) : room.id == null;
}
@Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
@Override
public String toString() {
return "Room{" + "id='" + id + '\'' + ", name='" + name + '\'' + '}';
}
}

View File

@ -1,33 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model;
import java.util.Collection;
/**
* Room list data object.
*
* @author Pepijn de Geus - Initial contribution
*/
public class RoomList {
private Collection<Room> rooms;
public Collection<Room> getRooms() {
return rooms;
}
public void setRooms(Collection<Room> rooms) {
this.rooms = rooms;
}
}

View File

@ -1,40 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model;
/**
* System data object.
*
* @author Pepijn de Geus - Initial contribution
*/
public class System {
private String id;
private int apiVersion;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getApiVersion() {
return apiVersion;
}
public void setApiVersion(int apiVersion) {
this.apiVersion = apiVersion;
}
}

View File

@ -1,246 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.openhab.core.items.GenericItem;
import org.openhab.core.items.Item;
import org.openhab.core.items.StateChangeListener;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.types.State;
import org.openhab.io.imperihome.internal.action.Action;
import org.openhab.io.imperihome.internal.action.ActionRegistry;
import org.openhab.io.imperihome.internal.model.param.DeviceParam;
import org.openhab.io.imperihome.internal.model.param.DeviceParameters;
import org.openhab.io.imperihome.internal.model.param.ParamType;
import org.openhab.io.imperihome.internal.processor.DeviceRegistry;
import org.openhab.io.imperihome.internal.processor.TagType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Abstract parent of all devices. Sets up and tears down state listeners and contains parameter and link data.
*
* @author Pepijn de Geus - Initial contribution
*/
public abstract class AbstractDevice implements StateChangeListener {
protected final transient Logger logger = LoggerFactory.getLogger(getClass());
private String id;
private String name;
private String room;
private DeviceType type;
private String defaultIcon;
private final DeviceParameters params;
private transient boolean inverted;
private transient String roomName;
private transient Item item;
private final transient Map<String, String> links;
private transient Map<String, String> mapping;
private transient DeviceRegistry deviceRegistry;
private transient ActionRegistry actionRegistry;
public AbstractDevice(DeviceType type, Item item) {
this.type = type;
this.item = item;
params = new DeviceParameters();
links = new HashMap<>();
if (item instanceof GenericItem) {
((GenericItem) item).addStateChangeListener(this);
}
}
public void destroy() {
if (item instanceof GenericItem) {
((GenericItem) item).removeStateChangeListener(this);
}
deviceRegistry = null;
actionRegistry = null;
item = null;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRoom() {
return room;
}
public void setRoom(String room) {
this.room = room;
}
public String getRoomName() {
return roomName;
}
public void setRoomName(String roomName) {
this.roomName = roomName;
}
public DeviceType getType() {
return type;
}
public void setType(DeviceType type) {
this.type = type;
}
public boolean isInverted() {
return inverted;
}
public void setInverted(boolean inverted) {
this.inverted = inverted;
}
public String getDefaultIcon() {
return defaultIcon;
}
public void setDefaultIcon(String defaultIcon) {
this.defaultIcon = defaultIcon;
}
public DeviceParameters getParams() {
return params;
}
public void addParam(DeviceParam param) {
logger.trace("Setting param for device {}: {}", this, param);
params.set(param);
}
public Map<String, String> getLinks() {
return links;
}
public void addLink(String linkType, String deviceId) {
links.put(linkType, deviceId);
}
public void setMapping(Map<String, String> mapping) {
this.mapping = mapping;
}
public Map<String, String> getMapping() {
return mapping;
}
public void setDeviceRegistry(DeviceRegistry deviceRegistry) {
this.deviceRegistry = deviceRegistry;
}
protected DeviceRegistry getDeviceRegistry() {
return deviceRegistry;
}
public void setActionRegistry(ActionRegistry actionRegistry) {
this.actionRegistry = actionRegistry;
}
protected ActionRegistry getActionRegistry() {
return actionRegistry;
}
public Item getItem() {
return item;
}
public String getItemName() {
return item.getName();
}
/**
* Process any device-specific ISS tags.
*
* @param issTags ISS tags map.
*/
public void processCustomTags(Map<TagType, List<String>> issTags) {
}
/**
* Can be implemented by Devices that require their state to be updated manually, instead of relying (only) on Item
* state change events.
* This method is called just before serializing the device to JSON.
*/
public void updateParams() {
logger.trace("updateParams on {}", this);
}
/**
* Performs an action on this device.
*
* @param action Action name.
* @param value Action value.
*/
public void performAction(String action, String value) {
Action actionInst = actionRegistry.get(action);
if (actionInst == null) {
logger.warn("Unknown action: {}", action);
return;
}
Item item = getItem();
if (!actionInst.supports(this, item)) {
logger.warn("Action '{}' not supported on this device ({})", action, this);
return;
}
actionInst.perform(this, item, value);
}
@Override
public void stateChanged(Item item, State oldState, State newState) {
}
@Override
public void stateUpdated(Item item, State newState) {
logger.debug("Device item {} state changed to {}", item, newState);
OnOffType onOffState = (OnOffType) item.getStateAs(OnOffType.class);
if (onOffState != null) {
boolean isOn = onOffState == OnOffType.ON;
DeviceParam param = new DeviceParam(ParamType.STATUS, isOn ^ isInverted() ? "1" : "0");
addParam(param);
}
}
@Override
public String toString() {
return getClass().getSimpleName() + "{id='" + id + '\'' + ", name='" + name + '\'' + ", room='" + room + '\''
+ ", type=" + type + ", invert=" + inverted + ", icon=" + defaultIcon + ", links=" + links + '}';
}
}

View File

@ -1,53 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import org.openhab.core.items.Item;
import org.openhab.io.imperihome.internal.model.param.NumericValueParam;
import org.openhab.io.imperihome.internal.model.param.ParamType;
import org.openhab.io.imperihome.internal.processor.ItemProcessor;
/**
* Abstraction of devices that allow a link to a current energy consumption item.
*
* @author Pepijn de Geus - Initial contribution
*/
public abstract class AbstractEnergyLinkDevice extends AbstractDevice {
public AbstractEnergyLinkDevice(DeviceType type, Item item) {
super(type, item);
}
@Override
public void updateParams() {
super.updateParams();
if (getLinks().containsKey("energy")) {
String deviceName = getLinks().get("energy");
String deviceId = ItemProcessor.getDeviceId(deviceName);
AbstractDevice energyDevice = getDeviceRegistry().getDevice(deviceId);
if (energyDevice == null) {
logger.error("Couldn't resolve linked energy device '{}', make sure the Item has iss tags", deviceName);
} else {
NumericValueParam valueParam = (NumericValueParam) energyDevice.getParams().get(ParamType.WATTS);
if (valueParam == null) {
logger.warn("Linked energy device has no Watts value parameter: {}", energyDevice);
} else {
NumericValueParam energyParam = new NumericValueParam(ParamType.ENERGY, valueParam.getUnit(), null);
energyParam.setValue(valueParam.getValue());
addParam(energyParam);
}
}
}
}
}

View File

@ -1,44 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import org.openhab.core.items.Item;
import org.openhab.io.imperihome.internal.model.param.NumericValueParam;
/**
* Parent of devices with a {@link NumericValueParam}. Contains the value unit.
*
* @author Pepijn de Geus - Initial contribution
*/
public abstract class AbstractNumericValueDevice extends AbstractDevice {
private transient String unit;
public AbstractNumericValueDevice(DeviceType type, Item item, String defaultUnit) {
super(type, item);
this.unit = defaultUnit;
}
public String getUnit() {
return unit;
}
public void setUnit(String unit) {
this.unit = unit;
}
@Override
public String toString() {
return getClass().getSimpleName() + "{" + "super=" + super.toString() + ", unit='" + unit + '\'' + '}';
}
}

View File

@ -1,39 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import org.openhab.core.items.Item;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.State;
import org.openhab.io.imperihome.internal.model.param.NumericValueParam;
import org.openhab.io.imperihome.internal.model.param.ParamType;
/**
* CO2 sensor device.
*
* @author Pepijn de Geus - Initial contribution
*/
public class Co2SensorDevice extends AbstractNumericValueDevice {
public Co2SensorDevice(Item item) {
super(DeviceType.CO2, item, "ppm");
}
@Override
public void stateUpdated(Item item, State newState) {
super.stateUpdated(item, newState);
DecimalType value = (DecimalType) item.getStateAs(DecimalType.class);
addParam(new NumericValueParam(ParamType.CO2_VALUE, getUnit(), value));
}
}

View File

@ -1,38 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import java.util.Collection;
/**
* Device list holder.
*
* @author Pepijn de Geus - Initial contribution
*/
public class DeviceList {
private Collection<AbstractDevice> devices;
public Collection<AbstractDevice> getDevices() {
return devices;
}
public void setDevices(Collection<AbstractDevice> devices) {
this.devices = devices;
}
@Override
public String toString() {
return "DeviceList{" + "devices=" + devices + '}';
}
}

View File

@ -1,76 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
/**
* Device type enumeration. Contains ImperiHome API type strings.
*
* @author Pepijn de Geus - Initial contribution
*/
public enum DeviceType {
SWITCH("DevSwitch"),
DIMMER("DevDimmer"),
CAMERA("DevCamera"),
CO2("DevCO2"),
CO2_ALERT("DevCO2Alert"),
DOOR("DevDoor"),
ELECTRICITY("DevElectricity"),
FLOOD("DevFlood"),
GENERIC_SENSOR("DevGenericSensor"),
HYGROMETRY("DevHygrometry"),
LOCK("DevLock"),
LUMINOSITY("DevLuminosity"),
MOTION("DevMotion"),
MULTI_SWITCH("DevMultiSwitch"),
NOISE("DevNoise"),
PLAYER("DevPlayer"),
PLAYLIST("DevPlaylist"),
PRESSURE("DevPressure"),
RAIN("DevRain"),
RGB_LIGHT("DevRGBLight"),
SCENE("DevScene"),
SHUTTER("DevShutter"),
SMOKE("DevSmoke"),
TEMPERATURE("DevTemperature"),
TEMP_HYGRO("DevTempHygro"),
THERMOSTAT("DevThermostat", "curmode", "curtemp"),
UV("DevUV"),
WIND("DevWind");
private final String apiString;
private final String[] requiredLinks;
DeviceType(String apiString, String... requiredLinks) {
this.apiString = apiString;
this.requiredLinks = requiredLinks;
}
public String getApiString() {
return apiString;
}
public String[] getRequiredLinks() {
return requiredLinks;
}
public static DeviceType forApiString(String apiString) {
for (DeviceType deviceType : values()) {
if (deviceType.getApiString().equalsIgnoreCase(apiString.trim())) {
return deviceType;
}
}
return null;
}
}

View File

@ -1,46 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import org.openhab.core.items.Item;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.types.State;
import org.openhab.io.imperihome.internal.model.param.DeviceParam;
import org.openhab.io.imperihome.internal.model.param.ParamType;
/**
* Dimmer device, containing on/off status and dim level.
*
* @author Pepijn de Geus - Initial contribution
*/
public class DimmerDevice extends AbstractEnergyLinkDevice {
public DimmerDevice(Item item) {
super(DeviceType.DIMMER, item);
}
@Override
public void stateUpdated(Item item, State newState) {
super.stateUpdated(item, newState);
int level = 0;
PercentType percentState = (PercentType) item.getStateAs(PercentType.class);
if (percentState != null) {
level = percentState.intValue();
}
addParam(new DeviceParam(ParamType.LEVEL, String.valueOf(level)));
addParam(new DeviceParam(ParamType.STATUS, (level > 0) ^ isInverted() ? "1" : "0"));
}
}

View File

@ -1,118 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import org.openhab.core.items.Item;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.State;
import org.openhab.io.imperihome.internal.model.param.NumericValueParam;
import org.openhab.io.imperihome.internal.model.param.ParamType;
import org.openhab.io.imperihome.internal.processor.ItemProcessor;
/**
* Electricity device, containing current (Watt) and total (KWh) consumption.
*
* @author Pepijn de Geus - Initial contribution
*/
public class ElectricityDevice extends AbstractNumericValueDevice {
private static final String LINK_WATTS = "watt";
private static final String LINK_KWH = "kwh";
public ElectricityDevice(Item item) {
super(DeviceType.ELECTRICITY, item, "W");
}
@Override
public void addLink(String linkType, String deviceId) {
super.addLink(linkType, deviceId);
if (getLinks().containsKey(LINK_WATTS)) {
setUnit("KWh");
} else if (getLinks().containsKey(LINK_KWH)) {
setUnit("W");
}
}
@Override
public void stateUpdated(Item item, State newState) {
super.stateUpdated(item, newState);
DecimalType value = item.getStateAs(DecimalType.class);
if (getLinks().containsKey(LINK_WATTS) || getUnit().equalsIgnoreCase(LINK_KWH)) {
addParam(new NumericValueParam(ParamType.KWH, getUnit(), value));
} else if (getLinks().isEmpty() || getLinks().containsKey(LINK_KWH)) {
addParam(new NumericValueParam(ParamType.WATTS, getUnit(), value));
}
}
@Override
public void updateParams() {
super.updateParams();
if (getLinks().containsKey(LINK_WATTS)) {
String deviceName = getLinks().get(LINK_WATTS);
String deviceId = ItemProcessor.getDeviceId(deviceName);
AbstractDevice wattsDevice = getDeviceRegistry().getDevice(deviceId);
if (wattsDevice == null) {
logger.error("Couldn't resolve linked watts device '{}', make sure the Item has iss tags", deviceName);
} else {
setWattsParam(wattsDevice);
}
}
if (getLinks().containsKey(LINK_KWH)) {
String deviceName = getLinks().get(LINK_KWH);
String deviceId = ItemProcessor.getDeviceId(deviceName);
AbstractDevice kwhDevice = getDeviceRegistry().getDevice(deviceId);
if (kwhDevice == null) {
logger.error("Couldn't resolve linked KWh device '{}', make sure the Item has iss tags", deviceName);
} else {
setKwhParam(kwhDevice);
}
}
}
private void setWattsParam(AbstractDevice device) {
NumericValueParam valueParam = (NumericValueParam) device.getParams().get(ParamType.WATTS);
if (valueParam == null) {
logger.warn("Linked Watts device has no Watt value parameter: {}", device);
return;
}
NumericValueParam wattsParam = new NumericValueParam(ParamType.WATTS, valueParam.getUnit(), null);
String unit = wattsParam.getUnit();
if (unit == null || unit.isEmpty()) {
wattsParam.setUnit("W");
}
wattsParam.setValue(valueParam.getValue());
addParam(wattsParam);
}
private void setKwhParam(AbstractDevice device) {
NumericValueParam valueParam = (NumericValueParam) device.getParams().get(ParamType.KWH);
if (valueParam == null) {
logger.warn("Linked KWh device has no KWh value parameter: {}", device);
return;
}
NumericValueParam kwhParam = new NumericValueParam(ParamType.KWH, valueParam.getUnit(), null);
String unit = kwhParam.getUnit();
if (unit == null || unit.isEmpty()) {
kwhParam.setUnit("KWh");
}
kwhParam.setValue(valueParam.getValue());
addParam(kwhParam);
}
}

View File

@ -1,46 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import org.openhab.core.items.Item;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.State;
import org.openhab.io.imperihome.internal.model.param.DeviceParam;
import org.openhab.io.imperihome.internal.model.param.NumericValueParam;
import org.openhab.io.imperihome.internal.model.param.ParamType;
/**
* Generic sensor device.
*
* @author Pepijn de Geus - Initial contribution
*/
public class GenericSensorDevice extends AbstractNumericValueDevice {
public GenericSensorDevice(Item item) {
super(DeviceType.GENERIC_SENSOR, item, null);
}
@Override
public void stateUpdated(Item item, State newState) {
super.stateUpdated(item, newState);
DecimalType value = (DecimalType) item.getStateAs(DecimalType.class);
if (value != null) {
addParam(new NumericValueParam(ParamType.GENERIC_VALUE, getUnit(), value));
} else {
State state = item.getState();
String strVal = (state == null) ? null : state.toFullString();
addParam(new DeviceParam(ParamType.GENERIC_VALUE, strVal));
}
}
}

View File

@ -1,39 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import org.openhab.core.items.Item;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.State;
import org.openhab.io.imperihome.internal.model.param.NumericValueParam;
import org.openhab.io.imperihome.internal.model.param.ParamType;
/**
* Hygrometry sensor device.
*
* @author Pepijn de Geus - Initial contribution
*/
public class HygrometryDevice extends AbstractNumericValueDevice {
public HygrometryDevice(Item item) {
super(DeviceType.HYGROMETRY, item, "%");
}
@Override
public void stateUpdated(Item item, State newState) {
super.stateUpdated(item, newState);
DecimalType value = (DecimalType) item.getStateAs(DecimalType.class);
addParam(new NumericValueParam(ParamType.HYGROMETRY_VALUE, getUnit(), value));
}
}

View File

@ -1,45 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import org.openhab.core.items.Item;
import org.openhab.core.library.types.OpenClosedType;
import org.openhab.core.types.State;
import org.openhab.io.imperihome.internal.model.param.DeviceParam;
import org.openhab.io.imperihome.internal.model.param.ParamType;
/**
* Lock device.
*
* @author Pepijn de Geus - Initial contribution
*/
public class LockDevice extends AbstractDevice {
public LockDevice(Item item) {
super(DeviceType.LOCK, item);
}
@Override
public void stateUpdated(Item item, State newState) {
super.stateUpdated(item, newState);
if (getParams().get(ParamType.STATUS) == null) {
OpenClosedType openClosedState = (OpenClosedType) item.getStateAs(OpenClosedType.class);
if (openClosedState != null) {
boolean value = openClosedState == OpenClosedType.OPEN;
DeviceParam param = new DeviceParam(ParamType.STATUS, value ^ isInverted() ? "1" : "0");
addParam(param);
}
}
}
}

View File

@ -1,39 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import org.openhab.core.items.Item;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.State;
import org.openhab.io.imperihome.internal.model.param.NumericValueParam;
import org.openhab.io.imperihome.internal.model.param.ParamType;
/**
* Luminosity sensor device.
*
* @author Pepijn de Geus - Initial contribution
*/
public class LuminosityDevice extends AbstractNumericValueDevice {
public LuminosityDevice(Item item) {
super(DeviceType.LUMINOSITY, item, "lux");
}
@Override
public void stateUpdated(Item item, State newState) {
super.stateUpdated(item, newState);
DecimalType value = (DecimalType) item.getStateAs(DecimalType.class);
addParam(new NumericValueParam(ParamType.LUMINOSITY_VALUE, getUnit(), value));
}
}

View File

@ -1,70 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import java.util.Map;
import java.util.stream.Collectors;
import org.openhab.core.items.Item;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.State;
import org.openhab.io.imperihome.internal.model.param.DeviceParam;
import org.openhab.io.imperihome.internal.model.param.ParamType;
/**
* MultiSwitch device, mimics behavior of an OH Switch with a mapping.
*
* @author Pepijn de Geus - Initial contribution
*/
public class MultiSwitchDevice extends AbstractDevice {
private String itemValue = "";
public MultiSwitchDevice(Item item) {
super(DeviceType.MULTI_SWITCH, item);
}
@Override
public void updateParams() {
super.updateParams();
Map<String, String> mapping = getMapping();
if (mapping == null || mapping.isEmpty()) {
logger.error("MultiSwitch device {} contains no mapping", this);
return;
}
DeviceParam choicesParam = new DeviceParam(ParamType.CHOICES,
mapping.values().stream().collect(Collectors.joining(",")));
addParam(choicesParam);
// Find current value text
String currentValue = "";
if (mapping.containsKey(itemValue)) {
currentValue = mapping.get(itemValue);
}
DeviceParam valueParam = new DeviceParam(ParamType.MULTISWITCH_VALUE, currentValue);
addParam(valueParam);
}
@Override
public void stateUpdated(Item item, State newState) {
super.stateUpdated(item, newState);
State state = item.getStateAs(DecimalType.class);
if (state instanceof DecimalType) {
itemValue = String.valueOf(((DecimalType) state).intValue());
}
}
}

View File

@ -1,39 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import org.openhab.core.items.Item;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.State;
import org.openhab.io.imperihome.internal.model.param.NumericValueParam;
import org.openhab.io.imperihome.internal.model.param.ParamType;
/**
* Noise sensor device.
*
* @author Pepijn de Geus - Initial contribution
*/
public class NoiseDevice extends AbstractNumericValueDevice {
public NoiseDevice(Item item) {
super(DeviceType.NOISE, item, "dB");
}
@Override
public void stateUpdated(Item item, State newState) {
super.stateUpdated(item, newState);
DecimalType value = (DecimalType) item.getStateAs(DecimalType.class);
addParam(new NumericValueParam(ParamType.NOISE_VALUE, getUnit(), value));
}
}

View File

@ -1,39 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import org.openhab.core.items.Item;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.State;
import org.openhab.io.imperihome.internal.model.param.NumericValueParam;
import org.openhab.io.imperihome.internal.model.param.ParamType;
/**
* Pressure sensor device.
*
* @author Pepijn de Geus - Initial contribution
*/
public class PressureDevice extends AbstractNumericValueDevice {
public PressureDevice(Item item) {
super(DeviceType.PRESSURE, item, "mbar");
}
@Override
public void stateUpdated(Item item, State newState) {
super.stateUpdated(item, newState);
DecimalType value = (DecimalType) item.getStateAs(DecimalType.class);
addParam(new NumericValueParam(ParamType.PRESSURE_VALUE, getUnit(), value));
}
}

View File

@ -1,73 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import org.openhab.core.items.Item;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.State;
import org.openhab.io.imperihome.internal.model.param.NumericValueParam;
import org.openhab.io.imperihome.internal.model.param.ParamType;
import org.openhab.io.imperihome.internal.processor.ItemProcessor;
/**
* Rain sensor device.
*
* @author Pepijn de Geus - Initial contribution
*/
public class RainDevice extends AbstractNumericValueDevice {
private static final String LINK_ACCUMULATION = "accum";
public RainDevice(Item item) {
super(DeviceType.RAIN, item, "mm/h");
}
@Override
public void updateParams() {
super.updateParams();
if (getLinks().containsKey(LINK_ACCUMULATION)) {
String deviceName = getLinks().get(LINK_ACCUMULATION);
String deviceId = ItemProcessor.getDeviceId(deviceName);
AbstractDevice accumDevice = getDeviceRegistry().getDevice(deviceId);
if (accumDevice == null) {
logger.error("Couldn't resolve linked accumulation device '{}', make sure the Item has iss tags",
deviceName);
return;
}
NumericValueParam valueParam = (NumericValueParam) accumDevice.getParams().get(ParamType.GENERIC_VALUE);
if (valueParam == null) {
logger.warn("Linked Accumulation device has no Value parameter: {}", accumDevice);
return;
}
NumericValueParam accumParam = new NumericValueParam(ParamType.ACCUMULATION, valueParam.getUnit(), null);
String unit = accumParam.getUnit();
if (unit == null || unit.isBlank()) {
accumParam.setUnit("mm");
}
accumParam.setValue(valueParam.getValue());
addParam(accumParam);
}
}
@Override
public void stateUpdated(Item item, State newState) {
super.stateUpdated(item, newState);
DecimalType value = item.getStateAs(DecimalType.class);
addParam(new NumericValueParam(ParamType.RAIN_VALUE, getUnit(), value));
}
}

View File

@ -1,90 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import java.math.BigDecimal;
import java.math.RoundingMode;
import org.openhab.core.items.Item;
import org.openhab.core.library.types.HSBType;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.types.State;
import org.openhab.io.imperihome.internal.model.param.DeviceParam;
import org.openhab.io.imperihome.internal.model.param.ParamType;
import org.openhab.io.imperihome.internal.util.StringUtils;
/**
* RGB light device.
*
* @author Pepijn de Geus - Initial contribution
*/
public class RgbLightDevice extends AbstractEnergyLinkDevice {
public RgbLightDevice(Item item) {
super(DeviceType.RGB_LIGHT, item);
}
@Override
public void stateUpdated(Item item, State newState) {
super.stateUpdated(item, newState);
boolean status = false;
int level = 0;
String color = "00000000";
State state = item.getStateAs(HSBType.class);
boolean isHsbState = state instanceof HSBType;
// State can be of UndefType, even with the getStateAs above
if (isHsbState) {
HSBType hsbState = (HSBType) state;
PercentType[] rgb = hsbState.toRGB();
// Set state to ON if any channel > 0
boolean isOn = rgb[0].doubleValue() > 0 || rgb[1].doubleValue() > 0 || rgb[2].doubleValue() > 0;
if (isOn) {
status = true;
}
// Build hex string
int r = convertPercentToByte(rgb[0]) & 0xFF;
int g = convertPercentToByte(rgb[1]) & 0xFF;
int b = convertPercentToByte(rgb[2]) & 0xFF;
color = (isOn ? "FF" : "00") + toHex(r) + toHex(g) + toHex(b);
}
State pState = item.getStateAs(PercentType.class);
if (pState instanceof PercentType) {
level = ((PercentType) pState).intValue();
if (level > 0) {
status = true;
}
}
addParam(new DeviceParam(ParamType.STATUS, status ^ isInverted() ? "1" : "0"));
addParam(new DeviceParam(ParamType.LEVEL, String.valueOf(level)));
addParam(new DeviceParam(ParamType.DIMMABLE, "0"));
addParam(new DeviceParam(ParamType.WHITE_CHANNEL, "1"));
addParam(new DeviceParam(ParamType.COLOR, color));
}
private String toHex(int value) {
String hex = Integer.toHexString(value);
return StringUtils.padLeft(hex, 2, "0");
}
private int convertPercentToByte(PercentType percent) {
return percent.toBigDecimal().multiply(BigDecimal.valueOf(255))
.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP).intValue();
}
}

View File

@ -1,27 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import org.openhab.core.items.Item;
/**
* Scene activation device.
*
* @author Pepijn de Geus - Initial contribution
*/
public class SceneDevice extends AbstractDevice {
public SceneDevice(Item item) {
super(DeviceType.SCENE, item);
}
}

View File

@ -1,47 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import org.openhab.core.items.Item;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.types.State;
import org.openhab.io.imperihome.internal.model.param.DeviceParam;
import org.openhab.io.imperihome.internal.model.param.ParamType;
/**
* Shutter device, containing level. Stoppable and pulseable attributes currently hardcoded to 0 (false).
*
* @author Pepijn de Geus - Initial contribution
*/
public class ShutterDevice extends AbstractEnergyLinkDevice {
public ShutterDevice(Item item) {
super(DeviceType.SHUTTER, item);
}
@Override
public void stateUpdated(Item item, State newState) {
super.stateUpdated(item, newState);
int level = 0;
PercentType percentState = (PercentType) item.getStateAs(PercentType.class);
if (percentState != null) {
level = percentState.intValue();
}
addParam(new DeviceParam(ParamType.PULSEABLE, "0"));
addParam(new DeviceParam(ParamType.STOPPABLE, getLinks().containsKey("stopper") ? "1" : "0"));
addParam(new DeviceParam(ParamType.LEVEL, String.valueOf(level)));
}
}

View File

@ -1,45 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import org.openhab.core.items.Item;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.types.State;
import org.openhab.io.imperihome.internal.model.param.DeviceParam;
import org.openhab.io.imperihome.internal.model.param.ParamType;
/**
* Simple on/off switch device.
*
* @author Pepijn de Geus - Initial contribution
*/
public class SwitchDevice extends AbstractEnergyLinkDevice {
public SwitchDevice(Item item) {
super(DeviceType.SWITCH, item);
}
@Override
public void stateUpdated(Item item, State newState) {
super.stateUpdated(item, newState);
if (getParams().get(ParamType.STATUS) == null) {
PercentType percentState = (PercentType) item.getStateAs(PercentType.class);
if (percentState != null) {
boolean value = percentState.intValue() > 0;
DeviceParam param = new DeviceParam(ParamType.STATUS, value ^ isInverted() ? "1" : "0");
addParam(param);
}
}
}
}

View File

@ -1,121 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import org.openhab.core.items.Item;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.State;
import org.openhab.io.imperihome.internal.model.param.NumericValueParam;
import org.openhab.io.imperihome.internal.model.param.ParamType;
import org.openhab.io.imperihome.internal.processor.ItemProcessor;
/**
* Combined temperature/hygro sensor device. Can be specified on either a temp or hygro Item, with a link to the other
* one.
* The linked value will be retrieved in {@link #updateParams()}.
*
* @author Pepijn de Geus - Initial contribution
*/
public class TempHygroDevice extends AbstractNumericValueDevice {
private static final String LINK_HYGRO = "hygro";
private static final String LINK_TEMP = "temp";
public TempHygroDevice(Item item) {
super(DeviceType.TEMP_HYGRO, item, null);
}
@Override
public void addLink(String linkType, String deviceId) {
super.addLink(linkType, deviceId);
if (getLinks().containsKey(LINK_HYGRO)) {
setUnit("°C");
} else if (getLinks().containsKey(LINK_TEMP)) {
setUnit("%");
}
}
@Override
public void stateUpdated(Item item, State newState) {
super.stateUpdated(item, newState);
DecimalType value = (DecimalType) item.getStateAs(DecimalType.class);
if (getLinks().containsKey(LINK_HYGRO)) {
addParam(new NumericValueParam(ParamType.TEMPERATURE_DUAL, getUnit(), value));
} else if (getLinks().containsKey(LINK_TEMP)) {
addParam(new NumericValueParam(ParamType.HYGROMETRY_DUAL, getUnit(), value));
}
}
@Override
public void updateParams() {
super.updateParams();
boolean foundLink = false;
if (getLinks().containsKey(LINK_HYGRO)) {
String deviceName = getLinks().get(LINK_HYGRO);
String deviceId = ItemProcessor.getDeviceId(deviceName);
AbstractDevice hygroDevice = getDeviceRegistry().getDevice(deviceId);
if (hygroDevice == null) {
logger.error("Couldn't resolve linked hygro device '{}', make sure the Item has iss tags", deviceName);
} else {
setHygroParam(hygroDevice);
foundLink = true;
}
}
if (getLinks().containsKey(LINK_TEMP)) {
String deviceName = getLinks().get(LINK_TEMP);
String deviceId = ItemProcessor.getDeviceId(deviceName);
AbstractDevice tempDevice = getDeviceRegistry().getDevice(deviceId);
if (tempDevice == null) {
logger.error("Couldn't resolve linked temp device '{}', make sure the Item has iss tags", deviceName);
} else {
setTempParam(tempDevice);
foundLink = true;
}
}
if (!foundLink) {
logger.warn(
"DevTempHygro device contains no valid 'hygro' or 'temp' link. Add a link to another item using 'iss:link:<type>:<item>'");
}
}
private void setHygroParam(AbstractDevice device) {
NumericValueParam valueParam = (NumericValueParam) device.getParams().get(ParamType.HYGROMETRY_VALUE);
if (valueParam == null) {
logger.warn("Linked Hygro device has no Value parameter: {}", device);
return;
}
NumericValueParam hygroParam = new NumericValueParam(ParamType.HYGROMETRY_DUAL, valueParam.getUnit(), null);
hygroParam.setValue(valueParam.getValue());
addParam(hygroParam);
}
private void setTempParam(AbstractDevice device) {
NumericValueParam valueParam = (NumericValueParam) device.getParams().get(ParamType.TEMPERATURE_VALUE);
if (valueParam == null) {
logger.warn("Linked Temperature device has no Value parameter: {}", device);
return;
}
NumericValueParam tempParam = new NumericValueParam(ParamType.TEMPERATURE_DUAL, valueParam.getUnit(), null);
tempParam.setValue(valueParam.getValue());
addParam(tempParam);
}
}

View File

@ -1,39 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import org.openhab.core.items.Item;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.State;
import org.openhab.io.imperihome.internal.model.param.NumericValueParam;
import org.openhab.io.imperihome.internal.model.param.ParamType;
/**
* Temperature sensor device.
*
* @author Pepijn de Geus - Initial contribution
*/
public class TemperatureDevice extends AbstractNumericValueDevice {
public TemperatureDevice(Item item) {
super(DeviceType.TEMPERATURE, item, "°C");
}
@Override
public void stateUpdated(Item item, State newState) {
super.stateUpdated(item, newState);
DecimalType value = (DecimalType) item.getStateAs(DecimalType.class);
addParam(new NumericValueParam(ParamType.TEMPERATURE_VALUE, getUnit(), value));
}
}

View File

@ -1,126 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import java.util.List;
import java.util.Map;
import org.openhab.core.items.Item;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.State;
import org.openhab.io.imperihome.internal.model.param.DeviceParam;
import org.openhab.io.imperihome.internal.model.param.NumericValueParam;
import org.openhab.io.imperihome.internal.model.param.ParamType;
import org.openhab.io.imperihome.internal.processor.ItemProcessor;
import org.openhab.io.imperihome.internal.processor.TagType;
/**
* Thermostat device.
*
* @author Pepijn de Geus - Initial contribution
*/
public class ThermostatDevice extends AbstractDevice {
public ThermostatDevice(Item item) {
super(DeviceType.THERMOSTAT, item);
}
@Override
public void processCustomTags(Map<TagType, List<String>> issTags) {
if (issTags.containsKey(TagType.STEP)) {
setStep(issTags.get(TagType.STEP).get(0));
}
if (issTags.containsKey(TagType.MIN_VAL)) {
setMinValue(issTags.get(TagType.MIN_VAL).get(0));
}
if (issTags.containsKey(TagType.MAX_VAL)) {
setMaxValue(issTags.get(TagType.MAX_VAL).get(0));
}
if (issTags.containsKey(TagType.MODES)) {
setAvailableModes(issTags.get(TagType.MODES).get(0));
}
}
@Override
public void stateUpdated(Item item, State newState) {
DecimalType state = (DecimalType) item.getStateAs(DecimalType.class);
if (state != null) {
DeviceParam param = new DeviceParam(ParamType.CUR_SETPOINT, state.floatValue());
addParam(param);
}
}
@Override
public void updateParams() {
AbstractDevice curModeDevice = getLinkedDevice("curmode", true);
if (curModeDevice != null) {
setCurModeParam(curModeDevice);
}
AbstractDevice curTempDevice = getLinkedDevice("curtemp", true);
if (curTempDevice != null) {
setCurTempParam(curTempDevice);
}
}
public void setStep(String step) {
addParam(new DeviceParam(ParamType.STEP, step));
}
public void setMinValue(String minValue) {
addParam(new DeviceParam(ParamType.MIN_VAL, minValue));
}
public void setMaxValue(String maxValue) {
addParam(new DeviceParam(ParamType.MAX_VAL, maxValue));
}
public void setAvailableModes(String modes) {
addParam(new DeviceParam(ParamType.AVAIL_MODE, modes));
}
private void setCurModeParam(AbstractDevice device) {
DeviceParam valueParam = device.getParams().get(ParamType.GENERIC_VALUE);
if (valueParam == null) {
logger.warn("Linked curmode device has no Value parameter: {}", device);
return;
}
addParam(new DeviceParam(ParamType.CUR_MODE, valueParam.getValue()));
}
private void setCurTempParam(AbstractDevice device) {
NumericValueParam valueParam = (NumericValueParam) device.getParams().get(ParamType.TEMPERATURE_VALUE);
if (valueParam == null) {
logger.warn("Linked curtemp device has no Value parameter: {}", device);
return;
}
NumericValueParam tempParam = new NumericValueParam(ParamType.CUR_TEMP, valueParam.getUnit(), null);
tempParam.setValue(valueParam.getValue());
addParam(tempParam);
}
private AbstractDevice getLinkedDevice(String linkName, boolean logWhenMissing) {
String deviceName = getLinks().get(linkName);
AbstractDevice device = null;
if (deviceName != null) {
String deviceId = ItemProcessor.getDeviceId(deviceName);
device = getDeviceRegistry().getDevice(deviceId);
}
if (logWhenMissing && device == null) {
logger.error("Couldn't resolve linked {} device '{}', make sure the Item has iss tags", linkName,
deviceName);
}
return device;
}
}

View File

@ -1,67 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import org.openhab.core.items.Item;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.OpenClosedType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.types.State;
import org.openhab.io.imperihome.internal.model.param.DeviceParam;
import org.openhab.io.imperihome.internal.model.param.ParamType;
/**
* Abstraction of devices that are trippable, i.e. DevDoor, DevFlood, DevMotion, DevSmoke, DevCO2Alert.
*
* @author Pepijn de Geus - Initial contribution
*/
public class TrippableDevice extends AbstractDevice {
public TrippableDevice(DeviceType type, Item item) {
super(type, item);
addParam(new DeviceParam(ParamType.ARMABLE, "0"));
addParam(new DeviceParam(ParamType.ARMED, "1"));
addParam(new DeviceParam(ParamType.ACKABLE, "0"));
}
@Override
public void stateUpdated(Item item, State newState) {
super.stateUpdated(item, newState);
boolean tripped = false;
if (item.getStateAs(OpenClosedType.class) != null) {
OpenClosedType state = item.getStateAs(OpenClosedType.class);
tripped = state == OpenClosedType.CLOSED;
} else if (item.getStateAs(OnOffType.class) != null) {
OnOffType state = item.getStateAs(OnOffType.class);
tripped = state == OnOffType.ON;
} else if (item.getStateAs(DecimalType.class) != null) {
DecimalType state = item.getStateAs(DecimalType.class);
tripped = state != null && state.intValue() != 0;
} else if (item.getStateAs(StringType.class) != null) {
StringType state = item.getStateAs(StringType.class);
tripped = state != null && !state.toString().isBlank() && !state.toString().trim().equals("ok");
} else {
logger.debug("Can't interpret state {} as tripped status", item.getState());
}
addParam(new DeviceParam(ParamType.TRIPPED, tripped ^ isInverted() ? "1" : "0"));
if (tripped) {
addParam(new DeviceParam(ParamType.LAST_TRIP, String.valueOf(System.currentTimeMillis())));
}
}
}

View File

@ -1,39 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import org.openhab.core.items.Item;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.State;
import org.openhab.io.imperihome.internal.model.param.NumericValueParam;
import org.openhab.io.imperihome.internal.model.param.ParamType;
/**
* UV sensor device.
*
* @author Pepijn de Geus - Initial contribution
*/
public class UvDevice extends AbstractNumericValueDevice {
public UvDevice(Item item) {
super(DeviceType.PRESSURE, item, "index");
}
@Override
public void stateUpdated(Item item, State newState) {
super.stateUpdated(item, newState);
DecimalType value = (DecimalType) item.getStateAs(DecimalType.class);
addParam(new NumericValueParam(ParamType.UV_VALUE, getUnit(), value));
}
}

View File

@ -1,73 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.device;
import org.openhab.core.items.Item;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.State;
import org.openhab.io.imperihome.internal.model.param.NumericValueParam;
import org.openhab.io.imperihome.internal.model.param.ParamType;
import org.openhab.io.imperihome.internal.processor.ItemProcessor;
/**
* Wind sensor device.
*
* @author Pepijn de Geus - Initial contribution
*/
public class WindDevice extends AbstractNumericValueDevice {
private static final String LINK_DIRECTION = "direction";
public WindDevice(Item item) {
super(DeviceType.WIND, item, "km/h");
}
@Override
public void updateParams() {
super.updateParams();
if (getLinks().containsKey(LINK_DIRECTION)) {
String deviceName = getLinks().get(LINK_DIRECTION);
String deviceId = ItemProcessor.getDeviceId(deviceName);
AbstractDevice dirDevice = getDeviceRegistry().getDevice(deviceId);
if (dirDevice == null) {
logger.error("Couldn't resolve linked wind direction device '{}', make sure the Item has iss tags",
deviceName);
return;
}
NumericValueParam valueParam = (NumericValueParam) dirDevice.getParams().get(ParamType.GENERIC_VALUE);
if (valueParam == null) {
logger.warn("Linked Wind direction device has no Value parameter: {}", dirDevice);
return;
}
NumericValueParam dirParam = new NumericValueParam(ParamType.DIRECTION, valueParam.getUnit(), null);
String unit = dirParam.getUnit();
if (unit == null || unit.isEmpty()) {
dirParam.setUnit("Degrees");
}
dirParam.setValue(valueParam.getValue());
addParam(dirParam);
}
}
@Override
public void stateUpdated(Item item, State newState) {
super.stateUpdated(item, newState);
DecimalType value = item.getStateAs(DecimalType.class);
addParam(new NumericValueParam(ParamType.SPEED, getUnit(), value));
}
}

View File

@ -1,72 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.param;
/**
* Basic device key/value parameter.
*
* @author Pepijn de Geus - Initial contribution
*/
public class DeviceParam {
private ParamType key;
private Object value;
public DeviceParam(ParamType type) {
this.key = type;
}
public DeviceParam(ParamType type, Object value) {
this.key = type;
this.value = value;
}
public ParamType getKey() {
return key;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof DeviceParam)) {
return false;
}
DeviceParam that = (DeviceParam) o;
if (key != that.key) {
return false;
}
return value != null ? value.equals(that.value) : that.value == null;
}
@Override
public int hashCode() {
return key.hashCode();
}
@Override
public String toString() {
return "DeviceParam{" + "key=" + key + ", value='" + value + '\'' + '}';
}
}

View File

@ -1,31 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.param;
import java.util.HashMap;
/**
* No-op extension of HashMap storing device parameters. This class exists because it allows the use of a Map in Device
* and at the same
* time makes it possible to expose the values as a JSON array using a custom serializer.
*
* @author Pepijn de Geus - Initial contribution
*/
public class DeviceParameters extends HashMap<ParamType, DeviceParam> {
private static final long serialVersionUID = -3877582034887195137L;
public void set(DeviceParam param) {
put(param.getKey(), param);
}
}

View File

@ -1,87 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.param;
import org.openhab.core.library.types.DecimalType;
/**
* Numeric value param
*
* @author Pepijn de Geus - Initial contribution
*/
public class NumericValueParam extends DeviceParam {
private String unit;
private boolean graphable = true;
public NumericValueParam(ParamType type, String unit) {
super(type);
setUnit(unit);
}
public NumericValueParam(ParamType type, String unit, DecimalType value) {
this(type, unit);
setValue(value == null ? 0 : value.doubleValue());
}
@Override
public Number getValue() {
return (Number) super.getValue();
}
public void setValue(Number value) {
super.setValue(value);
}
public String getUnit() {
return unit;
}
public void setUnit(String unit) {
this.unit = unit;
}
public boolean isGraphable() {
return graphable;
}
public void setGraphable(boolean graphable) {
this.graphable = graphable;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof NumericValueParam)) {
return false;
}
if (!super.equals(o)) {
return false;
}
NumericValueParam that = (NumericValueParam) o;
if (graphable != that.graphable) {
return false;
}
return unit != null ? unit.equals(that.unit) : that.unit == null;
}
@Override
public String toString() {
return "NumericValueParam{" + "super=" + super.toString() + ", unit='" + unit + '\'' + ", graphable="
+ graphable + '}';
}
}

View File

@ -1,73 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.model.param;
/**
* Parameter type enumeration. Contains the ISS API parameter key string.
*
* @author Pepijn de Geus - Initial contribution
*/
public enum ParamType {
DEFAULT_ICON("defaultIcon"),
GENERIC_VALUE("Value"),
TEMPERATURE_VALUE("Value"),
TEMPERATURE_DUAL("temp"),
LUMINOSITY_VALUE("Value"),
HYGROMETRY_DUAL("hygro"),
HYGROMETRY_VALUE("Value"),
CO2_VALUE("Value"),
PRESSURE_VALUE("Value"),
NOISE_VALUE("Value"),
RAIN_VALUE("Value"),
UV_VALUE("Value"),
DIMMABLE("dimmable"),
ENERGY("Energy"),
STATUS("Status"),
MULTISWITCH_VALUE("Value"),
CHOICES("Choices"),
COLOR("color"),
LEVEL("Level"),
WHITE_CHANNEL("whitechannel"),
WATTS("Watts"),
KWH("ConsoTotal"),
ARMABLE("armable"),
ARMED("Armed"),
ACKABLE("ackable"),
TRIPPED("Tripped"),
LAST_TRIP("lasttrip"),
ACCUMULATION("Accumulation"),
SPEED("Speed"),
DIRECTION("Direction"),
STOPPABLE("stopable"),
PULSEABLE("pulseable"),
// Thermostat parameters
CUR_MODE("curmode"),
CUR_SETPOINT("cursetpoint"),
CUR_TEMP("curtemp"),
MIN_VAL("minVal"),
MAX_VAL("maxVal"),
AVAIL_MODE("availablemodes"),
STEP("step");
private final String apiString;
ParamType(String apiString) {
this.apiString = apiString;
}
public String getApiString() {
return apiString;
}
}

View File

@ -1,116 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.processor;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.openhab.io.imperihome.internal.model.Room;
import org.openhab.io.imperihome.internal.model.device.AbstractDevice;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The device registry stores created devices by ID.
*
* @author Pepijn de Geus - Initial contribution
*/
public class DeviceRegistry implements Iterable<AbstractDevice> {
private final Logger logger = LoggerFactory.getLogger(DeviceRegistry.class);
private final Map<String, AbstractDevice> devices;
private Set<Room> rooms;
public DeviceRegistry() {
devices = new ConcurrentHashMap<>();
}
public AbstractDevice getDevice(String deviceId) {
return devices.get(deviceId);
}
public Map<String, AbstractDevice> getDevices() {
return new HashMap<>(devices);
}
public Collection<Room> getRooms() {
return new HashSet<>(rooms);
}
public boolean hasDevices() {
return !devices.isEmpty();
}
public boolean hasDevice(String deviceId) {
return devices.containsKey(deviceId);
}
public void add(AbstractDevice device) {
// Workaround for Eclipse SH bug: ignore add-event for same item
// https://github.com/eclipse/smarthome/issues/3160
if (devices.containsKey(device.getId())) {
logger.warn("Ignoring duplicate device #{}, name={}, item={}", device.getId(), device.getName(),
device.getItemName());
return;
}
devices.put(device.getId(), device);
updateRooms();
logger.debug("Device {} added, registry now contains {} total", device.getName(), devices.size());
}
public AbstractDevice remove(String deviceId) {
AbstractDevice removed = devices.remove(deviceId);
if (removed != null) {
updateRooms();
logger.debug("Device {} removed, registry now contains {} total", removed.getName(), devices.size());
}
return removed;
}
@Override
public Iterator<AbstractDevice> iterator() {
return devices.values().iterator();
}
public void clear() {
for (AbstractDevice device : devices.values()) {
device.destroy();
}
devices.clear();
if (rooms != null) {
rooms.clear();
}
logger.debug("Device registry cleared");
}
private void updateRooms() {
Set<Room> newRooms = new HashSet<>();
for (AbstractDevice device : devices.values()) {
Room room = new Room();
room.setId(device.getRoom());
room.setName(device.getRoomName());
newRooms.add(room);
}
rooms = newRooms;
}
}

View File

@ -1,455 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.processor;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.openhab.core.items.Item;
import org.openhab.core.items.ItemRegistry;
import org.openhab.core.items.ItemRegistryChangeListener;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.HSBType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.OpenClosedType;
import org.openhab.core.types.State;
import org.openhab.io.imperihome.internal.ImperiHomeConfig;
import org.openhab.io.imperihome.internal.action.ActionRegistry;
import org.openhab.io.imperihome.internal.model.device.AbstractDevice;
import org.openhab.io.imperihome.internal.model.device.AbstractNumericValueDevice;
import org.openhab.io.imperihome.internal.model.device.Co2SensorDevice;
import org.openhab.io.imperihome.internal.model.device.DeviceType;
import org.openhab.io.imperihome.internal.model.device.DimmerDevice;
import org.openhab.io.imperihome.internal.model.device.ElectricityDevice;
import org.openhab.io.imperihome.internal.model.device.GenericSensorDevice;
import org.openhab.io.imperihome.internal.model.device.HygrometryDevice;
import org.openhab.io.imperihome.internal.model.device.LockDevice;
import org.openhab.io.imperihome.internal.model.device.LuminosityDevice;
import org.openhab.io.imperihome.internal.model.device.MultiSwitchDevice;
import org.openhab.io.imperihome.internal.model.device.NoiseDevice;
import org.openhab.io.imperihome.internal.model.device.PressureDevice;
import org.openhab.io.imperihome.internal.model.device.RainDevice;
import org.openhab.io.imperihome.internal.model.device.RgbLightDevice;
import org.openhab.io.imperihome.internal.model.device.SceneDevice;
import org.openhab.io.imperihome.internal.model.device.ShutterDevice;
import org.openhab.io.imperihome.internal.model.device.SwitchDevice;
import org.openhab.io.imperihome.internal.model.device.TempHygroDevice;
import org.openhab.io.imperihome.internal.model.device.TemperatureDevice;
import org.openhab.io.imperihome.internal.model.device.ThermostatDevice;
import org.openhab.io.imperihome.internal.model.device.TrippableDevice;
import org.openhab.io.imperihome.internal.model.device.UvDevice;
import org.openhab.io.imperihome.internal.model.device.WindDevice;
import org.openhab.io.imperihome.internal.model.param.DeviceParam;
import org.openhab.io.imperihome.internal.model.param.ParamType;
import org.openhab.io.imperihome.internal.util.DigestUtil;
import org.openhab.io.imperihome.internal.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Processor of openHAB Items. Parses ISS tags and creates and registers {@link AbstractDevice} implementations where
* applicable.
*
* @author Pepijn de Geus - Initial contribution
*/
public class ItemProcessor implements ItemRegistryChangeListener {
private static final String PREFIX_ISS = "iss:";
private final Logger logger = LoggerFactory.getLogger(ItemProcessor.class);
private final ItemRegistry itemRegistry;
private final DeviceRegistry deviceRegistry;
private final ActionRegistry actionRegistry;
private final ImperiHomeConfig config;
public ItemProcessor(ItemRegistry itemRegistry, DeviceRegistry deviceRegistry, ActionRegistry actionRegistry,
ImperiHomeConfig config) {
this.itemRegistry = itemRegistry;
this.deviceRegistry = deviceRegistry;
this.actionRegistry = actionRegistry;
this.config = config;
allItemsChanged(Collections.emptyList());
itemRegistry.addRegistryChangeListener(this);
}
public void destroy() {
itemRegistry.removeRegistryChangeListener(this);
// Destroy all Devices (unregisters state listeners)
synchronized (deviceRegistry) {
for (AbstractDevice device : deviceRegistry) {
device.destroy();
}
deviceRegistry.clear();
}
}
private void parseItem(Item item) {
Map<TagType, List<String>> issTags = getIssTags(item);
if (!issTags.isEmpty()) {
logger.debug("Found item {} with ISS tags: {}", item, issTags);
DeviceType deviceType = getDeviceType(item, issTags);
if (deviceType == null) {
logger.warn("Unrecognized device type for item: {}", item);
} else {
AbstractDevice device = getDeviceInstance(deviceType, item);
device.setId(getDeviceId(item));
device.setName(getLabel(item, issTags));
device.setInverted(isInverted(issTags));
device.setActionRegistry(actionRegistry);
setIcon(device, issTags);
setDeviceRoom(device, issTags);
setDeviceLinks(device, item, issTags);
setMapping(device, item, issTags);
setUnit(device, issTags);
device.processCustomTags(issTags);
// Set initial state
logger.debug("Setting initial state of {} to {}", device, item.getState());
device.stateUpdated(item, item.getState());
logger.debug("Item parsed to device: {}", device);
synchronized (deviceRegistry) {
deviceRegistry.add(device);
}
}
}
}
private void setIcon(AbstractDevice device, Map<TagType, List<String>> issTags) {
if (!issTags.containsKey(TagType.ICON)) {
return;
}
String icon = issTags.get(TagType.ICON).get(0);
if (!icon.toLowerCase().startsWith("http")) {
String rootUrl = config.getRootUrl();
if (rootUrl == null || rootUrl.isEmpty()) {
logger.error("Can't set icon; 'openhab.rootUrl' not set in configuration");
return;
}
icon = rootUrl + "icon/" + icon;
}
device.addParam(new DeviceParam(ParamType.DEFAULT_ICON, icon));
}
private AbstractDevice getDeviceInstance(DeviceType deviceType, Item item) {
switch (deviceType) {
case SWITCH:
return new SwitchDevice(item);
case DIMMER:
return new DimmerDevice(item);
case RGB_LIGHT:
return new RgbLightDevice(item);
case TEMPERATURE:
return new TemperatureDevice(item);
case TEMP_HYGRO:
return new TempHygroDevice(item);
case LUMINOSITY:
return new LuminosityDevice(item);
case HYGROMETRY:
return new HygrometryDevice(item);
case CO2:
return new Co2SensorDevice(item);
case ELECTRICITY:
return new ElectricityDevice(item);
case SCENE:
return new SceneDevice(item);
case MULTI_SWITCH:
return new MultiSwitchDevice(item);
case GENERIC_SENSOR:
return new GenericSensorDevice(item);
case PRESSURE:
return new PressureDevice(item);
case UV:
return new UvDevice(item);
case NOISE:
return new NoiseDevice(item);
case RAIN:
return new RainDevice(item);
case WIND:
return new WindDevice(item);
case LOCK:
return new LockDevice(item);
case SHUTTER:
return new ShutterDevice(item);
case THERMOSTAT:
return new ThermostatDevice(item);
case CO2_ALERT:
case SMOKE:
case DOOR:
case MOTION:
case FLOOD:
return new TrippableDevice(deviceType, item);
default:
break;
}
throw new IllegalArgumentException("Unknown device type: " + deviceType);
}
private String getLabel(Item item, Map<TagType, List<String>> issTags) {
if (issTags.containsKey(TagType.LABEL)) {
return issTags.get(TagType.LABEL).get(0);
}
String label = item.getLabel();
if (label != null && !label.isBlank()) {
label = label.trim();
if (label.matches("\\[.*\\]$")) {
label = label.substring(0, label.indexOf('['));
}
return label;
}
return item.getName();
}
private boolean isInverted(Map<TagType, List<String>> issTags) {
return issTags.containsKey(TagType.INVERT) && StringUtils.toBoolean(issTags.get(TagType.INVERT).get(0));
}
private void setDeviceRoom(AbstractDevice device, Map<TagType, List<String>> issTags) {
String roomName = "No room";
if (issTags.containsKey(TagType.ROOM)) {
roomName = issTags.get(TagType.ROOM).get(0);
}
device.setRoom(DigestUtil.sha1(roomName));
device.setRoomName(roomName);
}
private void setDeviceLinks(AbstractDevice device, Item item, Map<TagType, List<String>> issTags) {
if (issTags.containsKey(TagType.LINK)) {
// Pass device registry to device for linked device lookup
device.setDeviceRegistry(deviceRegistry);
// Parse link tags
for (String link : issTags.get(TagType.LINK)) {
String[] parts = link.split(":");
if (parts.length == 2) {
device.addLink(parts[0].toLowerCase().trim(), parts[1].trim());
} else {
logger.error("Item has incorrect link format (should be 'iss:link:<type>:<item>'): {}", item);
}
}
// Check required links
for (String requiredLink : device.getType().getRequiredLinks()) {
if (!device.getLinks().containsKey(requiredLink)) {
logger.error("Item doesn't contain required link {} for {}: {}", requiredLink,
device.getType().getApiString(), item);
}
}
}
}
/**
* Parses a mapping tag, if it exists. Format: "iss:mapping:1=Foo,2=Bar,3=Foobar".
*/
private void setMapping(AbstractDevice device, Item item, Map<TagType, List<String>> issTags) {
if (issTags.containsKey(TagType.MAPPING)) {
String mapItems = issTags.get(TagType.MAPPING).get(0);
Map<String, String> mapping = new HashMap<>();
for (String mapItem : mapItems.split(",")) {
String[] keyVal = mapItem.split("=", 2);
if (keyVal.length != 2) {
logger.error("Invalid mapping syntax for Item {}", item);
return;
}
mapping.put(keyVal[0].trim(), keyVal[1].trim());
}
device.setMapping(mapping);
}
}
/**
* Parses the unit tag, if it exists. Format: "iss:unit:°C".
*/
private void setUnit(AbstractDevice device, Map<TagType, List<String>> issTags) {
if (issTags.containsKey(TagType.UNIT)) {
if (!(device instanceof AbstractNumericValueDevice)) {
logger.warn("Unit tag is not supported for device {}", device);
return;
}
((AbstractNumericValueDevice) device).setUnit(issTags.get(TagType.UNIT).get(0));
}
}
/**
* Determines the Device type for the given Item. Uses the 'type' tag first, tries to auto-detect the type if no
* such tag exists.
*/
private DeviceType getDeviceType(Item item, Map<TagType, List<String>> issTags) {
if (issTags.containsKey(TagType.TYPE)) {
return DeviceType.forApiString(issTags.get(TagType.TYPE).get(0));
}
List<Class<? extends State>> acceptedDataTypes = item.getAcceptedDataTypes();
String name = item.getName().toLowerCase();
if (acceptedDataTypes.contains(DecimalType.class)) {
if (name.contains("tempe")) {
return DeviceType.TEMPERATURE;
} else if (name.contains("lumi")) {
return DeviceType.LUMINOSITY;
} else if (name.contains("hygro")) {
return DeviceType.HYGROMETRY;
} else if (name.contains("wind")) {
return DeviceType.WIND;
} else {
return DeviceType.GENERIC_SENSOR;
}
}
if (acceptedDataTypes.contains(HSBType.class)) {
return DeviceType.RGB_LIGHT;
}
if (acceptedDataTypes.contains(OpenClosedType.class)) {
return DeviceType.DOOR;
}
if (acceptedDataTypes.contains(OnOffType.class)) {
return DeviceType.SWITCH;
}
return null;
}
private Map<TagType, List<String>> getIssTags(Item item) {
Map<TagType, List<String>> tags = new EnumMap<>(TagType.class);
for (String tag : item.getTags()) {
if (tag.startsWith(PREFIX_ISS)) {
String issTag = tag.substring(PREFIX_ISS.length());
for (TagType tagType : TagType.values()) {
if (issTag.startsWith(tagType.getPrefix() + ':')) {
String tagValue = issTag.substring(tagType.getPrefix().length() + 1);
if (!tags.containsKey(tagType)) {
tags.put(tagType, new LinkedList<>());
} else if (!tagType.isMultiValue()) {
logger.error("Found multiple values for tag {} - only first value is used",
tagType.getPrefix());
}
tags.get(tagType).add(tagValue);
break;
}
}
}
}
return tags;
}
/**
* Removes the given item for the device list.
*
* @param item Item to remove.
*/
private void removeItem(Item item) {
removeItem(item.getName());
}
/**
* Removes the given item for the device list.
*
* @param itemName Name of the Item to remove.
*/
private void removeItem(String itemName) {
String deviceId = getDeviceId(itemName);
AbstractDevice device;
synchronized (deviceRegistry) {
device = deviceRegistry.remove(deviceId);
}
if (device != null) {
logger.debug("Removing Device from ISS registry for Item: {}", itemName);
device.destroy();
}
}
/**
* Generates an unique device ID for the given item.
*
* @param item Item to get device ID for.
* @return Device ID.
*/
public static String getDeviceId(Item item) {
return getDeviceId(item.getName());
}
/**
* Generates an unique device ID for the given item name.
*
* @param itemName Item name.
* @return Device ID.
*/
public static String getDeviceId(String itemName) {
return DigestUtil.sha1(itemName);
}
@Override
public void added(Item item) {
logger.debug("Processing item added event");
parseItem(item);
}
@Override
public void removed(Item item) {
logger.debug("Processing item removed event");
removeItem(item);
}
@Override
public void updated(Item oldItem, Item newItem) {
logger.debug("Processing item updated event");
removeItem(oldItem);
parseItem(newItem);
}
@Override
public void allItemsChanged(Collection<String> oldItems) {
synchronized (deviceRegistry) {
logger.debug("Processing allItemsChanged event");
for (String oldItem : oldItems) {
removeItem(oldItem);
}
if (deviceRegistry.hasDevices()) {
logger.warn("There are still Devices left after processing all Items from allItemsChanged(): {}",
deviceRegistry.getDevices());
deviceRegistry.clear();
}
for (Item item : itemRegistry.getItems()) {
parseItem(item);
}
}
}
}

View File

@ -1,57 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.processor;
/**
* ISS tag types enumeration.
*
* @author Pepijn de Geus - Initial contribution
*/
public enum TagType {
LABEL("label", false),
ROOM("room", false),
TYPE("type", false),
MAPPING("mapping", false),
LINK("link", true),
UNIT("unit", false),
INVERT("invert", false),
ICON("icon", false),
STEP("step", false),
MIN_VAL("minVal", false),
MAX_VAL("maxVal", false),
MODES("modes", false);
private final String prefix;
private final boolean multiValue;
TagType(String prefix, boolean multiValue) {
this.prefix = prefix;
this.multiValue = multiValue;
}
/**
* @return Tag prefix.
*/
public String getPrefix() {
return prefix;
}
/**
* @return True if this tag may exist multiple times on a single item.
*/
public boolean isMultiValue() {
return multiValue;
}
}

View File

@ -1,42 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.util;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* Digest utility.
*
* @author Pepijn de Geus - Initial contribution
*/
public final class DigestUtil {
public static String sha1(String input) {
try {
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(input.getBytes(StandardCharsets.UTF_8));
return new BigInteger(1, crypt.digest()).toString(16);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Could not generate SHA-1 hash", e);
}
}
// Hidden constructor
private DigestUtil() {
}
}

View File

@ -1,44 +0,0 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.imperihome.internal.util;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* The {@link StringUtils} class defines some static string utility methods
*
* @author Leo Siepel - Initial contribution
*/
@NonNullByDefault
public class StringUtils {
/**
* Simple method to create boolean from string.
* 'true', 'on', 'y', 't' or 'yes' (case insensitive) will return true. Otherwise, false is returned.
*/
public static boolean toBoolean(@Nullable String input) {
if (input != null) {
input = input.toLowerCase();
}
return "true".equals(input) || "on".equals(input) || "y".equals(input) || "t".equals(input)
|| "yes".equals(input);
}
public static String padLeft(@Nullable String input, int minSize, String padString) {
if (input == null) {
input = "";
}
return String.format("%" + minSize + "s", input).replace(" ", padString);
}
}

View File

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<addon:addon id="imperihome" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:addon="https://openhab.org/schemas/addon/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/addon/v1.0.0 https://openhab.org/schemas/addon-1.0.0.xsd">
<type>misc</type>
<name>ImperiHome</name>
<description>Exposes openHAB to the Evertygo dashboard.</description>
<service-id>org.openhab.imperihome</service-id>
<config-description-ref uri="io:imperihome"/>
</addon:addon>

View File

@ -1,10 +0,0 @@
<?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="io:imperihome">
</config-description>
</config-description:config-descriptions>

View File

@ -1,3 +0,0 @@
# service
service.io.imperihome.label = ImperiHome Integration

View File

@ -1,3 +0,0 @@
# service
service.io.imperihome.label = ImperiHome Integration

View File

@ -1,3 +0,0 @@
# service
service.io.imperihome.label = ImperiHome -integraatio

View File

@ -1,3 +0,0 @@
# service
service.io.imperihome.label = Intégration ImperiHome

View File

@ -1,3 +0,0 @@
# service
service.io.imperihome.label = Integrazione ImperiHome

View File

@ -28,7 +28,6 @@
<!-- io -->
<module>org.openhab.io.homekit</module>
<module>org.openhab.io.hueemulation</module>
<module>org.openhab.io.imperihome</module>
<module>org.openhab.io.metrics</module>
<module>org.openhab.io.neeo</module>
<module>org.openhab.io.openhabcloud</module>