mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 07:02:02 +01:00
[Qbus] Initial contribution (#9191)
Signed-off-by: Koen Schockaert <ks@qbus.be>
This commit is contained in:
parent
dae4743fe0
commit
16ffeecb90
@ -222,6 +222,7 @@
|
||||
/bundles/org.openhab.binding.pulseaudio/ @peuter
|
||||
/bundles/org.openhab.binding.pushbullet/ @hakan42
|
||||
/bundles/org.openhab.binding.pushover/ @cweitkamp
|
||||
/bundles/org.openhab.binding.qbus/ @QbusKoen
|
||||
/bundles/org.openhab.binding.radiothermostat/ @mlobstein
|
||||
/bundles/org.openhab.binding.regoheatpump/ @crnjan
|
||||
/bundles/org.openhab.binding.revogi/ @andibraeu
|
||||
|
13
bundles/org.openhab.binding.qbus/NOTICE
Normal file
13
bundles/org.openhab.binding.qbus/NOTICE
Normal file
@ -0,0 +1,13 @@
|
||||
This content is produced and maintained by the openHAB project.
|
||||
|
||||
* Project home: https://www.openhab.org
|
||||
|
||||
== Declared Project Licenses
|
||||
|
||||
This program and the accompanying materials are made available under the terms
|
||||
of the Eclipse Public License 2.0 which is available at
|
||||
https://www.eclipse.org/legal/epl-2.0/.
|
||||
|
||||
== Source Code
|
||||
|
||||
https://github.com/openhab/openhab-addons
|
110
bundles/org.openhab.binding.qbus/README.md
Normal file
110
bundles/org.openhab.binding.qbus/README.md
Normal file
@ -0,0 +1,110 @@
|
||||
# Qbus Binding
|
||||
|
||||
![Qbus Logo](doc/Logo.JPG)
|
||||
|
||||
This binding for [Qbus](https://qbus.be) communicates with all controllers of the Qbus home automation system.
|
||||
|
||||
We also host a site which contains a [manual](https://manualoh.schockaert.tk/) where you can find lots of information to set up openHAB with Qbus client and server (for the moment only in Dutch).
|
||||
|
||||
The controllers can not communicate directly with openHAB, therefore we developed a client/server application which you must install prior to enable this binding.
|
||||
More information can be found here:
|
||||
[Qbus Client/Server](https://github.com/QbusKoen/QbusClientServer-Installer)
|
||||
|
||||
With this binding you can control and read almost every output from the Qbus system.
|
||||
|
||||
## Supported Things
|
||||
|
||||
The following things are supported by the Qbus binding:
|
||||
|
||||
- `dimmer`: Dimmer 1 button, 2 button and clc
|
||||
- `onOff`: Bistabiel, Timer1-3, Interval
|
||||
- `thermostats`: Thermostats - normal and PID
|
||||
- `scene`: Scenes
|
||||
- `co2`: CO2
|
||||
- `rollershutter`: Rollershutter
|
||||
- `rollershutter_slats`: Rollerhutter with slats
|
||||
|
||||
For now the following Qbus things are not yet supported but will come:
|
||||
|
||||
- DMX
|
||||
- Timer 4 & 5
|
||||
- HVAC
|
||||
- Humidity
|
||||
- Renson
|
||||
- Duco
|
||||
- Kinetura
|
||||
- Energy monitor
|
||||
- Weather station
|
||||
|
||||
|
||||
## Discovery
|
||||
|
||||
The discovery service is not yet implemented but the System Manager III software of Qbus generates things and item files from the programming, which you can use directly in openHAB.
|
||||
|
||||
## Bridge configuration
|
||||
|
||||
```
|
||||
Bridge qbus:bridge:CTD001122 [ addr="localhost", sn="001122", port=8447, serverCheck=10 ] {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
| Property | Default | Required | Description |
|
||||
| ------------- | --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `addr` | localhost | YES | The ip address of the machine where the Qbus Server runs |
|
||||
| `sn` | | YES | The serial number of your controller |
|
||||
| `port` | 8447 | YES | The communication port of the client/server |
|
||||
| `serverCheck` | 10 | NO | Refresh time - After x minutes there will be a check if server is still running and if client is still connected. If not - reconnect |
|
||||
|
||||
|
||||
|
||||
## Things configuration
|
||||
|
||||
| Thing Type ID | Channel Name | Read only | description |
|
||||
| --------------------- | ------------- | --------- | ------------------------------------------------------ |
|
||||
| `onOff` | switch | No | This is the channel for Bistable, Timers and Intervals |
|
||||
| `dimmer` | brightness | No | This is the channel for Dimmers 1&2 buttons and CLC |
|
||||
| `scene` | Switch | No | This is the channel for scenes |
|
||||
| `co2` | co2 | Yes | This is the channel for CO2 sensors |
|
||||
| `rollershutter` | rollershutter | No | This is the channel for rollershutters |
|
||||
| `rollershutter_slats` | rollershutter | No | This is the channel for rollershutters with slats |
|
||||
| `thermostat` | setpoint | No | This is the channel for thermostats setpoint |
|
||||
| `thermostat` | measured | Yes | This is the channel for thermostats currenttemp |
|
||||
| `thermostat` | mode | No | This is the channel for thermostats mode |
|
||||
|
||||
|
||||
## Full Example
|
||||
|
||||
### Things
|
||||
|
||||
```
|
||||
Bridge qbus:bridge:CTD001122 [ addr="localhost", sn="001122", port=8447, serverCheck=10 ] {
|
||||
dimmer 1 "ToonzaalLED" [ dimmerId=100 ]
|
||||
onOff 30 "Toonzaal230V" [ bistabielId=76 ]
|
||||
thermostat 50 "Service" [ thermostatId=99 ]
|
||||
scene 70 "Disco" [ sceneId=36 ]
|
||||
co2 100 "Productie" [ co2Id=26 ]
|
||||
rollershutter 120 "Roller1" [ rolId=268 ]
|
||||
rollershutter_slats 121 "Roller2" [ rolId=264 ]
|
||||
}
|
||||
```
|
||||
|
||||
### Items
|
||||
|
||||
```
|
||||
Dimmer ToonzaalLED <light> [ "Lighting" ] {channel="qbus:dimmer:CTD007841:1:brightness"}
|
||||
Switch Toonzaal230V <light> {channel="qbus:onOff:CTD007841:30:switch"}
|
||||
Number:Temperature ServiceSP"[%.1f %unit%]" (GroepThermostaten) {channel="qbus:thermostat:CTD007841:50:setpoint"}
|
||||
Number:Temperature ServiceCT"[%.1f %unit%]" (GroepThermostaten) {channel="qbus:thermostat:CTD007841:50:measured"}
|
||||
Number ServiceMode (GroepThermostaten) {channel="qbus:thermostat:CTD007841:50:mode",ihc="0x33c311" , autoupdate="true"}
|
||||
Switch Disco <light> {channel="qbus:scene:CTD007841:36:scene"}
|
||||
Number ProductieCO2 {channel="qbus:co2:CTD007841:100:co2"}
|
||||
Rollershutter Roller1 {channel="qbus:rollershutter:CTD007841:120:rollershutter"}
|
||||
Rollershutter Roller2 {channel="qbus:rollershutter_slats:CTD007841:121:rollershutter"}
|
||||
Dimmer Roller2_slats {channel="qbus:rollershutter_slats:CTD007841:121:slats"}
|
||||
```
|
||||
|
||||
This is the link to the [Qbus forum](https://qbusforum.be). This forum is mainly in dutch and you can find a lot of information about the pre testings of this binding and offers a way to communicate with other users.
|
||||
|
BIN
bundles/org.openhab.binding.qbus/doc/Logo.JPG
Normal file
BIN
bundles/org.openhab.binding.qbus/doc/Logo.JPG
Normal file
Binary file not shown.
After Width: | Height: | Size: 888 KiB |
17
bundles/org.openhab.binding.qbus/pom.xml
Normal file
17
bundles/org.openhab.binding.qbus/pom.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
|
||||
<version>3.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>org.openhab.binding.qbus</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: Qbus Binding</name>
|
||||
|
||||
</project>
|
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2010-2020 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
|
||||
|
||||
-->
|
||||
<features name="org.openhab.binding.qbus-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
|
||||
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
|
||||
|
||||
<feature name="openhab-binding-qbus" description="Qbus Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.qbus/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.qbus.internal;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link QbusBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Koen Schockaert - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class QbusBindingConstants {
|
||||
|
||||
private static final String BINDING_ID = "qbus";
|
||||
|
||||
// bridge
|
||||
public static final ThingTypeUID BRIDGE_THING_TYPE = new ThingTypeUID(BINDING_ID, "bridge");
|
||||
public static final Set<ThingTypeUID> BRIDGE_THING_TYPES_UIDS = Collections.singleton(BRIDGE_THING_TYPE);
|
||||
// Bridge config properties
|
||||
public static final String CONFIG_HOST_NAME = "addr";
|
||||
public static final String CONFIG_PORT = "port";
|
||||
public static final String CONFIG_SN = "sn";
|
||||
public static final String CONFIG_SERVERCHECK = "serverCheck";
|
||||
|
||||
// generic thing types
|
||||
public static final ThingTypeUID THING_TYPE_CO2 = new ThingTypeUID(BINDING_ID, "co2");
|
||||
public static final ThingTypeUID THING_TYPE_SCENE = new ThingTypeUID(BINDING_ID, "scene");
|
||||
public static final ThingTypeUID THING_TYPE_ON_OFF_LIGHT = new ThingTypeUID(BINDING_ID, "onOff");
|
||||
public static final ThingTypeUID THING_TYPE_DIMMABLE_LIGHT = new ThingTypeUID(BINDING_ID, "dimmer");
|
||||
public static final ThingTypeUID THING_TYPE_ROLLERSHUTTER = new ThingTypeUID(BINDING_ID, "rollershutter");
|
||||
public static final ThingTypeUID THING_TYPE_ROLLERSHUTTER_SLATS = new ThingTypeUID(BINDING_ID,
|
||||
"rollershutter_slats");
|
||||
public static final ThingTypeUID THING_TYPE_THERMOSTAT = new ThingTypeUID(BINDING_ID, "thermostat");
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final Set<ThingTypeUID> SCENE_THING_TYPES_UIDS = Set.of(THING_TYPE_SCENE);
|
||||
public static final Set<ThingTypeUID> CO2_THING_TYPES_UIDS = Set.of(THING_TYPE_CO2);
|
||||
public static final Set<ThingTypeUID> ROLLERSHUTTER_THING_TYPES_UIDS = Set.of(THING_TYPE_ROLLERSHUTTER);
|
||||
public static final Set<ThingTypeUID> ROLLERSHUTTER_SLATS_THING_TYPES_UIDS = Set.of(THING_TYPE_ROLLERSHUTTER_SLATS);
|
||||
public static final Set<ThingTypeUID> BISTABIEL_THING_TYPES_UIDS = Set.of(THING_TYPE_ON_OFF_LIGHT);
|
||||
public static final Set<ThingTypeUID> THERMOSTAT_THING_TYPES_UIDS = Set.of(THING_TYPE_THERMOSTAT);
|
||||
public static final Set<ThingTypeUID> DIMMER_THING_TYPES_UIDS = Set.of(THING_TYPE_ON_OFF_LIGHT,
|
||||
THING_TYPE_DIMMABLE_LIGHT);
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_ON_OFF_LIGHT,
|
||||
THING_TYPE_DIMMABLE_LIGHT, THING_TYPE_THERMOSTAT, THING_TYPE_SCENE, THING_TYPE_CO2,
|
||||
THING_TYPE_ROLLERSHUTTER, THING_TYPE_ROLLERSHUTTER_SLATS);
|
||||
|
||||
// List of all Channel ids
|
||||
public static final String CHANNEL_SWITCH = "switch";
|
||||
public static final String CHANNEL_SCENE = "scene";
|
||||
public static final String CHANNEL_BRIGHTNESS = "brightness";
|
||||
public static final String CHANNEL_MEASURED = "measured";
|
||||
public static final String CHANNEL_SETPOINT = "setpoint";
|
||||
public static final String CHANNEL_MODE = "mode";
|
||||
public static final String CHANNEL_CO2 = "co2";
|
||||
public static final String CHANNEL_ROLLERSHUTTER = "rollershutter";
|
||||
public static final String CHANNEL_SLATS = "slats";
|
||||
|
||||
// Thing config properties
|
||||
public static final String CONFIG_BISTABIEL_ID = "bistabielId";
|
||||
public static final String CONFIG_DIMMER_ID = "dimmerId";
|
||||
public static final String CONFIG_THERMOSTAT_ID = "thermostatId";
|
||||
public static final String CONFIG_SCENE_ID = "sceneId";
|
||||
public static final String CONFIG_CO2_ID = "co2Id";
|
||||
public static final String CONFIG_ROLLERSHUTTER_ID = "rolId";
|
||||
public static final String CONFIG_STEP_VALUE = "step";
|
||||
}
|
@ -0,0 +1,359 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
|
||||
package org.openhab.binding.qbus.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.qbus.internal.protocol.QbusCommunication;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.ThingStatusInfo;
|
||||
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* {@link QbusBridgeHandler} is the handler for a Qbus controller
|
||||
*
|
||||
* @author Koen Schockaert - Initial Contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class QbusBridgeHandler extends BaseBridgeHandler {
|
||||
|
||||
private @Nullable QbusCommunication qbusComm;
|
||||
|
||||
protected @Nullable QbusConfiguration bridgeConfig = new QbusConfiguration();
|
||||
|
||||
private @Nullable ScheduledFuture<?> refreshTimer;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(QbusBridgeHandler.class);
|
||||
|
||||
public QbusBridgeHandler(Bridge Bridge) {
|
||||
super(Bridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the bridge
|
||||
*/
|
||||
@Override
|
||||
public void initialize() {
|
||||
Integer serverCheck = getServerCheck();
|
||||
|
||||
readConfig();
|
||||
|
||||
createCommunicationObject();
|
||||
|
||||
if (serverCheck != null) {
|
||||
this.setupRefreshTimer(serverCheck);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Bridge call back
|
||||
*/
|
||||
private void setBridgeCallBack() {
|
||||
QbusCommunication qbusCommunication = getQbusCommunication();
|
||||
if (qbusCommunication != null) {
|
||||
qbusCommunication.setBridgeCallBack(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create communication object to Qbus server and start communication.
|
||||
*
|
||||
* @param addr : IP address of Qbus server
|
||||
* @param port : Communication port of QbusServer
|
||||
*/
|
||||
private void createCommunicationObject() {
|
||||
scheduler.submit(() -> {
|
||||
|
||||
setQbusCommunication(new QbusCommunication(thing));
|
||||
|
||||
QbusCommunication qbusCommunication = getQbusCommunication();
|
||||
|
||||
setBridgeCallBack();
|
||||
|
||||
Integer serverCheck = getServerCheck();
|
||||
String sn = getSn();
|
||||
if (serverCheck != null) {
|
||||
if (sn != null) {
|
||||
if (qbusCommunication != null) {
|
||||
try {
|
||||
qbusCommunication.startCommunication();
|
||||
} catch (InterruptedException e) {
|
||||
String msg = e.getMessage();
|
||||
bridgeOffline(ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Communication wit Qbus server could not be established, will try to reconnect every "
|
||||
+ serverCheck + " minutes. InterruptedException: " + msg);
|
||||
return;
|
||||
} catch (IOException e) {
|
||||
String msg = e.getMessage();
|
||||
bridgeOffline(ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Communication wit Qbus server could not be established, will try to reconnect every "
|
||||
+ serverCheck + " minutes. IOException: " + msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!qbusCommunication.communicationActive()) {
|
||||
bridgeOffline(ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"No communication with Qbus Server, will try to reconnect every " + serverCheck
|
||||
+ " minutes");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!qbusCommunication.clientConnected()) {
|
||||
bridgePending("Waiting for Qbus client to come online");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates offline status off the Bridge when an error occurs.
|
||||
*
|
||||
* @param status
|
||||
* @param detail
|
||||
* @param message
|
||||
*/
|
||||
public void bridgeOffline(ThingStatusDetail detail, String message) {
|
||||
updateStatus(ThingStatus.OFFLINE, detail, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates pending status off the Bridge (usualay when Qbus client id not connected)
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
public void bridgePending(String message) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_CONFIGURATION_PENDING, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put bridge online when error in communication resolved.
|
||||
*/
|
||||
public void bridgeOnline() {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a timer that check the communication with Qbus server/client and tries to re-establish communication.
|
||||
*
|
||||
* @param refreshInterval Time before refresh in minutes.
|
||||
*/
|
||||
private void setupRefreshTimer(int refreshInterval) {
|
||||
ScheduledFuture<?> timer = refreshTimer;
|
||||
|
||||
if (timer != null) {
|
||||
timer.cancel(true);
|
||||
refreshTimer = null;
|
||||
}
|
||||
|
||||
if (refreshInterval == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
refreshTimer = scheduler.scheduleWithFixedDelay(() -> {
|
||||
QbusCommunication comm = getCommunication();
|
||||
Integer serverCheck = getServerCheck();
|
||||
|
||||
if (comm != null) {
|
||||
if (serverCheck != null) {
|
||||
if (!comm.communicationActive()) {
|
||||
// Disconnected from Qbus Server, restart communication
|
||||
try {
|
||||
comm.startCommunication();
|
||||
} catch (InterruptedException e) {
|
||||
String msg = e.getMessage();
|
||||
bridgeOffline(ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Communication wit Qbus server could not be established, will try to reconnect every "
|
||||
+ serverCheck + " minutes. InterruptedException: " + msg);
|
||||
} catch (IOException e) {
|
||||
String msg = e.getMessage();
|
||||
bridgeOffline(ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Communication wit Qbus server could not be established, will try to reconnect every "
|
||||
+ serverCheck + " minutes. IOException: " + msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, refreshInterval, refreshInterval, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes the Bridge and stops communication with the Qbus server
|
||||
*/
|
||||
@Override
|
||||
public void dispose() {
|
||||
ScheduledFuture<?> timer = refreshTimer;
|
||||
if (timer != null) {
|
||||
timer.cancel(true);
|
||||
}
|
||||
|
||||
refreshTimer = null;
|
||||
|
||||
QbusCommunication comm = getCommunication();
|
||||
|
||||
if (comm != null) {
|
||||
try {
|
||||
comm.stopCommunication();
|
||||
} catch (IOException e) {
|
||||
String message = e.toString();
|
||||
logger.debug("Error on stopping communication.{} ", message);
|
||||
}
|
||||
}
|
||||
|
||||
comm = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconnect to Qbus server if controller is offline
|
||||
*/
|
||||
public void ctdOffline() {
|
||||
bridgePending("Waiting for CTD connection");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get BridgeCommunication
|
||||
*
|
||||
* @return BridgeCommunication
|
||||
*/
|
||||
public @Nullable QbusCommunication getQbusCommunication() {
|
||||
if (this.qbusComm != null) {
|
||||
return this.qbusComm;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets BridgeCommunication
|
||||
*
|
||||
* @param BridgeCommunication
|
||||
*/
|
||||
void setQbusCommunication(QbusCommunication comm) {
|
||||
this.qbusComm = comm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the status off the Bridge
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ThingStatus getStatus() {
|
||||
return thing.getStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the status off the Bridge
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ThingStatusDetail getStatusDetails() {
|
||||
ThingStatusInfo status = thing.getStatusInfo();
|
||||
ThingStatusDetail detail = status.getStatusDetail();
|
||||
return detail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the configuration parameters
|
||||
*/
|
||||
protected void readConfig() {
|
||||
bridgeConfig = getConfig().as(QbusConfiguration.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Qbus communication object.
|
||||
*
|
||||
* @return Qbus communication object
|
||||
*/
|
||||
public @Nullable QbusCommunication getCommunication() {
|
||||
return this.qbusComm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ip address of the Qbus server.
|
||||
*
|
||||
* @return the ip address
|
||||
*/
|
||||
public @Nullable String getAddress() {
|
||||
QbusConfiguration localConfig = this.bridgeConfig;
|
||||
|
||||
if (localConfig != null) {
|
||||
return localConfig.addr;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the listening port of the Qbus server.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public @Nullable Integer getPort() {
|
||||
QbusConfiguration localConfig = this.bridgeConfig;
|
||||
|
||||
if (localConfig != null) {
|
||||
return localConfig.port;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the serial nr of the Qbus server.
|
||||
*
|
||||
* @return the serial nr of the controller
|
||||
*/
|
||||
public @Nullable String getSn() {
|
||||
QbusConfiguration localConfig = this.bridgeConfig;
|
||||
|
||||
if (localConfig != null) {
|
||||
return localConfig.sn;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the refresh interval.
|
||||
*
|
||||
* @return the refresh interval
|
||||
*/
|
||||
public @Nullable Integer getServerCheck() {
|
||||
QbusConfiguration localConfig = this.bridgeConfig;
|
||||
|
||||
if (localConfig != null) {
|
||||
return localConfig.serverCheck;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
|
||||
package org.openhab.binding.qbus.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Class {@link QbusConfiguration} Configuration Class
|
||||
*
|
||||
* @author Koen Schockaert - Initial Contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class QbusConfiguration {
|
||||
public @Nullable String addr;
|
||||
public @Nullable Integer port;
|
||||
public @Nullable String sn;
|
||||
public @Nullable Integer serverCheck;
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.qbus.internal;
|
||||
|
||||
import static org.openhab.binding.qbus.internal.QbusBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.qbus.internal.handler.QbusBistabielHandler;
|
||||
import org.openhab.binding.qbus.internal.handler.QbusCO2Handler;
|
||||
import org.openhab.binding.qbus.internal.handler.QbusDimmerHandler;
|
||||
import org.openhab.binding.qbus.internal.handler.QbusRolHandler;
|
||||
import org.openhab.binding.qbus.internal.handler.QbusSceneHandler;
|
||||
import org.openhab.binding.qbus.internal.handler.QbusThermostatHandler;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
|
||||
/**
|
||||
* The {@link qbusHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Koen Schockaert - Initial Contribution
|
||||
*/
|
||||
|
||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.qbus")
|
||||
@NonNullByDefault
|
||||
public class QbusHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID) || BRIDGE_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
if (BRIDGE_THING_TYPES_UIDS.contains(thing.getThingTypeUID())) {
|
||||
QbusBridgeHandler handler = new QbusBridgeHandler((Bridge) thing);
|
||||
return handler;
|
||||
} else if (SCENE_THING_TYPES_UIDS.contains(thing.getThingTypeUID())) {
|
||||
return new QbusSceneHandler(thing);
|
||||
} else if (BISTABIEL_THING_TYPES_UIDS.contains(thing.getThingTypeUID())) {
|
||||
return new QbusBistabielHandler(thing);
|
||||
} else if (THERMOSTAT_THING_TYPES_UIDS.contains(thing.getThingTypeUID())) {
|
||||
return new QbusThermostatHandler(thing);
|
||||
} else if (DIMMER_THING_TYPES_UIDS.contains(thing.getThingTypeUID())) {
|
||||
return new QbusDimmerHandler(thing);
|
||||
} else if (CO2_THING_TYPES_UIDS.contains(thing.getThingTypeUID())) {
|
||||
return new QbusCO2Handler(thing);
|
||||
} else if (ROLLERSHUTTER_THING_TYPES_UIDS.contains(thing.getThingTypeUID())) {
|
||||
return new QbusRolHandler(thing);
|
||||
} else if (ROLLERSHUTTER_SLATS_THING_TYPES_UIDS.contains(thing.getThingTypeUID())) {
|
||||
return new QbusRolHandler(thing);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,244 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.qbus.internal.handler;
|
||||
|
||||
import static org.openhab.binding.qbus.internal.QbusBindingConstants.CHANNEL_SWITCH;
|
||||
import static org.openhab.core.types.RefreshType.REFRESH;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.qbus.internal.QbusBridgeHandler;
|
||||
import org.openhab.binding.qbus.internal.protocol.QbusBistabiel;
|
||||
import org.openhab.binding.qbus.internal.protocol.QbusCommunication;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link QbusBistabielHandler} is responsible for handling the Bistable outputs of Qbus
|
||||
*
|
||||
* @author Koen Schockaert - Initial Contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class QbusBistabielHandler extends QbusGlobalHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(QbusBistabielHandler.class);
|
||||
|
||||
protected @Nullable QbusThingsConfig bistabielConfig = new QbusThingsConfig();
|
||||
|
||||
private @Nullable Integer bistabielId;
|
||||
|
||||
private @Nullable String sn;
|
||||
|
||||
public QbusBistabielHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main initialization
|
||||
*/
|
||||
@Override
|
||||
public void initialize() {
|
||||
readConfig();
|
||||
|
||||
this.bistabielId = getId();
|
||||
|
||||
setSN();
|
||||
|
||||
scheduler.submit(() -> {
|
||||
QbusCommunication controllerComm;
|
||||
|
||||
if (this.bistabielId != null) {
|
||||
controllerComm = getCommunication("Bistabiel", this.bistabielId);
|
||||
} else {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR, "ID for BISTABIEL no set! " + this.bistabielId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (controllerComm == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"ID for BISTABIEL not known in controller " + this.bistabielId);
|
||||
return;
|
||||
}
|
||||
|
||||
Map<Integer, QbusBistabiel> bistabielCommLocal = controllerComm.getBistabiel();
|
||||
|
||||
QbusBistabiel outputLocal = bistabielCommLocal.get(this.bistabielId);
|
||||
|
||||
if (outputLocal == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"Bridge could not initialize BISTABIEL ID " + this.bistabielId);
|
||||
return;
|
||||
}
|
||||
|
||||
outputLocal.setThingHandler(this);
|
||||
handleStateUpdate(outputLocal);
|
||||
|
||||
QbusBridgeHandler qBridgeHandler = getBridgeHandler("Bistabiel", this.bistabielId);
|
||||
|
||||
if (qBridgeHandler != null) {
|
||||
if (qBridgeHandler.getStatus() == ThingStatus.ONLINE) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE,
|
||||
"Bridge offline for BISTABIEL ID " + this.bistabielId);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the status update from the bistabiel
|
||||
*/
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
QbusCommunication qComm = getCommunication("Bistabiel", this.bistabielId);
|
||||
|
||||
if (qComm == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"ID for BISTABIEL not known in controller " + this.bistabielId);
|
||||
return;
|
||||
} else {
|
||||
Map<Integer, QbusBistabiel> bistabielComm = qComm.getBistabiel();
|
||||
|
||||
QbusBistabiel qBistabiel = bistabielComm.get(this.bistabielId);
|
||||
|
||||
if (qBistabiel == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"ID for BISTABIEL not known in controller " + this.bistabielId);
|
||||
return;
|
||||
} else {
|
||||
scheduler.submit(() -> {
|
||||
if (!qComm.communicationActive()) {
|
||||
restartCommunication(qComm, "Bistabiel", this.bistabielId);
|
||||
}
|
||||
|
||||
if (qComm.communicationActive()) {
|
||||
if (command == REFRESH) {
|
||||
handleStateUpdate(qBistabiel);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_SWITCH:
|
||||
try {
|
||||
handleSwitchCommand(qBistabiel, command);
|
||||
} catch (IOException e) {
|
||||
String message = e.getMessage();
|
||||
logger.warn("Error on executing Switch for bistabiel ID {}. IOException: {}",
|
||||
this.bistabielId, message);
|
||||
} catch (InterruptedException e) {
|
||||
String message = e.getMessage();
|
||||
logger.warn(
|
||||
"Error on executing Switch for bistabiel ID {}. Interruptedexception {}",
|
||||
this.bistabielId, message);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
thingOffline(ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Unknown Channel " + channelUID.getId());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the switch command
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private void handleSwitchCommand(QbusBistabiel qBistabiel, Command command)
|
||||
throws InterruptedException, IOException {
|
||||
String snr = getSN();
|
||||
if (snr != null) {
|
||||
if (command instanceof OnOffType) {
|
||||
if (command == OnOffType.OFF) {
|
||||
qBistabiel.execute(0, snr);
|
||||
} else {
|
||||
qBistabiel.execute(100, snr);
|
||||
}
|
||||
} else {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"No serial number configured for BISTABIEL " + this.bistabielId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to update state of channel, called from Qbus Bistabiel.
|
||||
*
|
||||
* @param qBistabiel
|
||||
*/
|
||||
public void handleStateUpdate(QbusBistabiel qBistabiel) {
|
||||
Integer bistabielState = qBistabiel.getState();
|
||||
if (bistabielState != null) {
|
||||
updateState(CHANNEL_SWITCH, (bistabielState == 0) ? OnOffType.OFF : OnOffType.ON);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the serial number of the controller
|
||||
*
|
||||
* @return the serial nr
|
||||
*/
|
||||
public @Nullable String getSN() {
|
||||
return sn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the serial number of the controller
|
||||
*/
|
||||
public void setSN() {
|
||||
QbusBridgeHandler qBridgeHandler = getBridgeHandler("Bistabiel", this.bistabielId);
|
||||
if (qBridgeHandler == null) {
|
||||
thingOffline(ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"No communication with Qbus Bridge for BISTABIEL " + this.bistabielId);
|
||||
return;
|
||||
}
|
||||
sn = qBridgeHandler.getSn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the configuration
|
||||
*/
|
||||
protected synchronized void readConfig() {
|
||||
bistabielConfig = getConfig().as(QbusThingsConfig.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Id from the configuration
|
||||
*
|
||||
* @return outputId
|
||||
*/
|
||||
public @Nullable Integer getId() {
|
||||
QbusThingsConfig localConfig = bistabielConfig;
|
||||
if (localConfig != null) {
|
||||
return localConfig.bistabielId;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,197 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.qbus.internal.handler;
|
||||
|
||||
import static org.openhab.binding.qbus.internal.QbusBindingConstants.CHANNEL_CO2;
|
||||
import static org.openhab.core.types.RefreshType.REFRESH;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.qbus.internal.QbusBridgeHandler;
|
||||
import org.openhab.binding.qbus.internal.protocol.QbusCO2;
|
||||
import org.openhab.binding.qbus.internal.protocol.QbusCommunication;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.Command;
|
||||
|
||||
/**
|
||||
* The {@link QbusCO2Handler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Koen Schockaert - Initial Contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class QbusCO2Handler extends QbusGlobalHandler {
|
||||
protected @Nullable QbusThingsConfig config;
|
||||
|
||||
protected @Nullable QbusThingsConfig co2Config = new QbusThingsConfig();
|
||||
|
||||
private @Nullable Integer co2Id;
|
||||
|
||||
private @Nullable String sn;
|
||||
|
||||
public QbusCO2Handler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main initialization
|
||||
*/
|
||||
@Override
|
||||
public void initialize() {
|
||||
readConfig();
|
||||
|
||||
this.co2Id = getId();
|
||||
|
||||
setSN();
|
||||
|
||||
scheduler.submit(() -> {
|
||||
QbusCommunication controllerComm;
|
||||
|
||||
if (this.co2Id != null) {
|
||||
controllerComm = getCommunication("CO2", this.co2Id);
|
||||
} else {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR, "ID for CO2 no set! " + this.co2Id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (controllerComm == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR, "ID for CO2 not known in controller " + this.co2Id);
|
||||
return;
|
||||
}
|
||||
|
||||
Map<Integer, QbusCO2> co2CommLocal = controllerComm.getCo2();
|
||||
|
||||
QbusCO2 outputLocal = co2CommLocal.get(this.co2Id);
|
||||
|
||||
if (outputLocal == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR, "Bridge could not initialize CO2 ID " + this.co2Id);
|
||||
return;
|
||||
}
|
||||
|
||||
outputLocal.setThingHandler(this);
|
||||
handleStateUpdate(outputLocal);
|
||||
|
||||
QbusBridgeHandler qBridgeHandler = getBridgeHandler("CO2", this.co2Id);
|
||||
|
||||
if (qBridgeHandler != null) {
|
||||
if (qBridgeHandler.getStatus() == ThingStatus.ONLINE) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE,
|
||||
"Bridge offline for CO2 ID " + this.co2Id);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the status update from the thing
|
||||
*/
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
QbusCommunication qComm = getCommunication("CO2", this.co2Id);
|
||||
|
||||
if (qComm == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR, "ID for CO2 not known in controller " + this.co2Id);
|
||||
return;
|
||||
} else {
|
||||
Map<Integer, QbusCO2> co2Comm = qComm.getCo2();
|
||||
|
||||
QbusCO2 qCo2 = co2Comm.get(this.co2Id);
|
||||
|
||||
if (qCo2 == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR, "ID for CO2 not known in controller " + this.co2Id);
|
||||
return;
|
||||
} else {
|
||||
scheduler.submit(() -> {
|
||||
if (!qComm.communicationActive()) {
|
||||
restartCommunication(qComm, "CO2", this.co2Id);
|
||||
}
|
||||
|
||||
if (qComm.communicationActive()) {
|
||||
if (command == REFRESH) {
|
||||
handleStateUpdate(qCo2);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (channelUID.getId()) {
|
||||
default:
|
||||
thingOffline(ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Unknown Channel " + channelUID.getId());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to update state of channel, called from Qbus CO2.
|
||||
*/
|
||||
public void handleStateUpdate(QbusCO2 qCo2) {
|
||||
Integer co2State = qCo2.getState();
|
||||
if (co2State != null) {
|
||||
updateState(CHANNEL_CO2, new DecimalType(co2State));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the serial number of the controller
|
||||
*
|
||||
* @return the serial nr
|
||||
*/
|
||||
public @Nullable String getSN() {
|
||||
return sn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the serial number of the controller
|
||||
*/
|
||||
public void setSN() {
|
||||
QbusBridgeHandler qBridgeHandler = getBridgeHandler("CO2", this.co2Id);
|
||||
if (qBridgeHandler == null) {
|
||||
thingOffline(ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"No communication with Qbus Bridge for CO2 " + this.co2Id);
|
||||
return;
|
||||
}
|
||||
sn = qBridgeHandler.getSn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the configuration
|
||||
*/
|
||||
protected synchronized void readConfig() {
|
||||
co2Config = getConfig().as(QbusThingsConfig.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Id from the configuration
|
||||
*
|
||||
* @return outputId
|
||||
*/
|
||||
public @Nullable Integer getId() {
|
||||
QbusThingsConfig localConfig = this.co2Config;
|
||||
if (localConfig != null) {
|
||||
return localConfig.co2Id;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,310 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.qbus.internal.handler;
|
||||
|
||||
import static org.openhab.binding.qbus.internal.QbusBindingConstants.*;
|
||||
import static org.openhab.core.types.RefreshType.REFRESH;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.qbus.internal.QbusBridgeHandler;
|
||||
import org.openhab.binding.qbus.internal.protocol.QbusCommunication;
|
||||
import org.openhab.binding.qbus.internal.protocol.QbusDimmer;
|
||||
import org.openhab.core.library.types.IncreaseDecreaseType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link QbusDimmerHandler} is responsible for handling the dimmable outputs of Qbus
|
||||
*
|
||||
* @author Koen Schockaert - Initial Contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class QbusDimmerHandler extends QbusGlobalHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(QbusDimmerHandler.class);
|
||||
|
||||
protected @Nullable QbusThingsConfig dimmerConfig = new QbusThingsConfig();
|
||||
|
||||
private @Nullable Integer dimmerId;
|
||||
|
||||
private @Nullable String sn;
|
||||
|
||||
public QbusDimmerHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main initialization
|
||||
*/
|
||||
@Override
|
||||
public void initialize() {
|
||||
readConfig();
|
||||
|
||||
this.dimmerId = getId();
|
||||
|
||||
setSN();
|
||||
|
||||
scheduler.submit(() -> {
|
||||
QbusCommunication controllerComm;
|
||||
|
||||
if (this.dimmerId != null) {
|
||||
controllerComm = getCommunication("Dimmer", this.dimmerId);
|
||||
} else {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR, "ID for DIMMER no set! " + this.dimmerId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (controllerComm == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"ID for DIMMER not known in controller " + this.dimmerId);
|
||||
return;
|
||||
}
|
||||
|
||||
Map<Integer, QbusDimmer> dimmerCommLocal = controllerComm.getDimmer();
|
||||
|
||||
QbusDimmer outputLocal = dimmerCommLocal.get(this.dimmerId);
|
||||
|
||||
if (outputLocal == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"Bridge could not initialize DIMMER ID " + this.dimmerId);
|
||||
return;
|
||||
}
|
||||
|
||||
outputLocal.setThingHandler(this);
|
||||
handleStateUpdate(outputLocal);
|
||||
|
||||
QbusBridgeHandler qBridgeHandler = getBridgeHandler("Dimmer", this.dimmerId);
|
||||
|
||||
if (qBridgeHandler != null) {
|
||||
if (qBridgeHandler.getStatus() == ThingStatus.ONLINE) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE,
|
||||
"Bridge offline for DIMMER ID " + this.dimmerId);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the status update from the dimmer
|
||||
*/
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
QbusCommunication qComm = getCommunication("Dimmer", this.dimmerId);
|
||||
|
||||
if (qComm == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"ID for DIMMER not known in controller " + this.dimmerId);
|
||||
return;
|
||||
} else {
|
||||
Map<Integer, QbusDimmer> dimmerComm = qComm.getDimmer();
|
||||
|
||||
QbusDimmer qDimmer = dimmerComm.get(this.dimmerId);
|
||||
|
||||
if (qDimmer == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"ID for DIMMER not known in controller " + this.dimmerId);
|
||||
return;
|
||||
} else {
|
||||
scheduler.submit(() -> {
|
||||
if (!qComm.communicationActive()) {
|
||||
restartCommunication(qComm, "Dimmer", this.dimmerId);
|
||||
}
|
||||
|
||||
if (qComm.communicationActive()) {
|
||||
if (command == REFRESH) {
|
||||
handleStateUpdate(qDimmer);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_SWITCH:
|
||||
try {
|
||||
handleSwitchCommand(qDimmer, command);
|
||||
} catch (IOException e) {
|
||||
String message = e.getMessage();
|
||||
logger.warn("Error on executing Switch for dimmer ID {}. IOException: {}",
|
||||
this.dimmerId, message);
|
||||
} catch (InterruptedException e) {
|
||||
String message = e.getMessage();
|
||||
logger.warn("Error on executing Switch for dimmer ID {}. Interruptedexception {}",
|
||||
this.dimmerId, message);
|
||||
}
|
||||
break;
|
||||
|
||||
case CHANNEL_BRIGHTNESS:
|
||||
try {
|
||||
handleBrightnessCommand(qDimmer, command);
|
||||
} catch (IOException e) {
|
||||
String message = e.getMessage();
|
||||
logger.warn("Error on executing Brightness for dimmer ID {}. IOException: {}",
|
||||
this.dimmerId, message);
|
||||
} catch (InterruptedException e) {
|
||||
String message = e.getMessage();
|
||||
logger.warn(
|
||||
"Error on executing Brightness for dimmer ID {}. Interruptedexception {}",
|
||||
this.dimmerId, message);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
thingOffline(ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Unknown Channel " + channelUID.getId());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the switch command
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private void handleSwitchCommand(QbusDimmer qDimmer, Command command) throws InterruptedException, IOException {
|
||||
if (command instanceof OnOffType) {
|
||||
String snr = getSN();
|
||||
if (snr != null) {
|
||||
if (command == OnOffType.OFF) {
|
||||
qDimmer.execute(0, snr);
|
||||
} else {
|
||||
qDimmer.execute(1000, snr);
|
||||
}
|
||||
} else {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"No serial number configured for DIMMER " + this.dimmerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the brightness command
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private void handleBrightnessCommand(QbusDimmer qDimmer, Command command) throws InterruptedException, IOException {
|
||||
String snr = getSN();
|
||||
|
||||
if (snr == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"No serial number configured for DIMMER " + this.dimmerId);
|
||||
return;
|
||||
} else {
|
||||
if (command instanceof OnOffType) {
|
||||
if (command == OnOffType.OFF) {
|
||||
qDimmer.execute(0, snr);
|
||||
} else {
|
||||
qDimmer.execute(100, snr);
|
||||
}
|
||||
} else if (command instanceof IncreaseDecreaseType) {
|
||||
int stepValue = ((Number) getConfig().get(CONFIG_STEP_VALUE)).intValue();
|
||||
Integer currentValue = qDimmer.getState();
|
||||
Integer newValue;
|
||||
Integer sendvalue;
|
||||
if (currentValue != null) {
|
||||
if (command == IncreaseDecreaseType.INCREASE) {
|
||||
newValue = currentValue + stepValue;
|
||||
// round down to step multiple
|
||||
newValue = newValue - newValue % stepValue;
|
||||
sendvalue = newValue > 100 ? 100 : newValue;
|
||||
qDimmer.execute(sendvalue, snr);
|
||||
} else {
|
||||
newValue = currentValue - stepValue;
|
||||
// round up to step multiple
|
||||
newValue = newValue + newValue % stepValue;
|
||||
sendvalue = newValue < 0 ? 0 : newValue;
|
||||
qDimmer.execute(sendvalue, snr);
|
||||
}
|
||||
}
|
||||
} else if (command instanceof PercentType) {
|
||||
int percentToInt = ((PercentType) command).intValue();
|
||||
if (command == PercentType.ZERO) {
|
||||
qDimmer.execute(0, snr);
|
||||
} else {
|
||||
qDimmer.execute(percentToInt, snr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to update state of channel, called from Qbus Dimmer.
|
||||
*
|
||||
* @param qDimmer
|
||||
*/
|
||||
public void handleStateUpdate(QbusDimmer qDimmer) {
|
||||
Integer dimmerState = qDimmer.getState();
|
||||
if (dimmerState != null) {
|
||||
updateState(CHANNEL_BRIGHTNESS, new PercentType(dimmerState));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the serial number of the controller
|
||||
*
|
||||
* @return the serial number
|
||||
*/
|
||||
public @Nullable String getSN() {
|
||||
return sn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the serial number of the controller
|
||||
*/
|
||||
public void setSN() {
|
||||
QbusBridgeHandler qBridgeHandler = getBridgeHandler("Dimmer", this.dimmerId);
|
||||
if (qBridgeHandler == null) {
|
||||
thingOffline(ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"No communication with Qbus Bridge for DIMMER " + this.dimmerId);
|
||||
return;
|
||||
}
|
||||
this.sn = qBridgeHandler.getSn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the configuration
|
||||
*/
|
||||
protected synchronized void readConfig() {
|
||||
dimmerConfig = getConfig().as(QbusThingsConfig.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Id from the configuration
|
||||
*
|
||||
* @return outputId
|
||||
*/
|
||||
public @Nullable Integer getId() {
|
||||
QbusThingsConfig localConfig = dimmerConfig;
|
||||
if (localConfig != null) {
|
||||
return localConfig.dimmerId;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.qbus.internal.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.qbus.internal.QbusBridgeHandler;
|
||||
import org.openhab.binding.qbus.internal.protocol.QbusCommunication;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
|
||||
/**
|
||||
* The {@link QbusGlobalHandler} is used in other handlers, to share the functions.
|
||||
*
|
||||
* @author Koen Schockaert - Initial Contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public abstract class QbusGlobalHandler extends BaseThingHandler {
|
||||
|
||||
public QbusGlobalHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Bridge communication
|
||||
*
|
||||
* @param type
|
||||
* @param globalId
|
||||
* @return
|
||||
*/
|
||||
public @Nullable QbusCommunication getCommunication(String type, @Nullable Integer globalId) {
|
||||
QbusBridgeHandler qBridgeHandler = null;
|
||||
if (globalId != null) {
|
||||
qBridgeHandler = getBridgeHandler(type, globalId);
|
||||
}
|
||||
|
||||
if (qBridgeHandler == null) {
|
||||
updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.BRIDGE_UNINITIALIZED,
|
||||
"No bridge handler initialized for " + type + " with id " + globalId + ".");
|
||||
return null;
|
||||
}
|
||||
QbusCommunication qComm = qBridgeHandler.getCommunication();
|
||||
return qComm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Bridge handler
|
||||
*
|
||||
* @param type
|
||||
* @param globalId
|
||||
* @return
|
||||
*/
|
||||
public @Nullable QbusBridgeHandler getBridgeHandler(String type, @Nullable Integer globalId) {
|
||||
Bridge qBridge = getBridge();
|
||||
if (qBridge == null) {
|
||||
updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.BRIDGE_UNINITIALIZED,
|
||||
"No bridge initialized for " + type + " with ID " + globalId);
|
||||
return null;
|
||||
}
|
||||
QbusBridgeHandler qBridgeHandler = (QbusBridgeHandler) qBridge.getHandler();
|
||||
return qBridgeHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param qComm
|
||||
* @param type
|
||||
* @param globalId
|
||||
*/
|
||||
public void restartCommunication(QbusCommunication qComm, String type, @Nullable Integer globalId) {
|
||||
try {
|
||||
qComm.restartCommunication();
|
||||
} catch (InterruptedException e) {
|
||||
String message = e.toString();
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, message);
|
||||
} catch (IOException e) {
|
||||
String message = e.toString();
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, message);
|
||||
}
|
||||
|
||||
QbusBridgeHandler qBridgeHandler = getBridgeHandler(type, globalId);
|
||||
|
||||
if (qBridgeHandler != null && qComm.communicationActive()) {
|
||||
qBridgeHandler.bridgeOnline();
|
||||
} else {
|
||||
thingOffline(ThingStatusDetail.COMMUNICATION_ERROR, "Communication socket error");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Put thing offline
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
public void thingOffline(ThingStatusDetail detail, String message) {
|
||||
updateStatus(ThingStatus.OFFLINE, detail, message);
|
||||
}
|
||||
}
|
@ -0,0 +1,333 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.qbus.internal.handler;
|
||||
|
||||
import static org.openhab.binding.qbus.internal.QbusBindingConstants.*;
|
||||
import static org.openhab.core.library.types.UpDownType.DOWN;
|
||||
import static org.openhab.core.types.RefreshType.REFRESH;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.qbus.internal.QbusBridgeHandler;
|
||||
import org.openhab.binding.qbus.internal.protocol.QbusCommunication;
|
||||
import org.openhab.binding.qbus.internal.protocol.QbusRol;
|
||||
import org.openhab.core.library.types.IncreaseDecreaseType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.library.types.UpDownType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link QbusRolHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Koen Schockaert - Initial Contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class QbusRolHandler extends QbusGlobalHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(QbusRolHandler.class);
|
||||
|
||||
protected @Nullable QbusThingsConfig rolConfig = new QbusThingsConfig();
|
||||
|
||||
private @Nullable Integer rolId;
|
||||
|
||||
private @Nullable String sn;
|
||||
|
||||
public QbusRolHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main initialization
|
||||
*/
|
||||
@Override
|
||||
public void initialize() {
|
||||
readConfig();
|
||||
|
||||
this.rolId = getId();
|
||||
|
||||
setSN();
|
||||
|
||||
scheduler.submit(() -> {
|
||||
QbusCommunication controllerComm;
|
||||
|
||||
if (this.rolId != null) {
|
||||
controllerComm = getCommunication("Screen/Store", this.rolId);
|
||||
} else {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR, "ID for Screen/Store no set! " + this.rolId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (controllerComm == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"ID for Screen/Store not known in controller " + this.rolId);
|
||||
return;
|
||||
}
|
||||
|
||||
Map<Integer, QbusRol> rolCommLocal = controllerComm.getRol();
|
||||
|
||||
QbusRol outputLocal = rolCommLocal.get(this.rolId);
|
||||
|
||||
if (outputLocal == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"Bridge could not initialize Screen/Store ID " + this.rolId);
|
||||
return;
|
||||
}
|
||||
|
||||
outputLocal.setThingHandler(this);
|
||||
handleStateUpdate(outputLocal);
|
||||
|
||||
QbusBridgeHandler qBridgeHandler = getBridgeHandler("Screen/Store", this.rolId);
|
||||
|
||||
if (qBridgeHandler != null) {
|
||||
if (qBridgeHandler.getStatus() == ThingStatus.ONLINE) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE,
|
||||
"Bridge offline for SCREEN/STORE ID " + this.rolId);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the status update from the thing
|
||||
*/
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
QbusCommunication qComm = getCommunication("Screen/Store", this.rolId);
|
||||
|
||||
if (qComm == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"ID for ROLLERSHUTTER/SCREEN not known in controller " + this.rolId);
|
||||
return;
|
||||
} else {
|
||||
Map<Integer, QbusRol> rolComm = qComm.getRol();
|
||||
|
||||
QbusRol qRol = rolComm.get(this.rolId);
|
||||
|
||||
if (qRol == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"ID for ROLLERSHUTTER/SCREEN not known in controller " + this.rolId);
|
||||
return;
|
||||
} else {
|
||||
scheduler.submit(() -> {
|
||||
if (!qComm.communicationActive()) {
|
||||
restartCommunication(qComm, "Screen/Store", this.rolId);
|
||||
}
|
||||
|
||||
if (qComm.communicationActive()) {
|
||||
if (command == REFRESH) {
|
||||
handleStateUpdate(qRol);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_ROLLERSHUTTER:
|
||||
try {
|
||||
handleScreenposCommand(qRol, command);
|
||||
} catch (IOException e) {
|
||||
String message = e.getMessage();
|
||||
logger.warn("Error on executing Rollershutter for screen ID {}. IOException: {}",
|
||||
this.rolId, message);
|
||||
} catch (InterruptedException e) {
|
||||
String message = e.toString();
|
||||
logger.warn(
|
||||
"Error on executing Rollershutter for screen ID {}. Interruptedexception {}",
|
||||
this.rolId, message);
|
||||
}
|
||||
break;
|
||||
|
||||
case CHANNEL_SLATS:
|
||||
try {
|
||||
handleSlatsposCommand(qRol, command);
|
||||
} catch (IOException e) {
|
||||
String message = e.getMessage();
|
||||
logger.warn("Error on executing Slats for screen ID {}. IOException: {}",
|
||||
this.rolId, message);
|
||||
} catch (InterruptedException e) {
|
||||
String message = e.toString();
|
||||
logger.warn("Error on executing Slats for screen ID {}. Interruptedexception {}",
|
||||
this.rolId, message);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command for screen up/down position
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private void handleScreenposCommand(QbusRol qRol, Command command) throws InterruptedException, IOException {
|
||||
String snr = getSN();
|
||||
if (snr != null) {
|
||||
if (command instanceof UpDownType) {
|
||||
UpDownType upDown = (UpDownType) command;
|
||||
if (upDown == DOWN) {
|
||||
qRol.execute(0, snr);
|
||||
} else {
|
||||
qRol.execute(100, snr);
|
||||
}
|
||||
} else if (command instanceof IncreaseDecreaseType) {
|
||||
IncreaseDecreaseType inc = (IncreaseDecreaseType) command;
|
||||
int stepValue = ((Number) getConfig().get(CONFIG_STEP_VALUE)).intValue();
|
||||
Integer currentValue = qRol.getState();
|
||||
int newValue;
|
||||
int sendValue;
|
||||
if (currentValue != null) {
|
||||
if (inc == IncreaseDecreaseType.INCREASE) {
|
||||
newValue = currentValue + stepValue;
|
||||
// round down to step multiple
|
||||
newValue = newValue - newValue % stepValue;
|
||||
sendValue = newValue > 100 ? 100 : newValue;
|
||||
qRol.execute(sendValue, snr);
|
||||
} else {
|
||||
newValue = currentValue - stepValue;
|
||||
// round up to step multiple
|
||||
newValue = newValue + newValue % stepValue;
|
||||
sendValue = newValue > 100 ? 100 : newValue;
|
||||
qRol.execute(sendValue, snr);
|
||||
}
|
||||
}
|
||||
} else if (command instanceof PercentType) {
|
||||
PercentType p = (PercentType) command;
|
||||
int pp = p.intValue();
|
||||
if (p == PercentType.ZERO) {
|
||||
qRol.execute(0, snr);
|
||||
} else {
|
||||
qRol.execute(pp, snr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command for screen slats position
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private void handleSlatsposCommand(QbusRol qRol, Command command) throws InterruptedException, IOException {
|
||||
String snr = getSN();
|
||||
if (snr != null) {
|
||||
if (command instanceof UpDownType) {
|
||||
if (command == DOWN) {
|
||||
qRol.executeSlats(0, snr);
|
||||
} else {
|
||||
qRol.executeSlats(100, snr);
|
||||
}
|
||||
} else if (command instanceof IncreaseDecreaseType) {
|
||||
int stepValue = ((Number) getConfig().get(CONFIG_STEP_VALUE)).intValue();
|
||||
Integer currentValue = qRol.getState();
|
||||
int newValue;
|
||||
int sendValue;
|
||||
if (currentValue != null) {
|
||||
if (command == IncreaseDecreaseType.INCREASE) {
|
||||
newValue = currentValue + stepValue;
|
||||
// round down to step multiple
|
||||
newValue = newValue - newValue % stepValue;
|
||||
sendValue = newValue > 100 ? 100 : newValue;
|
||||
qRol.executeSlats(sendValue, snr);
|
||||
} else {
|
||||
newValue = currentValue - stepValue;
|
||||
// round up to step multiple
|
||||
newValue = newValue + newValue % stepValue;
|
||||
sendValue = newValue > 100 ? 100 : newValue;
|
||||
qRol.executeSlats(sendValue, snr);
|
||||
}
|
||||
}
|
||||
} else if (command instanceof PercentType) {
|
||||
int percentToInt = ((PercentType) command).intValue();
|
||||
if (command == PercentType.ZERO) {
|
||||
qRol.executeSlats(0, snr);
|
||||
} else {
|
||||
qRol.executeSlats(percentToInt, snr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to update state of channel, called from Qbus Screen/Store.
|
||||
*/
|
||||
public void handleStateUpdate(QbusRol qRol) {
|
||||
Integer rolState = qRol.getState();
|
||||
Integer slatState = qRol.getStateSlats();
|
||||
|
||||
if (rolState != null) {
|
||||
updateState(CHANNEL_ROLLERSHUTTER, new PercentType(rolState));
|
||||
}
|
||||
if (slatState != null) {
|
||||
updateState(CHANNEL_SLATS, new PercentType(slatState));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the serial number of the controller
|
||||
*
|
||||
* @return the serial nr
|
||||
*/
|
||||
public @Nullable String getSN() {
|
||||
return sn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the serial number of the controller
|
||||
*/
|
||||
public void setSN() {
|
||||
QbusBridgeHandler qBridgeHandler = getBridgeHandler("Screen/Store", this.rolId);
|
||||
if (qBridgeHandler == null) {
|
||||
thingOffline(ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"No communication with Qbus Bridge for ROLLERSHUTTER/SCREEN " + this.rolId);
|
||||
return;
|
||||
}
|
||||
sn = qBridgeHandler.getSn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the configuration
|
||||
*/
|
||||
protected synchronized void readConfig() {
|
||||
rolConfig = getConfig().as(QbusThingsConfig.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Id from the configuration
|
||||
*
|
||||
* @return outputId
|
||||
*/
|
||||
public @Nullable Integer getId() {
|
||||
QbusThingsConfig localConfig = rolConfig;
|
||||
if (localConfig != null) {
|
||||
return localConfig.rolId;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,217 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.qbus.internal.handler;
|
||||
|
||||
import static org.openhab.binding.qbus.internal.QbusBindingConstants.CHANNEL_SCENE;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.qbus.internal.QbusBridgeHandler;
|
||||
import org.openhab.binding.qbus.internal.protocol.QbusCommunication;
|
||||
import org.openhab.binding.qbus.internal.protocol.QbusScene;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link QbusSceneHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Koen Schockaert - Initial Contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class QbusSceneHandler extends QbusGlobalHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(QbusSceneHandler.class);
|
||||
|
||||
protected @Nullable QbusThingsConfig sceneConfig = new QbusThingsConfig();
|
||||
|
||||
private @Nullable Integer sceneId;
|
||||
|
||||
private @Nullable String sn;
|
||||
|
||||
public QbusSceneHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main initialization
|
||||
*/
|
||||
@Override
|
||||
public void initialize() {
|
||||
readConfig();
|
||||
|
||||
this.sceneId = getId();
|
||||
|
||||
setSN();
|
||||
|
||||
scheduler.submit(() -> {
|
||||
QbusCommunication controllerComm;
|
||||
|
||||
if (this.sceneId != null) {
|
||||
controllerComm = getCommunication("Scene", this.sceneId);
|
||||
} else {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR, "ID for SCENE no set! " + this.sceneId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (controllerComm == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"ID for SCENE not known in controller " + this.sceneId);
|
||||
return;
|
||||
}
|
||||
|
||||
Map<Integer, QbusScene> sceneCommLocal = controllerComm.getScene();
|
||||
|
||||
QbusScene outputLocal = sceneCommLocal.get(this.sceneId);
|
||||
|
||||
if (outputLocal == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"Bridge could not initialize SCENE ID " + this.sceneId);
|
||||
return;
|
||||
}
|
||||
|
||||
outputLocal.setThingHandler(this);
|
||||
|
||||
QbusBridgeHandler qBridgeHandler = getBridgeHandler("Scene", this.sceneId);
|
||||
|
||||
if ((qBridgeHandler != null) && (qBridgeHandler.getStatus() == ThingStatus.ONLINE)) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
thingOffline(ThingStatusDetail.COMMUNICATION_ERROR, "Bridge offline for SCENE ID " + this.sceneId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the status update from the thing
|
||||
*/
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
QbusCommunication qComm = getCommunication("Scene", this.sceneId);
|
||||
|
||||
if (qComm == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR, "ID for SCENE not known in controller " + this.sceneId);
|
||||
return;
|
||||
} else {
|
||||
Map<Integer, QbusScene> sceneComm = qComm.getScene();
|
||||
QbusScene qScene = sceneComm.get(this.sceneId);
|
||||
|
||||
if (qScene == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"ID for SCENE not known in controller " + this.sceneId);
|
||||
return;
|
||||
} else {
|
||||
scheduler.submit(() -> {
|
||||
if (!qComm.communicationActive()) {
|
||||
restartCommunication(qComm, "Scene", this.sceneId);
|
||||
}
|
||||
|
||||
if (qComm.communicationActive()) {
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_SCENE:
|
||||
try {
|
||||
handleSwitchCommand(qScene, channelUID, command);
|
||||
} catch (IOException e) {
|
||||
String message = e.getMessage();
|
||||
logger.warn("Error on executing Scene for scene ID {}. IOException: {}",
|
||||
this.sceneId, message);
|
||||
} catch (InterruptedException e) {
|
||||
String message = e.getMessage();
|
||||
logger.warn("Error on executing Scene for scene ID {}. Interruptedexception {}",
|
||||
this.sceneId, message);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
thingOffline(ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Unknown Channel " + channelUID.getId());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the scene command
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
void handleSwitchCommand(QbusScene qScene, ChannelUID channelUID, Command command)
|
||||
throws InterruptedException, IOException {
|
||||
String snr = getSN();
|
||||
if (snr != null) {
|
||||
if (command instanceof OnOffType) {
|
||||
if (command == OnOffType.OFF) {
|
||||
qScene.execute(0, snr);
|
||||
} else {
|
||||
qScene.execute(100, snr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the serial number of the controller
|
||||
*
|
||||
* @return the serial nr
|
||||
*/
|
||||
public @Nullable String getSN() {
|
||||
return sn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the serial number of the controller
|
||||
*/
|
||||
public void setSN() {
|
||||
QbusBridgeHandler qBridgeHandler = getBridgeHandler("Scene", this.sceneId);
|
||||
if (qBridgeHandler == null) {
|
||||
thingOffline(ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"No communication with Qbus Bridge for SCENE " + this.sceneId);
|
||||
return;
|
||||
}
|
||||
sn = qBridgeHandler.getSn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the configuration
|
||||
*/
|
||||
protected synchronized void readConfig() {
|
||||
sceneConfig = getConfig().as(QbusThingsConfig.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Id from the configuration
|
||||
*
|
||||
* @return outputId
|
||||
*/
|
||||
public @Nullable Integer getId() {
|
||||
QbusThingsConfig localConfig = sceneConfig;
|
||||
if (localConfig != null) {
|
||||
return localConfig.sceneId;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,295 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.qbus.internal.handler;
|
||||
|
||||
import static org.openhab.binding.qbus.internal.QbusBindingConstants.*;
|
||||
import static org.openhab.core.library.unit.SIUnits.CELSIUS;
|
||||
import static org.openhab.core.types.RefreshType.REFRESH;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.qbus.internal.QbusBridgeHandler;
|
||||
import org.openhab.binding.qbus.internal.protocol.QbusCommunication;
|
||||
import org.openhab.binding.qbus.internal.protocol.QbusThermostat;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link QbusThermostatHandler} is responsible for handling the Thermostat outputs of Qbus
|
||||
*
|
||||
* @author Koen Schockaert - Initial Contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class QbusThermostatHandler extends QbusGlobalHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(QbusThermostatHandler.class);
|
||||
|
||||
protected @Nullable QbusThingsConfig thermostatConfig = new QbusThingsConfig();
|
||||
|
||||
private @Nullable Integer thermostatId;
|
||||
|
||||
private @Nullable String sn;
|
||||
|
||||
public QbusThermostatHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main initialization
|
||||
*/
|
||||
@Override
|
||||
public void initialize() {
|
||||
readConfig();
|
||||
|
||||
this.thermostatId = getId();
|
||||
|
||||
setSN();
|
||||
|
||||
scheduler.submit(() -> {
|
||||
QbusCommunication controllerComm;
|
||||
|
||||
if (this.thermostatId != null) {
|
||||
controllerComm = getCommunication("Thermostat", this.thermostatId);
|
||||
} else {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR, "ID for THERMOSTAT no set! " + this.thermostatId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (controllerComm == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"ID for THERMOSTAT not known in controller " + this.thermostatId);
|
||||
return;
|
||||
}
|
||||
|
||||
Map<Integer, QbusThermostat> thermostatlCommLocal = controllerComm.getThermostat();
|
||||
|
||||
QbusThermostat outputLocal = thermostatlCommLocal.get(this.thermostatId);
|
||||
|
||||
if (outputLocal == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"Bridge could not initialize THERMOSTAT ID " + this.thermostatId);
|
||||
return;
|
||||
}
|
||||
|
||||
outputLocal.setThingHandler(this);
|
||||
handleStateUpdate(outputLocal);
|
||||
|
||||
QbusBridgeHandler qBridgeHandler = getBridgeHandler("Thermostat", this.thermostatId);
|
||||
|
||||
if (qBridgeHandler != null) {
|
||||
if (qBridgeHandler.getStatus() == ThingStatus.ONLINE) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE,
|
||||
"Bridge offline for THERMOSTAT ID " + this.thermostatId);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the status update from the thermostat
|
||||
*/
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
QbusCommunication qComm = getCommunication("Thermostat", this.thermostatId);
|
||||
|
||||
if (qComm == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"ID for THERMOSTAT not known in controller " + this.thermostatId);
|
||||
return;
|
||||
} else {
|
||||
Map<Integer, QbusThermostat> thermostatComm = qComm.getThermostat();
|
||||
|
||||
QbusThermostat qThermostat = thermostatComm.get(this.thermostatId);
|
||||
|
||||
if (qThermostat == null) {
|
||||
thingOffline(ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"ID for THERMOSTAT not known in controller " + this.thermostatId);
|
||||
return;
|
||||
} else {
|
||||
scheduler.submit(() -> {
|
||||
if (!qComm.communicationActive()) {
|
||||
restartCommunication(qComm, "Thermostat", this.thermostatId);
|
||||
}
|
||||
|
||||
if (qComm.communicationActive()) {
|
||||
if (command == REFRESH) {
|
||||
handleStateUpdate(qThermostat);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_MODE:
|
||||
try {
|
||||
handleModeCommand(qThermostat, command);
|
||||
} catch (IOException e) {
|
||||
String message = e.getMessage();
|
||||
logger.warn("Error on executing Mode for thermostat ID {}. IOException: {} ",
|
||||
this.thermostatId, message);
|
||||
} catch (InterruptedException e) {
|
||||
String message = e.getMessage();
|
||||
logger.warn(
|
||||
"Error on executing Mode for thermostat ID {}. Interruptedexception {} ",
|
||||
this.thermostatId, message);
|
||||
}
|
||||
break;
|
||||
|
||||
case CHANNEL_SETPOINT:
|
||||
try {
|
||||
handleSetpointCommand(qThermostat, command);
|
||||
} catch (IOException e) {
|
||||
String message = e.getMessage();
|
||||
logger.warn("Error on executing Setpoint for thermostat ID {}. IOException: {} ",
|
||||
this.thermostatId, message);
|
||||
} catch (InterruptedException e) {
|
||||
String message = e.getMessage();
|
||||
logger.warn(
|
||||
"Error on executing Setpoint for thermostat ID {}. Interruptedexception {} ",
|
||||
this.thermostatId, message);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
thingOffline(ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Unknown Channel " + channelUID.getId());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the Mode command
|
||||
*
|
||||
* @param qThermostat
|
||||
* @param command
|
||||
* @param snr
|
||||
* @throws InterruptedException
|
||||
* @throws IOException
|
||||
*/
|
||||
private void handleModeCommand(QbusThermostat qThermostat, Command command)
|
||||
throws InterruptedException, IOException {
|
||||
String snr = getSN();
|
||||
if (snr != null) {
|
||||
if (command instanceof DecimalType) {
|
||||
int mode = ((DecimalType) command).intValue();
|
||||
qThermostat.executeMode(mode, snr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the Setpoint command
|
||||
*
|
||||
* @param qThermostat
|
||||
* @param command
|
||||
* @param snr
|
||||
* @throws InterruptedException
|
||||
* @throws IOException
|
||||
*/
|
||||
private void handleSetpointCommand(QbusThermostat qThermostat, Command command)
|
||||
throws InterruptedException, IOException {
|
||||
String snr = getSN();
|
||||
if (snr != null) {
|
||||
if (command instanceof QuantityType<?>) {
|
||||
QuantityType<?> s = (QuantityType<?>) command;
|
||||
double sp = s.doubleValue();
|
||||
QuantityType<?> spCelcius = s.toUnit(CELSIUS);
|
||||
|
||||
if (spCelcius != null) {
|
||||
qThermostat.executeSetpoint(sp, snr);
|
||||
} else {
|
||||
logger.warn("Could not set setpoint for thermostat (conversion failed) {}", this.thermostatId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to update state of all channels, called from Qbus thermostat.
|
||||
*
|
||||
* @param qThermostat
|
||||
*/
|
||||
public void handleStateUpdate(QbusThermostat qThermostat) {
|
||||
Double measured = qThermostat.getMeasured();
|
||||
if (measured != null) {
|
||||
updateState(CHANNEL_MEASURED, new QuantityType<>(measured, CELSIUS));
|
||||
}
|
||||
|
||||
Double setpoint = qThermostat.getSetpoint();
|
||||
if (setpoint != null) {
|
||||
updateState(CHANNEL_SETPOINT, new QuantityType<>(setpoint, CELSIUS));
|
||||
}
|
||||
|
||||
Integer mode = qThermostat.getMode();
|
||||
if (mode != null) {
|
||||
updateState(CHANNEL_MODE, new DecimalType(mode));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the serial number of the controller
|
||||
*
|
||||
* @return the serial nr
|
||||
*/
|
||||
public @Nullable String getSN() {
|
||||
return sn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the serial number of the controller
|
||||
*/
|
||||
public void setSN() {
|
||||
QbusBridgeHandler qBridgeHandler = getBridgeHandler("Thermostsat", this.thermostatId);
|
||||
if (qBridgeHandler == null) {
|
||||
thingOffline(ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"No communication with Qbus Bridge for THERMOSTAT " + this.thermostatId);
|
||||
return;
|
||||
}
|
||||
sn = qBridgeHandler.getSn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the configuration
|
||||
*/
|
||||
protected synchronized void readConfig() {
|
||||
thermostatConfig = getConfig().as(QbusThingsConfig.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Id from the configuration
|
||||
*
|
||||
* @return outputId
|
||||
*/
|
||||
public @Nullable Integer getId() {
|
||||
QbusThingsConfig localConfig = thermostatConfig;
|
||||
if (localConfig != null) {
|
||||
return localConfig.thermostatId;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.qbus.internal.handler;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link QbusThingsConfig} is responible for handling configurations for all things
|
||||
*
|
||||
* @author Koen Schockaert - Initial Contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class QbusThingsConfig {
|
||||
public @Nullable Integer bistabielId;
|
||||
public @Nullable Integer dimmerId;
|
||||
public @Nullable Integer co2Id;
|
||||
public @Nullable Integer rolId;
|
||||
public @Nullable Integer sceneId;
|
||||
public @Nullable Integer thermostatId;
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.qbus.internal.protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.qbus.internal.handler.QbusBistabielHandler;
|
||||
|
||||
/**
|
||||
* The {@link QbusBistabiel} class represents the Qbus BISTABIEL output.
|
||||
*
|
||||
* @author Koen Schockaert - Initial Contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public final class QbusBistabiel {
|
||||
|
||||
private @Nullable QbusCommunication qComm;
|
||||
|
||||
private Integer id;
|
||||
|
||||
private @Nullable Integer state;
|
||||
|
||||
private @Nullable QbusBistabielHandler thingHandler;
|
||||
|
||||
QbusBistabiel(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should be called if the ThingHandler for the thing corresponding to this bistabiel is initialized.
|
||||
* It keeps a record of the thing handler in this object so the thing can be updated when
|
||||
* the bistable output receives an update from the Qbus client.
|
||||
*
|
||||
* @param handler
|
||||
*/
|
||||
public void setThingHandler(QbusBistabielHandler handler) {
|
||||
this.thingHandler = handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets a pointer to the qComm BISTABIEL of class {@link QbusCommuncation}.
|
||||
* This is then used to be able to call back the sendCommand method in this class to send a command to the
|
||||
* Qbus client.
|
||||
*
|
||||
* @param qComm
|
||||
*/
|
||||
public void setQComm(QbusCommunication qComm) {
|
||||
this.qComm = qComm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the value of the Bistabiel.
|
||||
*
|
||||
* @param state
|
||||
*/
|
||||
void updateState(@Nullable Integer state) {
|
||||
this.state = state;
|
||||
QbusBistabielHandler handler = this.thingHandler;
|
||||
if (handler != null) {
|
||||
handler.handleStateUpdate(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the Bistabiel.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public @Nullable Integer getState() {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends Bistabiel state to Qbus.
|
||||
*
|
||||
* @param value
|
||||
* @param sn
|
||||
* @throws InterruptedException
|
||||
* @throws IOException
|
||||
*/
|
||||
public void execute(int value, String sn) throws InterruptedException, IOException {
|
||||
QbusMessageCmd qCmd = new QbusMessageCmd(sn, "executeBistabiel").withId(this.id).withState(value);
|
||||
QbusCommunication comm = this.qComm;
|
||||
if (comm != null) {
|
||||
comm.sendMessage(qCmd);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
|
||||
package org.openhab.binding.qbus.internal.protocol;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.qbus.internal.handler.QbusCO2Handler;
|
||||
|
||||
/**
|
||||
* The {@link QbusCO2} class represents the action Qbus CO2 output.
|
||||
*
|
||||
* @author Koen Schockaert - Initial Contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public final class QbusCO2 {
|
||||
|
||||
private @Nullable Integer state;
|
||||
|
||||
private @Nullable QbusCO2Handler thingHandler;
|
||||
|
||||
/**
|
||||
* This method should be called if the ThingHandler for the thing corresponding to this CO2 is initialized.
|
||||
* It keeps a record of the thing handler in this object so the thing can be updated when
|
||||
* the CO2 output receives an update from the Qbus IP-interface.
|
||||
*
|
||||
* @param handler
|
||||
*/
|
||||
public void setThingHandler(QbusCO2Handler handler) {
|
||||
this.thingHandler = handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get state of CO2.
|
||||
*
|
||||
* @return CO2 state
|
||||
*/
|
||||
public @Nullable Integer getState() {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the value of the CO2.
|
||||
*
|
||||
* @param CO2 value
|
||||
*/
|
||||
void updateState(@Nullable Integer state) {
|
||||
this.state = state;
|
||||
QbusCO2Handler handler = this.thingHandler;
|
||||
if (handler != null) {
|
||||
handler.handleStateUpdate(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,796 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.qbus.internal.protocol;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.qbus.internal.QbusBridgeHandler;
|
||||
import org.openhab.core.common.NamedThreadFactory;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonParseException;
|
||||
|
||||
/**
|
||||
* The {@link QbusCommunication} class is able to do the following tasks with Qbus
|
||||
* CTD controllers:
|
||||
* <ul>
|
||||
* <li>Start and stop TCP socket connection with Qbus Server.
|
||||
* <li>Read all the outputs and their status from the Qbus Controller.
|
||||
* <li>Execute Qbus commands.
|
||||
* <li>Listen to events from Qbus.
|
||||
* </ul>
|
||||
*
|
||||
* A class instance is instantiated from the {@link QbusBridgeHandler} class initialization.
|
||||
*
|
||||
* @author Koen Schockaert - Initial Contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public final class QbusCommunication extends BaseThingHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(QbusCommunication.class);
|
||||
|
||||
private @Nullable Socket qSocket;
|
||||
private @Nullable PrintWriter qOut;
|
||||
private @Nullable BufferedReader qIn;
|
||||
|
||||
private boolean listenerStopped;
|
||||
private boolean qbusListenerRunning;
|
||||
|
||||
private Gson gsonOut = new Gson();
|
||||
private Gson gsonIn;
|
||||
|
||||
private @Nullable String ctd;
|
||||
private boolean ctdConnected;
|
||||
|
||||
private List<Map<String, String>> outputs = new ArrayList<>();
|
||||
private final Map<Integer, QbusBistabiel> bistabiel = new HashMap<>();
|
||||
private final Map<Integer, QbusScene> scene = new HashMap<>();
|
||||
private final Map<Integer, QbusDimmer> dimmer = new HashMap<>();
|
||||
private final Map<Integer, QbusRol> rol = new HashMap<>();
|
||||
private final Map<Integer, QbusThermostat> thermostat = new HashMap<>();
|
||||
private final Map<Integer, QbusCO2> co2 = new HashMap<>();
|
||||
|
||||
private final ExecutorService threadExecutor = Executors
|
||||
.newSingleThreadExecutor(new NamedThreadFactory(getThing().getUID().getAsString(), true));
|
||||
|
||||
private @Nullable QbusBridgeHandler bridgeCallBack;
|
||||
|
||||
public QbusCommunication(Thing thing) {
|
||||
super(thing);
|
||||
GsonBuilder gsonBuilder = new GsonBuilder();
|
||||
gsonBuilder.registerTypeAdapter(QbusMessageBase.class, new QbusMessageDeserializer());
|
||||
gsonIn = gsonBuilder.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts main communication thread.
|
||||
* <ul>
|
||||
* <li>Connect to Qbus server
|
||||
* <li>Requests outputs
|
||||
* <li>Start listener
|
||||
* </ul>
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public synchronized void startCommunication() throws IOException, InterruptedException {
|
||||
QbusBridgeHandler handler = bridgeCallBack;
|
||||
ctdConnected = false;
|
||||
|
||||
if (qbusListenerRunning) {
|
||||
throw new IOException("Previous listening thread is still active.");
|
||||
}
|
||||
|
||||
if (handler == null) {
|
||||
throw new IOException("No Bridge handler initialised.");
|
||||
}
|
||||
|
||||
InetAddress addr = InetAddress.getByName(handler.getAddress());
|
||||
Integer port = handler.getPort();
|
||||
|
||||
if (port != null) {
|
||||
Socket socket = new Socket(addr, port);
|
||||
qSocket = socket;
|
||||
qOut = new PrintWriter(socket.getOutputStream(), true);
|
||||
qIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
setSN();
|
||||
getSN();
|
||||
|
||||
// Connect to Qbus server
|
||||
connect();
|
||||
|
||||
// Then start thread to listen to incoming updates from Qbus.
|
||||
threadExecutor.execute(() -> {
|
||||
try {
|
||||
qbusListener();
|
||||
} catch (IOException e) {
|
||||
String msg = e.getMessage();
|
||||
logger.warn("Could not start listening thread, IOException: {}", msg);
|
||||
} catch (InterruptedException e) {
|
||||
String msg = e.getMessage();
|
||||
logger.warn("Could not start listening thread, InterruptedException: {}", msg);
|
||||
}
|
||||
});
|
||||
|
||||
if (!ctdConnected) {
|
||||
handler.bridgePending("Waiting for CTD to come online...");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup socket when the communication with Qbus Server is closed.
|
||||
*
|
||||
* @throws IOException
|
||||
*
|
||||
*/
|
||||
public synchronized void stopCommunication() throws IOException {
|
||||
listenerStopped = true;
|
||||
|
||||
Socket socket = qSocket;
|
||||
|
||||
if (socket != null) {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException ignore) {
|
||||
// ignore IO Error when trying to close the socket if the intention is to close it anyway
|
||||
}
|
||||
}
|
||||
|
||||
BufferedReader reader = this.qIn;
|
||||
if (reader != null) {
|
||||
reader.close();
|
||||
}
|
||||
|
||||
PrintWriter writer = this.qOut;
|
||||
if (writer != null) {
|
||||
writer.close();
|
||||
}
|
||||
|
||||
qSocket = null;
|
||||
qbusListenerRunning = false;
|
||||
ctdConnected = false;
|
||||
|
||||
logger.trace("Communication stopped from thread {}", Thread.currentThread().getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Close and restart communication with Qbus Server.
|
||||
*
|
||||
* @throws InterruptedException
|
||||
* @throws IOException
|
||||
*/
|
||||
public synchronized void restartCommunication() throws InterruptedException, IOException {
|
||||
stopCommunication();
|
||||
|
||||
startCommunication();
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread that handles incoming messages from Qbus client.
|
||||
* <p>
|
||||
* The thread listens to the TCP socket opened at instantiation of the {@link QbusCommunication} class
|
||||
* and interprets all incomming json messages. It triggers state updates for active channels linked to the
|
||||
* Qbus outputs. It is started after initialization of the communication.
|
||||
*
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*
|
||||
*
|
||||
*/
|
||||
private void qbusListener() throws IOException, InterruptedException {
|
||||
String qMessage;
|
||||
|
||||
listenerStopped = false;
|
||||
qbusListenerRunning = true;
|
||||
|
||||
BufferedReader reader = this.qIn;
|
||||
|
||||
if (reader == null) {
|
||||
throw new IOException("Bufferreader for incoming messages not initialized.");
|
||||
}
|
||||
|
||||
try {
|
||||
while (!Thread.currentThread().isInterrupted() && ((qMessage = reader.readLine()) != null)) {
|
||||
readMessage(qMessage);
|
||||
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (!listenerStopped) {
|
||||
qbusListenerRunning = false;
|
||||
// the IO has stopped working, so we need to close cleanly and try to restart
|
||||
restartCommunication();
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
qbusListenerRunning = false;
|
||||
}
|
||||
|
||||
if (!listenerStopped) {
|
||||
qbusListenerRunning = false;
|
||||
|
||||
QbusBridgeHandler handler = bridgeCallBack;
|
||||
|
||||
if (handler != null) {
|
||||
ctdConnected = false;
|
||||
handler.bridgeOffline(ThingStatusDetail.COMMUNICATION_ERROR, "No communication with Qbus server");
|
||||
}
|
||||
}
|
||||
|
||||
qbusListenerRunning = false;
|
||||
logger.trace("Event listener thread stopped on thread {}", Thread.currentThread().getId());
|
||||
};
|
||||
|
||||
/**
|
||||
* Called by other methods to send json data to Qbus.
|
||||
*
|
||||
* @param qMessage
|
||||
* @throws InterruptedException
|
||||
* @throws IOException
|
||||
*/
|
||||
synchronized void sendMessage(Object qMessage) throws InterruptedException, IOException {
|
||||
PrintWriter writer = qOut;
|
||||
String json = gsonOut.toJson(qMessage);
|
||||
|
||||
if (writer != null) {
|
||||
writer.println(json);
|
||||
// Delay after sending data to improve scene execution
|
||||
TimeUnit.MILLISECONDS.sleep(250);
|
||||
}
|
||||
|
||||
if ((writer == null) || (writer.checkError())) {
|
||||
logger.warn("Error sending message, trying to restart communication");
|
||||
|
||||
restartCommunication();
|
||||
|
||||
// retry sending after restart
|
||||
writer = qOut;
|
||||
if (writer != null) {
|
||||
writer.println(json);
|
||||
}
|
||||
if ((writer == null) || (writer.checkError())) {
|
||||
logger.warn("Error resending message");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that interprets all feedback from Qbus Server application and calls appropriate handling methods.
|
||||
* <ul>
|
||||
* <li>Get request & update states for Bistabiel/Timers/Intervals/Mono outputs
|
||||
* <li>Get request & update states for the Scenes
|
||||
* <li>Get request & update states for Dimmers 1T and 2T
|
||||
* <li>Get request & update states for Shutters
|
||||
* <li>Get request & update states for Thermostats
|
||||
* <li>Get request & update states for CO2
|
||||
* </ul>
|
||||
*
|
||||
* @param qMessage message read from Qbus.
|
||||
* @throws InterruptedException
|
||||
* @throws IOException
|
||||
*
|
||||
*/
|
||||
private void readMessage(String qMessage) {
|
||||
String sn = null;
|
||||
String cmd = "";
|
||||
String ctd = null;
|
||||
Integer id = null;
|
||||
Integer state = null;
|
||||
Integer mode = null;
|
||||
Double setpoint = null;
|
||||
Double measured = null;
|
||||
Integer slats = null;
|
||||
|
||||
QbusMessageBase qMessageGson;
|
||||
try {
|
||||
qMessageGson = gsonIn.fromJson(qMessage, QbusMessageBase.class);
|
||||
|
||||
if (qMessageGson != null) {
|
||||
ctd = qMessageGson.getSn();
|
||||
cmd = qMessageGson.getCmd();
|
||||
id = qMessageGson.getId();
|
||||
state = qMessageGson.getState();
|
||||
mode = qMessageGson.getMode();
|
||||
setpoint = qMessageGson.getSetPoint();
|
||||
measured = qMessageGson.getMeasured();
|
||||
slats = qMessageGson.getSlatState();
|
||||
}
|
||||
} catch (JsonParseException e) {
|
||||
String msg = e.getMessage();
|
||||
logger.trace("Not acted on unsupported json {} : {}", qMessage, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
QbusBridgeHandler handler = bridgeCallBack;
|
||||
|
||||
if (handler != null) {
|
||||
sn = handler.getSn();
|
||||
}
|
||||
|
||||
if (sn != null && ctd != null) {
|
||||
try {
|
||||
if (sn.equals(ctd) && qMessageGson != null) { // Check if commands are for this Bridge
|
||||
// Handle all outputs from Qbus
|
||||
if ("returnOutputs".equals(cmd)) {
|
||||
outputs = ((QbusMessageListMap) qMessageGson).getOutputs();
|
||||
|
||||
for (Map<String, String> ctdOutputs : outputs) {
|
||||
|
||||
String ctdType = ctdOutputs.get("type");
|
||||
String ctdIdStr = ctdOutputs.get("id");
|
||||
Integer ctdId = null;
|
||||
|
||||
if (ctdIdStr != null) {
|
||||
ctdId = Integer.parseInt(ctdIdStr);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctdType != null) {
|
||||
String ctdState = ctdOutputs.get("state");
|
||||
String ctdMmode = ctdOutputs.get("regime");
|
||||
String ctdSetpoint = ctdOutputs.get("setpoint");
|
||||
String ctdMeasured = ctdOutputs.get("measured");
|
||||
String ctdSlats = ctdOutputs.get("slats");
|
||||
|
||||
Integer ctdStateI = null;
|
||||
if (ctdState != null) {
|
||||
ctdStateI = Integer.parseInt(ctdState);
|
||||
}
|
||||
|
||||
Integer ctdSlatsI = null;
|
||||
if (ctdSlats != null) {
|
||||
ctdSlatsI = Integer.parseInt(ctdSlats);
|
||||
}
|
||||
|
||||
Integer ctdMmodeI = null;
|
||||
if (ctdMmode != null) {
|
||||
ctdMmodeI = Integer.parseInt(ctdMmode);
|
||||
}
|
||||
|
||||
Double ctdSetpointD = null;
|
||||
if (ctdSetpoint != null) {
|
||||
ctdSetpointD = Double.parseDouble(ctdSetpoint);
|
||||
}
|
||||
|
||||
Double ctdMeasuredD = null;
|
||||
if (ctdMeasured != null) {
|
||||
ctdMeasuredD = Double.parseDouble(ctdMeasured);
|
||||
}
|
||||
|
||||
if (ctdState != null) {
|
||||
if (ctdType.equals("bistabiel")) {
|
||||
QbusBistabiel output = new QbusBistabiel(ctdId);
|
||||
if (!bistabiel.containsKey(ctdId)) {
|
||||
output.setQComm(this);
|
||||
output.updateState(ctdStateI);
|
||||
bistabiel.put(ctdId, output);
|
||||
} else {
|
||||
output.updateState(ctdStateI);
|
||||
}
|
||||
} else if (ctdType.equals("dimmer")) {
|
||||
QbusDimmer output = new QbusDimmer(ctdId);
|
||||
if (!dimmer.containsKey(ctdId)) {
|
||||
output.setQComm(this);
|
||||
output.updateState(ctdStateI);
|
||||
dimmer.put(ctdId, output);
|
||||
} else {
|
||||
output.updateState(ctdStateI);
|
||||
}
|
||||
} else if (ctdType.equals("CO2")) {
|
||||
QbusCO2 output = new QbusCO2();
|
||||
if (!co2.containsKey(ctdId)) {
|
||||
output.updateState(ctdStateI);
|
||||
co2.put(ctdId, output);
|
||||
} else {
|
||||
output.updateState(ctdStateI);
|
||||
}
|
||||
} else if (ctdType.equals("scene")) {
|
||||
QbusScene output = new QbusScene(ctdId);
|
||||
if (!scene.containsKey(ctdId)) {
|
||||
output.setQComm(this);
|
||||
scene.put(ctdId, output);
|
||||
}
|
||||
} else if (ctdType.equals("rol")) {
|
||||
QbusRol output = new QbusRol(ctdId);
|
||||
if (!rol.containsKey(ctdId)) {
|
||||
output.setQComm(this);
|
||||
output.updateState(ctdStateI);
|
||||
if (ctdSlats != null) {
|
||||
output.updateSlats(ctdSlatsI);
|
||||
}
|
||||
rol.put(ctdId, output);
|
||||
} else {
|
||||
output.updateState(ctdStateI);
|
||||
if (ctdSlats != null) {
|
||||
output.updateSlats(ctdSlatsI);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (ctdMeasuredD != null && ctdSetpointD != null && ctdMmodeI != null) {
|
||||
if (ctdType.equals("thermostat")) {
|
||||
QbusThermostat output = new QbusThermostat(ctdId);
|
||||
if (!thermostat.containsKey(ctdId)) {
|
||||
output.setQComm(this);
|
||||
output.updateState(ctdMeasuredD, ctdSetpointD, ctdMmodeI);
|
||||
thermostat.put(ctdId, output);
|
||||
} else {
|
||||
output.updateState(ctdMeasuredD, ctdSetpointD, ctdMmodeI);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Handle update commands from Qbus
|
||||
} else if ("updateBistabiel".equals(cmd)) {
|
||||
if (id != null && state != null) {
|
||||
updateBistabiel(id, state);
|
||||
}
|
||||
} else if ("updateDimmer".equals(cmd)) {
|
||||
if (id != null && state != null) {
|
||||
updateDimmer(id, state);
|
||||
}
|
||||
} else if ("updateDimmer".equals(cmd)) {
|
||||
if (id != null && state != null) {
|
||||
updateDimmer(id, state);
|
||||
}
|
||||
} else if ("updateCo2".equals(cmd)) {
|
||||
if (id != null && state != null) {
|
||||
updateCO2(id, state);
|
||||
}
|
||||
} else if ("updateThermostat".equals(cmd)) {
|
||||
if (id != null && measured != null && setpoint != null && mode != null) {
|
||||
updateThermostat(id, mode, setpoint, measured);
|
||||
}
|
||||
} else if ("updateRol02p".equals(cmd)) {
|
||||
if (id != null && state != null) {
|
||||
updateRol(id, state);
|
||||
}
|
||||
} else if ("updateRol02pSlat".equals(cmd)) {
|
||||
if (id != null && state != null && slats != null) {
|
||||
updateRolSlats(id, state, slats);
|
||||
}
|
||||
// Incomming commands from Qbus server to verify the client connection
|
||||
} else if ("noconnection".equals(cmd)) {
|
||||
eventDisconnect();
|
||||
} else if ("connected".equals(cmd)) {
|
||||
// threadExecutor.execute(() -> {
|
||||
try {
|
||||
requestOutputs();
|
||||
} catch (InterruptedException e) {
|
||||
String msg = e.getMessage();
|
||||
logger.warn("Could not request outputs. InterruptedException: {}", msg);
|
||||
} catch (IOException e) {
|
||||
String msg = e.getMessage();
|
||||
logger.warn("Could not request outputs. IOException: {}", msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (JsonParseException e) {
|
||||
String msg = e.getMessage();
|
||||
logger.warn("Not acted on unsupported json {}, {}", qMessage, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the communication object
|
||||
*/
|
||||
@Override
|
||||
public void initialize() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initial connection to Qbus Server to open a communication channel
|
||||
*
|
||||
* @throws InterruptedException
|
||||
* @throws IOException
|
||||
*/
|
||||
private void connect() throws InterruptedException, IOException {
|
||||
String snr = getSN();
|
||||
|
||||
if (snr != null) {
|
||||
QbusMessageCmd qCmd = new QbusMessageCmd(snr, "openHAB");
|
||||
|
||||
sendMessage(qCmd);
|
||||
|
||||
BufferedReader reader = qIn;
|
||||
|
||||
if (reader == null) {
|
||||
throw new IOException("Cannot read from socket, reader not connected.");
|
||||
}
|
||||
readMessage(reader.readLine());
|
||||
|
||||
} else {
|
||||
QbusBridgeHandler handler = bridgeCallBack;
|
||||
if (handler != null) {
|
||||
handler.bridgeOffline(ThingStatusDetail.CONFIGURATION_ERROR, "No serial nr defined");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a request for all available outputs and initializes them via readMessage
|
||||
*
|
||||
* @throws InterruptedException
|
||||
* @throws IOException
|
||||
*/
|
||||
private void requestOutputs() throws InterruptedException, IOException {
|
||||
String snr = getSN();
|
||||
QbusBridgeHandler handler = bridgeCallBack;
|
||||
|
||||
if (snr != null) {
|
||||
QbusMessageCmd qCmd = new QbusMessageCmd(snr, "all");
|
||||
sendMessage(qCmd);
|
||||
|
||||
BufferedReader reader = qIn;
|
||||
if (reader == null) {
|
||||
throw new IOException("Cannot read from socket, reader not connected.");
|
||||
}
|
||||
readMessage(reader.readLine());
|
||||
ctdConnected = true;
|
||||
|
||||
if (handler != null) {
|
||||
handler.bridgeOnline();
|
||||
}
|
||||
|
||||
} else {
|
||||
if (handler != null) {
|
||||
handler.bridgeOffline(ThingStatusDetail.CONFIGURATION_ERROR, "No serial nr defined");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event on incoming Bistabiel/Timer/Mono/Interval updates
|
||||
*
|
||||
* @param id
|
||||
* @param state
|
||||
*/
|
||||
private void updateBistabiel(Integer id, Integer state) {
|
||||
QbusBistabiel qBistabiel = this.bistabiel.get(id);
|
||||
|
||||
if (qBistabiel != null) {
|
||||
qBistabiel.updateState(state);
|
||||
} else {
|
||||
logger.trace("Bistabiel in controller not known {}", id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event on incoming Dimmer updates
|
||||
*
|
||||
* @param id
|
||||
* @param state
|
||||
*/
|
||||
private void updateDimmer(Integer id, Integer state) {
|
||||
QbusDimmer qDimmer = this.dimmer.get(id);
|
||||
|
||||
if (qDimmer != null) {
|
||||
qDimmer.updateState(state);
|
||||
} else {
|
||||
logger.trace("Dimmer in controller not known {}", id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event on incoming thermostat updates
|
||||
*
|
||||
* @param id
|
||||
* @param mode
|
||||
* @param sp
|
||||
* @param ct
|
||||
*/
|
||||
private void updateThermostat(Integer id, int mode, double sp, double ct) {
|
||||
QbusThermostat qThermostat = this.thermostat.get(id);
|
||||
|
||||
if (qThermostat != null) {
|
||||
qThermostat.updateState(ct, sp, mode);
|
||||
} else {
|
||||
logger.trace("Thermostat in controller not known {}", id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event on incoming CO2 updates
|
||||
*
|
||||
* @param id
|
||||
* @param state
|
||||
*/
|
||||
private void updateCO2(Integer id, Integer state) {
|
||||
QbusCO2 qCO2 = this.co2.get(id);
|
||||
|
||||
if (qCO2 != null) {
|
||||
qCO2.updateState(state);
|
||||
} else {
|
||||
logger.trace("CO2 in controller not known {}", id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event on incoming screen updates
|
||||
*
|
||||
* @param id
|
||||
* @param state
|
||||
*/
|
||||
private void updateRol(Integer id, Integer state) {
|
||||
QbusRol qRol = this.rol.get(id);
|
||||
|
||||
if (qRol != null) {
|
||||
qRol.updateState(state);
|
||||
} else {
|
||||
logger.trace("ROL02P in controller not known {}", id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event on incoming screen with slats updates
|
||||
*
|
||||
* @param id
|
||||
* @param state
|
||||
* @param slats
|
||||
*/
|
||||
private void updateRolSlats(Integer id, Integer state, Integer slats) {
|
||||
QbusRol qRol = this.rol.get(id);
|
||||
|
||||
if (qRol != null) {
|
||||
qRol.updateState(state);
|
||||
qRol.updateSlats(slats);
|
||||
} else {
|
||||
logger.trace("ROL02P with slats in controller not known {}", id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Put Bridge offline when there is no connection from the QbusClient
|
||||
*
|
||||
*/
|
||||
private void eventDisconnect() {
|
||||
QbusBridgeHandler handler = bridgeCallBack;
|
||||
|
||||
if (handler != null) {
|
||||
handler.bridgePending("Waiting for CTD connection");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all Bistabiel/Timers/Mono/Intervals in the Qbus Controller.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Map<Integer, QbusBistabiel> getBistabiel() {
|
||||
return this.bistabiel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all Scenes in the Qbus Controller
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Map<Integer, QbusScene> getScene() {
|
||||
return this.scene;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all Dimmers outputs in the Qbus Controller.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Map<Integer, QbusDimmer> getDimmer() {
|
||||
return this.dimmer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all rollershutter/screen outputs in the Qbus Controller.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Map<Integer, QbusRol> getRol() {
|
||||
return this.rol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all Thermostats outputs in the Qbus Controller.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Map<Integer, QbusThermostat> getThermostat() {
|
||||
return this.thermostat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all CO2 outputs in the Qbus Controller.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Map<Integer, QbusCO2> getCo2() {
|
||||
return this.co2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to check if communication with Qbus Server is active
|
||||
*
|
||||
* @return True if active
|
||||
*/
|
||||
public boolean communicationActive() {
|
||||
return qSocket != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to check if communication with Qbus Client is active
|
||||
*
|
||||
* @return True if active
|
||||
*/
|
||||
public boolean clientConnected() {
|
||||
return ctdConnected;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bridgeCallBack the bridgeCallBack to set
|
||||
*/
|
||||
public void setBridgeCallBack(QbusBridgeHandler bridgeCallBack) {
|
||||
this.bridgeCallBack = bridgeCallBack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the serial number of the CTD as configured in the Bridge.
|
||||
*
|
||||
* @return serial number of controller
|
||||
*/
|
||||
public @Nullable String getSN() {
|
||||
return this.ctd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the serial number of the CTD, as configured in the Bridge.
|
||||
*/
|
||||
public void setSN() {
|
||||
QbusBridgeHandler qBridgeHandler = bridgeCallBack;
|
||||
|
||||
if (qBridgeHandler != null) {
|
||||
this.ctd = qBridgeHandler.getSn();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
}
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.qbus.internal.protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.qbus.internal.handler.QbusDimmerHandler;
|
||||
|
||||
/**
|
||||
* The {@link QbusDimmer} class represents the action Qbus Dimmer output.
|
||||
*
|
||||
* @author Koen Schockaert - Initial Contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public final class QbusDimmer {
|
||||
|
||||
private @Nullable QbusCommunication qComm;
|
||||
|
||||
private Integer id;
|
||||
|
||||
private @Nullable Integer state;
|
||||
|
||||
private @Nullable QbusDimmerHandler thingHandler;
|
||||
|
||||
QbusDimmer(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should be called if the ThingHandler for the thing corresponding to this dimmer is initialized.
|
||||
* It keeps a record of the thing handler in this object so the thing can be updated when
|
||||
* the dimmer receives an update from the Qbus client.
|
||||
*
|
||||
* @param handler
|
||||
*/
|
||||
public void setThingHandler(QbusDimmerHandler handler) {
|
||||
this.thingHandler = handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets a pointer to the qComm Dimmer of class {@link QbusCommuncation}.
|
||||
* This is then used to be able to call back the sendCommand method in this class to send a command to the
|
||||
* Qbus client.
|
||||
*
|
||||
* @param qComm
|
||||
*/
|
||||
public void setQComm(QbusCommunication qComm) {
|
||||
this.qComm = qComm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the value of the dimmer
|
||||
*
|
||||
* @param state
|
||||
*/
|
||||
public void updateState(@Nullable Integer state) {
|
||||
this.state = state;
|
||||
QbusDimmerHandler handler = this.thingHandler;
|
||||
if (handler != null) {
|
||||
handler.handleStateUpdate(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state of dimmer.
|
||||
*
|
||||
* @return dimmer state
|
||||
*/
|
||||
public @Nullable Integer getState() {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state of Dimmer.
|
||||
*
|
||||
* @param dimmer state
|
||||
*/
|
||||
void setState(int state) {
|
||||
this.state = state;
|
||||
QbusDimmerHandler handler = thingHandler;
|
||||
if (handler != null) {
|
||||
handler.handleStateUpdate(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the dimmer state to Qbus.
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void execute(int percent, String sn) throws InterruptedException, IOException {
|
||||
QbusMessageCmd qCmd = new QbusMessageCmd(sn, "executeDimmer").withId(this.id).withState(percent);
|
||||
QbusCommunication comm = this.qComm;
|
||||
if (comm != null) {
|
||||
comm.sendMessage(qCmd);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.qbus.internal.protocol;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Class {@link QbusMessageBase} used as base class for output from gson for cmd or event feedback from the Qbus server.
|
||||
* This class only contains the common base fields required for the deserializer
|
||||
* {@link QbusMessageDeserializer} to select the specific formats implemented in {@link QbusMessageMap},
|
||||
* {@link QbusMessageListMap}, {@link QbusMessageCmd}.
|
||||
* <p>
|
||||
*
|
||||
* @author Koen Schockaert - Initial Contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
abstract class QbusMessageBase {
|
||||
|
||||
private @Nullable String ctd;
|
||||
protected @Nullable String cmd;
|
||||
protected @Nullable String type;
|
||||
protected @Nullable Integer id;
|
||||
protected @Nullable Integer state;
|
||||
protected @Nullable Integer mode;
|
||||
protected @Nullable Double setpoint;
|
||||
protected @Nullable Double measured;
|
||||
protected @Nullable Integer slatState;
|
||||
|
||||
@Nullable
|
||||
String getSn() {
|
||||
return this.ctd;
|
||||
}
|
||||
|
||||
void setSn(String ctd) {
|
||||
this.ctd = ctd;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
String getCmd() {
|
||||
return this.cmd;
|
||||
}
|
||||
|
||||
void setCmd(String cmd) {
|
||||
this.cmd = cmd;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(int state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public void setMode(int mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Double getSetPoint() {
|
||||
return setpoint;
|
||||
}
|
||||
|
||||
public void setSetPoint(Double setpoint) {
|
||||
this.setpoint = setpoint;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Double getMeasured() {
|
||||
return measured;
|
||||
}
|
||||
|
||||
public void setMeasured(Double measured) {
|
||||
this.measured = measured;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getSlatState() {
|
||||
return slatState;
|
||||
}
|
||||
|
||||
public void setSlatState(int slatState) {
|
||||
this.slatState = slatState;
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.qbus.internal.protocol;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Class {@link QbusMessageCmd} used as input to gson to send commands to Qbus. Extends
|
||||
* {@link QbusMessageBase}.
|
||||
* <p>
|
||||
* Example: <code>{"cmd":"executebistabiel","id":1,"value1":0}</code>
|
||||
*
|
||||
* @author Koen Schockaert - Initial Contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
class QbusMessageCmd extends QbusMessageBase {
|
||||
|
||||
QbusMessageCmd(String CTD) {
|
||||
super.setSn(CTD);
|
||||
}
|
||||
|
||||
QbusMessageCmd(String CTD, String cmd) {
|
||||
this(CTD);
|
||||
this.cmd = cmd;
|
||||
}
|
||||
|
||||
QbusMessageCmd withId(Integer id) {
|
||||
this.setId(id);
|
||||
return this;
|
||||
}
|
||||
|
||||
QbusMessageCmd withState(int state) {
|
||||
this.setState(state);
|
||||
return this;
|
||||
}
|
||||
|
||||
QbusMessageCmd withMode(int mode) {
|
||||
this.setMode(mode);
|
||||
return this;
|
||||
}
|
||||
|
||||
QbusMessageCmd withSetPoint(Double setpoint) {
|
||||
this.setSetPoint(setpoint);
|
||||
return this;
|
||||
}
|
||||
|
||||
QbusMessageCmd withSlatState(int slatState) {
|
||||
this.setSlatState(slatState);
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,157 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.qbus.internal.protocol;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
|
||||
/**
|
||||
* Class {@link QbusMessageDeserializer} deserializes all json messages from Qbus. Various json
|
||||
* message formats are supported. The format is selected based on the content of the cmd and event json objects.
|
||||
*
|
||||
* @author Koen Schockaert - Initial Contribution
|
||||
*
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
class QbusMessageDeserializer implements JsonDeserializer<QbusMessageBase> {
|
||||
|
||||
@Override
|
||||
public @Nullable QbusMessageBase deserialize(final JsonElement json, final Type typeOfT,
|
||||
final JsonDeserializationContext context) throws JsonParseException {
|
||||
final JsonObject jsonObject = json.getAsJsonObject();
|
||||
|
||||
String ctd = null;
|
||||
String cmd = null;
|
||||
Integer id = null;
|
||||
Integer state = null;
|
||||
Integer mode = null;
|
||||
Double measured = null;
|
||||
Double setpoint = null;
|
||||
Integer slats = null;
|
||||
|
||||
QbusMessageBase message = null;
|
||||
|
||||
JsonElement jsonOutputs = null;
|
||||
try {
|
||||
if (jsonObject.has("CTD")) {
|
||||
ctd = jsonObject.get("CTD").getAsString();
|
||||
}
|
||||
|
||||
if (jsonObject.has("cmd")) {
|
||||
cmd = jsonObject.get("cmd").getAsString();
|
||||
}
|
||||
|
||||
if (jsonObject.has("id")) {
|
||||
id = jsonObject.get("id").getAsInt();
|
||||
}
|
||||
|
||||
if (jsonObject.has("state")) {
|
||||
state = jsonObject.get("state").getAsInt();
|
||||
}
|
||||
|
||||
if (jsonObject.has("mode")) {
|
||||
mode = jsonObject.get("mode").getAsInt();
|
||||
}
|
||||
|
||||
if (jsonObject.has("measured")) {
|
||||
measured = jsonObject.get("measured").getAsDouble();
|
||||
}
|
||||
|
||||
if (jsonObject.has("setpoint")) {
|
||||
setpoint = jsonObject.get("setpoint").getAsDouble();
|
||||
}
|
||||
|
||||
if (jsonObject.has("slats")) {
|
||||
slats = jsonObject.get("slats").getAsInt();
|
||||
}
|
||||
|
||||
if (jsonObject.has("outputs")) {
|
||||
jsonOutputs = jsonObject.get("outputs");
|
||||
|
||||
}
|
||||
|
||||
if (ctd != null && cmd != null) {
|
||||
if (jsonOutputs != null) {
|
||||
if (jsonOutputs.isJsonArray()) {
|
||||
JsonArray jsonOutputsArray = jsonOutputs.getAsJsonArray();
|
||||
message = new QbusMessageListMap();
|
||||
message.setCmd(cmd);
|
||||
message.setSn(ctd);
|
||||
|
||||
List<Map<String, String>> outputsList = new ArrayList<>();
|
||||
for (int i = 0; i < jsonOutputsArray.size(); i++) {
|
||||
JsonObject jsonOutputsObject = jsonOutputsArray.get(i).getAsJsonObject();
|
||||
|
||||
Map<String, String> outputs = new HashMap<>();
|
||||
for (Entry<String, JsonElement> entry : jsonOutputsObject.entrySet()) {
|
||||
outputs.put(entry.getKey(), entry.getValue().getAsString());
|
||||
}
|
||||
outputsList.add(outputs);
|
||||
}
|
||||
((QbusMessageListMap) message).setOutputs(outputsList);
|
||||
}
|
||||
|
||||
} else {
|
||||
message = new QbusMessageMap();
|
||||
|
||||
message.setCmd(cmd);
|
||||
message.setSn(ctd);
|
||||
|
||||
if (id != null) {
|
||||
message.setId(id);
|
||||
}
|
||||
|
||||
if (state != null) {
|
||||
message.setState(state);
|
||||
}
|
||||
|
||||
if (slats != null) {
|
||||
message.setSlatState(slats);
|
||||
}
|
||||
|
||||
if (mode != null) {
|
||||
message.setMode(mode);
|
||||
}
|
||||
|
||||
if (measured != null) {
|
||||
message.setMeasured(measured);
|
||||
}
|
||||
|
||||
if (setpoint != null) {
|
||||
message.setSetPoint(setpoint);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return message;
|
||||
} catch (IllegalStateException e) {
|
||||
String mess = e.getMessage();
|
||||
throw new JsonParseException("Unexpected Json format " + mess + " for " + jsonObject.toString());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.qbus.internal.protocol;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Class {@link QbusMessageListMap} used as output from gson for cmd or event feedback from Qbus where the
|
||||
* data part is enclosed by [] and contains a list of json strings. Extends {@link QbusMessageBase}.
|
||||
* <p>
|
||||
*
|
||||
* @author Koen Schockaert - Initial Contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
class QbusMessageListMap extends QbusMessageBase {
|
||||
|
||||
private List<Map<String, String>> outputs = new ArrayList<>();
|
||||
|
||||
List<Map<String, String>> getOutputs() {
|
||||
return this.outputs;
|
||||
}
|
||||
|
||||
void setOutputs(List<Map<String, String>> outputs) {
|
||||
this.outputs = outputs;
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.qbus.internal.protocol;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Class {@link QbusMessageMap} used as output from gson for cmd or event feedback from Qbus where the
|
||||
* data part is a simple json string. Extends {@link QbusMessageBase}.
|
||||
* <p>
|
||||
*
|
||||
* @author Koen Schockaert - Initial Contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
class QbusMessageMap extends QbusMessageBase {
|
||||
|
||||
private Map<String, String> outputs = new HashMap<>();
|
||||
|
||||
Map<String, String> getData() {
|
||||
return this.outputs;
|
||||
}
|
||||
|
||||
void setOutputs(Map<String, String> outputs) {
|
||||
this.outputs = outputs;
|
||||
}
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.qbus.internal.protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.qbus.internal.handler.QbusRolHandler;
|
||||
|
||||
/**
|
||||
* The {@link QbusRol} class represents the action Qbus Shutter/Slats output.
|
||||
*
|
||||
* @author Koen Schockaert - Initial Contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public final class QbusRol {
|
||||
|
||||
private @Nullable QbusCommunication qComm;
|
||||
|
||||
private Integer id;
|
||||
|
||||
private @Nullable Integer state;
|
||||
|
||||
private @Nullable Integer slats;
|
||||
|
||||
private @Nullable QbusRolHandler thingHandler;
|
||||
|
||||
QbusRol(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should be called if the ThingHandler for the thing corresponding to this Shutter/Slats is
|
||||
* initialized.
|
||||
* It keeps a record of the thing handler in this object so the thing can be updated when
|
||||
* the shutter/slat receives an update from the Qbus client.
|
||||
*
|
||||
* @param qbusRolHandler
|
||||
*/
|
||||
public void setThingHandler(QbusRolHandler qbusRolHandler) {
|
||||
this.thingHandler = qbusRolHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets a pointer to the qComm Shutter/Slats of class {@link QbusCommuncation}.
|
||||
* This is then used to be able to call back the sendCommand method in this class to send a command to the
|
||||
* Qbus IP-interface when..
|
||||
*
|
||||
* @param qComm
|
||||
*/
|
||||
public void setQComm(QbusCommunication qComm) {
|
||||
this.qComm = qComm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the value of the Shutter.
|
||||
*
|
||||
* @param Shutter value
|
||||
*/
|
||||
public void updateState(@Nullable Integer state) {
|
||||
this.state = state;
|
||||
QbusRolHandler handler = this.thingHandler;
|
||||
if (handler != null) {
|
||||
handler.handleStateUpdate(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the value of the Slats.
|
||||
*
|
||||
* @param Slat value
|
||||
*/
|
||||
public void updateSlats(@Nullable Integer Slats) {
|
||||
this.slats = Slats;
|
||||
QbusRolHandler handler = this.thingHandler;
|
||||
if (handler != null) {
|
||||
handler.handleStateUpdate(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the Shutter.
|
||||
*
|
||||
* @return shutter value
|
||||
*/
|
||||
public @Nullable Integer getState() {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the Slats.
|
||||
*
|
||||
* @return slats value
|
||||
*/
|
||||
public @Nullable Integer getStateSlats() {
|
||||
return this.slats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends shutter state to Qbus.
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void execute(int value, String sn) throws InterruptedException, IOException {
|
||||
QbusMessageCmd qCmd = new QbusMessageCmd(sn, "executeStore").withId(this.id).withState(value);
|
||||
QbusCommunication comm = qComm;
|
||||
if (comm != null) {
|
||||
comm.sendMessage(qCmd);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends slats state to Qbus.
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void executeSlats(int value, String sn) throws InterruptedException, IOException {
|
||||
QbusMessageCmd qCmd = new QbusMessageCmd(sn, "executeSlats").withId(this.id).withState(value);
|
||||
QbusCommunication comm = qComm;
|
||||
if (comm != null) {
|
||||
comm.sendMessage(qCmd);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.qbus.internal.protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.qbus.internal.handler.QbusSceneHandler;
|
||||
|
||||
/**
|
||||
* The {@link QbusScene} class represents the action Qbus Scene output.
|
||||
*
|
||||
* @author Koen Schockaert - Initial Contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public final class QbusScene {
|
||||
|
||||
private @Nullable QbusCommunication qComm;
|
||||
|
||||
public @Nullable QbusSceneHandler thingHandler;
|
||||
|
||||
private @Nullable Integer state;
|
||||
|
||||
private Integer id;
|
||||
|
||||
QbusScene(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should be called if the ThingHandler for the thing corresponding to this scene is initialized.
|
||||
* It keeps a record of the thing handler in this object so the thing can be updated when
|
||||
* the scene output receives an update from the Qbus client.
|
||||
*
|
||||
* @param handler
|
||||
*/
|
||||
public void setThingHandler(QbusSceneHandler handler) {
|
||||
this.thingHandler = handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets a pointer to the qComm SCENE of class {@link QbusCommuncation}.
|
||||
* This is then used to be able to call back the sendCommand method in this class to send a command to the
|
||||
* Qbus client.
|
||||
*
|
||||
* @param qComm
|
||||
*/
|
||||
public void setQComm(QbusCommunication qComm) {
|
||||
this.qComm = qComm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the Scene.
|
||||
*
|
||||
* @return Scene value
|
||||
*/
|
||||
public @Nullable Integer getState() {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends Scene state to Qbus.
|
||||
*
|
||||
* @param value
|
||||
* @param sn
|
||||
* @throws InterruptedException
|
||||
* @throws IOException
|
||||
*/
|
||||
public void execute(int value, String sn) throws InterruptedException, IOException {
|
||||
QbusMessageCmd qCmd = new QbusMessageCmd(sn, "executeScene").withId(this.id).withState(value);
|
||||
QbusCommunication comm = qComm;
|
||||
if (comm != null) {
|
||||
comm.sendMessage(qCmd);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.qbus.internal.protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.qbus.internal.handler.QbusThermostatHandler;
|
||||
|
||||
/**
|
||||
* The {@link QbusThermostat} class represents the thermostat Qbus communication object. It contains all
|
||||
* fields representing a Qbus thermostat and has methods to set the thermostat mode and setpoint in Qbus and
|
||||
* receive thermostat updates.
|
||||
*
|
||||
* @author Koen Schockaert - Initial Contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public final class QbusThermostat {
|
||||
|
||||
private @Nullable QbusCommunication qComm;
|
||||
|
||||
private Integer id;
|
||||
private double measured = 0.0;
|
||||
private double setpoint = 0.0;
|
||||
private @Nullable Integer mode;
|
||||
|
||||
private @Nullable QbusThermostatHandler thingHandler;
|
||||
|
||||
QbusThermostat(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should be called if the ThingHandler for the thing corresponding to the termostat is initialized.
|
||||
* It keeps a record of the thing handler in this object so the thing can be updated when
|
||||
* the thermostat receives an update from the Qbus client.
|
||||
*
|
||||
* @param handler
|
||||
*/
|
||||
public void setThingHandler(QbusThermostatHandler handler) {
|
||||
this.thingHandler = handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets a pointer to the qComm THERMOSTAT of class {@link QbusCommuncation}.
|
||||
* This is then used to be able to call back the sendCommand method in this class to send a command to the
|
||||
* Qbus client.
|
||||
*
|
||||
* @param qComm
|
||||
*/
|
||||
public void setQComm(QbusCommunication qComm) {
|
||||
this.qComm = qComm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all values of the Thermostat
|
||||
*
|
||||
* @param measured current temperature in 1°C multiples
|
||||
* @param setpoint the setpoint temperature in 1°C multiples
|
||||
* @param mode 0="Manual", 1="Freeze", 2="Economic", 3="Comfort", 4="Night"
|
||||
*/
|
||||
public void updateState(Double measured, Double setpoint, Integer mode) {
|
||||
this.measured = measured;
|
||||
this.setpoint = setpoint;
|
||||
this.mode = mode;
|
||||
|
||||
QbusThermostatHandler handler = this.thingHandler;
|
||||
if (handler != null) {
|
||||
handler.handleStateUpdate(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get measured temperature of the Thermostat.
|
||||
*
|
||||
* @return measured temperature in 0.5°C multiples
|
||||
*/
|
||||
public @Nullable Double getMeasured() {
|
||||
return this.measured;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get setpoint temperature of the Thermostat.
|
||||
*
|
||||
* @return the setpoint temperature in 0.5°C multiples
|
||||
*/
|
||||
public @Nullable Double getSetpoint() {
|
||||
return this.setpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Thermostat mode.
|
||||
*
|
||||
* @return the mode: 0="Manual", 1="Freeze", 2="Economic", 3="Comfort", 4="Night"
|
||||
*/
|
||||
public @Nullable Integer getMode() {
|
||||
return this.mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends Thermostat mode to Qbus.
|
||||
*
|
||||
* @param mode
|
||||
* @param sn
|
||||
* @throws InterruptedException
|
||||
* @throws IOException
|
||||
*/
|
||||
public void executeMode(int mode, String sn) throws InterruptedException, IOException {
|
||||
QbusMessageCmd qCmd = new QbusMessageCmd(sn, "executeThermostat").withId(this.id).withMode(mode);
|
||||
QbusCommunication comm = this.qComm;
|
||||
if (comm != null) {
|
||||
comm.sendMessage(qCmd);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends Thermostat setpoint to Qbus.
|
||||
*
|
||||
* @param setpoint
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void executeSetpoint(double setpoint, String sn) throws InterruptedException, IOException {
|
||||
QbusMessageCmd qCmd = new QbusMessageCmd(sn, "executeThermostat").withId(this.id).withSetPoint(setpoint);
|
||||
QbusCommunication comm = this.qComm;
|
||||
if (comm != null) {
|
||||
comm.sendMessage(qCmd);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="qbus" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||
|
||||
<name>Qbus Binding</name>
|
||||
<description>This is the binding for the Qbus home automation system. Qbus is a system made and developed in Belgium
|
||||
(https://www.qbus.be/nl-nl)</description>
|
||||
|
||||
</binding:binding>
|
@ -0,0 +1,85 @@
|
||||
# binding
|
||||
binding.qbus.name = Qbus Binding
|
||||
binding.qbus.description = Deze binding maakt via een server applicate verbinding met de Qbus controller.
|
||||
|
||||
# thing types
|
||||
thing-type.qbus.bridge.label = Qbus Bridge
|
||||
thing-type.qbus.bridge.description = De Qbus Bridge Maakt Verbinding Met de Qbus Server.
|
||||
thing-type.config.qbus.bridge.addr.label = IP Adres of Host Naam
|
||||
thing-type.config.qbus.bridge.addr.description = IP adres van de Qbus server, meestal 'localhost'
|
||||
thing-type.config.qbus.bridge.sn.label = Serienummer van de Controller
|
||||
thing-type.config.qbus.bridge.sn.description = Serienummer van de CTD controller
|
||||
thing-type.config.qbus.bridge.port.label = Poort
|
||||
thing-type.config.qbus.bridge.port.description = Communicatiepoort van de Qbus server (standaard: 8447)
|
||||
thing-type.config.qbus.bridge.serverCheck.label = Server Connectie
|
||||
thing-type.config.qbus.bridge.serverCheck.description = Ingestelde timer, bij het verlopen van de timer zal de communicatie met de Qbus server gecontroleerd worden en indien nodig herstart.
|
||||
|
||||
thing-type.qbus.onOff.label = Aan/uit
|
||||
thing-type.qbus.onOff.description = Alle Bistabiel-Mono-Timer-Interval uitgangen
|
||||
thing-type.config.qbus.onOff.bistabielId.label = Qbus ID
|
||||
thing-type.config.qbus.onOff.bistabielId.description = Identificatienummer van de uitgang (zie SMIII)
|
||||
|
||||
thing-type.qbus.scene.label = Sfeer
|
||||
thing-type.qbus.scene.description = Alle sferen
|
||||
thing-type.config.qbus.scene.sceneId.label = Qbus ID
|
||||
thing-type.config.qbus.scene.sceneId.description = Identificatienummer van de sfeer (zie SMIII)
|
||||
|
||||
thing-type.qbus.co2.label = CO2
|
||||
thing-type.qbus.co2.description = Alle CO2 Uitgangen
|
||||
thing-type.config.qbus.co2.co2Id.label = Qbus ID
|
||||
thing-type.config.qbus.co2.co2Id.description = Identificatienummer van de uitgang (zie SMIII)
|
||||
|
||||
thing-type.qbus.dimmer.label = Dimmer
|
||||
thing-type.qbus.dimmer.description = Alle Dimbare Uitgangen
|
||||
thing-type.config.qbus.dimmer.dimmerId.label = Qbus ID
|
||||
thing-type.config.qbus.dimmer.dimmerId.description = Identificatienummer van de uitgang (zie SMIII)
|
||||
thing-type.config.qbus.dimmer.step.label = Stappenwaarde
|
||||
thing-type.config.qbus.dimmer.step.description = Waarde gebruikt voor het dimmen in stappen (standaard 10%)
|
||||
|
||||
thing-type.qbus.rollershutter.label = Rolluik
|
||||
thing-type.qbus.rollershutter.description = Alle Rolluik (ROL02P) Uitgangen
|
||||
thing-type.config.qbus.rollershutter.rolId.label = Qbus ID
|
||||
thing-type.config.qbus.rollershutter.rolId.description = Identificatienummer van de uitgang (zie SMIII)
|
||||
|
||||
thing-type.qbus.rollershutter_slats.label = Rolluik (met lamellen)
|
||||
thing-type.qbus.rollershutter_slats.description = Alle schermen met lamellen (ROL02P) uitgang
|
||||
thing-type.config.qbus.rollershutter_slats.rolId.label = Qbus ID
|
||||
thing-type.config.qbus.rollershutter_slats.rolId.description = Identificatienummer van de uitgang (zie SMIII)
|
||||
|
||||
thing-type.qbus.thermostat.label = Thermostaat
|
||||
thing-type.qbus.thermostat.description = Alle thermostaten
|
||||
thing-type.config.qbus.thermostat.thermostatId.label = Qbus ID
|
||||
thing-type.config.qbus.thermostat.thermostatId.description = Identificatienummer van de uitgang (zie SMIII)
|
||||
|
||||
channel-type.qbus.scene.label = Sfeer
|
||||
channel-type.qbus.scene.description = Bediening van de sfeer
|
||||
|
||||
channel-type.qbus.co2.label = CO2
|
||||
channel-type.qbus.co2.description = Uitlezing van de CO2 waarde
|
||||
|
||||
channel-type.qbus.switch.label = Schakelaar
|
||||
channel-type.qbus.switch.description = Schakelaar bediening van de uitgangen
|
||||
|
||||
channel-type.qbus.brightness.label = Helderheid
|
||||
channel-type.qbus.brightness.description = Helderheid bediening van de uitgangen
|
||||
|
||||
channel-type.qbus.measured.label = Gemeten Temperatuur
|
||||
channel-type.qbus.measured.description = Uitlezing van de gemeten Temperatuur
|
||||
|
||||
channel-type.qbus.setpoint.label = Ingestelde Temperatuur
|
||||
channel-type.qbus.setpoint.description = Ingestelde temperatuur bediening van de uitgangen
|
||||
|
||||
channel-type.qbus.mode.label = Ingesteld Regime
|
||||
channel-type.qbus.mode.description = Regime bediening van de uitgangen
|
||||
channel-type.qbus.mode.state.option.0 = Manueel
|
||||
channel-type.qbus.mode.state.option.1 = Vorst
|
||||
channel-type.qbus.mode.state.option.2 = Economisch
|
||||
channel-type.qbus.mode.state.option.3 = Comfort
|
||||
channel-type.qbus.mode.state.option.4 = Nacht
|
||||
|
||||
channel-type.qbus.rollershutter.label = Rolluik Bediening
|
||||
channel-type.qbus.rollershutter.description = Rolluik bediening van de uitgangen
|
||||
|
||||
channel-type.qbus.slats.label = Lamellen Bediening
|
||||
channel-type.qbus.slats.description = Lamellen bediening van de uitgangen
|
||||
|
@ -0,0 +1,231 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="qbus"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<bridge-type id="bridge">
|
||||
<label>Qbus Bridge</label>
|
||||
<description>This bridge represents a Qbus client</description>
|
||||
<config-description>
|
||||
<parameter name="addr" type="text" required="true">
|
||||
<label>Hostname</label>
|
||||
<description>IP address or hostname of Qbus server, usually 'localhost'</description>
|
||||
<default>localhost</default>
|
||||
<context>network-address</context>
|
||||
</parameter>
|
||||
<parameter name="sn" type="text" required="true">
|
||||
<label>Serial Number</label>
|
||||
<description>Serial number of the CTD controller</description>
|
||||
</parameter>
|
||||
<parameter name="port" type="integer" required="false">
|
||||
<label>Bridge Port</label>
|
||||
<description>Port to communicate with Qbus server, default 8447</description>
|
||||
<default>8447</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="serverCheck" type="integer" required="false" unit="min" min="1">
|
||||
<label>Server Check</label>
|
||||
<description>Time to check communication with Qbus Server (min), default 10. If set to 0 or left empty, no refresh
|
||||
will be scheduled</description>
|
||||
<default>10</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</bridge-type>
|
||||
|
||||
<thing-type id="onOff">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Switch</label>
|
||||
<description>Bistabiel-Mono-Timer-Interval Output</description>
|
||||
<channels>
|
||||
<channel id="switch" typeId="system.power"/>
|
||||
</channels>
|
||||
<config-description>
|
||||
<parameter name="bistabielId" type="integer" required="true">
|
||||
<label>Qbus ID</label>
|
||||
<description>Qbus Bistabiel ID</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="scene">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Scene</label>
|
||||
<description>Qbus Scene</description>
|
||||
<channels>
|
||||
<channel id="scene" typeId="scene"/>
|
||||
</channels>
|
||||
<config-description>
|
||||
<parameter name="sceneId" type="integer" required="true">
|
||||
<label>Qbus Scene ID</label>
|
||||
<description>Qbus Scene ID</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="co2">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>CO2</label>
|
||||
<description>Qbus CO2</description>
|
||||
<channels>
|
||||
<channel id="co2" typeId="co2"/>
|
||||
</channels>
|
||||
<config-description>
|
||||
<parameter name="co2Id" type="integer" required="true">
|
||||
<label>Qbus CO2 ID</label>
|
||||
<description>Qbus CO2 ID</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="dimmer">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Dimmer</label>
|
||||
<description>Qbus Dimmer Output</description>
|
||||
<channels>
|
||||
<channel id="brightness" typeId="system.brightness"/>
|
||||
</channels>
|
||||
<config-description>
|
||||
<parameter name="dimmerId" type="integer" required="true">
|
||||
<label>Output ID</label>
|
||||
<description>Qbus Dimmer ID</description>
|
||||
</parameter>
|
||||
<parameter name="step" type="integer" required="true">
|
||||
<label>Step Value</label>
|
||||
<description>Step value used for increase/decrease of dimmer brightness, default 10%</description>
|
||||
<default>10</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="rollershutter">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>RollerShutter</label>
|
||||
<description>Qbus shutter (ROL02P) control</description>
|
||||
<channels>
|
||||
<channel id="rollershutter" typeId="rollershutter"/>
|
||||
</channels>
|
||||
<config-description>
|
||||
<parameter name="rolId" type="integer" required="true">
|
||||
<label>Rol ID</label>
|
||||
<description>Qbus Rol Id</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="rollershutter_slats">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>RollerShutter (With Slats)</label>
|
||||
<description>Qbus shutter with slats control</description>
|
||||
<channels>
|
||||
<channel id="rollershutter" typeId="rollershutter"/>
|
||||
<channel id="slats" typeId="slats"/>
|
||||
</channels>
|
||||
<config-description>
|
||||
<parameter name="rolId" type="integer" required="true">
|
||||
<label>Rol ID</label>
|
||||
<description>Qbus Rol Id</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="thermostat">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Thermostat</label>
|
||||
<description>Qbus Thermostat</description>
|
||||
<channels>
|
||||
<channel id="measured" typeId="measured"/>
|
||||
<channel id="mode" typeId="mode"/>
|
||||
<channel id="setpoint" typeId="setpoint"/>
|
||||
</channels>
|
||||
<config-description>
|
||||
<parameter name="thermostatId" type="integer" required="true">
|
||||
<label>Thermostat ID</label>
|
||||
<description>Qbus Thermostat ID</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<channel-type id="scene">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Scene</label>
|
||||
<description>Scene Control for Qbus</description>
|
||||
<category>Scene</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="measured">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Measured</label>
|
||||
<description>Temperature Measured by Thermostat</description>
|
||||
<category>Temperature</category>
|
||||
<tags>
|
||||
<tag>CurrentTemperature</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="setpoint">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Setpoint</label>
|
||||
<description>Setpoint Temperature of Thermostat</description>
|
||||
<category>Temperature</category>
|
||||
<tags>
|
||||
<tag>TargetTemperature</tag>
|
||||
</tags>
|
||||
<state min="0" max="100" step="0.5" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="mode">
|
||||
<item-type>Number</item-type>
|
||||
<label>Mode</label>
|
||||
<description>Thermostat Mode</description>
|
||||
<category>Number</category>
|
||||
<state>
|
||||
<options>
|
||||
<option value="0">Manual</option>
|
||||
<option value="1">Freeze</option>
|
||||
<option value="2">Economic</option>
|
||||
<option value="3">Comfort</option>
|
||||
<option value="4">Night</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="co2">
|
||||
<item-type>Number</item-type>
|
||||
<label>CO2</label>
|
||||
<description>CO2 value for Qbus</description>
|
||||
<category>CO2</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="rollershutter">
|
||||
<item-type>Rollershutter</item-type>
|
||||
<label>Rollershutter</label>
|
||||
<description>Rollershutter Control for Qbus</description>
|
||||
<category>Blinds</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="slats">
|
||||
<item-type>Dimmer</item-type>
|
||||
<label>Slatcontrol</label>
|
||||
<description>Slatcontrol for Qbus</description>
|
||||
<category>Blinds</category>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
@ -253,6 +253,7 @@
|
||||
<module>org.openhab.binding.pulseaudio</module>
|
||||
<module>org.openhab.binding.pushbullet</module>
|
||||
<module>org.openhab.binding.pushover</module>
|
||||
<module>org.openhab.binding.qbus</module>
|
||||
<module>org.openhab.binding.radiothermostat</module>
|
||||
<module>org.openhab.binding.regoheatpump</module>
|
||||
<module>org.openhab.binding.revogi</module>
|
||||
|
Loading…
Reference in New Issue
Block a user