added migrated 2.x add-ons

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer
2020-09-21 01:58:32 +02:00
parent bbf1a7fd29
commit 6df6783b60
11662 changed files with 1302875 additions and 11 deletions

View File

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

View File

@@ -0,0 +1,224 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link VelbusBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusBindingConstants {
public static final String BINDING_ID = "velbus";
// bridges
public static final ThingTypeUID BRIDGE_THING_TYPE = new ThingTypeUID(BINDING_ID, "bridge");
public static final ThingTypeUID NETWORK_BRIDGE_THING_TYPE = new ThingTypeUID(BINDING_ID, "networkbridge");
// generic thing types
public static final ThingTypeUID THING_TYPE_VMB1BL = new ThingTypeUID(BINDING_ID, "vmb1bl");
public static final ThingTypeUID THING_TYPE_VMB1BLS = new ThingTypeUID(BINDING_ID, "vmb1bls");
public static final ThingTypeUID THING_TYPE_VMB1DM = new ThingTypeUID(BINDING_ID, "vmb1dm");
public static final ThingTypeUID THING_TYPE_VMB1LED = new ThingTypeUID(BINDING_ID, "vmb1led");
public static final ThingTypeUID THING_TYPE_VMB1RY = new ThingTypeUID(BINDING_ID, "vmb1ry");
public static final ThingTypeUID THING_TYPE_VMB1RYNO = new ThingTypeUID(BINDING_ID, "vmb1ryno");
public static final ThingTypeUID THING_TYPE_VMB1RYNOS = new ThingTypeUID(BINDING_ID, "vmb1rynos");
public static final ThingTypeUID THING_TYPE_VMB1RYS = new ThingTypeUID(BINDING_ID, "vmb1rys");
public static final ThingTypeUID THING_TYPE_VMB1TS = new ThingTypeUID(BINDING_ID, "vmb1ts");
public static final ThingTypeUID THING_TYPE_VMB2BL = new ThingTypeUID(BINDING_ID, "vmb2bl");
public static final ThingTypeUID THING_TYPE_VMB2BLE = new ThingTypeUID(BINDING_ID, "vmb2ble");
public static final ThingTypeUID THING_TYPE_VMB2PBN = new ThingTypeUID(BINDING_ID, "vmb2pbn");
public static final ThingTypeUID THING_TYPE_VMB4AN = new ThingTypeUID(BINDING_ID, "vmb4an");
public static final ThingTypeUID THING_TYPE_VMB4DC = new ThingTypeUID(BINDING_ID, "vmb4dc");
public static final ThingTypeUID THING_TYPE_VMB4RY = new ThingTypeUID(BINDING_ID, "vmb4ry");
public static final ThingTypeUID THING_TYPE_VMB4RYLD = new ThingTypeUID(BINDING_ID, "vmb4ryld");
public static final ThingTypeUID THING_TYPE_VMB4RYNO = new ThingTypeUID(BINDING_ID, "vmb4ryno");
public static final ThingTypeUID THING_TYPE_VMB6IN = new ThingTypeUID(BINDING_ID, "vmb6in");
public static final ThingTypeUID THING_TYPE_VMB6PBN = new ThingTypeUID(BINDING_ID, "vmb6pbn");
public static final ThingTypeUID THING_TYPE_VMB7IN = new ThingTypeUID(BINDING_ID, "vmb7in");
public static final ThingTypeUID THING_TYPE_VMB8IR = new ThingTypeUID(BINDING_ID, "vmb8ir");
public static final ThingTypeUID THING_TYPE_VMB8PB = new ThingTypeUID(BINDING_ID, "vmb8pb");
public static final ThingTypeUID THING_TYPE_VMB8PBU = new ThingTypeUID(BINDING_ID, "vmb8pbu");
public static final ThingTypeUID THING_TYPE_VMBDME = new ThingTypeUID(BINDING_ID, "vmbdme");
public static final ThingTypeUID THING_TYPE_VMBDMI = new ThingTypeUID(BINDING_ID, "vmbdmi");
public static final ThingTypeUID THING_TYPE_VMBDMIR = new ThingTypeUID(BINDING_ID, "vmbdmir");
public static final ThingTypeUID THING_TYPE_VMBEL1 = new ThingTypeUID(BINDING_ID, "vmbel1");
public static final ThingTypeUID THING_TYPE_VMBEL2 = new ThingTypeUID(BINDING_ID, "vmbel2");
public static final ThingTypeUID THING_TYPE_VMBEL4 = new ThingTypeUID(BINDING_ID, "vmbel4");
public static final ThingTypeUID THING_TYPE_VMBELO = new ThingTypeUID(BINDING_ID, "vmbelo");
public static final ThingTypeUID THING_TYPE_VMBGP1 = new ThingTypeUID(BINDING_ID, "vmbgp1");
public static final ThingTypeUID THING_TYPE_VMBGP1_2 = new ThingTypeUID(BINDING_ID, "vmbgp1-2");
public static final ThingTypeUID THING_TYPE_VMBGP2 = new ThingTypeUID(BINDING_ID, "vmbgp2");
public static final ThingTypeUID THING_TYPE_VMBGP2_2 = new ThingTypeUID(BINDING_ID, "vmbgp2-2");
public static final ThingTypeUID THING_TYPE_VMBGP4 = new ThingTypeUID(BINDING_ID, "vmbgp4");
public static final ThingTypeUID THING_TYPE_VMBGP4_2 = new ThingTypeUID(BINDING_ID, "vmbgp4-2");
public static final ThingTypeUID THING_TYPE_VMBGP4PIR = new ThingTypeUID(BINDING_ID, "vmbgp4pir");
public static final ThingTypeUID THING_TYPE_VMBGP4PIR_2 = new ThingTypeUID(BINDING_ID, "vmbgp4pir-2");
public static final ThingTypeUID THING_TYPE_VMBGPO = new ThingTypeUID(BINDING_ID, "vmbgpo");
public static final ThingTypeUID THING_TYPE_VMBGPOD = new ThingTypeUID(BINDING_ID, "vmbgpod");
public static final ThingTypeUID THING_TYPE_VMBGPOD_2 = new ThingTypeUID(BINDING_ID, "vmbgpod-2");
public static final ThingTypeUID THING_TYPE_VMBMETEO = new ThingTypeUID(BINDING_ID, "vmbmeteo");
public static final ThingTypeUID THING_TYPE_VMBPIRC = new ThingTypeUID(BINDING_ID, "vmbpirc");
public static final ThingTypeUID THING_TYPE_VMBPIRM = new ThingTypeUID(BINDING_ID, "vmbpirm");
public static final ThingTypeUID THING_TYPE_VMBPIRO = new ThingTypeUID(BINDING_ID, "vmbpiro");
public static final ThingTypeUID THING_TYPE_VMBRFR8S = new ThingTypeUID(BINDING_ID, "vmbrfr8s");
// thing type sets
public static final Set<ThingTypeUID> BRIDGE_THING_TYPES_UIDS = Collections
.unmodifiableSet(new HashSet<>(Arrays.asList(BRIDGE_THING_TYPE, NETWORK_BRIDGE_THING_TYPE)));
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.unmodifiableSet(
new HashSet<>(Arrays.asList(THING_TYPE_VMB1BL, THING_TYPE_VMB1BLS, THING_TYPE_VMB1DM, THING_TYPE_VMB1LED,
THING_TYPE_VMB1RY, THING_TYPE_VMB1RYNO, THING_TYPE_VMB1RYNOS, THING_TYPE_VMB1RYS, THING_TYPE_VMB1TS,
THING_TYPE_VMB2BL, THING_TYPE_VMB2BLE, THING_TYPE_VMB2PBN, THING_TYPE_VMB4AN, THING_TYPE_VMB4DC,
THING_TYPE_VMB4RY, THING_TYPE_VMB4RYLD, THING_TYPE_VMB4RYNO, THING_TYPE_VMB6IN, THING_TYPE_VMB6PBN,
THING_TYPE_VMB7IN, THING_TYPE_VMB8IR, THING_TYPE_VMB8PB, THING_TYPE_VMB8PBU, THING_TYPE_VMBDME,
THING_TYPE_VMBDMI, THING_TYPE_VMBDMIR, THING_TYPE_VMBEL1, THING_TYPE_VMBEL2, THING_TYPE_VMBEL4,
THING_TYPE_VMBELO, THING_TYPE_VMBGP1, THING_TYPE_VMBGP1_2, THING_TYPE_VMBGP2, THING_TYPE_VMBGP2_2,
THING_TYPE_VMBGP4, THING_TYPE_VMBGP4_2, THING_TYPE_VMBGP4PIR, THING_TYPE_VMBGP4PIR_2,
THING_TYPE_VMBGPO, THING_TYPE_VMBGPOD, THING_TYPE_VMBGPOD_2, THING_TYPE_VMBMETEO,
THING_TYPE_VMBPIRC, THING_TYPE_VMBPIRM, THING_TYPE_VMBPIRO, THING_TYPE_VMBRFR8S)));
// Velbus module types
public static final byte MODULE_TYPE_VMB8PB = 0x01;
public static final byte MODULE_TYPE_VMB1RY = 0x02;
public static final byte MODULE_TYPE_VMB1BL = 0x03;
public static final byte MODULE_TYPE_VMB6IN = 0x05;
public static final byte MODULE_TYPE_VMB1DM = 0x07;
public static final byte MODULE_TYPE_VMB4RY = 0x08;
public static final byte MODULE_TYPE_VMB2BL = 0x09;
public static final byte MODULE_TYPE_VMB8IR = 0x0A;
public static final byte MODULE_TYPE_VMB1TS = 0x0C;
public static final byte MODULE_TYPE_VMB1LED = 0x0F;
public static final byte MODULE_TYPE_VMB4RYLD = 0x10;
public static final byte MODULE_TYPE_VMB4RYNO = 0x11;
public static final byte MODULE_TYPE_VMB4DC = 0x12;
public static final byte MODULE_TYPE_VMBDME = 0x14;
public static final byte MODULE_TYPE_VMBDMI = 0x15;
public static final byte MODULE_TYPE_VMB8PBU = 0x16;
public static final byte MODULE_TYPE_VMB6PBN = 0x17;
public static final byte MODULE_TYPE_VMB2PBN = 0x18;
public static final byte MODULE_TYPE_VMB1RYNO = 0x1B;
public static final byte MODULE_TYPE_VMB2BLE = 0x1D;
public static final byte MODULE_TYPE_VMBGP1 = 0x1E;
public static final byte MODULE_TYPE_VMBGP2 = 0x1F;
public static final byte MODULE_TYPE_VMBGP4 = 0x20;
public static final byte MODULE_TYPE_VMBGPO = 0x21;
public static final byte MODULE_TYPE_VMB7IN = 0x22;
public static final byte MODULE_TYPE_VMBGPOD = 0x28;
public static final byte MODULE_TYPE_VMB1RYNOS = 0x29;
public static final byte MODULE_TYPE_VMBPIRM = 0x2A;
public static final byte MODULE_TYPE_VMBPIRC = 0x2B;
public static final byte MODULE_TYPE_VMBPIRO = 0x2C;
public static final byte MODULE_TYPE_VMBGP4PIR = 0x2D;
public static final byte MODULE_TYPE_VMB1BLS = 0x2E;
public static final byte MODULE_TYPE_VMBDMIR = 0x2F;
public static final byte MODULE_TYPE_VMBRFR8S = 0x30;
public static final byte MODULE_TYPE_VMBMETEO = 0x31;
public static final byte MODULE_TYPE_VMB4AN = 0x32;
public static final byte MODULE_TYPE_VMBEL1 = 0x34;
public static final byte MODULE_TYPE_VMBEL2 = 0x35;
public static final byte MODULE_TYPE_VMBEL4 = 0x36;
public static final byte MODULE_TYPE_VMBELO = 0x37;
public static final byte MODULE_TYPE_VMBGP1_2 = 0x3A;
public static final byte MODULE_TYPE_VMBGP2_2 = 0x3B;
public static final byte MODULE_TYPE_VMBGP4_2 = 0x3C;
public static final byte MODULE_TYPE_VMBGPOD_2 = 0x3D;
public static final byte MODULE_TYPE_VMBGP4PIR_2 = 0x3E;
public static final byte MODULE_TYPE_VMB1RYS = 0x41;
// Velbus commands
public static final byte COMMAND_PUSH_BUTTON_STATUS = 0x00;
public static final byte COMMAND_SWITCH_RELAY_OFF = 0x01;
public static final byte COMMAND_SWITCH_RELAY_ON = 0x02;
public static final byte COMMAND_SWITCH_BLIND_OFF = 0x04;
public static final byte COMMAND_BLIND_UP = 0x05;
public static final byte COMMAND_BLIND_DOWN = 0x06;
public static final byte COMMAND_SET_VALUE = 0x07;
public static final byte COMMAND_SLIDER_STATUS = 0x0F;
public static final byte COMMAND_RESTORE_LAST_DIMVALUE = 0x11;
public static final byte COMMAND_BLIND_POS = 0x1C;
public static final byte COMMAND_SENSOR_RAW_DATA = (byte) 0xA9;
public static final byte COMMAND_LIGHT_VALUE_REQUEST = (byte) 0xAA;
public static final byte COMMAND_TEXT = (byte) 0xAC;
public static final byte COMMAND_DAYLIGHT_SAVING_STATUS = (byte) 0xAF;
public static final byte COMMAND_SUBTYPE = (byte) 0xB0;
public static final byte COMMAND_SET_REALTIME_DATE = (byte) 0xB7;
public static final byte COMMAND_DIMMERCONTROLLER_STATUS = (byte) 0xB8;
public static final byte COMMAND_TEMP_SENSOR_SETTINGS_PART4 = (byte) 0xB9;
public static final byte COMMAND_COUNTER_STATUS_REQUEST = (byte) 0xBD;
public static final byte COMMAND_COUNTER_STATUS = (byte) 0xBE;
public static final byte COMMAND_SET_ALARM_CLOCK = (byte) 0xC3;
public static final byte COMMAND_TEMP_SENSOR_SETTINGS_PART3 = (byte) 0xC6;
public static final byte COMMAND_READ_MEMORY_BLOCK = (byte) 0xC9;
public static final byte COMMAND_MEMORY_DATA_BLOCK = (byte) 0xCC;
public static final byte COMMAND_SET_REALTIME_CLOCK = (byte) 0xD8;
public static final byte COMMAND_SWITCH_TO_COMFORT_MODE = (byte) 0xDB;
public static final byte COMMAND_SWITCH_TO_DAY_MODE = (byte) 0xDC;
public static final byte COMMAND_SWITCH_TO_NIGHT_MODE = (byte) 0xDD;
public static final byte COMMAND_SWITCH_TO_SAFE_MODE = (byte) 0xDE;
public static final byte COMMAND_SET_COOLING_MODE = (byte) 0xDF;
public static final byte COMMAND_SET_HEATING_MODE = (byte) 0xE0;
public static final byte COMMAND_SET_TEMP = (byte) 0xE4;
public static final byte COMMAND_SENSOR_READOUT_REQUEST = (byte) 0xE5;
public static final byte COMMAND_SENSOR_TEMPERATURE = (byte) 0xE6;
public static final byte COMMAND_TEMP_SENSOR_SETTINGS_REQUEST = (byte) 0xE7;
public static final byte COMMAND_TEMP_SENSOR_SETTINGS_PART1 = (byte) 0xE8;
public static final byte COMMAND_TEMP_SENSOR_SETTINGS_PART2 = (byte) 0xE9;
public static final byte COMMAND_TEMP_SENSOR_STATUS = (byte) 0xEA;
public static final byte COMMAND_BLIND_STATUS = (byte) 0xEC;
public static final byte COMMAND_MODULE_STATUS = (byte) 0xED;
public static final byte COMMAND_DIMMER_STATUS = (byte) 0xEE;
public static final byte COMMAND_MODULE_NAME_REQUEST = (byte) 0xEF;
public static final byte COMMAND_MODULE_NAME_PART1 = (byte) 0xF0;
public static final byte COMMAND_MODULE_NAME_PART2 = (byte) 0xF1;
public static final byte COMMAND_MODULE_NAME_PART3 = (byte) 0xF2;
public static final byte COMMAND_CLEAR_LED = (byte) 0xF5;
public static final byte COMMAND_SET_LED = (byte) 0xF6;
public static final byte COMMAND_SLOW_BLINK_LED = (byte) 0xF7;
public static final byte COMMAND_FAST_BLINK_LED = (byte) 0xF8;
public static final byte COMMAND_VERY_FAST_BLINK_LED = (byte) 0xF9;
public static final byte COMMAND_STATUS_REQUEST = (byte) 0xFA;
public static final byte COMMAND_RELAY_STATUS = (byte) 0xFB;
public static final byte COMMAND_WRITE_DATA_TO_MEMORY = (byte) 0xFC;
public static final byte COMMAND_READ_DATA_FROM_MEMORY = (byte) 0xFD;
public static final byte COMMAND_MEMORY_DATA = (byte) 0xFE;
public static final byte COMMAND_MODULE_TYPE = (byte) 0xFF;
public static final byte ALL_CHANNELS = (byte) 0xFF;
// Module properties
public static final String PORT = "port";
public static final String ADDRESS = "address";
public static final String REFRESH_INTERVAL = "refresh";
public static final String COUNTER1_PULSE_MULTIPLIER = "COUNTER1_PULSE_MULTIPLIER";
public static final String COUNTER2_PULSE_MULTIPLIER = "COUNTER2_PULSE_MULTIPLIER";
public static final String COUNTER3_PULSE_MULTIPLIER = "COUNTER3_PULSE_MULTIPLIER";
public static final String COUNTER4_PULSE_MULTIPLIER = "COUNTER4_PULSE_MULTIPLIER";
public static final String RECONNECTION_INTERVAL = "reconnectionInterval";
public static final String TIME_UPDATE_INTERVAL = "timeUpdateInterval";
public static final String MODULE_SERIAL_NUMBER = "serial number";
public static final String MODULE_MEMORY_MAP_VERSION = "memory map version";
public static final String MODULE_BUILD = "build";
public static final String CHANNEL = "CH";
public static final String SUB_ADDRESS = "subaddress";
public static final String DIMSPEED = "dimspeed";
}

View File

@@ -0,0 +1,53 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusChannelIdentifier} represents a class with properties that uniquely identify a channel.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusChannelIdentifier {
private byte address;
private byte channel;
public VelbusChannelIdentifier(byte address, byte channel) {
this.address = address;
this.channel = channel;
}
public byte getAddress() {
return address;
}
public byte getChannelByte() {
return channel;
}
public int getChannelNumberFromBitNumber() {
int position = 0;
byte remainingChannelBits = channel;
while (remainingChannelBits != 0) {
position++;
if ((remainingChannelBits & ((byte) 1)) != 0) {
return position;
}
remainingChannelBits = (byte) (remainingChannelBits >>> 1);
}
return position;
}
}

View File

@@ -0,0 +1,87 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusClockAlarm} represents a class that contains the state representation of a velbus clock alarm.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusClockAlarm {
private boolean enabled;
private boolean isLocal;
private byte wakeupHour;
private byte wakeupMinute;
private byte bedtimeHour;
private byte bedtimeMinute;
public VelbusClockAlarm() {
this.enabled = true;
this.isLocal = true;
this.wakeupHour = 7;
this.wakeupMinute = 0;
this.bedtimeHour = 23;
this.bedtimeMinute = 0;
}
public boolean isEnabled() {
return this.enabled;
}
public boolean isLocal() {
return this.isLocal;
}
public void setEnabled(boolean value) {
this.enabled = value;
}
public void setLocal(boolean value) {
this.isLocal = value;
}
public byte getWakeupHour() {
return this.wakeupHour;
}
public void setWakeupHour(byte value) {
this.wakeupHour = value;
}
public byte getWakeupMinute() {
return this.wakeupMinute;
}
public void setWakeupMinute(byte value) {
this.wakeupMinute = value;
}
public byte getBedtimeHour() {
return this.bedtimeHour;
}
public void setBedtimeHour(byte value) {
this.bedtimeHour = value;
}
public byte getBedtimeMinute() {
return this.bedtimeMinute;
}
public void setBedtimeMinute(byte value) {
this.bedtimeMinute = value;
}
}

View File

@@ -0,0 +1,49 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusClockAlarmConfiguration} represents a class that contains the configuration of a velbus clock alarm.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusClockAlarmConfiguration {
private VelbusClockAlarm alarmClock1;
private VelbusClockAlarm alarmClock2;
public VelbusClockAlarmConfiguration() {
this.alarmClock1 = new VelbusClockAlarm();
this.alarmClock2 = new VelbusClockAlarm();
}
public VelbusClockAlarm getAlarmClock1() {
return alarmClock1;
}
public VelbusClockAlarm getAlarmClock2() {
return alarmClock2;
}
public VelbusClockAlarm getAlarmClock(int alarmNumber) {
if (alarmNumber == 1) {
return getAlarmClock1();
} else if (alarmNumber == 2) {
return getAlarmClock2();
} else {
throw new IllegalArgumentException("The alarm clock '" + alarmNumber + "' does not exist.");
}
}
}

View File

@@ -0,0 +1,55 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusFirstGenerationDeviceModuleAddress} represents the address Velbus
* module of the 1st generation.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusFirstGenerationDeviceModuleAddress extends VelbusModuleAddress {
public VelbusFirstGenerationDeviceModuleAddress(byte address) {
super(address, 0);
}
@Override
public int getChannelNumber(VelbusChannelIdentifier velbusChannelIdentifier) {
byte channelByte = velbusChannelIdentifier.getChannelByte();
if (channelByte == (byte) 0x03) {
return 1;
} else if (channelByte == (byte) 0x0C) {
return 2;
}
throw new IllegalArgumentException("The byte '" + channelByte
+ "' does not represent a valid channel on the first generation device with address '"
+ velbusChannelIdentifier.getAddress() + "'.");
}
@Override
public VelbusChannelIdentifier getChannelIdentifier(int channelIndex) {
if (channelIndex == 0) {
return new VelbusChannelIdentifier(getAddress(), (byte) 0x03);
} else if (channelIndex == 1) {
return new VelbusChannelIdentifier(getAddress(), (byte) 0x0C);
} else {
throw new IllegalArgumentException("The channel index '" + channelIndex
+ "' is not valid for the first generation device on the address '" + getAddress() + "'.");
}
}
}

View File

@@ -0,0 +1,110 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.velbus.internal.handler.VelbusBlindsHandler;
import org.openhab.binding.velbus.internal.handler.VelbusBridgeHandler;
import org.openhab.binding.velbus.internal.handler.VelbusDimmerHandler;
import org.openhab.binding.velbus.internal.handler.VelbusNetworkBridgeHandler;
import org.openhab.binding.velbus.internal.handler.VelbusRelayHandler;
import org.openhab.binding.velbus.internal.handler.VelbusSensorHandler;
import org.openhab.binding.velbus.internal.handler.VelbusSensorWithAlarmClockHandler;
import org.openhab.binding.velbus.internal.handler.VelbusSerialBridgeHandler;
import org.openhab.binding.velbus.internal.handler.VelbusVMB1TSHandler;
import org.openhab.binding.velbus.internal.handler.VelbusVMB4ANHandler;
import org.openhab.binding.velbus.internal.handler.VelbusVMB7INHandler;
import org.openhab.binding.velbus.internal.handler.VelbusVMBELHandler;
import org.openhab.binding.velbus.internal.handler.VelbusVMBELOHandler;
import org.openhab.binding.velbus.internal.handler.VelbusVMBGPHandler;
import org.openhab.binding.velbus.internal.handler.VelbusVMBGPOHandler;
import org.openhab.binding.velbus.internal.handler.VelbusVMBMeteoHandler;
import org.openhab.binding.velbus.internal.handler.VelbusVMBPIROHandler;
import org.openhab.core.io.transport.serial.SerialPortManager;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
/**
* The {@link VelbusHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.velbus")
public class VelbusHandlerFactory extends BaseThingHandlerFactory {
private final SerialPortManager serialPortManager;
@Activate
public VelbusHandlerFactory(final @Reference SerialPortManager serialPortManager) {
this.serialPortManager = serialPortManager;
}
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return BRIDGE_THING_TYPES_UIDS.contains(thingTypeUID) || SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
ThingHandler thingHandler = null;
if (BRIDGE_THING_TYPES_UIDS.contains(thingTypeUID)) {
VelbusBridgeHandler velbusBridgeHandler = thingTypeUID.equals(NETWORK_BRIDGE_THING_TYPE)
? new VelbusNetworkBridgeHandler((Bridge) thing)
: new VelbusSerialBridgeHandler((Bridge) thing, serialPortManager);
thingHandler = velbusBridgeHandler;
} else if (VelbusRelayHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
thingHandler = new VelbusRelayHandler(thing);
} else if (VelbusDimmerHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
thingHandler = new VelbusDimmerHandler(thing);
} else if (VelbusBlindsHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
thingHandler = new VelbusBlindsHandler(thing);
} else if (VelbusSensorHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
thingHandler = new VelbusSensorHandler(thing);
} else if (VelbusSensorWithAlarmClockHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
thingHandler = new VelbusSensorWithAlarmClockHandler(thing);
} else if (VelbusVMBMeteoHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
thingHandler = new VelbusVMBMeteoHandler(thing);
} else if (VelbusVMBGPHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
thingHandler = new VelbusVMBGPHandler(thing);
} else if (VelbusVMBGPOHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
thingHandler = new VelbusVMBGPOHandler(thing);
} else if (VelbusVMBPIROHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
thingHandler = new VelbusVMBPIROHandler(thing);
} else if (VelbusVMB7INHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
thingHandler = new VelbusVMB7INHandler(thing);
} else if (VelbusVMBELHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
thingHandler = new VelbusVMBELHandler(thing);
} else if (VelbusVMBELOHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
thingHandler = new VelbusVMBELOHandler(thing);
} else if (VelbusVMB4ANHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
thingHandler = new VelbusVMB4ANHandler(thing);
} else if (VelbusVMB1TSHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
thingHandler = new VelbusVMB1TSHandler(thing);
}
return thingHandler;
}
}

View File

@@ -0,0 +1,161 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.velbus.internal.handler.VelbusBridgeHandler;
import org.openhab.binding.velbus.internal.packets.VelbusChannelNameRequestPacket;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
/**
* The {@link VelbusModule} represents a generic module and its basic properties
* in the Velbus system.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusModule {
private final HashMap<Integer, String[]> channelNames = new HashMap<>();
private VelbusModuleAddress velbusModuleAddress;
private byte highByteOfSerialNumber;
private byte lowByteOfSerialNumber;
private byte memoryMapVersion;
private byte buildYear;
private byte buildWeek;
private int numberOfChannels;
private ThingTypeUID thingTypeUID;
public VelbusModule(VelbusModuleAddress velbusModuleAddress, byte moduleType, byte highByteOfSerialNumber,
byte lowByteOfSerialNumber, byte memoryMapVersion, byte buildYear, byte buildWeek,
ThingTypeUID thingTypeUID, int numberOfChannels) {
this.velbusModuleAddress = velbusModuleAddress;
this.highByteOfSerialNumber = highByteOfSerialNumber;
this.lowByteOfSerialNumber = lowByteOfSerialNumber;
this.memoryMapVersion = memoryMapVersion;
this.buildYear = buildYear;
this.buildWeek = buildWeek;
this.thingTypeUID = thingTypeUID;
this.numberOfChannels = numberOfChannels;
}
public VelbusModuleAddress getModuleAddress() {
return velbusModuleAddress;
}
public String getAddress() {
return String.format("%02X", velbusModuleAddress.getAddress());
}
public String getModuleSerialNumber() {
return String.format("%02X", highByteOfSerialNumber) + String.format("%02X", lowByteOfSerialNumber);
}
public String getMemoryMapVersion() {
return String.format("%02X", memoryMapVersion);
}
public String getModuleBuild() {
return String.format("%02X", buildYear) + String.format("%02X", buildWeek);
}
public ThingTypeUID getThingTypeUID() {
return this.thingTypeUID;
}
public ThingUID getThingUID(ThingUID bridgeUID) {
return new ThingUID(getThingTypeUID(), bridgeUID, getAddress());
}
public String getLabel() {
return getThingTypeUID() + " (Address " + getAddress() + ")";
}
protected String getChannelName(int channelIndex) {
String channelName = "";
Integer key = channelIndex - 1;
if (channelNames.containsKey(key)) {
for (int i = 0; i < 3; i++) {
String channelNamePart = channelNames.get(key)[i];
if (channelNamePart != null) {
channelName = channelName + channelNamePart;
}
}
}
return channelName;
}
public void sendChannelNameRequests(@Nullable VelbusBridgeHandler bridgeHandler) {
if (bridgeHandler != null) {
VelbusChannelNameRequestPacket channelNameRequest = new VelbusChannelNameRequestPacket(
velbusModuleAddress.getAddress());
bridgeHandler.sendPacket(channelNameRequest.getBytes());
}
}
public void setChannelName(VelbusChannelIdentifier channelIdentifier, int namePartNumber, byte[] namePart) {
StringBuilder contents = new StringBuilder();
for (int i = 0; i < namePart.length; i++) {
byte currentChar = namePart[i];
if (currentChar != (byte) 0xFF) {
contents.append((char) currentChar);
}
}
Integer key = numberOfChannels <= 8 ? velbusModuleAddress.getChannelIndex(channelIdentifier)
: channelIdentifier.getChannelByte() - 1;
if (!channelNames.containsKey(key)) {
channelNames.put(key, new String[3]);
}
channelNames.get(key)[namePartNumber - 1] = contents.toString();
}
public Map<String, Object> getProperties() {
Map<String, Object> properties = new TreeMap<>();
properties.put(ADDRESS, getAddress());
properties.put(MODULE_SERIAL_NUMBER, getModuleSerialNumber());
properties.put(MODULE_MEMORY_MAP_VERSION, getMemoryMapVersion());
properties.put(MODULE_BUILD, getModuleBuild());
Integer[] keys = channelNames.keySet().toArray(new Integer[0]);
Arrays.sort(keys);
for (Integer key : keys) {
String channelName = getChannelName(key);
if (channelName.length() > 0) {
properties.put(CHANNEL + key, channelName);
}
}
byte[] subAddresses = velbusModuleAddress.getSubAddresses();
for (int i = 1; i <= subAddresses.length; i++) {
properties.put(SUB_ADDRESS + i, String.format("%02X", subAddresses[i - 1]));
}
return properties;
}
}

View File

@@ -0,0 +1,126 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ChannelUID;
/**
* The {@link VelbusModuleAddress} represents the address and possible subaddresses of a Velbus module.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusModuleAddress {
private byte address;
private byte[] subAddresses;
public VelbusModuleAddress(byte address, int numberOfSubAddresses) {
this(address, getInitialSubAddresses(numberOfSubAddresses));
}
public VelbusModuleAddress(byte address, byte[] subAddresses) {
this.address = address;
this.subAddresses = subAddresses;
}
public byte getAddress() {
return address;
}
public void setSubAddresses(byte[] subAddresses) {
this.subAddresses = subAddresses;
}
public byte[] getSubAddresses() {
return subAddresses;
}
public byte[] getActiveAddresses() {
List<Byte> activeAddresses = new ArrayList<>();
activeAddresses.add(address);
for (int i = 0; i < subAddresses.length; i++) {
if (subAddresses[i] != (byte) 0xFF) {
activeAddresses.add(subAddresses[i]);
}
}
byte[] result = new byte[activeAddresses.size()];
for (int i = 0; i < activeAddresses.size(); i++) {
result[i] = activeAddresses.get(i);
}
return result;
}
public VelbusChannelIdentifier getChannelIdentifier(ChannelUID channelUID) {
int channelIndex = getChannelIndex(channelUID);
return getChannelIdentifier(channelIndex);
}
public int getChannelNumber(ChannelUID channelUID) {
return Integer.parseInt(channelUID.getIdWithoutGroup().substring(2));
}
public int getChannelIndex(ChannelUID channelUID) {
return getChannelNumber(channelUID) - 1;
}
public String getChannelId(VelbusChannelIdentifier velbusChannelIdentifier) {
return "CH" + getChannelNumber(velbusChannelIdentifier);
}
public int getChannelIndex(VelbusChannelIdentifier velbusChannelIdentifier) {
return this.getChannelNumber(velbusChannelIdentifier) - 1;
}
public int getChannelNumber(VelbusChannelIdentifier velbusChannelIdentifier) {
byte[] activeAddresses = getActiveAddresses();
for (int i = 0; i < activeAddresses.length; i++) {
if (velbusChannelIdentifier.getAddress() == activeAddresses[i]) {
return (i * 8) + velbusChannelIdentifier.getChannelNumberFromBitNumber();
}
}
throw new IllegalArgumentException("The byte '" + velbusChannelIdentifier.getChannelByte()
+ "' does not represent a valid channel on the address '" + velbusChannelIdentifier.getAddress()
+ "'.");
}
public VelbusChannelIdentifier getChannelIdentifier(int channelIndex) {
int addressIndex = channelIndex / 8;
int addressChannelIndex = channelIndex % 8;
byte address = addressIndex == 0 ? this.address : subAddresses[addressIndex - 1];
byte channel = (byte) Math.pow(2, addressChannelIndex);
return new VelbusChannelIdentifier(address, channel);
}
private static byte[] getInitialSubAddresses(int numberOfSubAddresses) {
byte[] subAddresses = new byte[numberOfSubAddresses];
for (int i = 0; i < numberOfSubAddresses; i++) {
subAddresses[i] = (byte) 0xFF;
}
return subAddresses;
}
}

View File

@@ -0,0 +1,135 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.velbus.internal.packets.VelbusPacket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link VelbusPacketInputStream} is a wrapper around an InputStream that
* aggregates bytes from the input stream to meaningfull packets in the Velbus system.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusPacketInputStream {
private final Logger logger = LoggerFactory.getLogger(VelbusPacketInputStream.class);
public InputStream inputStream;
private ArrayList<Byte> currentData = new ArrayList<Byte>();
private @Nullable Byte currentSTX = null;
private @Nullable Byte currentPriority = null;
private @Nullable Byte currentAddress = null;
private @Nullable Byte currentDataLength = null;
private @Nullable Byte currentChecksum = null;
public VelbusPacketInputStream(InputStream inputStream) {
this.inputStream = inputStream;
}
public byte[] readPacket() throws IOException {
int currentDataByte;
while ((currentDataByte = inputStream.read()) > -1) {
if (currentSTX == null) {
if (((byte) currentDataByte) == VelbusPacket.STX) {
currentSTX = (byte) currentDataByte;
} else {
resetCurrentState();
logger.debug("Packet with invalid start byte: {}", currentDataByte);
}
} else if (currentPriority == null) {
if (((byte) currentDataByte) == VelbusPacket.PRIO_HI
|| ((byte) currentDataByte) == VelbusPacket.PRIO_LOW) {
currentPriority = (byte) currentDataByte;
} else {
resetCurrentState();
logger.debug("Packet with invalid priority received: {}", currentDataByte);
}
} else if (currentAddress == null) {
currentAddress = (byte) currentDataByte;
} else if (currentDataLength == null && currentDataByte <= 8) {
currentDataLength = (byte) currentDataByte;
} else if (currentDataLength == null) {
currentDataLength = 1;
currentData.add((byte) currentDataByte);
} else if (currentDataLength != null && (currentData.size() < currentDataLength)) {
currentData.add((byte) currentDataByte);
} else if (currentChecksum == null) {
currentChecksum = (byte) currentDataByte;
byte[] packet = getCurrentPacket();
byte expectedChecksum = VelbusPacket.computeCRCByte(packet);
if (currentChecksum != expectedChecksum) {
resetCurrentState();
logger.debug("Packet with invalid checksum received: {} instead of {}", currentChecksum,
expectedChecksum);
}
} else if (((byte) currentDataByte) == VelbusPacket.ETX) {
byte[] packet = getCurrentPacket();
resetCurrentState();
return packet;
} else {
resetCurrentState();
logger.debug("Packet with invalid ETX received: {}", currentDataByte);
}
}
return new byte[0];
}
public void close() throws IOException {
inputStream.close();
}
protected byte[] getCurrentPacket() {
if (currentDataLength != null && currentSTX != null && currentPriority != null && currentAddress != null
&& currentChecksum != null) {
byte[] packet = new byte[6 + currentDataLength];
packet[0] = currentSTX;
packet[1] = currentPriority;
packet[2] = currentAddress;
packet[3] = currentDataLength;
for (int i = 0; i < currentDataLength; i++) {
packet[4 + i] = currentData.get(i);
}
packet[4 + currentDataLength] = currentChecksum;
packet[5 + currentDataLength] = VelbusPacket.ETX;
return packet;
}
return new byte[0];
}
protected void resetCurrentState() {
currentSTX = null;
currentPriority = null;
currentAddress = null;
currentDataLength = null;
currentData = new ArrayList<>();
currentChecksum = null;
}
}

View File

@@ -0,0 +1,31 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusPacketListener} is notified when a Velbus packet for
* the listener's address is sent on the bus.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public interface VelbusPacketListener {
/**
* This method is called whenever the state of the given relay has changed.
*
* @param packet The bytes of the received packet.
*/
void onPacketReceived(byte[] packet);
}

View File

@@ -0,0 +1,26 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusBridgeConfig} class represents the configuration of a Velbus Bridge.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusBridgeConfig {
public int timeUpdateInterval;
public int reconnectionInterval;
}

View File

@@ -0,0 +1,25 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusDimmerConfig} class represents the configuration of a Velbus dimmer.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusDimmerConfig {
public int dimspeed;
}

View File

@@ -0,0 +1,26 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusNetworkBridgeConfig} class represents the configuration of a Velbus Network Bridge.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusNetworkBridgeConfig {
public String address = "";
public int port;
}

View File

@@ -0,0 +1,25 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusSensorConfig} class represents the configuration of a Velbus Temperature Sensor.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusSensorConfig {
public int refresh;
}

View File

@@ -0,0 +1,25 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusSerialBridgeConfig} class represents the configuration of a Velbus Serial Bridge.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusSerialBridgeConfig {
public String port = "";
}

View File

@@ -0,0 +1,25 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusThingConfig} class represents the configuration of a Velbus thing.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusThingConfig {
public String address = "";
}

View File

@@ -0,0 +1,28 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusVMB7INConfig} class represents the configuration of a Velbus VMB7IN module.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusVMB7INConfig extends VelbusSensorConfig {
public double counter1PulseMultiplier;
public double counter2PulseMultiplier;
public double counter3PulseMultiplier;
public double counter4PulseMultiplier;
}

View File

@@ -0,0 +1,379 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.discovery;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.*;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.velbus.internal.VelbusChannelIdentifier;
import org.openhab.binding.velbus.internal.VelbusFirstGenerationDeviceModuleAddress;
import org.openhab.binding.velbus.internal.VelbusModule;
import org.openhab.binding.velbus.internal.VelbusModuleAddress;
import org.openhab.binding.velbus.internal.VelbusPacketListener;
import org.openhab.binding.velbus.internal.handler.VelbusBridgeHandler;
import org.openhab.binding.velbus.internal.packets.VelbusPacket;
import org.openhab.binding.velbus.internal.packets.VelbusScanPacket;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* If the user scans manually for things this
* {@link VelbusThingDiscoveryService}
* is used to return Velbus Modules as things to the framework.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusThingDiscoveryService extends AbstractDiscoveryService
implements DiscoveryService, ThingHandlerService, VelbusPacketListener {
private static final int SEARCH_TIME = 60;
private final Logger logger = LoggerFactory.getLogger(VelbusThingDiscoveryService.class);
private Map<Byte, VelbusModule> velbusModules = new HashMap<>();
private @Nullable VelbusBridgeHandler velbusBridgeHandler;
public VelbusThingDiscoveryService() {
super(SUPPORTED_THING_TYPES_UIDS, SEARCH_TIME);
}
@Override
public void deactivate() {
removeOlderResults(new Date().getTime());
final VelbusBridgeHandler velbusBridgeHandler = this.velbusBridgeHandler;
if (velbusBridgeHandler != null) {
velbusBridgeHandler.clearDefaultPacketListener();
}
}
@Override
protected void startScan() {
for (int i = 0x00; i <= 0xFF; i++) {
VelbusScanPacket packet = new VelbusScanPacket((byte) i);
byte[] packetBytes = packet.getBytes();
final VelbusBridgeHandler velbusBridgeHandler = this.velbusBridgeHandler;
if (velbusBridgeHandler != null) {
velbusBridgeHandler.sendPacket(packetBytes);
}
}
}
@Override
public void onPacketReceived(byte[] packet) {
if (packet[0] == VelbusPacket.STX && packet.length >= 5) {
byte address = packet[2];
byte length = packet[3];
byte command = packet[4];
if (command == COMMAND_MODULE_TYPE && packet.length >= 10) {
handleModuleTypeCommand(packet, address);
} else if (command == COMMAND_MODULE_NAME_PART1 & packet.length >= 4 + length) {
handleChannelNameCommand(packet, address, length, 1);
} else if (command == COMMAND_MODULE_NAME_PART2 && packet.length >= 4 + length) {
handleChannelNameCommand(packet, address, length, 2);
} else if (command == COMMAND_MODULE_NAME_PART3 && packet.length >= 4 + length) {
handleChannelNameCommand(packet, address, length, 3);
} else if (command == COMMAND_SUBTYPE && packet.length >= 4 + length) {
handleModuleSubtypeCommand(packet, address);
} else {
logger.debug("Unknown command '{}' to address '{}'.", String.format("%02X", command),
String.format("%02X", address));
}
}
}
private void handleModuleTypeCommand(byte[] packet, byte address) {
byte moduleType = packet[5];
byte highByteOfSerialNumber = packet[6];
byte lowByteOfSerialNumber = packet[7];
byte memoryMapVersion = packet[8];
byte buildYear = packet[9];
byte buildWeek = packet[10];
VelbusModule velbusModule = null;
switch (moduleType) {
case MODULE_TYPE_VMB1BL:
velbusModule = new VelbusModule(new VelbusFirstGenerationDeviceModuleAddress(address), moduleType,
highByteOfSerialNumber, lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek,
THING_TYPE_VMB1BL, 1);
break;
case MODULE_TYPE_VMB1BLS:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1BLS, 1);
break;
case MODULE_TYPE_VMB1DM:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1DM, 1);
break;
case MODULE_TYPE_VMB1LED:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1LED, 1);
break;
case MODULE_TYPE_VMB1RY:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1RY, 1);
break;
case MODULE_TYPE_VMB1RYNO:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1RYNO, 5);
break;
case MODULE_TYPE_VMB1RYNOS:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1RYNOS, 5);
break;
case MODULE_TYPE_VMB1RYS:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1RYS, 5);
break;
case MODULE_TYPE_VMB1TS:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1TS, 1);
break;
case MODULE_TYPE_VMB2BL:
velbusModule = new VelbusModule(new VelbusFirstGenerationDeviceModuleAddress(address), moduleType,
highByteOfSerialNumber, lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek,
THING_TYPE_VMB2BL, 2);
break;
case MODULE_TYPE_VMB2BLE:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB2BLE, 2);
break;
case MODULE_TYPE_VMB2PBN:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB2PBN, 8);
break;
case MODULE_TYPE_VMB4AN:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4AN, 4);
break;
case MODULE_TYPE_VMB4DC:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4DC, 4);
break;
case MODULE_TYPE_VMB4RY:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4RY, 4);
break;
case MODULE_TYPE_VMB4RYLD:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4RYLD, 5);
break;
case MODULE_TYPE_VMB4RYNO:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4RYNO, 5);
break;
case MODULE_TYPE_VMB6IN:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB6IN, 6);
break;
case MODULE_TYPE_VMB6PBN:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB6PBN, 8);
break;
case MODULE_TYPE_VMB7IN:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB7IN, 8);
break;
case MODULE_TYPE_VMB8IR:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB8IR, 8);
break;
case MODULE_TYPE_VMB8PB:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB8PB, 8);
break;
case MODULE_TYPE_VMB8PBU:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB8PBU, 8);
break;
case MODULE_TYPE_VMBDME:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBDME, 1);
break;
case MODULE_TYPE_VMBDMI:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBDMI, 1);
break;
case MODULE_TYPE_VMBDMIR:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBDMIR, 1);
break;
case MODULE_TYPE_VMBEL1:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBEL1, 9);
break;
case MODULE_TYPE_VMBEL2:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBEL2, 9);
break;
case MODULE_TYPE_VMBEL4:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBEL4, 9);
break;
case MODULE_TYPE_VMBELO:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBELO, 33);
break;
case MODULE_TYPE_VMBGP1:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP1, 9);
break;
case MODULE_TYPE_VMBGP1_2:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP1_2, 9);
break;
case MODULE_TYPE_VMBGP2:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP2, 9);
break;
case MODULE_TYPE_VMBGP2_2:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP2_2, 9);
break;
case MODULE_TYPE_VMBGP4:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP4, 9);
break;
case MODULE_TYPE_VMBGP4_2:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP4_2, 9);
break;
case MODULE_TYPE_VMBGP4PIR:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP4PIR, 9);
break;
case MODULE_TYPE_VMBGP4PIR_2:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP4PIR_2, 9);
break;
case MODULE_TYPE_VMBGPO:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGPO, 33);
break;
case MODULE_TYPE_VMBGPOD:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGPOD, 33);
break;
case MODULE_TYPE_VMBGPOD_2:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGPOD_2, 33);
break;
case MODULE_TYPE_VMBMETEO:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBMETEO, 13);
break;
case MODULE_TYPE_VMBPIRC:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBPIRC, 7);
break;
case MODULE_TYPE_VMBPIRM:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBPIRM, 7);
break;
case MODULE_TYPE_VMBPIRO:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBPIRO, 9);
break;
case MODULE_TYPE_VMBRFR8S:
velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBRFR8S, 8);
break;
}
if (velbusModule != null) {
registerVelbusModule(address, velbusModule);
}
}
private void handleModuleSubtypeCommand(byte[] packet, byte address) {
if (velbusModules.containsKey(address)) {
VelbusModule velbusModule = velbusModules.get(address);
byte[] subAddresses = new byte[4];
System.arraycopy(packet, 8, subAddresses, 0, 4);
velbusModule.getModuleAddress().setSubAddresses(subAddresses);
for (int i = 0; i < subAddresses.length; i++) {
if (subAddresses[i] != (byte) 0xFF) {
velbusModules.put(subAddresses[i], velbusModule);
}
}
notifyDiscoveredVelbusModule(velbusModule);
}
}
protected void registerVelbusModule(byte address, VelbusModule velbusModule) {
velbusModules.put(address, velbusModule);
notifyDiscoveredVelbusModule(velbusModule);
velbusModule.sendChannelNameRequests(velbusBridgeHandler);
}
private void handleChannelNameCommand(byte[] packet, byte address, byte length, int namePartNumber) {
if (velbusModules.containsKey(address)) {
VelbusModule velbusModule = velbusModules.get(address);
byte channel = packet[5];
byte[] namePart = Arrays.copyOfRange(packet, 6, 6 + length - 2);
VelbusChannelIdentifier velbusChannelIdentifier = new VelbusChannelIdentifier(address, channel);
velbusModule.setChannelName(velbusChannelIdentifier, namePartNumber, namePart);
notifyDiscoveredVelbusModule(velbusModule);
}
}
private void notifyDiscoveredVelbusModule(VelbusModule velbusModule) {
final VelbusBridgeHandler velbusBridgeHandler = this.velbusBridgeHandler;
if (velbusBridgeHandler != null) {
ThingUID bridgeUID = velbusBridgeHandler.getThing().getUID();
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(velbusModule.getThingUID(bridgeUID))
.withThingType(velbusModule.getThingTypeUID()).withProperties(velbusModule.getProperties())
.withRepresentationProperty(ADDRESS).withBridge(bridgeUID).withLabel(velbusModule.getLabel())
.build();
thingDiscovered(discoveryResult);
}
}
@Override
public void setThingHandler(@Nullable ThingHandler handler) {
if (handler instanceof VelbusBridgeHandler) {
final VelbusBridgeHandler velbusBridgeHandler = (VelbusBridgeHandler) handler;
this.velbusBridgeHandler = velbusBridgeHandler;
velbusBridgeHandler.setDefaultPacketListener(this);
}
}
@Override
public @Nullable ThingHandler getThingHandler() {
return this.velbusBridgeHandler;
}
}

View File

@@ -0,0 +1,150 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.handler;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.velbus.internal.VelbusChannelIdentifier;
import org.openhab.binding.velbus.internal.VelbusFirstGenerationDeviceModuleAddress;
import org.openhab.binding.velbus.internal.VelbusModuleAddress;
import org.openhab.binding.velbus.internal.config.VelbusThingConfig;
import org.openhab.binding.velbus.internal.packets.VelbusBlindOffPacket;
import org.openhab.binding.velbus.internal.packets.VelbusBlindPositionPacket;
import org.openhab.binding.velbus.internal.packets.VelbusBlindUpDownPacket;
import org.openhab.binding.velbus.internal.packets.VelbusPacket;
import org.openhab.binding.velbus.internal.packets.VelbusStatusRequestPacket;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.library.types.StopMoveType;
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.thing.ThingTypeUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
/**
* The {@link VelbusBlindsHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusBlindsHandler extends VelbusThingHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(
Arrays.asList(THING_TYPE_VMB1BL, THING_TYPE_VMB1BLS, THING_TYPE_VMB2BL, THING_TYPE_VMB2BLE));
public VelbusBlindsHandler(Thing thing) {
super(thing, 0);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
if (velbusBridgeHandler == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
return;
}
if (command instanceof RefreshType) {
VelbusStatusRequestPacket packet = new VelbusStatusRequestPacket(
getModuleAddress().getChannelIdentifier(channelUID));
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
} else if (command instanceof UpDownType) {
UpDownType s = (UpDownType) command;
if (s == UpDownType.UP) {
byte commandByte = COMMAND_BLIND_UP;
VelbusBlindUpDownPacket packet = new VelbusBlindUpDownPacket(
getModuleAddress().getChannelIdentifier(channelUID), commandByte);
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
} else {
byte commandByte = COMMAND_BLIND_DOWN;
VelbusBlindUpDownPacket packet = new VelbusBlindUpDownPacket(
getModuleAddress().getChannelIdentifier(channelUID), commandByte);
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
}
} else if (command instanceof StopMoveType) {
StopMoveType s = (StopMoveType) command;
if (s == StopMoveType.STOP) {
VelbusBlindOffPacket packet = new VelbusBlindOffPacket(
getModuleAddress().getChannelIdentifier(channelUID));
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
}
} else if (command instanceof PercentType) {
VelbusBlindPositionPacket packet = new VelbusBlindPositionPacket(
getModuleAddress().getChannelIdentifier(channelUID), ((PercentType) command).byteValue());
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
} else {
logger.debug("The command '{}' is not supported by this handler.", command.getClass());
}
}
@Override
protected @Nullable VelbusModuleAddress createVelbusModuleAddress(int numberOfSubAddresses) {
final VelbusThingConfig velbusThingConfig = this.velbusThingConfig;
if (velbusThingConfig != null) {
byte address = hexToByte(velbusThingConfig.address);
if (isFirstGenerationDevice()) {
return new VelbusFirstGenerationDeviceModuleAddress(address);
}
return new VelbusModuleAddress(address, numberOfSubAddresses);
}
return null;
}
private Boolean isFirstGenerationDevice() {
ThingTypeUID thingTypeUID = this.getThing().getThingTypeUID();
return thingTypeUID.equals(THING_TYPE_VMB1BL) || thingTypeUID.equals(THING_TYPE_VMB2BL);
}
@Override
public void onPacketReceived(byte[] packet) {
logger.trace("onPacketReceived() was called");
if (packet[0] == VelbusPacket.STX && packet.length >= 5) {
byte command = packet[4];
if (command == COMMAND_BLIND_STATUS && packet.length >= 9) {
byte address = packet[2];
byte channel = packet[5];
byte blindPosition = packet[9];
VelbusChannelIdentifier velbusChannelIdentifier = new VelbusChannelIdentifier(address, channel);
PercentType state = new PercentType(blindPosition);
updateState(getModuleAddress().getChannelId(velbusChannelIdentifier), state);
}
}
}
}

View File

@@ -0,0 +1,284 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.handler;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;
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.velbus.internal.VelbusPacketInputStream;
import org.openhab.binding.velbus.internal.VelbusPacketListener;
import org.openhab.binding.velbus.internal.config.VelbusBridgeConfig;
import org.openhab.binding.velbus.internal.discovery.VelbusThingDiscoveryService;
import org.openhab.binding.velbus.internal.packets.VelbusSetDatePacket;
import org.openhab.binding.velbus.internal.packets.VelbusSetDaylightSavingsStatusPacket;
import org.openhab.binding.velbus.internal.packets.VelbusSetRealtimeClockPacket;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* {@link VelbusBridgeHandler} is an abstract handler for a Velbus interface and connects it to
* the framework.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public abstract class VelbusBridgeHandler extends BaseBridgeHandler {
private final Logger logger = LoggerFactory.getLogger(VelbusBridgeHandler.class);
private long lastPacketTimeMillis;
protected @Nullable VelbusPacketListener defaultPacketListener;
protected Map<Byte, VelbusPacketListener> packetListeners = new HashMap<>();
private @NonNullByDefault({}) VelbusBridgeConfig bridgeConfig;
private @Nullable ScheduledFuture<?> timeUpdateJob;
private @Nullable ScheduledFuture<?> reconnectionHandler;
private @NonNullByDefault({}) OutputStream outputStream;
private @NonNullByDefault({}) VelbusPacketInputStream inputStream;
private boolean listenerStopped;
public VelbusBridgeHandler(Bridge velbusBridge) {
super(velbusBridge);
}
@Override
public void initialize() {
logger.debug("Initializing velbus bridge handler.");
bridgeConfig = getConfigAs(VelbusBridgeConfig.class);
connect();
initializeTimeUpdate();
}
private void initializeTimeUpdate() {
int timeUpdateInterval = bridgeConfig.timeUpdateInterval;
if (timeUpdateInterval > 0) {
startTimeUpdates(timeUpdateInterval);
}
}
private void startTimeUpdates(int timeUpdatesInterval) {
timeUpdateJob = scheduler.scheduleWithFixedDelay(this::updateDateTime, 0, timeUpdatesInterval,
TimeUnit.MINUTES);
}
private void updateDateTime() {
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(Instant.now(), TimeZone.getDefault().toZoneId());
updateDate(zonedDateTime);
updateTime(zonedDateTime);
updateDaylightSavingsStatus(zonedDateTime);
}
private void updateTime(ZonedDateTime zonedDateTime) {
VelbusSetRealtimeClockPacket packet = new VelbusSetRealtimeClockPacket((byte) 0x00, zonedDateTime);
byte[] packetBytes = packet.getBytes();
this.sendPacket(packetBytes);
}
private void updateDate(ZonedDateTime zonedDateTime) {
VelbusSetDatePacket packet = new VelbusSetDatePacket((byte) 0x00, zonedDateTime);
byte[] packetBytes = packet.getBytes();
this.sendPacket(packetBytes);
}
private void updateDaylightSavingsStatus(ZonedDateTime zonedDateTime) {
VelbusSetDaylightSavingsStatusPacket packet = new VelbusSetDaylightSavingsStatusPacket((byte) 0x00,
zonedDateTime);
byte[] packetBytes = packet.getBytes();
this.sendPacket(packetBytes);
}
protected void initializeStreams(OutputStream outputStream, InputStream inputStream) {
this.outputStream = outputStream;
this.inputStream = new VelbusPacketInputStream(inputStream);
}
@Override
public void dispose() {
final ScheduledFuture<?> timeUpdateJob = this.timeUpdateJob;
if (timeUpdateJob != null) {
timeUpdateJob.cancel(true);
}
disconnect();
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
// There is nothing to handle in the bridge handler
}
public synchronized void sendPacket(byte[] packet) {
long currentTimeMillis = System.currentTimeMillis();
long timeSinceLastPacket = currentTimeMillis - lastPacketTimeMillis;
if (timeSinceLastPacket < 60) {
// When sending you need a delay of 60ms between each packet (to prevent flooding the VMB1USB).
long timeToDelay = 60 - timeSinceLastPacket;
scheduler.schedule(() -> {
sendPacket(packet);
}, timeToDelay, TimeUnit.MILLISECONDS);
return;
}
writePacket(packet);
lastPacketTimeMillis = System.currentTimeMillis();
}
private void readPacket(byte[] packet) {
byte address = packet[2];
if (packetListeners.containsKey(address)) {
VelbusPacketListener packetListener = packetListeners.get(address);
packetListener.onPacketReceived(packet);
} else {
final VelbusPacketListener defaultPacketListener = this.defaultPacketListener;
if (defaultPacketListener != null) {
defaultPacketListener.onPacketReceived(packet);
}
}
}
protected void readPackets() {
if (inputStream == null) {
onConnectionLost();
return;
}
byte[] packet;
listenerStopped = false;
try {
while (!listenerStopped & ((packet = inputStream.readPacket()).length > 0)) {
readPacket(packet);
}
} catch (IOException e) {
if (!listenerStopped) {
onConnectionLost();
}
}
}
private void writePacket(byte[] packet) {
if (outputStream == null) {
onConnectionLost();
return;
}
try {
outputStream.write(packet);
outputStream.flush();
} catch (IOException e) {
onConnectionLost();
}
}
protected void onConnectionLost() {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"A network communication error occurred.");
disconnect();
startReconnectionHandler();
}
/**
* Makes a connection to the Velbus system.
*
* @return True if the connection succeeded, false if the connection did not succeed.
*/
protected abstract boolean connect();
protected void disconnect() {
listenerStopped = true;
try {
if (outputStream != null) {
outputStream.close();
}
} catch (IOException e) {
logger.debug("Error while closing output stream", e);
}
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
logger.debug("Error while closing input stream", e);
}
}
public void startReconnectionHandler() {
final ScheduledFuture<?> reconnectionHandler = this.reconnectionHandler;
if (reconnectionHandler == null || reconnectionHandler.isCancelled()) {
int reconnectionInterval = bridgeConfig.reconnectionInterval;
if (reconnectionInterval > 0) {
this.reconnectionHandler = scheduler.scheduleWithFixedDelay(() -> {
if (connect() && reconnectionHandler != null) {
reconnectionHandler.cancel(false);
}
}, reconnectionInterval, reconnectionInterval, TimeUnit.SECONDS);
}
}
}
@Override
public Collection<Class<? extends ThingHandlerService>> getServices() {
return Collections.singleton(VelbusThingDiscoveryService.class);
}
public void setDefaultPacketListener(VelbusPacketListener velbusPacketListener) {
defaultPacketListener = velbusPacketListener;
}
public void clearDefaultPacketListener() {
defaultPacketListener = null;
}
public void registerPacketListener(byte address, VelbusPacketListener packetListener) {
packetListeners.put(Byte.valueOf(address), packetListener);
}
public void unregisterRelayStatusListener(byte address) {
packetListeners.remove(Byte.valueOf(address));
}
}

View File

@@ -0,0 +1,131 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.handler;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.velbus.internal.VelbusChannelIdentifier;
import org.openhab.binding.velbus.internal.config.VelbusDimmerConfig;
import org.openhab.binding.velbus.internal.packets.VelbusDimmerPacket;
import org.openhab.binding.velbus.internal.packets.VelbusPacket;
import org.openhab.binding.velbus.internal.packets.VelbusStatusRequestPacket;
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.thing.ThingTypeUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
/**
* The {@link VelbusDimmerHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusDimmerHandler extends VelbusThingHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(Arrays.asList(THING_TYPE_VMB1DM,
THING_TYPE_VMB1LED, THING_TYPE_VMB4DC, THING_TYPE_VMBDME, THING_TYPE_VMBDMI, THING_TYPE_VMBDMIR));
private @NonNullByDefault({}) VelbusDimmerConfig dimmerConfig;
public VelbusDimmerHandler(Thing thing) {
super(thing, 0);
}
@Override
public void initialize() {
this.dimmerConfig = getConfigAs(VelbusDimmerConfig.class);
super.initialize();
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
if (velbusBridgeHandler == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
return;
}
if (command instanceof RefreshType) {
VelbusStatusRequestPacket packet = new VelbusStatusRequestPacket(
getModuleAddress().getChannelIdentifier(channelUID));
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
} else if (command instanceof PercentType) {
byte commandByte = COMMAND_SET_VALUE;
VelbusDimmerPacket packet = new VelbusDimmerPacket(getModuleAddress().getChannelIdentifier(channelUID),
commandByte, ((PercentType) command).byteValue(), this.dimmerConfig.dimspeed,
isFirstGenerationDevice());
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
} else if (command instanceof OnOffType) {
byte commandByte = determineCommandByte((OnOffType) command);
VelbusDimmerPacket packet = new VelbusDimmerPacket(getModuleAddress().getChannelIdentifier(channelUID),
commandByte, (byte) 0x00, this.dimmerConfig.dimspeed, isFirstGenerationDevice());
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
} else {
logger.debug("The command '{}' is not supported by this handler.", command.getClass());
}
}
private byte determineCommandByte(OnOffType command) {
return (command == OnOffType.ON) ? COMMAND_RESTORE_LAST_DIMVALUE : COMMAND_SET_VALUE;
}
private Boolean isFirstGenerationDevice() {
ThingTypeUID thingTypeUID = this.getThing().getThingTypeUID();
return thingTypeUID.equals(THING_TYPE_VMB1DM) || thingTypeUID.equals(THING_TYPE_VMB1LED)
|| thingTypeUID.equals(THING_TYPE_VMBDME);
}
@Override
public void onPacketReceived(byte[] packet) {
logger.trace("onPacketReceived() was called");
if (packet[0] == VelbusPacket.STX && packet.length >= 5) {
byte address = packet[2];
byte command = packet[4];
if ((command == COMMAND_DIMMERCONTROLLER_STATUS) && packet.length >= 8) {
byte channel = packet[5];
byte dimValue = packet[7];
VelbusChannelIdentifier velbusChannelIdentifier = new VelbusChannelIdentifier(address, channel);
PercentType state = new PercentType(dimValue);
updateState(getModuleAddress().getChannelId(velbusChannelIdentifier), state);
} else if ((command == COMMAND_DIMMER_STATUS) && packet.length >= 7) {
byte dimValue = packet[6];
VelbusChannelIdentifier velbusChannelIdentifier = new VelbusChannelIdentifier(address, (byte) 0x01);
PercentType state = new PercentType(dimValue);
updateState(getModuleAddress().getChannelId(velbusChannelIdentifier), state);
}
}
}
}

View File

@@ -0,0 +1,73 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.velbus.internal.packets.VelbusMemoTextPacket;
import org.openhab.core.library.types.StringType;
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 VelbusMemoHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public abstract class VelbusMemoHandler extends VelbusThermostatHandler {
public static final int MEMO_TEXT_MAX_LENGTH = 63;
private final ChannelUID memoChannel = new ChannelUID(thing.getUID(), "oledDisplay", "MEMO");
public VelbusMemoHandler(Thing thing) {
super(thing, 4, new ChannelUID(thing.getUID(), "input", "CH33"));
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
super.handleCommand(channelUID, command);
VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
if (velbusBridgeHandler == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
return;
}
if (channelUID.equals(memoChannel) && command instanceof StringType) {
String memoText = ((StringType) command).toFullString();
String trucatedMemoText = memoText.substring(0, Math.min(memoText.length(), MEMO_TEXT_MAX_LENGTH));
String[] splittedMemoText = trucatedMemoText.split("(?<=\\G.....)");
for (int i = 0; i < splittedMemoText.length; i++) {
VelbusMemoTextPacket packet = new VelbusMemoTextPacket(getModuleAddress().getAddress(), (byte) (i * 5),
splittedMemoText[i].toCharArray());
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
// The last character must be zero
if ((((i * 5) + 5) >= trucatedMemoText.length()) && (splittedMemoText[i].length() == 5)) {
packet = new VelbusMemoTextPacket(getModuleAddress().getAddress(), (byte) ((i + 1) * 5),
new char[0]);
packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
}
}
}
}
}

View File

@@ -0,0 +1,96 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.handler;
import java.io.IOException;
import java.net.Socket;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.velbus.internal.config.VelbusNetworkBridgeConfig;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ThingStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* {@link VelbusNetworkBridgeHandler} is the handler for a Velbus network interface and connects it to
* the framework.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusNetworkBridgeHandler extends VelbusBridgeHandler {
private final Logger logger = LoggerFactory.getLogger(VelbusNetworkBridgeHandler.class);
private @Nullable Socket socket;
private @NonNullByDefault({}) VelbusNetworkBridgeConfig networkBridgeConfig;
public VelbusNetworkBridgeHandler(Bridge velbusBridge) {
super(velbusBridge);
}
@Override
public void initialize() {
this.networkBridgeConfig = getConfigAs(VelbusNetworkBridgeConfig.class);
super.initialize();
}
/**
* Makes a connection to the Velbus system.
*
* @return True if the connection succeeded, false if the connection did not succeed.
*/
@Override
protected boolean connect() {
try {
Socket socket = new Socket(networkBridgeConfig.address, networkBridgeConfig.port);
this.socket = socket;
initializeStreams(socket.getOutputStream(), socket.getInputStream());
updateStatus(ThingStatus.ONLINE);
logger.debug("Bridge online on network address {}:{}", networkBridgeConfig.address,
networkBridgeConfig.port);
return true;
} catch (IOException ex) {
onConnectionLost();
logger.debug("Failed to connect to network address {}:{}", networkBridgeConfig.address,
networkBridgeConfig.port);
}
// Start Velbus packet listener. This listener will act on all packets coming from
// IP-interface.
Thread thread = new Thread(this::readPackets, "OH-binding-" + this.thing.getUID());
thread.setDaemon(true);
thread.start();
return false;
}
@Override
protected void disconnect() {
final Socket socket = this.socket;
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
logger.debug("Error while closing socket", e);
}
this.socket = null;
}
super.disconnect();
}
}

View File

@@ -0,0 +1,100 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.handler;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.velbus.internal.VelbusChannelIdentifier;
import org.openhab.binding.velbus.internal.packets.VelbusPacket;
import org.openhab.binding.velbus.internal.packets.VelbusRelayPacket;
import org.openhab.binding.velbus.internal.packets.VelbusStatusRequestPacket;
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.thing.ThingTypeUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
/**
* The {@link VelbusRelayHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusRelayHandler extends VelbusThingHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(
Arrays.asList(THING_TYPE_VMB1RY, THING_TYPE_VMB1RYNO, THING_TYPE_VMB1RYNOS, THING_TYPE_VMB1RYS,
THING_TYPE_VMB4RY, THING_TYPE_VMB4RYLD, THING_TYPE_VMB4RYNO));
public VelbusRelayHandler(Thing thing) {
super(thing, 0);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
if (velbusBridgeHandler == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
return;
}
if (command instanceof RefreshType) {
VelbusStatusRequestPacket packet = new VelbusStatusRequestPacket(
getModuleAddress().getChannelIdentifier(channelUID));
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
} else if (command instanceof OnOffType) {
byte commandByte = determineCommandByte((OnOffType) command);
VelbusRelayPacket packet = new VelbusRelayPacket(getModuleAddress().getChannelIdentifier(channelUID),
commandByte);
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
} else {
logger.debug("The command '{}' is not supported by this handler.", command.getClass());
}
}
private byte determineCommandByte(OnOffType command) {
return (command == OnOffType.ON) ? COMMAND_SWITCH_RELAY_ON : COMMAND_SWITCH_RELAY_OFF;
}
@Override
public void onPacketReceived(byte[] packet) {
logger.trace("onPacketReceived() was called");
if (packet[0] == VelbusPacket.STX && packet.length >= 5) {
byte command = packet[4];
if (command == COMMAND_RELAY_STATUS && packet.length >= 7) {
byte address = packet[2];
byte channel = packet[5];
boolean on = packet[7] != 0x00;
VelbusChannelIdentifier velbusChannelIdentifier = new VelbusChannelIdentifier(address, channel);
OnOffType state = on ? OnOffType.ON : OnOffType.OFF;
updateState(getModuleAddress().getChannelId(velbusChannelIdentifier), state);
}
}
}
}

View File

@@ -0,0 +1,133 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.handler;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.velbus.internal.VelbusChannelIdentifier;
import org.openhab.binding.velbus.internal.packets.VelbusFeedbackLEDPacket;
import org.openhab.binding.velbus.internal.packets.VelbusPacket;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.CommonTriggerEvents;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.types.Command;
/**
* The {@link VelbusSensorHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusSensorHandler extends VelbusThingHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(
Arrays.asList(THING_TYPE_VMB6IN, THING_TYPE_VMB8IR, THING_TYPE_VMB8PB));
private static final StringType SET_LED = new StringType("SET_LED");
private static final StringType SLOW_BLINK_LED = new StringType("SLOW_BLINK_LED");
private static final StringType FAST_BLINK_LED = new StringType("FAST_BLINK_LED");
private static final StringType VERY_FAST_BLINK_LED = new StringType("VERY_FAST_BLINK_LED");
private static final StringType CLEAR_LED = new StringType("CLEAR_LED");
public VelbusSensorHandler(Thing thing) {
this(thing, 0);
}
public VelbusSensorHandler(Thing thing, int numberOfSubAddresses) {
super(thing, numberOfSubAddresses);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
if (velbusBridgeHandler == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
return;
}
if (isFeedbackChannel(channelUID) && command instanceof StringType) {
byte commandByte;
StringType stringTypeCommand = (StringType) command;
if (stringTypeCommand.equals(SET_LED)) {
commandByte = COMMAND_SET_LED;
} else if (stringTypeCommand.equals(SLOW_BLINK_LED)) {
commandByte = COMMAND_SLOW_BLINK_LED;
} else if (stringTypeCommand.equals(FAST_BLINK_LED)) {
commandByte = COMMAND_FAST_BLINK_LED;
} else if (stringTypeCommand.equals(VERY_FAST_BLINK_LED)) {
commandByte = COMMAND_VERY_FAST_BLINK_LED;
} else if (stringTypeCommand.equals(CLEAR_LED)) {
commandByte = COMMAND_CLEAR_LED;
} else {
throw new UnsupportedOperationException(
"The command '" + command + "' is not supported on channel '" + channelUID + "'.");
}
VelbusFeedbackLEDPacket packet = new VelbusFeedbackLEDPacket(
getModuleAddress().getChannelIdentifier(channelUID), commandByte);
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
}
}
private boolean isFeedbackChannel(ChannelUID channelUID) {
return "feedback".equals(channelUID.getGroupId());
}
@Override
public void onPacketReceived(byte[] packet) {
logger.trace("onPacketReceived() was called");
if (packet[0] == VelbusPacket.STX && packet.length >= 5) {
byte address = packet[2];
byte command = packet[4];
if (command == COMMAND_PUSH_BUTTON_STATUS && packet.length >= 6) {
byte channelJustPressed = packet[5];
if (channelJustPressed != 0) {
VelbusChannelIdentifier velbusChannelIdentifier = new VelbusChannelIdentifier(address,
channelJustPressed);
triggerChannel("input#" + getModuleAddress().getChannelId(velbusChannelIdentifier),
CommonTriggerEvents.PRESSED);
}
byte channelJustReleased = packet[6];
if (channelJustReleased != 0) {
VelbusChannelIdentifier velbusChannelIdentifier = new VelbusChannelIdentifier(address,
channelJustReleased);
triggerChannel("input#" + getModuleAddress().getChannelId(velbusChannelIdentifier),
CommonTriggerEvents.RELEASED);
}
byte channelLongPressed = packet[7];
if (channelLongPressed != 0) {
VelbusChannelIdentifier velbusChannelIdentifier = new VelbusChannelIdentifier(address,
channelLongPressed);
triggerChannel("input#" + getModuleAddress().getChannelId(velbusChannelIdentifier),
CommonTriggerEvents.LONG_PRESSED);
}
}
}
}
}

View File

@@ -0,0 +1,321 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.handler;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.velbus.internal.VelbusClockAlarm;
import org.openhab.binding.velbus.internal.VelbusClockAlarmConfiguration;
import org.openhab.binding.velbus.internal.packets.VelbusPacket;
import org.openhab.binding.velbus.internal.packets.VelbusSetLocalClockAlarmPacket;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
/**
* The {@link VelbusSensorWithAlarmClockHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusSensorWithAlarmClockHandler extends VelbusSensorHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(Arrays.asList(THING_TYPE_VMB2PBN,
THING_TYPE_VMB6PBN, THING_TYPE_VMB8PBU, THING_TYPE_VMBPIRC, THING_TYPE_VMBPIRM, THING_TYPE_VMBRFR8S));
private static final HashMap<ThingTypeUID, Integer> ALARM_CONFIGURATION_MEMORY_ADDRESSES = new HashMap<ThingTypeUID, Integer>();
static {
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMB2PBN, 0x0093);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMB4AN, 0x0046);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMB6PBN, 0x0093);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMB7IN, 0x0093);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMB8PBU, 0x0093);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBEL1, 0x0357);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBEL2, 0x0357);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBEL4, 0x0357);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBELO, 0x0593);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBPIRC, 0x0031);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBPIRM, 0x0031);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBPIRO, 0x0031);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBMETEO, 0x0083);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP1, 0x00A4);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP1_2, 0x00A4);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP2, 0x00A4);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP2_2, 0x00A4);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP4, 0x00A4);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP4_2, 0x00A4);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP4PIR, 0x00A4);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP4PIR_2, 0x00A4);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGPO, 0x0284);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGPOD, 0x0284);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGPOD_2, 0x0284);
ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBRFR8S, 0x0093);
}
private static final byte ALARM_CONFIGURATION_MEMORY_SIZE = 0x09;
private static final byte ALARM_1_ENABLED_MASK = 0x01;
private static final byte ALARM_1_TYPE_MASK = 0x02;
private static final byte ALARM_2_ENABLED_MASK = 0x04;
private static final byte ALARM_2_TYPE_MASK = 0x08;
private static final StringType ALARM_TYPE_LOCAL = new StringType("LOCAL");
private static final StringType ALARM_TYPE_GLOBAL = new StringType("GLOBAL");
private final ChannelUID clockAlarm1Enabled = new ChannelUID(thing.getUID(), "clockAlarm", "clockAlarm1Enabled");
private final ChannelUID clockAlarm1Type = new ChannelUID(thing.getUID(), "clockAlarm", "clockAlarm1Type");
private final ChannelUID clockAlarm1WakeupHour = new ChannelUID(thing.getUID(), "clockAlarm",
"clockAlarm1WakeupHour");
private final ChannelUID clockAlarm1WakeupMinute = new ChannelUID(thing.getUID(), "clockAlarm",
"clockAlarm1WakeupMinute");
private final ChannelUID clockAlarm1BedtimeHour = new ChannelUID(thing.getUID(), "clockAlarm",
"clockAlarm1BedtimeHour");
private final ChannelUID clockAlarm1BedtimeMinute = new ChannelUID(thing.getUID(), "clockAlarm",
"clockAlarm1BedtimeMinute");
private final ChannelUID clockAlarm2Enabled = new ChannelUID(thing.getUID(), "clockAlarm", "clockAlarm2Enabled");
private final ChannelUID clockAlarm2Type = new ChannelUID(thing.getUID(), "clockAlarm", "clockAlarm2Type");
private final ChannelUID clockAlarm2WakeupHour = new ChannelUID(thing.getUID(), "clockAlarm",
"clockAlarm2WakeupHour");
private final ChannelUID clockAlarm2WakeupMinute = new ChannelUID(thing.getUID(), "clockAlarm",
"clockAlarm2WakeupMinute");
private final ChannelUID clockAlarm2BedtimeHour = new ChannelUID(thing.getUID(), "clockAlarm",
"clockAlarm2BedtimeHour");
private final ChannelUID clockAlarm2BedtimeMinute = new ChannelUID(thing.getUID(), "clockAlarm",
"clockAlarm2BedtimeMinute");
private int clockAlarmConfigurationMemoryAddress;
private VelbusClockAlarmConfiguration alarmClockConfiguration = new VelbusClockAlarmConfiguration();
public VelbusSensorWithAlarmClockHandler(Thing thing) {
this(thing, 0);
}
public VelbusSensorWithAlarmClockHandler(Thing thing, int numberOfSubAddresses) {
super(thing, numberOfSubAddresses);
}
@Override
public void initialize() {
super.initialize();
if (ALARM_CONFIGURATION_MEMORY_ADDRESSES.containsKey(thing.getThingTypeUID())) {
this.clockAlarmConfigurationMemoryAddress = ALARM_CONFIGURATION_MEMORY_ADDRESSES
.get(thing.getThingTypeUID());
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
super.handleCommand(channelUID, command);
VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
if (velbusBridgeHandler == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
return;
}
if (isAlarmClockChannel(channelUID) && command instanceof RefreshType) {
sendReadMemoryBlockPacket(velbusBridgeHandler, this.clockAlarmConfigurationMemoryAddress + 0);
sendReadMemoryBlockPacket(velbusBridgeHandler, this.clockAlarmConfigurationMemoryAddress + 4);
sendReadMemoryPacket(velbusBridgeHandler, this.clockAlarmConfigurationMemoryAddress + 8);
} else if (isAlarmClockChannel(channelUID)) {
byte alarmNumber = determineAlarmNumber(channelUID);
VelbusClockAlarm alarmClock = alarmClockConfiguration.getAlarmClock(alarmNumber);
if ((channelUID.equals(clockAlarm1Enabled) || channelUID.equals(clockAlarm2Enabled))
&& command instanceof OnOffType) {
boolean enabled = command == OnOffType.ON;
alarmClock.setEnabled(enabled);
} else if ((channelUID.equals(clockAlarm1Type) || channelUID.equals(clockAlarm2Type))
&& command instanceof StringType) {
boolean isLocal = ((StringType) command).equals(ALARM_TYPE_LOCAL);
alarmClock.setLocal(isLocal);
} else if (channelUID.equals(clockAlarm1WakeupHour)
|| channelUID.equals(clockAlarm2WakeupHour) && command instanceof DecimalType) {
byte wakeupHour = ((DecimalType) command).byteValue();
alarmClock.setWakeupHour(wakeupHour);
} else if (channelUID.equals(clockAlarm1WakeupMinute)
|| channelUID.equals(clockAlarm2WakeupMinute) && command instanceof DecimalType) {
byte wakeupMinute = ((DecimalType) command).byteValue();
alarmClock.setWakeupMinute(wakeupMinute);
} else if (channelUID.equals(clockAlarm1BedtimeHour)
|| channelUID.equals(clockAlarm2BedtimeHour) && command instanceof DecimalType) {
byte bedTimeHour = ((DecimalType) command).byteValue();
alarmClock.setBedtimeHour(bedTimeHour);
} else if (channelUID.equals(clockAlarm1BedtimeMinute)
|| channelUID.equals(clockAlarm2BedtimeMinute) && command instanceof DecimalType) {
byte bedTimeMinute = ((DecimalType) command).byteValue();
alarmClock.setBedtimeMinute(bedTimeMinute);
}
byte address = alarmClock.isLocal() ? getModuleAddress().getAddress() : 0x00;
VelbusSetLocalClockAlarmPacket packet = new VelbusSetLocalClockAlarmPacket(address, alarmNumber,
alarmClock);
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
} else {
logger.debug("The command '{}' is not supported by this handler.", command.getClass());
}
}
@Override
public void onPacketReceived(byte[] packet) {
super.onPacketReceived(packet);
logger.trace("onPacketReceived() was called");
if (packet[0] == VelbusPacket.STX && packet.length >= 5) {
byte command = packet[4];
if ((command == COMMAND_MEMORY_DATA_BLOCK && packet.length >= 11)
|| (command == COMMAND_MEMORY_DATA && packet.length >= 8)) {
byte highMemoryAddress = packet[5];
byte lowMemoryAddress = packet[6];
int memoryAddress = ((highMemoryAddress & 0xff) << 8) | (lowMemoryAddress & 0xff);
byte[] data = (command == COMMAND_MEMORY_DATA_BLOCK)
? new byte[] { packet[7], packet[8], packet[9], packet[10] }
: new byte[] { packet[7] };
for (int i = 0; i < data.length; i++) {
if (isClockAlarmConfigurationByte(memoryAddress + i)) {
setClockAlarmConfigurationByte(memoryAddress + i, data[i]);
}
}
} else if (command == COMMAND_MODULE_STATUS) {
int clockAlarmAndProgramSelectionIndexInModuleStatus = this
.getClockAlarmAndProgramSelectionIndexInModuleStatus();
if (packet.length >= clockAlarmAndProgramSelectionIndexInModuleStatus + 1) {
byte alarmAndProgramSelection = packet[clockAlarmAndProgramSelectionIndexInModuleStatus];
boolean alarmClock1Enabled = (alarmAndProgramSelection & 0x04) > 0;
boolean alarmClock1IsLocal = (alarmAndProgramSelection & 0x08) == 0;
VelbusClockAlarm alarmClock1 = this.alarmClockConfiguration.getAlarmClock1();
alarmClock1.setEnabled(alarmClock1Enabled);
alarmClock1.setLocal(alarmClock1IsLocal);
updateState(clockAlarm1Enabled, alarmClock1.isEnabled() ? OnOffType.ON : OnOffType.OFF);
updateState(clockAlarm1Type, alarmClock1.isLocal() ? ALARM_TYPE_LOCAL : ALARM_TYPE_GLOBAL);
boolean alarmClock2Enabled = (alarmAndProgramSelection & 0x10) > 0;
boolean alarmClock2IsLocal = (alarmAndProgramSelection & 0x20) == 0;
VelbusClockAlarm alarmClock2 = this.alarmClockConfiguration.getAlarmClock2();
alarmClock2.setEnabled(alarmClock2Enabled);
alarmClock2.setLocal(alarmClock2IsLocal);
updateState(clockAlarm2Enabled, alarmClock2.isEnabled() ? OnOffType.ON : OnOffType.OFF);
updateState(clockAlarm2Type, alarmClock2.isLocal() ? ALARM_TYPE_LOCAL : ALARM_TYPE_GLOBAL);
}
}
}
}
public Boolean isClockAlarmConfigurationByte(int memoryAddress) {
return memoryAddress >= this.clockAlarmConfigurationMemoryAddress
&& memoryAddress < (this.clockAlarmConfigurationMemoryAddress + ALARM_CONFIGURATION_MEMORY_SIZE);
}
public void setClockAlarmConfigurationByte(int memoryAddress, byte data) {
VelbusClockAlarm alarmClock1 = this.alarmClockConfiguration.getAlarmClock1();
VelbusClockAlarm alarmClock2 = this.alarmClockConfiguration.getAlarmClock2();
switch (memoryAddress - this.clockAlarmConfigurationMemoryAddress) {
case 0:
alarmClock1.setEnabled((data & ALARM_1_ENABLED_MASK) > 0);
alarmClock1.setLocal((data & ALARM_1_TYPE_MASK) > 0);
updateState(clockAlarm1Enabled, alarmClock1.isEnabled() ? OnOffType.ON : OnOffType.OFF);
updateState(clockAlarm1Type, alarmClock1.isLocal() ? ALARM_TYPE_LOCAL : ALARM_TYPE_GLOBAL);
alarmClock2.setEnabled((data & ALARM_2_ENABLED_MASK) > 0);
alarmClock2.setLocal((data & ALARM_2_TYPE_MASK) > 0);
updateState(clockAlarm2Enabled, alarmClock2.isEnabled() ? OnOffType.ON : OnOffType.OFF);
updateState(clockAlarm2Type, alarmClock2.isLocal() ? ALARM_TYPE_LOCAL : ALARM_TYPE_GLOBAL);
break;
case 1:
alarmClock1.setWakeupHour(data);
updateState(clockAlarm1WakeupHour, new DecimalType(alarmClock1.getWakeupHour()));
break;
case 2:
alarmClock1.setWakeupMinute(data);
updateState(clockAlarm1WakeupMinute, new DecimalType(alarmClock1.getWakeupMinute()));
break;
case 3:
alarmClock1.setBedtimeHour(data);
updateState(clockAlarm1BedtimeHour, new DecimalType(alarmClock1.getBedtimeHour()));
break;
case 4:
alarmClock1.setBedtimeMinute(data);
updateState(clockAlarm1BedtimeMinute, new DecimalType(alarmClock1.getBedtimeMinute()));
break;
case 5:
alarmClock2.setWakeupHour(data);
updateState(clockAlarm2WakeupHour, new DecimalType(alarmClock2.getWakeupHour()));
break;
case 6:
alarmClock2.setWakeupMinute(data);
updateState(clockAlarm2WakeupMinute, new DecimalType(alarmClock2.getWakeupMinute()));
break;
case 7:
alarmClock2.setBedtimeHour(data);
updateState(clockAlarm2BedtimeHour, new DecimalType(alarmClock2.getBedtimeHour()));
break;
case 8:
alarmClock2.setBedtimeMinute(data);
updateState(clockAlarm2BedtimeMinute, new DecimalType(alarmClock2.getBedtimeMinute()));
break;
default:
throw new IllegalArgumentException("The memory address '" + memoryAddress
+ "' does not represent a clock alarm configuration for the thing '" + this.thing.getUID()
+ "'.");
}
}
protected boolean isAlarmClockChannel(ChannelUID channelUID) {
return channelUID.equals(clockAlarm1Enabled) || channelUID.equals(clockAlarm1Type)
|| channelUID.equals(clockAlarm1WakeupHour) || channelUID.equals(clockAlarm1WakeupMinute)
|| channelUID.equals(clockAlarm1BedtimeHour) || channelUID.equals(clockAlarm1BedtimeMinute)
|| channelUID.equals(clockAlarm2Enabled) || channelUID.equals(clockAlarm2Type)
|| channelUID.equals(clockAlarm2WakeupHour) || channelUID.equals(clockAlarm2WakeupMinute)
|| channelUID.equals(clockAlarm2BedtimeHour) || channelUID.equals(clockAlarm2BedtimeMinute);
}
protected byte determineAlarmNumber(ChannelUID channelUID) {
if (channelUID.equals(clockAlarm1Enabled) || channelUID.equals(clockAlarm1Type)
|| channelUID.equals(clockAlarm1WakeupHour) || channelUID.equals(clockAlarm1WakeupMinute)
|| channelUID.equals(clockAlarm1BedtimeHour) || channelUID.equals(clockAlarm1BedtimeMinute)) {
return 1;
} else if (channelUID.equals(clockAlarm2Enabled) || channelUID.equals(clockAlarm2Type)
|| channelUID.equals(clockAlarm2WakeupHour) || channelUID.equals(clockAlarm2WakeupMinute)
|| channelUID.equals(clockAlarm2BedtimeHour) || channelUID.equals(clockAlarm2BedtimeMinute)) {
return 2;
} else {
throw new IllegalArgumentException("The given channelUID is not an alarm clock channel: " + channelUID);
}
}
protected int getClockAlarmAndProgramSelectionIndexInModuleStatus() {
return 10;
}
}

View File

@@ -0,0 +1,128 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.handler;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.TooManyListenersException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.velbus.internal.config.VelbusSerialBridgeConfig;
import org.openhab.core.io.transport.serial.PortInUseException;
import org.openhab.core.io.transport.serial.SerialPort;
import org.openhab.core.io.transport.serial.SerialPortEvent;
import org.openhab.core.io.transport.serial.SerialPortEventListener;
import org.openhab.core.io.transport.serial.SerialPortIdentifier;
import org.openhab.core.io.transport.serial.SerialPortManager;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* {@link VelbusSerialBridgeHandler} is the handler for a Velbus Serial-interface and connects it to
* the framework.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusSerialBridgeHandler extends VelbusBridgeHandler implements SerialPortEventListener {
private final Logger logger = LoggerFactory.getLogger(VelbusSerialBridgeHandler.class);
private SerialPortManager serialPortManager;
private @Nullable SerialPort serialPort;
private @NonNullByDefault({}) VelbusSerialBridgeConfig serialBridgeConfig;
public VelbusSerialBridgeHandler(Bridge velbusBridge, SerialPortManager serialPortManager) {
super(velbusBridge);
this.serialPortManager = serialPortManager;
}
@Override
public void initialize() {
this.serialBridgeConfig = getConfigAs(VelbusSerialBridgeConfig.class);
super.initialize();
}
@Override
public void serialEvent(SerialPortEvent event) {
logger.debug("Serial port event triggered");
if (event.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
readPackets();
}
}
/**
* Makes a connection to the Velbus system.
*
* @return True if the connection succeeded, false if the connection did not succeed.
*/
@Override
protected boolean connect() {
// parse ports and if the port is found, initialize the reader
SerialPortIdentifier portId = serialPortManager.getIdentifier(serialBridgeConfig.port);
if (portId == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, "Port is not known!");
return false;
}
// initialize serial port
try {
SerialPort serialPort = portId.open(getThing().getUID().toString(), 2000);
this.serialPort = serialPort;
OutputStream outputStream = serialPort.getOutputStream();
InputStream inputStream = serialPort.getInputStream();
if (outputStream != null && inputStream != null) {
initializeStreams(outputStream, inputStream);
serialPort.addEventListener(this);
serialPort.notifyOnDataAvailable(true);
updateStatus(ThingStatus.ONLINE);
logger.debug("Bridge online on serial port {}", serialBridgeConfig.port);
return true;
}
} catch (final IOException ex) {
onConnectionLost();
logger.debug("I/O error on serial port {}", serialBridgeConfig.port);
} catch (PortInUseException e) {
onConnectionLost();
logger.debug("Port {} is in use", serialBridgeConfig.port);
} catch (TooManyListenersException e) {
onConnectionLost();
logger.debug("Cannot attach listener to port {}", serialBridgeConfig.port);
}
return false;
}
@Override
protected void disconnect() {
final SerialPort serialPort = this.serialPort;
if (serialPort != null) {
serialPort.removeEventListener();
serialPort.close();
this.serialPort = null;
}
super.disconnect();
}
}

View File

@@ -0,0 +1,137 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.handler;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.COMMAND_SENSOR_TEMPERATURE;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import javax.measure.quantity.Temperature;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.velbus.internal.config.VelbusSensorConfig;
import org.openhab.binding.velbus.internal.packets.VelbusPacket;
import org.openhab.binding.velbus.internal.packets.VelbusSensorTemperatureRequestPacket;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
/**
* The {@link VelbusTemperatureSensorHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public abstract class VelbusTemperatureSensorHandler extends VelbusSensorWithAlarmClockHandler {
private @Nullable ScheduledFuture<?> refreshJob;
private @NonNullByDefault({}) VelbusSensorConfig sensorConfig;
private ChannelUID temperatureChannel;
public VelbusTemperatureSensorHandler(Thing thing, int numberOfSubAddresses, ChannelUID temperatureChannel) {
super(thing, numberOfSubAddresses);
this.temperatureChannel = temperatureChannel;
}
@Override
public void initialize() {
this.sensorConfig = getConfigAs(VelbusSensorConfig.class);
super.initialize();
initializeAutomaticRefresh();
}
private void initializeAutomaticRefresh() {
int refreshInterval = this.sensorConfig.refresh;
if (refreshInterval > 0) {
startAutomaticRefresh(refreshInterval);
}
}
@Override
public void dispose() {
final ScheduledFuture<?> refreshJob = this.refreshJob;
if (refreshJob != null) {
refreshJob.cancel(true);
}
}
private void startAutomaticRefresh(int refreshInterval) {
VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
if (velbusBridgeHandler == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
return;
}
refreshJob = scheduler.scheduleWithFixedDelay(() -> {
sendSensorReadoutRequest(velbusBridgeHandler);
}, 0, refreshInterval, TimeUnit.SECONDS);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
super.handleCommand(channelUID, command);
VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
if (velbusBridgeHandler == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
return;
}
if (command instanceof RefreshType) {
if (channelUID.equals(temperatureChannel)) {
sendSensorReadoutRequest(velbusBridgeHandler);
}
}
}
protected void sendSensorReadoutRequest(VelbusBridgeHandler velbusBridgeHandler) {
VelbusSensorTemperatureRequestPacket packet = new VelbusSensorTemperatureRequestPacket(
getModuleAddress().getAddress());
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
}
@Override
public void onPacketReceived(byte[] packet) {
super.onPacketReceived(packet);
logger.trace("onPacketReceived() was called");
if (packet[0] == VelbusPacket.STX && packet.length >= 5) {
byte command = packet[4];
if (command == COMMAND_SENSOR_TEMPERATURE && packet.length >= 6) {
byte highByteCurrentSensorTemperature = packet[5];
byte lowByteCurrentSensorTemperature = packet[6];
boolean negative = (highByteCurrentSensorTemperature & 0x80) == 0x80;
double temperature = ((((highByteCurrentSensorTemperature & 0x7f) << 3)
+ ((lowByteCurrentSensorTemperature & 0xff) >> 5)) - (negative ? 0x400 : 0)) * 0.0625;
QuantityType<Temperature> state = new QuantityType<>(temperature, SIUnits.CELSIUS);
updateState(temperatureChannel, state);
}
}
}
}

View File

@@ -0,0 +1,324 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.handler;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.velbus.internal.packets.VelbusPacket;
import org.openhab.binding.velbus.internal.packets.VelbusSensorSettingsRequestPacket;
import org.openhab.binding.velbus.internal.packets.VelbusSetTemperaturePacket;
import org.openhab.binding.velbus.internal.packets.VelbusThermostatModePacket;
import org.openhab.binding.velbus.internal.packets.VelbusThermostatOperatingModePacket;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.CommonTriggerEvents;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
/**
* The {@link VelbusThermostatHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public abstract class VelbusThermostatHandler extends VelbusTemperatureSensorHandler {
private static final double THERMOSTAT_TEMPERATURE_SETPOINT_RESOLUTION = 0.5;
private static final StringType OPERATING_MODE_HEATING = new StringType("HEATING");
private static final StringType OPERATING_MODE_COOLING = new StringType("COOLING");
private static final byte OPERATING_MODE_MASK = (byte) 0x80;
private static final byte COOLING_MODE_MASK = (byte) 0x80;
private static final StringType MODE_COMFORT = new StringType("COMFORT");
private static final StringType MODE_DAY = new StringType("DAY");
private static final StringType MODE_NIGHT = new StringType("NIGHT");
private static final StringType MODE_SAFE = new StringType("SAFE");
private static final byte MODE_MASK = (byte) 0x70;
private static final byte COMFORT_MODE_MASK = (byte) 0x40;
private static final byte DAY_MODE_MASK = (byte) 0x20;
private static final byte NIGHT_MODE_MASK = (byte) 0x10;
private final ChannelUID currentTemperatureSetpointChannel = new ChannelUID(thing.getUID(), "thermostat",
"currentTemperatureSetpoint");
private final ChannelUID heatingModeComfortTemperatureSetpointChannel = new ChannelUID(thing.getUID(), "thermostat",
"heatingModeComfortTemperatureSetpoint");
private final ChannelUID heatingModeDayTemperatureSetpointChannel = new ChannelUID(thing.getUID(), "thermostat",
"heatingModeDayTemperatureSetpoint");
private final ChannelUID heatingModeNightTemperatureSetpointChannel = new ChannelUID(thing.getUID(), "thermostat",
"heatingModeNightTemperatureSetpoint");
private final ChannelUID heatingModeAntifrostTemperatureSetpointChannel = new ChannelUID(thing.getUID(),
"thermostat", "heatingModeAntiFrostTemperatureSetpoint");
private final ChannelUID coolingModeComfortTemperatureSetpointChannel = new ChannelUID(thing.getUID(), "thermostat",
"coolingModeComfortTemperatureSetpoint");
private final ChannelUID coolingModeDayTemperatureSetpointChannel = new ChannelUID(thing.getUID(), "thermostat",
"coolingModeDayTemperatureSetpoint");
private final ChannelUID coolingModeNightTemperatureSetpointChannel = new ChannelUID(thing.getUID(), "thermostat",
"coolingModeNightTemperatureSetpoint");
private final ChannelUID coolingModeSafeTemperatureSetpointChannel = new ChannelUID(thing.getUID(), "thermostat",
"coolingModeSafeTemperatureSetpoint");
private final ChannelUID operatingModeChannel = new ChannelUID(thing.getUID(), "thermostat", "operatingMode");
private final ChannelUID modeChannel = new ChannelUID(thing.getUID(), "thermostat", "mode");
private final ChannelUID heaterChannel = new ChannelUID(thing.getUID(), "thermostat", "heater");
private final ChannelUID boostChannel = new ChannelUID(thing.getUID(), "thermostat", "boost");
private final ChannelUID pumpChannel = new ChannelUID(thing.getUID(), "thermostat", "pump");
private final ChannelUID coolerChannel = new ChannelUID(thing.getUID(), "thermostat", "cooler");
private final ChannelUID alarm1Channel = new ChannelUID(thing.getUID(), "thermostat", "alarm1");
private final ChannelUID alarm2Channel = new ChannelUID(thing.getUID(), "thermostat", "alarm2");
private final ChannelUID alarm3Channel = new ChannelUID(thing.getUID(), "thermostat", "alarm3");
private final ChannelUID alarm4Channel = new ChannelUID(thing.getUID(), "thermostat", "alarm4");
public VelbusThermostatHandler(Thing thing, int numberOfSubAddresses, ChannelUID temperatureChannel) {
super(thing, numberOfSubAddresses, temperatureChannel);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
super.handleCommand(channelUID, command);
VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
if (velbusBridgeHandler == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
return;
}
if (isThermostatChannel(channelUID) && command instanceof RefreshType) {
VelbusSensorSettingsRequestPacket packet = new VelbusSensorSettingsRequestPacket(
getModuleAddress().getAddress());
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
} else if (isThermostatChannel(channelUID)
&& (command instanceof QuantityType<?> || command instanceof DecimalType)) {
byte temperatureVariable = determineTemperatureVariable(channelUID);
QuantityType<?> temperatureInDegreesCelcius = (command instanceof QuantityType<?>)
? ((QuantityType<?>) command).toUnit(SIUnits.CELSIUS)
: new QuantityType<>(((DecimalType) command), SIUnits.CELSIUS);
if (temperatureInDegreesCelcius != null) {
byte temperature = convertToTwoComplementByte(temperatureInDegreesCelcius.doubleValue(),
THERMOSTAT_TEMPERATURE_SETPOINT_RESOLUTION);
VelbusSetTemperaturePacket packet = new VelbusSetTemperaturePacket(getModuleAddress().getAddress(),
temperatureVariable, temperature);
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
}
} else if (channelUID.equals(operatingModeChannel) && command instanceof StringType) {
byte commandByte = ((StringType) command).equals(OPERATING_MODE_HEATING) ? COMMAND_SET_HEATING_MODE
: COMMAND_SET_COOLING_MODE;
VelbusThermostatOperatingModePacket packet = new VelbusThermostatOperatingModePacket(
getModuleAddress().getAddress(), commandByte);
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
} else if (channelUID.equals(modeChannel) && command instanceof StringType) {
byte commandByte = COMMAND_SWITCH_TO_SAFE_MODE;
StringType stringTypeCommand = (StringType) command;
if (stringTypeCommand.equals(MODE_COMFORT)) {
commandByte = COMMAND_SWITCH_TO_COMFORT_MODE;
} else if (stringTypeCommand.equals(MODE_DAY)) {
commandByte = COMMAND_SWITCH_TO_DAY_MODE;
} else if (stringTypeCommand.equals(MODE_NIGHT)) {
commandByte = COMMAND_SWITCH_TO_NIGHT_MODE;
}
VelbusThermostatModePacket packet = new VelbusThermostatModePacket(getModuleAddress().getAddress(),
commandByte);
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
} else {
logger.debug("The command '{}' is not supported by this handler.", command.getClass());
}
}
@Override
public void onPacketReceived(byte[] packet) {
super.onPacketReceived(packet);
logger.trace("onPacketReceived() was called");
if (packet[0] == VelbusPacket.STX && packet.length >= 5) {
byte address = packet[2];
byte command = packet[4];
if (command == COMMAND_TEMP_SENSOR_SETTINGS_PART1 && packet.length >= 9) {
byte currentTemperatureSetByte = packet[5];
byte heatingModeComfortTemperatureSetByte = packet[6];
byte heatingModeDayTemperatureSetByte = packet[7];
byte heatingModeNightTemperatureSetByte = packet[8];
byte heatingModeAntiFrostTemperatureSetByte = packet[9];
double currentTemperatureSet = convertFromTwoComplementByte(currentTemperatureSetByte,
THERMOSTAT_TEMPERATURE_SETPOINT_RESOLUTION);
double heatingModeComfortTemperatureSet = convertFromTwoComplementByte(
heatingModeComfortTemperatureSetByte, THERMOSTAT_TEMPERATURE_SETPOINT_RESOLUTION);
double heatingModeDayTemperatureSet = convertFromTwoComplementByte(heatingModeDayTemperatureSetByte,
THERMOSTAT_TEMPERATURE_SETPOINT_RESOLUTION);
double heatingModeNightTemperatureSet = convertFromTwoComplementByte(heatingModeNightTemperatureSetByte,
THERMOSTAT_TEMPERATURE_SETPOINT_RESOLUTION);
double heatingModeAntiFrostTemperatureSet = convertFromTwoComplementByte(
heatingModeAntiFrostTemperatureSetByte, THERMOSTAT_TEMPERATURE_SETPOINT_RESOLUTION);
updateState(currentTemperatureSetpointChannel,
new QuantityType<>(currentTemperatureSet, SIUnits.CELSIUS));
updateState(heatingModeComfortTemperatureSetpointChannel,
new QuantityType<>(heatingModeComfortTemperatureSet, SIUnits.CELSIUS));
updateState(heatingModeDayTemperatureSetpointChannel,
new QuantityType<>(heatingModeDayTemperatureSet, SIUnits.CELSIUS));
updateState(heatingModeNightTemperatureSetpointChannel,
new QuantityType<>(heatingModeNightTemperatureSet, SIUnits.CELSIUS));
updateState(heatingModeAntifrostTemperatureSetpointChannel,
new QuantityType<>(heatingModeAntiFrostTemperatureSet, SIUnits.CELSIUS));
} else if (command == COMMAND_TEMP_SENSOR_SETTINGS_PART2 && packet.length >= 8) {
byte coolingModeComfortTemperatureSetByte = packet[5];
byte coolingModeDayTemperatureSetByte = packet[6];
byte coolingModeNightTemperatureSetByte = packet[7];
byte coolingModeSafeTemperatureSetByte = packet[8];
double coolingModeComfortTemperatureSet = convertFromTwoComplementByte(
coolingModeComfortTemperatureSetByte, THERMOSTAT_TEMPERATURE_SETPOINT_RESOLUTION);
double coolingModeDayTemperatureSet = convertFromTwoComplementByte(coolingModeDayTemperatureSetByte,
THERMOSTAT_TEMPERATURE_SETPOINT_RESOLUTION);
double coolingModeNightTemperatureSet = convertFromTwoComplementByte(coolingModeNightTemperatureSetByte,
THERMOSTAT_TEMPERATURE_SETPOINT_RESOLUTION);
double coolingModeSafeTemperatureSet = convertFromTwoComplementByte(coolingModeSafeTemperatureSetByte,
THERMOSTAT_TEMPERATURE_SETPOINT_RESOLUTION);
updateState(coolingModeComfortTemperatureSetpointChannel,
new QuantityType<>(coolingModeComfortTemperatureSet, SIUnits.CELSIUS));
updateState(coolingModeDayTemperatureSetpointChannel,
new QuantityType<>(coolingModeDayTemperatureSet, SIUnits.CELSIUS));
updateState(coolingModeNightTemperatureSetpointChannel,
new QuantityType<>(coolingModeNightTemperatureSet, SIUnits.CELSIUS));
updateState(coolingModeSafeTemperatureSetpointChannel,
new QuantityType<>(coolingModeSafeTemperatureSet, SIUnits.CELSIUS));
} else if (command == COMMAND_TEMP_SENSOR_STATUS && packet.length >= 9) {
byte operatingMode = packet[5];
byte targetTemperature = packet[9];
if ((operatingMode & OPERATING_MODE_MASK) == COOLING_MODE_MASK) {
updateState(operatingModeChannel, OPERATING_MODE_COOLING);
} else {
updateState(operatingModeChannel, OPERATING_MODE_HEATING);
}
if ((operatingMode & MODE_MASK) == COMFORT_MODE_MASK) {
updateState(modeChannel, MODE_COMFORT);
} else if ((operatingMode & MODE_MASK) == DAY_MODE_MASK) {
updateState(modeChannel, MODE_DAY);
} else if ((operatingMode & MODE_MASK) == NIGHT_MODE_MASK) {
updateState(modeChannel, MODE_NIGHT);
} else {
updateState(modeChannel, MODE_SAFE);
}
double targetTemperatureValue = convertFromTwoComplementByte(targetTemperature,
THERMOSTAT_TEMPERATURE_SETPOINT_RESOLUTION);
updateState(currentTemperatureSetpointChannel,
new QuantityType<>(targetTemperatureValue, SIUnits.CELSIUS));
} else if (address != this.getModuleAddress().getAddress() && command == COMMAND_PUSH_BUTTON_STATUS) {
byte outputChannelsJustActivated = packet[5];
byte outputChannelsJustDeactivated = packet[6];
triggerThermostatChannels(outputChannelsJustActivated, CommonTriggerEvents.PRESSED);
triggerThermostatChannels(outputChannelsJustDeactivated, CommonTriggerEvents.RELEASED);
}
}
}
private void triggerThermostatChannels(byte outputChannels, String event) {
if ((outputChannels & 0x01) == 0x01) {
triggerChannel(heaterChannel, event);
}
if ((outputChannels & 0x02) == 0x02) {
triggerChannel(boostChannel, event);
}
if ((outputChannels & 0x04) == 0x04) {
triggerChannel(pumpChannel, event);
}
if ((outputChannels & 0x08) == 0x08) {
triggerChannel(coolerChannel, event);
}
if ((outputChannels & 0x10) == 0x10) {
triggerChannel(alarm1Channel, event);
}
if ((outputChannels & 0x20) == 0x20) {
triggerChannel(alarm2Channel, event);
}
if ((outputChannels & 0x40) == 0x40) {
triggerChannel(alarm3Channel, event);
}
if ((outputChannels & 0x80) == 0x80) {
triggerChannel(alarm4Channel, event);
}
}
protected boolean isThermostatChannel(ChannelUID channelUID) {
return channelUID.equals(currentTemperatureSetpointChannel)
|| channelUID.equals(heatingModeComfortTemperatureSetpointChannel)
|| channelUID.equals(heatingModeDayTemperatureSetpointChannel)
|| channelUID.equals(heatingModeNightTemperatureSetpointChannel)
|| channelUID.equals(heatingModeAntifrostTemperatureSetpointChannel)
|| channelUID.equals(coolingModeComfortTemperatureSetpointChannel)
|| channelUID.equals(coolingModeDayTemperatureSetpointChannel)
|| channelUID.equals(coolingModeNightTemperatureSetpointChannel)
|| channelUID.equals(coolingModeSafeTemperatureSetpointChannel)
|| channelUID.equals(operatingModeChannel) || channelUID.equals(modeChannel);
}
protected byte determineTemperatureVariable(ChannelUID channelUID) {
if (channelUID.equals(currentTemperatureSetpointChannel)) {
return 0x00;
} else if (channelUID.equals(heatingModeComfortTemperatureSetpointChannel)) {
return 0x01;
} else if (channelUID.equals(heatingModeDayTemperatureSetpointChannel)) {
return 0x02;
} else if (channelUID.equals(heatingModeNightTemperatureSetpointChannel)) {
return 0x03;
} else if (channelUID.equals(heatingModeAntifrostTemperatureSetpointChannel)) {
return 0x04;
} else if (channelUID.equals(coolingModeComfortTemperatureSetpointChannel)) {
return 0x07;
} else if (channelUID.equals(coolingModeDayTemperatureSetpointChannel)) {
return 0x08;
} else if (channelUID.equals(coolingModeNightTemperatureSetpointChannel)) {
return 0x09;
} else if (channelUID.equals(coolingModeSafeTemperatureSetpointChannel)) {
return 0x0A;
} else {
throw new IllegalArgumentException("The given channelUID is not a thermostat channel: " + channelUID);
}
}
protected double convertFromTwoComplementByte(byte value, double resolution) {
return ((value & 0x80) == 0x00) ? value * resolution : ((value & 0x7F) - 0x80) * resolution;
}
protected byte convertToTwoComplementByte(double value, double resolution) {
return (byte) (value / resolution);
}
}

View File

@@ -0,0 +1,241 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.handler;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.SUB_ADDRESS;
import java.lang.invoke.MethodHandles;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.velbus.internal.VelbusModuleAddress;
import org.openhab.binding.velbus.internal.VelbusPacketListener;
import org.openhab.binding.velbus.internal.config.VelbusThingConfig;
import org.openhab.binding.velbus.internal.packets.VelbusReadMemoryBlockPacket;
import org.openhab.binding.velbus.internal.packets.VelbusReadMemoryPacket;
import org.openhab.binding.velbus.internal.packets.VelbusStatusRequestPacket;
import org.openhab.binding.velbus.internal.packets.VelbusWriteMemoryPacket;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.builder.ChannelBuilder;
import org.openhab.core.thing.binding.builder.ThingBuilder;
import org.openhab.core.thing.type.ChannelKind;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.openhab.core.util.HexUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Base ThingHandler for all Velbus handlers.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public abstract class VelbusThingHandler extends BaseThingHandler implements VelbusPacketListener {
protected final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected @Nullable VelbusThingConfig velbusThingConfig;
private @Nullable VelbusBridgeHandler velbusBridgeHandler;
private @NonNullByDefault({}) VelbusModuleAddress velbusModuleAddress;
private int numberOfSubAddresses;
public VelbusThingHandler(Thing thing, int numberOfSubAddresses) {
super(thing);
this.numberOfSubAddresses = numberOfSubAddresses;
}
@Override
public void initialize() {
logger.debug("Initializing velbus handler.");
this.velbusThingConfig = getConfigAs(VelbusThingConfig.class);
Bridge bridge = getBridge();
initializeThing(bridge == null ? ThingStatus.OFFLINE : bridge.getStatus());
initializeChannelNames();
initializeChannelStates();
}
@Override
public void handleRemoval() {
VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
if (velbusBridgeHandler != null && velbusModuleAddress != null) {
byte[] activeAddresses = velbusModuleAddress.getActiveAddresses();
for (int i = 0; i < activeAddresses.length; i++) {
velbusBridgeHandler.unregisterRelayStatusListener(activeAddresses[i]);
}
}
super.handleRemoval();
}
protected VelbusModuleAddress getModuleAddress() {
return velbusModuleAddress;
}
protected void updateChannelLabel(ChannelUID channelUID, String channelName) {
Channel existingChannel = thing.getChannel(channelUID.getId());
if (existingChannel != null) {
String acceptedItem = existingChannel.getAcceptedItemType();
Configuration configuration = existingChannel.getConfiguration();
Set<String> defaultTags = existingChannel.getDefaultTags();
String description = existingChannel.getDescription();
ChannelKind kind = existingChannel.getKind();
Map<String, String> properties = existingChannel.getProperties();
ChannelTypeUID type = existingChannel.getChannelTypeUID();
ThingBuilder thingBuilder = editThing();
Channel channel = ChannelBuilder.create(channelUID, acceptedItem).withConfiguration(configuration)
.withDefaultTags(defaultTags).withDescription(description != null ? description : "").withKind(kind)
.withLabel(channelName).withProperties(properties).withType(type).build();
thingBuilder.withoutChannel(channelUID).withChannel(channel);
updateThing(thingBuilder.build());
}
}
private void initializeThing(ThingStatus bridgeStatus) {
this.velbusModuleAddress = createVelbusModuleAddress(numberOfSubAddresses);
if (this.velbusModuleAddress != null) {
logger.debug("initializeThing thing {} with address {} bridge status {}", getThing().getUID(),
velbusModuleAddress.getAddress(), bridgeStatus);
// note: this call implicitly registers our handler as a listener on
// the bridge
if (getVelbusBridgeHandler() != null) {
if (bridgeStatus == ThingStatus.ONLINE) {
updateStatus(ThingStatus.ONLINE);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
}
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
}
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, "Address is not known!");
}
}
protected @Nullable VelbusModuleAddress createVelbusModuleAddress(int numberOfSubAddresses) {
final VelbusThingConfig velbusThingConfig = this.velbusThingConfig;
if (velbusThingConfig != null) {
byte address = hexToByte(velbusThingConfig.address);
byte[] subAddresses = new byte[numberOfSubAddresses];
for (int i = 0; i < numberOfSubAddresses; i++) {
String propertyKey = SUB_ADDRESS + (i + 1);
if (getThing().getProperties().containsKey(propertyKey)) {
String subAddress = getThing().getProperties().get(propertyKey);
subAddresses[i] = hexToByte(subAddress);
} else {
subAddresses[i] = (byte) 0xFF;
}
}
return new VelbusModuleAddress(address, subAddresses);
}
return null;
}
private void initializeChannelNames() {
List<Channel> channels = this.getThing().getChannels();
for (int i = 0; i < channels.size(); i++) {
Channel channel = channels.get(i);
String channelUID = channel.getUID().getIdWithoutGroup();
if (getConfig().containsKey(channelUID)) {
String channelName = getConfig().get(channelUID).toString();
if (!channelName.equals(channel.getLabel())) {
updateChannelLabel(channel.getUID(), channelName);
}
}
}
}
private void initializeChannelStates() {
VelbusBridgeHandler velbusBridgeHandler = this.velbusBridgeHandler;
if (velbusBridgeHandler != null) {
VelbusStatusRequestPacket packet = new VelbusStatusRequestPacket(getModuleAddress().getAddress());
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
}
}
protected byte hexToByte(String hexString) {
if (hexString.length() > 2) {
throw new IllegalArgumentException("hexString contains more than one byte: " + hexString);
}
return HexUtils.hexToBytes(hexString)[0];
}
protected void sendReadMemoryBlockPacket(VelbusBridgeHandler velbusBridgeHandler, int memoryAddress) {
VelbusReadMemoryBlockPacket packet = new VelbusReadMemoryBlockPacket(getModuleAddress().getAddress(),
memoryAddress);
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
}
protected void sendReadMemoryPacket(VelbusBridgeHandler velbusBridgeHandler, int memoryAddress) {
VelbusReadMemoryPacket packet = new VelbusReadMemoryPacket(getModuleAddress().getAddress(), memoryAddress);
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
}
protected void sendWriteMemoryPacket(VelbusBridgeHandler velbusBridgeHandler, int memoryAddress, byte data) {
VelbusWriteMemoryPacket packet = new VelbusWriteMemoryPacket(getModuleAddress().getAddress(), memoryAddress,
data);
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
}
protected @Nullable synchronized VelbusBridgeHandler getVelbusBridgeHandler() {
if (this.velbusBridgeHandler == null) {
Bridge bridge = getBridge();
if (bridge == null) {
return null;
}
ThingHandler bridgeHandler = bridge.getHandler();
if (bridgeHandler instanceof VelbusBridgeHandler) {
VelbusBridgeHandler velbusBridgeHandler = (VelbusBridgeHandler) bridgeHandler;
this.velbusBridgeHandler = velbusBridgeHandler;
if (velbusModuleAddress != null) {
byte[] activeAddresses = velbusModuleAddress.getActiveAddresses();
for (int i = 0; i < activeAddresses.length; i++) {
velbusBridgeHandler.registerPacketListener(activeAddresses[i], this);
}
}
}
}
return this.velbusBridgeHandler;
}
}

View File

@@ -0,0 +1,39 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.handler;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.THING_TYPE_VMB1TS;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link VelbusVMB1TSHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusVMB1TSHandler extends VelbusThermostatHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(Arrays.asList(THING_TYPE_VMB1TS));
public VelbusVMB1TSHandler(Thing thing) {
super(thing, 0, new ChannelUID(thing.getUID(), "input", "CH1"));
}
}

View File

@@ -0,0 +1,271 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.handler;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.velbus.internal.VelbusChannelIdentifier;
import org.openhab.binding.velbus.internal.config.VelbusSensorConfig;
import org.openhab.binding.velbus.internal.packets.VelbusDimmerPacket;
import org.openhab.binding.velbus.internal.packets.VelbusPacket;
import org.openhab.binding.velbus.internal.packets.VelbusSensorReadoutRequestPacket;
import org.openhab.binding.velbus.internal.packets.VelbusStatusRequestPacket;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.library.unit.MetricPrefix;
import org.openhab.core.library.unit.SmartHomeUnits;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
/**
* The {@link VelbusVMB4ANHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusVMB4ANHandler extends VelbusSensorWithAlarmClockHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(Arrays.asList(THING_TYPE_VMB4AN));
private static final String ALARM_GROUP = "alarm";
private static final String ANALOG_INPUT_GROUP = "analogInput";
private static final String ANALOG_OUTPUT_GROUP = "analogOutput";
private static final String RAW_CHANNEL_SUFFIX = "Raw";
private static final byte VOLTAGE_SENSOR_TYPE = 0x00;
private static final byte CURRENT_SENSOR_TYPE = 0x01;
private static final byte RESISTANCE_SENSOR_TYPE = 0x02;
private static final byte PERIOD_MEASUREMENT_SENSOR_TYPE = 0x03;
private String[] channelText = new String[] { "", "", "", "" };
private @Nullable ScheduledFuture<?> refreshJob;
private @NonNullByDefault({}) VelbusSensorConfig sensorConfig;
public VelbusVMB4ANHandler(Thing thing) {
super(thing, 0);
}
@Override
public void initialize() {
this.sensorConfig = getConfigAs(VelbusSensorConfig.class);
super.initialize();
initializeAutomaticRefresh();
}
private void initializeAutomaticRefresh() {
int refreshInterval = sensorConfig.refresh;
if (refreshInterval > 0) {
startAutomaticRefresh(refreshInterval);
}
}
@Override
public void dispose() {
final ScheduledFuture<?> refreshJob = this.refreshJob;
if (refreshJob != null) {
refreshJob.cancel(true);
}
}
private void startAutomaticRefresh(int refreshInterval) {
VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
if (velbusBridgeHandler == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
return;
}
refreshJob = scheduler.scheduleWithFixedDelay(() -> {
sendSensorReadoutRequest(velbusBridgeHandler, ALL_CHANNELS);
}, 0, refreshInterval, TimeUnit.SECONDS);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
super.handleCommand(channelUID, command);
VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
if (velbusBridgeHandler == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
return;
}
byte channelByte = convertChannelUIDToChannelByte(channelUID);
if (command instanceof RefreshType) {
VelbusStatusRequestPacket packet = new VelbusStatusRequestPacket(channelByte);
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
} else if (command instanceof PercentType && isAnalogOutputChannel(channelUID)) {
VelbusDimmerPacket packet = new VelbusDimmerPacket(
new VelbusChannelIdentifier(this.getModuleAddress().getAddress(), channelByte), COMMAND_SET_VALUE,
((PercentType) command).byteValue(), 0x00, false);
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
}
}
protected void sendSensorReadoutRequest(VelbusBridgeHandler velbusBridgeHandler, byte channel) {
VelbusSensorReadoutRequestPacket packet = new VelbusSensorReadoutRequestPacket(getModuleAddress().getAddress(),
channel);
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
}
@Override
public void onPacketReceived(byte[] packet) {
super.onPacketReceived(packet);
logger.trace("onPacketReceived() was called");
if (packet[0] == VelbusPacket.STX && packet.length >= 5) {
byte command = packet[4];
if (command == COMMAND_SENSOR_RAW_DATA && packet.length >= 10) {
byte channel = packet[5];
byte operatingMode = packet[6];
byte upperByteSensorValue = packet[7];
byte highByteSensorValue = packet[8];
byte lowByteSensorValue = packet[9];
double sensorValue = (((upperByteSensorValue & 0xff) << 16) + ((highByteSensorValue & 0xff) << 8)
+ (lowByteSensorValue & 0xff));
String channelUID = convertAnalogInputChannelByteToRawChannelUID(channel);
switch (operatingMode) {
case VOLTAGE_SENSOR_TYPE:
double voltageResolution = 0.25;
double voltageSensorValueState = sensorValue * voltageResolution;
updateState(channelUID,
new QuantityType<>(voltageSensorValueState, MetricPrefix.MILLI(SmartHomeUnits.VOLT)));
break;
case CURRENT_SENSOR_TYPE:
double currentResolution = 5;
double currentSensorValueState = sensorValue * currentResolution;
updateState(channelUID,
new QuantityType<>(currentSensorValueState, MetricPrefix.MICRO(SmartHomeUnits.AMPERE)));
break;
case RESISTANCE_SENSOR_TYPE:
double resistanceResolution = 0.25;
double resistanceSensorValueState = sensorValue * resistanceResolution;
updateState(channelUID, new QuantityType<>(resistanceSensorValueState, SmartHomeUnits.OHM));
break;
case PERIOD_MEASUREMENT_SENSOR_TYPE:
double periodResolution = 0.5;
double periodSensorValueState = sensorValue * periodResolution;
updateState(channelUID,
new QuantityType<>(periodSensorValueState, MetricPrefix.MICRO(SmartHomeUnits.SECOND)));
break;
}
} else if (command == COMMAND_TEXT) {
byte channel = packet[5];
byte textStartPosition = packet[6];
StringBuilder contents = new StringBuilder();
for (int i = 7; i < packet.length - 2; i++) {
byte currentChar = packet[i];
if (currentChar == (byte) -0x50) {
contents.append("°");
} else if (currentChar != (byte) 0x00) {
contents.append((char) currentChar);
}
}
channelText[channel - 9] = channelText[channel - 9].substring(0, textStartPosition)
+ contents.toString()
+ (channelText[channel - 9].length() > textStartPosition + 5 ? channelText[channel - 9]
.substring(textStartPosition + 5, channelText[channel - 9].length()) : "");
String channelUID = convertAnalogInputChannelByteToChannelUID(channel);
updateState(channelUID, new StringType(channelText[channel - 9]));
}
}
}
protected byte convertChannelUIDToChannelByte(ChannelUID channelUID) {
if (isAlarmChannel(channelUID)) {
return convertAlarmChannelUIDToChannelByte(channelUID);
} else if (isTextAnalogInputChannel(channelUID)) {
return convertTextAnalogInputChannelUIDToChannelByte(channelUID);
} else if (isRawAnalogInputChannel(channelUID)) {
return convertRawAnalogInputChannelUIDToChannelByte(channelUID);
} else if (isAnalogOutputChannel(channelUID)) {
return convertAnalogOutputChannelUIDToChannelByte(channelUID);
} else {
throw new UnsupportedOperationException(
"The channel '" + channelUID + "' is not supported on a VMB4AN module.");
}
}
protected boolean isAlarmChannel(ChannelUID channelUID) {
return ALARM_GROUP.equals(channelUID.getGroupId());
}
protected byte convertAlarmChannelUIDToChannelByte(ChannelUID channelUID) {
return Byte.parseByte(channelUID.getIdWithoutGroup());
}
protected boolean isTextAnalogInputChannel(ChannelUID channelUID) {
return ANALOG_INPUT_GROUP.equals(channelUID.getGroupId())
&& !channelUID.getIdWithoutGroup().endsWith(RAW_CHANNEL_SUFFIX);
}
protected boolean isRawAnalogInputChannel(ChannelUID channelUID) {
return ANALOG_INPUT_GROUP.equals(channelUID.getGroupId())
&& channelUID.getIdWithoutGroup().endsWith(RAW_CHANNEL_SUFFIX);
}
protected byte convertRawAnalogInputChannelUIDToChannelByte(ChannelUID channelUID) {
return Byte.parseByte(channelUID.getIdWithoutGroup().replaceAll(RAW_CHANNEL_SUFFIX, ""));
}
protected byte convertTextAnalogInputChannelUIDToChannelByte(ChannelUID channelUID) {
return Byte.parseByte(channelUID.getIdWithoutGroup());
}
protected String convertAnalogInputChannelByteToRawChannelUID(byte channelByte) {
return convertAnalogInputChannelByteToChannelUID(channelByte) + RAW_CHANNEL_SUFFIX;
}
protected String convertAnalogInputChannelByteToChannelUID(byte channelByte) {
return ANALOG_INPUT_GROUP + "#" + channelByte;
}
protected boolean isAnalogOutputChannel(ChannelUID channelUID) {
return ANALOG_OUTPUT_GROUP.equals(channelUID.getGroupId());
}
protected byte convertAnalogOutputChannelUIDToChannelByte(ChannelUID channelUID) {
return Byte.parseByte(channelUID.getIdWithoutGroup());
}
}

View File

@@ -0,0 +1,179 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.handler;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.velbus.internal.VelbusChannelIdentifier;
import org.openhab.binding.velbus.internal.config.VelbusVMB7INConfig;
import org.openhab.binding.velbus.internal.packets.VelbusCounterStatusRequestPacket;
import org.openhab.binding.velbus.internal.packets.VelbusPacket;
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.thing.ThingTypeUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
/**
* The {@link VelbusVMB7INHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusVMB7INHandler extends VelbusSensorWithAlarmClockHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(Arrays.asList(THING_TYPE_VMB7IN));
private final ChannelUID counter1Channel = new ChannelUID(thing.getUID(), "counter", "counter1");
private final ChannelUID counter1ChannelCurrent = new ChannelUID(thing.getUID(), "counter", "counter1Current");
private final ChannelUID counter2Channel = new ChannelUID(thing.getUID(), "counter", "counter2");
private final ChannelUID counter2ChannelCurrent = new ChannelUID(thing.getUID(), "counter", "counter2Current");
private final ChannelUID counter3Channel = new ChannelUID(thing.getUID(), "counter", "counter3");
private final ChannelUID counter3ChannelCurrent = new ChannelUID(thing.getUID(), "counter", "counter3Current");
private final ChannelUID counter4Channel = new ChannelUID(thing.getUID(), "counter", "counter4");
private final ChannelUID counter4ChannelCurrent = new ChannelUID(thing.getUID(), "counter", "counter4Current");
public @NonNullByDefault({}) VelbusVMB7INConfig vmb7inConfig;
private @Nullable ScheduledFuture<?> refreshJob;
public VelbusVMB7INHandler(Thing thing) {
super(thing, 0);
}
@Override
public void initialize() {
this.vmb7inConfig = getConfigAs(VelbusVMB7INConfig.class);
super.initialize();
initializeAutomaticRefresh();
}
private void initializeAutomaticRefresh() {
int refreshInterval = vmb7inConfig.refresh;
if (refreshInterval > 0) {
startAutomaticRefresh(refreshInterval);
}
}
@Override
public void dispose() {
final ScheduledFuture<?> refreshJob = this.refreshJob;
if (refreshJob != null) {
refreshJob.cancel(true);
}
}
private void startAutomaticRefresh(int refreshInterval) {
VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
if (velbusBridgeHandler == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
return;
}
refreshJob = scheduler.scheduleWithFixedDelay(() -> {
sendCounterStatusRequest(velbusBridgeHandler, ALL_CHANNELS);
}, 0, refreshInterval, TimeUnit.SECONDS);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
super.handleCommand(channelUID, command);
VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
if (velbusBridgeHandler == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
return;
}
if (command instanceof RefreshType) {
if (channelUID.equals(counter1Channel)) {
sendCounterStatusRequest(velbusBridgeHandler, (byte) 0x01);
} else if (channelUID.equals(counter2Channel)) {
sendCounterStatusRequest(velbusBridgeHandler, (byte) 0x02);
} else if (channelUID.equals(counter3Channel)) {
sendCounterStatusRequest(velbusBridgeHandler, (byte) 0x03);
} else if (channelUID.equals(counter4Channel)) {
sendCounterStatusRequest(velbusBridgeHandler, (byte) 0x04);
}
}
}
protected void sendCounterStatusRequest(VelbusBridgeHandler velbusBridgeHandler, byte channel) {
VelbusCounterStatusRequestPacket packet = new VelbusCounterStatusRequestPacket(
new VelbusChannelIdentifier(getModuleAddress().getAddress(), channel));
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
}
@Override
public void onPacketReceived(byte[] packet) {
super.onPacketReceived(packet);
logger.trace("onPacketReceived() was called");
if (packet[0] == VelbusPacket.STX && packet.length >= 5) {
byte command = packet[4];
if (command == COMMAND_COUNTER_STATUS && packet.length >= 6) {
int counterChannel = packet[5] & 0x03;
int pulsesPerUnit = ((packet[5] & 0x7C) / 0x04) * 0x64;
double counterValue = ((double) (((packet[6] & 0xff) << 24) | ((packet[7] & 0xff) << 16)
| ((packet[8] & 0xff) << 8) | (packet[9] & 0xff))) / pulsesPerUnit;
double currentValue = (1000 * 3600)
/ (((double) (((packet[10] & 0xff) << 8) | (packet[11] & 0xff))) * pulsesPerUnit);
switch (counterChannel) {
case 0x00:
double counter1PulseMultiplier = vmb7inConfig.counter1PulseMultiplier;
updateState(counter1Channel, new DecimalType(counterValue / counter1PulseMultiplier));
updateState(counter1ChannelCurrent, new DecimalType(currentValue / counter1PulseMultiplier));
break;
case 0x01:
double counter2PulseMultiplier = vmb7inConfig.counter2PulseMultiplier;
updateState(counter2Channel, new DecimalType(counterValue / counter2PulseMultiplier));
updateState(counter2ChannelCurrent, new DecimalType(currentValue / counter2PulseMultiplier));
break;
case 0x02:
double counter3PulseMultiplier = vmb7inConfig.counter3PulseMultiplier;
updateState(counter3Channel, new DecimalType(counterValue / counter3PulseMultiplier));
updateState(counter3ChannelCurrent, new DecimalType(currentValue / counter3PulseMultiplier));
break;
case 0x03:
double counter4PulseMultiplier = vmb7inConfig.counter4PulseMultiplier;
updateState(counter4Channel, new DecimalType(counterValue / counter4PulseMultiplier));
updateState(counter4ChannelCurrent, new DecimalType(currentValue / counter4PulseMultiplier));
break;
default:
throw new IllegalArgumentException(
"The given channel is not a counter channel: " + counterChannel);
}
}
}
}
}

View File

@@ -0,0 +1,40 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.handler;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link VelbusVMBELHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusVMBELHandler extends VelbusThermostatHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(
Arrays.asList(THING_TYPE_VMBEL1, THING_TYPE_VMBEL2, THING_TYPE_VMBEL4));
public VelbusVMBELHandler(Thing thing) {
super(thing, 4, new ChannelUID(thing.getUID(), "input", "CH9"));
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.handler;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.THING_TYPE_VMBELO;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link VelbusVMBELOHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusVMBELOHandler extends VelbusMemoHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(Arrays.asList(THING_TYPE_VMBELO));
public VelbusVMBELOHandler(Thing thing) {
super(thing);
}
}

View File

@@ -0,0 +1,41 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.handler;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link VelbusVMBGPHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusVMBGPHandler extends VelbusThermostatHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(
Arrays.asList(THING_TYPE_VMBGP1, THING_TYPE_VMBGP1_2, THING_TYPE_VMBGP2, THING_TYPE_VMBGP2_2,
THING_TYPE_VMBGP4, THING_TYPE_VMBGP4_2, THING_TYPE_VMBGP4PIR, THING_TYPE_VMBGP4PIR_2));
public VelbusVMBGPHandler(Thing thing) {
super(thing, 4, new ChannelUID(thing.getUID(), "input", "CH9"));
}
}

View File

@@ -0,0 +1,105 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.handler;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.velbus.internal.packets.VelbusPacket;
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.thing.ThingTypeUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
/**
* The {@link VelbusVMBGPOHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusVMBGPOHandler extends VelbusMemoHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(
Arrays.asList(THING_TYPE_VMBGPO, THING_TYPE_VMBGPOD, THING_TYPE_VMBGPOD_2));
public static final int MODULESETTINGS_MEMORY_ADDRESS = 0x02F0;
public static final int LAST_MEMORY_LOCATION_ADDRESS = 0x1A03;
private final ChannelUID screensaverChannel = new ChannelUID(thing.getUID(), "oledDisplay", "SCREENSAVER");
private byte moduleSettings;
public VelbusVMBGPOHandler(Thing thing) {
super(thing);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
super.handleCommand(channelUID, command);
VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
if (velbusBridgeHandler == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
return;
}
if (channelUID.equals(screensaverChannel) && command instanceof RefreshType) {
sendReadMemoryPacket(velbusBridgeHandler, MODULESETTINGS_MEMORY_ADDRESS);
}
if (channelUID.equals(screensaverChannel) && command instanceof OnOffType) {
byte screenSaverOnOffByte = (byte) ((command == OnOffType.ON) ? 0x80 : 0x00);
moduleSettings = (byte) (screenSaverOnOffByte | (moduleSettings & 0x7F));
sendWriteMemoryPacket(velbusBridgeHandler, MODULESETTINGS_MEMORY_ADDRESS, moduleSettings);
sendWriteMemoryPacket(velbusBridgeHandler, LAST_MEMORY_LOCATION_ADDRESS, (byte) 0xFF);
}
}
@Override
public void onPacketReceived(byte[] packet) {
super.onPacketReceived(packet);
logger.trace("onPacketReceived() was called");
if (packet[0] == VelbusPacket.STX && packet.length >= 5) {
byte command = packet[4];
if ((command == COMMAND_MEMORY_DATA_BLOCK && packet.length >= 11)
|| (command == COMMAND_MEMORY_DATA && packet.length >= 8)) {
byte highMemoryAddress = packet[5];
byte lowMemoryAddress = packet[6];
int memoryAddress = ((highMemoryAddress & 0xff) << 8) | (lowMemoryAddress & 0xff);
byte[] data = (command == COMMAND_MEMORY_DATA_BLOCK)
? new byte[] { packet[7], packet[8], packet[9], packet[10] }
: new byte[] { packet[7] };
for (int i = 0; i < data.length; i++) {
if ((memoryAddress + i) == MODULESETTINGS_MEMORY_ADDRESS) {
this.moduleSettings = data[i];
OnOffType state = ((this.moduleSettings & 0x80) != 0x00) ? OnOffType.ON : OnOffType.OFF;
updateState(screensaverChannel, state);
}
}
}
}
}
}

View File

@@ -0,0 +1,137 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.handler;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.measure.quantity.Illuminance;
import javax.measure.quantity.Length;
import javax.measure.quantity.Speed;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.velbus.internal.packets.VelbusPacket;
import org.openhab.binding.velbus.internal.packets.VelbusSensorReadoutRequestPacket;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.MetricPrefix;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.SmartHomeUnits;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
/**
* The {@link VelbusVMBMeteoHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusVMBMeteoHandler extends VelbusTemperatureSensorHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(Arrays.asList(THING_TYPE_VMBMETEO));
private static final byte RAIN_SENSOR_CHANNEL = 0x02;
private static final byte LIGHT_SENSOR_CHANNEL = 0x04;
private static final byte WIND_SENSOR_CHANNEL = 0x08;
private static final byte ALL_SENSOR_CHANNELS = RAIN_SENSOR_CHANNEL | LIGHT_SENSOR_CHANNEL | WIND_SENSOR_CHANNEL;
private ChannelUID rainfallChannel;
private ChannelUID illuminanceChannel;
private ChannelUID windspeedChannel;
public VelbusVMBMeteoHandler(Thing thing) {
super(thing, 0, new ChannelUID(thing.getUID(), "weatherStation", "CH10"));
this.rainfallChannel = new ChannelUID(thing.getUID(), "weatherStation", "CH11");
this.illuminanceChannel = new ChannelUID(thing.getUID(), "weatherStation", "CH12");
this.windspeedChannel = new ChannelUID(thing.getUID(), "weatherStation", "CH13");
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
super.handleCommand(channelUID, command);
VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
if (velbusBridgeHandler == null) {
logger.warn("Velbus bridge handler not found. Cannot handle command without bridge.");
return;
}
if (command instanceof RefreshType) {
if (channelUID.equals(rainfallChannel)) {
sendSensorReadoutRequest(velbusBridgeHandler, RAIN_SENSOR_CHANNEL);
} else if (channelUID.equals(illuminanceChannel)) {
sendSensorReadoutRequest(velbusBridgeHandler, LIGHT_SENSOR_CHANNEL);
} else if (channelUID.equals(windspeedChannel)) {
sendSensorReadoutRequest(velbusBridgeHandler, WIND_SENSOR_CHANNEL);
}
}
}
@Override
protected void sendSensorReadoutRequest(VelbusBridgeHandler velbusBridgeHandler) {
super.sendSensorReadoutRequest(velbusBridgeHandler);
sendSensorReadoutRequest(velbusBridgeHandler, ALL_SENSOR_CHANNELS);
}
protected void sendSensorReadoutRequest(VelbusBridgeHandler velbusBridgeHandler, byte channel) {
VelbusSensorReadoutRequestPacket packet = new VelbusSensorReadoutRequestPacket(getModuleAddress().getAddress(),
channel);
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
}
@Override
protected int getClockAlarmAndProgramSelectionIndexInModuleStatus() {
return 8;
}
@Override
public void onPacketReceived(byte[] packet) {
super.onPacketReceived(packet);
logger.trace("onPacketReceived() was called");
if (packet[0] == VelbusPacket.STX && packet.length >= 5) {
byte command = packet[4];
if (command == COMMAND_SENSOR_RAW_DATA && packet.length >= 10) {
byte highByteCurrentRainValue = packet[5];
byte lowByteCurrentRainValue = packet[6];
byte highByteCurrentLightValue = packet[7];
byte lowByteCurrentLightValue = packet[8];
byte highByteCurrentWindValue = packet[9];
byte lowByteCurrentWindValue = packet[10];
double rainValue = (((highByteCurrentRainValue & 0xff) << 8) + (lowByteCurrentRainValue & 0xff)) / 10;
double lightValue = (((highByteCurrentLightValue & 0xff) << 8) + (lowByteCurrentLightValue & 0xff));
double windValue = (((highByteCurrentWindValue & 0xff) << 8) + (lowByteCurrentWindValue & 0xff)) / 10;
QuantityType<Length> rainValueState = new QuantityType<>(rainValue, MetricPrefix.MILLI(SIUnits.METRE));
QuantityType<Illuminance> lightValueState = new QuantityType<>(lightValue, SmartHomeUnits.LUX);
QuantityType<Speed> windValueState = new QuantityType<>(windValue, SIUnits.KILOMETRE_PER_HOUR);
updateState(rainfallChannel, rainValueState);
updateState(illuminanceChannel, lightValueState);
updateState(windspeedChannel, windValueState);
}
}
}
}

View File

@@ -0,0 +1,94 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.handler;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.measure.quantity.Illuminance;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.velbus.internal.packets.VelbusLightValueRequestPacket;
import org.openhab.binding.velbus.internal.packets.VelbusPacket;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SmartHomeUnits;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
/**
* The {@link VelbusVMBPIROHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusVMBPIROHandler extends VelbusTemperatureSensorHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(Arrays.asList(THING_TYPE_VMBPIRO));
private ChannelUID illuminanceChannel;
public VelbusVMBPIROHandler(Thing thing) {
super(thing, 0, new ChannelUID(thing.getUID(), "input", "CH9"));
this.illuminanceChannel = new ChannelUID(thing.getUID(), "input", "LIGHT");
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
super.handleCommand(channelUID, command);
VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
if (velbusBridgeHandler == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
return;
}
if (command instanceof RefreshType) {
if (channelUID.equals(illuminanceChannel)) {
VelbusLightValueRequestPacket packet = new VelbusLightValueRequestPacket(
getModuleAddress().getAddress());
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
}
}
}
@Override
public void onPacketReceived(byte[] packet) {
super.onPacketReceived(packet);
logger.trace("onPacketReceived() was called");
if (packet[0] == VelbusPacket.STX && packet.length >= 5) {
byte command = packet[4];
if (command == COMMAND_MODULE_STATUS && packet.length >= 6) {
byte highByteCurrentLightValue = packet[6];
byte lowByteCurrentLightValue = packet[7];
double lightValue = (((highByteCurrentLightValue & 0xff) << 8) + (lowByteCurrentLightValue & 0xff));
QuantityType<Illuminance> lightValueState = new QuantityType<>(lightValue, SmartHomeUnits.LUX);
updateState(illuminanceChannel, lightValueState);
}
}
}
}

View File

@@ -0,0 +1,40 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.COMMAND_SWITCH_BLIND_OFF;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.velbus.internal.VelbusChannelIdentifier;
/**
* The {@link VelbusBlindOffPacket} represents a Velbus packet that can be used to
* stop a moving blind.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusBlindOffPacket extends VelbusPacket {
private byte channel;
public VelbusBlindOffPacket(VelbusChannelIdentifier velbusChannelIdentifier) {
super(velbusChannelIdentifier.getAddress(), PRIO_HI);
this.channel = velbusChannelIdentifier.getChannelByte();
}
@Override
protected byte[] getDataBytes() {
return new byte[] { COMMAND_SWITCH_BLIND_OFF, channel };
}
}

View File

@@ -0,0 +1,42 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.COMMAND_BLIND_POS;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.velbus.internal.VelbusChannelIdentifier;
/**
* The {@link VelbusBlindPositionPacket} represents a Velbus packet that can be used to
* set blinds to a given position.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusBlindPositionPacket extends VelbusPacket {
private byte channel;
private byte percentage;
public VelbusBlindPositionPacket(VelbusChannelIdentifier velbusChannelIdentifier, byte percentage) {
super(velbusChannelIdentifier.getAddress(), PRIO_HI);
this.channel = velbusChannelIdentifier.getChannelByte();
this.percentage = percentage;
}
@Override
protected byte[] getDataBytes() {
return new byte[] { COMMAND_BLIND_POS, channel, percentage };
}
}

View File

@@ -0,0 +1,44 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.velbus.internal.VelbusChannelIdentifier;
/**
* The {@link VelbusBlindUpDownPacket} represents a Velbus packet that can be used to
* move a blind up or down.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusBlindUpDownPacket extends VelbusPacket {
private final byte timeoutHighByte = 0x00;
private final byte timeoutMidByte = 0x00;
private final byte timeoutLowByte = 0x00;
private byte command;
private byte channel;
public VelbusBlindUpDownPacket(VelbusChannelIdentifier velbusChannelIdentifier, byte command) {
super(velbusChannelIdentifier.getAddress(), PRIO_HI);
this.channel = velbusChannelIdentifier.getChannelByte();
this.command = command;
}
@Override
protected byte[] getDataBytes() {
return new byte[] { command, channel, timeoutHighByte, timeoutMidByte, timeoutLowByte };
}
}

View File

@@ -0,0 +1,36 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusChannelNameRequestPacket} represents a Velbus packet that can be used to
* request the name of a given channel.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusChannelNameRequestPacket extends VelbusPacket {
public VelbusChannelNameRequestPacket(byte address) {
super(address, PRIO_LOW);
}
@Override
protected byte[] getDataBytes() {
return new byte[] { COMMAND_MODULE_NAME_REQUEST, ALL_CHANNELS };
}
}

View File

@@ -0,0 +1,42 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.COMMAND_COUNTER_STATUS_REQUEST;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.velbus.internal.VelbusChannelIdentifier;
/**
* The {@link VelbusCounterStatusRequestPacket} represents a Velbus packet that can be used to
* request the counter status of the given Velbus module.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusCounterStatusRequestPacket extends VelbusPacket {
private byte channel;
private final byte autosendTimeInterval = 0x00;
public VelbusCounterStatusRequestPacket(VelbusChannelIdentifier velbusChannelIdentifier) {
super(velbusChannelIdentifier.getAddress(), PRIO_LOW);
this.channel = velbusChannelIdentifier.getChannelByte();
}
@Override
protected byte[] getDataBytes() {
return new byte[] { COMMAND_COUNTER_STATUS_REQUEST, channel, autosendTimeInterval };
}
}

View File

@@ -0,0 +1,58 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.velbus.internal.VelbusChannelIdentifier;
/**
* The {@link VelbusDimmerPacket} represents a Velbus packet that can be used to
* dim a light to a given percentage.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusDimmerPacket extends VelbusPacket {
private static final byte FIRST_GENERATION_DEVICE_FASTEST_DIMSPEED_HIGH_BYTE = (byte) 0xFF;
private static final byte FIRST_GENERATION_DEVICE_FASTEST_DIMSPEED_LOW_BYTE = (byte) 0xFF;
private Boolean isFirstGenerationDevice;
private byte command;
private byte channel;
private byte percentage;
private int dimspeed;
public VelbusDimmerPacket(VelbusChannelIdentifier velbusChannelIdentifier, byte command, byte percentage,
int dimspeed, Boolean isFirstGenerationDevice) {
super(velbusChannelIdentifier.getAddress(), PRIO_HI);
this.channel = velbusChannelIdentifier.getChannelByte();
this.command = command;
this.percentage = percentage;
this.dimspeed = dimspeed;
this.isFirstGenerationDevice = isFirstGenerationDevice;
}
@Override
protected byte[] getDataBytes() {
byte dimspeedHighByte = (byte) ((dimspeed & 0xFF00) / 0x100);
byte dimspeedLowByte = (byte) (dimspeed & 0xFF);
if (dimspeed == 0 && isFirstGenerationDevice) {
dimspeedHighByte = FIRST_GENERATION_DEVICE_FASTEST_DIMSPEED_HIGH_BYTE;
dimspeedLowByte = FIRST_GENERATION_DEVICE_FASTEST_DIMSPEED_LOW_BYTE;
}
return new byte[] { command, channel, percentage, dimspeedHighByte, dimspeedLowByte };
}
}

View File

@@ -0,0 +1,40 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.velbus.internal.VelbusChannelIdentifier;
/**
* The {@link VelbusFeedbackLEDPacket} represents a Velbus packet that can be used to
* set the feedback led (clear/set/slow blink/fast blink/very fast blink) of the given Velbus module.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusFeedbackLEDPacket extends VelbusPacket {
private byte command;
private byte channel;
public VelbusFeedbackLEDPacket(VelbusChannelIdentifier velbusChannelIdentifier, byte command) {
super(velbusChannelIdentifier.getAddress(), PRIO_LOW);
this.channel = velbusChannelIdentifier.getChannelByte();
this.command = command;
}
@Override
protected byte[] getDataBytes() {
return new byte[] { command, channel };
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.COMMAND_LIGHT_VALUE_REQUEST;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusLightValueRequestPacket} represents a Velbus packet that can be used to
* request the value of the light sensor of the given Velbus module.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusLightValueRequestPacket extends VelbusPacket {
private final byte autosendTimeInterval = 0x00;
public VelbusLightValueRequestPacket(byte address) {
super(address, PRIO_LOW);
}
@Override
protected byte[] getDataBytes() {
return new byte[] { COMMAND_LIGHT_VALUE_REQUEST, autosendTimeInterval };
}
}

View File

@@ -0,0 +1,60 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.COMMAND_TEXT;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusMemoTextPacket} represents a Velbus packet that can be used to
* set the mode (comfort/day/night/safe) of the given Velbus thermostat module.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusMemoTextPacket extends VelbusPacket {
private byte textStartPosition;
private byte character1;
private byte character2;
private byte character3;
private byte character4;
private byte character5;
public VelbusMemoTextPacket(byte address, byte textStartPosition, char[] text) {
super(address, PRIO_LOW);
if (textStartPosition < 0 || textStartPosition > 63) {
throw new IllegalArgumentException("The text start position '" + textStartPosition
+ "' is invalid, because it should be between 0 and 63.");
}
if (text.length > 5) {
throw new IllegalArgumentException(
"The text '" + text.toString() + "' is invalid, because it cannot be longer than 5 characters.");
}
this.textStartPosition = textStartPosition;
this.character1 = text.length > 0 ? (byte) text[0] : 0x00;
this.character2 = text.length > 1 ? (byte) text[1] : 0x00;
this.character3 = text.length > 2 ? (byte) text[2] : 0x00;
this.character4 = text.length > 3 ? (byte) text[3] : 0x00;
this.character5 = text.length > 4 ? (byte) text[4] : 0x00;
}
@Override
protected byte[] getDataBytes() {
return new byte[] { COMMAND_TEXT, 0x00, textStartPosition, character1, character2, character3, character4,
character5 };
}
}

View File

@@ -0,0 +1,73 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusPacket} represents a base class for a Velbus packet and contains
* functionality that is applicable to all Velbus packets.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public abstract class VelbusPacket {
public static final byte STX = 0x0F;
public static final byte PRIO_HI = (byte) 0xF8;
public static final byte PRIO_LOW = (byte) 0xFB;
public static final byte ETX = 0x04;
private byte address;
private byte priority;
private byte rtr;
protected VelbusPacket(byte address, byte priority) {
this(address, priority, false);
}
protected VelbusPacket(byte address, byte priority, boolean rtr) {
this.address = address;
this.priority = priority;
this.rtr = rtr ? (byte) 0x40 : (byte) 0x00;
}
public byte[] getBytes() {
byte[] dataBytes = getDataBytes();
int dataBytesLength = dataBytes.length;
byte[] packetBytes = new byte[6 + dataBytesLength];
packetBytes[0] = STX;
packetBytes[1] = priority;
packetBytes[2] = address;
packetBytes[3] = (byte) (rtr | dataBytesLength);
System.arraycopy(dataBytes, 0, packetBytes, 4, dataBytes.length);
packetBytes[4 + dataBytesLength] = computeCRCByte(packetBytes);
packetBytes[5 + dataBytesLength] = ETX;
return packetBytes;
}
protected abstract byte[] getDataBytes();
public static byte computeCRCByte(byte[] packetBytes) {
int crc = 0;
for (int i = 0; i < packetBytes.length - 2; i++) {
crc = (crc + (packetBytes[i] & 0xFF)) & 0xFF;
}
return (byte) (0x100 - crc);
}
}

View File

@@ -0,0 +1,41 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.COMMAND_READ_MEMORY_BLOCK;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusReadMemoryBlockPacket} represents a Velbus packet that can be used to
* request a block of 4 bytes from the memory of the given Velbus module.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusReadMemoryBlockPacket extends VelbusPacket {
private byte highMemoryAddress;
private byte lowMemoryAddress;
public VelbusReadMemoryBlockPacket(byte address, int memoryAddress) {
super(address, PRIO_LOW);
highMemoryAddress = (byte) ((memoryAddress >> 8) & 0xFF);
lowMemoryAddress = (byte) (memoryAddress & 0xFF);
}
@Override
protected byte[] getDataBytes() {
return new byte[] { COMMAND_READ_MEMORY_BLOCK, highMemoryAddress, lowMemoryAddress };
}
}

View File

@@ -0,0 +1,41 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.COMMAND_READ_DATA_FROM_MEMORY;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusReadMemoryPacket} represents a Velbus packet that can be used to
* request a byte from the memory of the given Velbus module.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusReadMemoryPacket extends VelbusPacket {
private byte highMemoryAddress;
private byte lowMemoryAddress;
public VelbusReadMemoryPacket(byte address, int memoryAddress) {
super(address, PRIO_LOW);
highMemoryAddress = (byte) ((memoryAddress >> 8) & 0xFF);
lowMemoryAddress = (byte) (memoryAddress & 0xFF);
}
@Override
protected byte[] getDataBytes() {
return new byte[] { COMMAND_READ_DATA_FROM_MEMORY, highMemoryAddress, lowMemoryAddress };
}
}

View File

@@ -0,0 +1,40 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.velbus.internal.VelbusChannelIdentifier;
/**
* The {@link VelbusRelayPacket} represents a Velbus packet that can be used to
* send commands to a Velbus relay module.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusRelayPacket extends VelbusPacket {
private byte command;
private byte channel;
public VelbusRelayPacket(VelbusChannelIdentifier velbusChannelIdentifier, byte command) {
super(velbusChannelIdentifier.getAddress(), PRIO_HI);
this.channel = velbusChannelIdentifier.getChannelByte();
this.command = command;
}
@Override
protected byte[] getDataBytes() {
return new byte[] { command, channel };
}
}

View File

@@ -0,0 +1,35 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusScanPacket} represents a Velbus packet that can be used to
* check if a Velbus module exists on the given address and to request this module's
* basic properties.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusScanPacket extends VelbusPacket {
public VelbusScanPacket(byte address) {
super(address, PRIO_LOW, true);
}
@Override
protected byte[] getDataBytes() {
return new byte[0];
}
}

View File

@@ -0,0 +1,42 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.COMMAND_SENSOR_READOUT_REQUEST;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusSensorReadoutRequestPacket} represents a Velbus packet that can be used to
* request the value of a sensor channel of the given Velbus module.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusSensorReadoutRequestPacket extends VelbusPacket {
private final byte autosendTimeInterval = 0x00;
private byte channel;
public VelbusSensorReadoutRequestPacket(byte address, byte channel) {
super(address, PRIO_LOW);
this.channel = channel;
}
@Override
protected byte[] getDataBytes() {
return new byte[] { COMMAND_SENSOR_READOUT_REQUEST, channel, autosendTimeInterval };
}
}

View File

@@ -0,0 +1,35 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.COMMAND_TEMP_SENSOR_SETTINGS_REQUEST;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusSensorSettingsRequestPacket} represents a Velbus packet that can be used to
* request the sensor settings of the given Velbus module.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusSensorSettingsRequestPacket extends VelbusPacket {
public VelbusSensorSettingsRequestPacket(byte address) {
super(address, PRIO_LOW);
}
@Override
protected byte[] getDataBytes() {
return new byte[] { COMMAND_TEMP_SENSOR_SETTINGS_REQUEST, 0x00 };
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.COMMAND_SENSOR_READOUT_REQUEST;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusSensorTemperatureRequestPacket} represents a Velbus packet that can be used to
* request the value of the temperature sensor of the given Velbus module.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusSensorTemperatureRequestPacket extends VelbusPacket {
private final byte autosendTimeInterval = 0x00;
public VelbusSensorTemperatureRequestPacket(byte address) {
super(address, PRIO_LOW);
}
@Override
protected byte[] getDataBytes() {
return new byte[] { COMMAND_SENSOR_READOUT_REQUEST, autosendTimeInterval };
}
}

View File

@@ -0,0 +1,57 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.COMMAND_SET_REALTIME_DATE;
import java.time.ZonedDateTime;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusSetDatePacket} represents a Velbus packet that can be used to
* set the date of the given Velbus module.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusSetDatePacket extends VelbusPacket {
private ZonedDateTime zonedDateTime;
public VelbusSetDatePacket(byte address, ZonedDateTime zonedDateTime) {
super(address, PRIO_LOW);
this.zonedDateTime = zonedDateTime;
}
public byte getDay() {
return (byte) this.zonedDateTime.getDayOfMonth();
}
public byte getMonth() {
return (byte) this.zonedDateTime.getMonthValue();
}
public byte getYearHighByte() {
return (byte) ((zonedDateTime.getYear() & 0xff00) / 0x100);
}
public byte getYearLowByte() {
return (byte) (zonedDateTime.getYear() & 0xff);
}
@Override
protected byte[] getDataBytes() {
return new byte[] { COMMAND_SET_REALTIME_DATE, getDay(), getMonth(), getYearHighByte(), getYearLowByte() };
}
}

View File

@@ -0,0 +1,45 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.COMMAND_DAYLIGHT_SAVING_STATUS;
import java.time.ZonedDateTime;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusSetDaylightSavingsStatusPacket} represents a Velbus packet that can be used to
* set the daylight saving status of the given Velbus module.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusSetDaylightSavingsStatusPacket extends VelbusPacket {
private ZonedDateTime zonedDateTime;
public VelbusSetDaylightSavingsStatusPacket(byte address, ZonedDateTime zonedDateTime) {
super(address, PRIO_LOW);
this.zonedDateTime = zonedDateTime;
}
public boolean isDaylightSavings() {
return zonedDateTime.getZone().getRules().isDaylightSavings(zonedDateTime.toInstant());
}
@Override
protected byte[] getDataBytes() {
return new byte[] { COMMAND_DAYLIGHT_SAVING_STATUS, (byte) (isDaylightSavings() ? 0x01 : 0x00) };
}
}

View File

@@ -0,0 +1,44 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.COMMAND_SET_ALARM_CLOCK;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.velbus.internal.VelbusClockAlarm;
/**
* The {@link VelbusSetLocalClockAlarmPacket} represents a Velbus packet that can be used to
* set the value of the local clock alarm of the given Velbus module.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusSetLocalClockAlarmPacket extends VelbusPacket {
private byte alarmNumber;
private VelbusClockAlarm alarmClock;
public VelbusSetLocalClockAlarmPacket(byte address, byte alarmNumber, VelbusClockAlarm alarmClock) {
super(address, PRIO_LOW);
this.alarmNumber = alarmNumber;
this.alarmClock = alarmClock;
}
@Override
protected byte[] getDataBytes() {
return new byte[] { COMMAND_SET_ALARM_CLOCK, alarmNumber, alarmClock.getWakeupHour(),
alarmClock.getWakeupMinute(), alarmClock.getBedtimeHour(), alarmClock.getBedtimeMinute(),
alarmClock.isEnabled() ? (byte) 0x01 : (byte) 0x00 };
}
}

View File

@@ -0,0 +1,72 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.COMMAND_SET_REALTIME_CLOCK;
import java.time.DayOfWeek;
import java.time.ZonedDateTime;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusSetRealtimeClockPacket} represents a Velbus packet that can be used to
* set the clock of the given Velbus module.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusSetRealtimeClockPacket extends VelbusPacket {
private ZonedDateTime zonedDateTime;
public VelbusSetRealtimeClockPacket(byte address, ZonedDateTime zonedDateTime) {
super(address, PRIO_LOW);
this.zonedDateTime = zonedDateTime;
}
public byte getHour() {
return (byte) this.zonedDateTime.getHour();
}
public byte getMinute() {
return (byte) this.zonedDateTime.getMinute();
}
public byte getWeekDay() {
DayOfWeek dayOfWeek = zonedDateTime.getDayOfWeek();
switch (dayOfWeek) {
case MONDAY:
return 0x00;
case TUESDAY:
return 0x01;
case WEDNESDAY:
return 0x02;
case THURSDAY:
return 0x03;
case FRIDAY:
return 0x04;
case SATURDAY:
return 0x05;
case SUNDAY:
return 0x06;
default:
throw new IllegalArgumentException("Day " + dayOfWeek + " is not a valid weekday.");
}
}
@Override
protected byte[] getDataBytes() {
return new byte[] { COMMAND_SET_REALTIME_CLOCK, this.getWeekDay(), getHour(), getMinute() };
}
}

View File

@@ -0,0 +1,42 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.COMMAND_SET_TEMP;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusSetTemperaturePacket} represents a Velbus packet that can be used to
* set the value of a temperature variable of the given Velbus module.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusSetTemperaturePacket extends VelbusPacket {
private byte temperatureVariable;
private byte temperature;
public VelbusSetTemperaturePacket(byte address, byte temperatureVariable, byte temperature) {
super(address, PRIO_LOW);
this.temperatureVariable = temperatureVariable;
this.temperature = temperature;
}
@Override
protected byte[] getDataBytes() {
return new byte[] { COMMAND_SET_TEMP, temperatureVariable, temperature };
}
}

View File

@@ -0,0 +1,44 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.velbus.internal.VelbusChannelIdentifier;
/**
* The {@link VelbusStatusRequestPacket} represents a Velbus packet that can be used to
* request the state of the given Velbus module.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusStatusRequestPacket extends VelbusPacket {
private byte channel;
public VelbusStatusRequestPacket(byte address) {
this(new VelbusChannelIdentifier(address, ALL_CHANNELS));
}
public VelbusStatusRequestPacket(VelbusChannelIdentifier velbusChannelIdentifier) {
super(velbusChannelIdentifier.getAddress(), PRIO_LOW);
this.channel = velbusChannelIdentifier.getChannelByte();
}
@Override
protected byte[] getDataBytes() {
return new byte[] { COMMAND_STATUS_REQUEST, channel };
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusThermostatModePacket} represents a Velbus packet that can be used to
* set the mode (comfort/day/night/safe) of the given Velbus thermostat module.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusThermostatModePacket extends VelbusPacket {
private byte commandByte;
public VelbusThermostatModePacket(byte address, byte commandByte) {
super(address, PRIO_LOW);
this.commandByte = commandByte;
}
@Override
protected byte[] getDataBytes() {
return new byte[] { commandByte, 0x00, 0x00 };
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusThermostatOperatingModePacket} represents a Velbus packet that can be used to
* set the operating mode (heating/cooling) of the given Velbus thermostat module.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusThermostatOperatingModePacket extends VelbusPacket {
private byte commandByte;
public VelbusThermostatOperatingModePacket(byte address, byte commandByte) {
super(address, PRIO_LOW);
this.commandByte = commandByte;
}
@Override
protected byte[] getDataBytes() {
return new byte[] { commandByte, 0x00 };
}
}

View File

@@ -0,0 +1,43 @@
/**
* 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
*/
package org.openhab.binding.velbus.internal.packets;
import static org.openhab.binding.velbus.internal.VelbusBindingConstants.COMMAND_WRITE_DATA_TO_MEMORY;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VelbusWriteMemoryPacket} represents a Velbus packet that can be used to
* request a byte from the memory of the given Velbus module.
*
* @author Cedric Boon - Initial contribution
*/
@NonNullByDefault
public class VelbusWriteMemoryPacket extends VelbusPacket {
private byte highMemoryAddress;
private byte lowMemoryAddress;
private byte data;
public VelbusWriteMemoryPacket(byte address, int memoryAddress, byte data) {
super(address, PRIO_LOW);
this.highMemoryAddress = (byte) ((memoryAddress >> 8) & 0xFF);
this.lowMemoryAddress = (byte) (memoryAddress & 0xFF);
this.data = data;
}
@Override
protected byte[] getDataBytes() {
return new byte[] { COMMAND_WRITE_DATA_TO_MEMORY, highMemoryAddress, lowMemoryAddress, data };
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="velbus" 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>Velbus Binding</name>
<description>This is the binding for Velbus.</description>
<author>Cedric Boon</author>
</binding:binding>

View File

@@ -0,0 +1,902 @@
<?xml version="1.0" encoding="UTF-8"?>
<config-description:config-descriptions
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0 https://openhab.org/schemas/config-description-1.0.0.xsd">
<config-description uri="bridge-type:velbus:bridge">
<parameter name="port" type="text">
<context>serial-port</context>
<limitToOptions>false</limitToOptions>
<label>Serial Port</label>
<description>Select serial port (COM1, /dev/ttyS0, ...)</description>
<required>true</required>
</parameter>
<parameter name="timeUpdateInterval" type="integer" unit="min">
<label>Time Update Interval</label>
<description>The interval (in minutes) at which the realtime clock, date and daylight savings status of the modules
will be updated, default 360. If set to 0 or left empty, no refresh will be scheduled.</description>
<default>360</default>
<advanced>true</advanced>
</parameter>
<parameter name="reconnectionInterval" type="integer" unit="s">
<label>Reconnection Interval</label>
<description>The interval (in seconds) at which reconnections should be reattempted in case of a communication
problem, default 15. If set to 0 or left empty, no reconnections will be attempted.</description>
<default>15</default>
<advanced>true</advanced>
</parameter>
</config-description>
<config-description uri="bridge-type:velbus:networkbridge">
<parameter name="address" type="text" required="true">
<context>network-address</context>
<label>IP Address or Hostname</label>
<description>IP Address or hostname of Velbus server</description>
<required>true</required>
</parameter>
<parameter name="port" type="integer" required="false">
<label>Port</label>
<description>Network port to communicate with Velbus server</description>
<required>true</required>
</parameter>
<parameter name="timeUpdateInterval" type="integer" unit="min">
<label>Time Update Interval</label>
<description>The interval (in minutes) at which the realtime clock, date and daylight savings status of the modules
will be updated, default 360. If set to 0 or left empty, no refresh will be scheduled.</description>
<default>360</default>
<advanced>true</advanced>
</parameter>
<parameter name="reconnectionInterval" type="integer" unit="s">
<label>Reconnection Interval</label>
<description>The interval (in seconds) at which reconnections should be reattempted in case of a communication
problem, default 15. If set to 0 or left empty, no reconnections will be attempted.</description>
<default>15</default>
<advanced>true</advanced>
</parameter>
</config-description>
<config-description uri="thing-type:velbus:temperatureSensorDevice">
<parameter name="address" type="text" required="true">
<label>Address</label>
<description>The velbus address of the device</description>
</parameter>
<parameter name="refresh" type="integer" unit="s">
<label>Refresh Interval</label>
<description>Refresh interval for the temperature sensor (in seconds), default 300. If set to 0 or left empty, no
refresh will be scheduled.</description>
<default>300</default>
<advanced>true</advanced>
</parameter>
</config-description>
<config-description uri="thing-type:velbus:1channelDevice">
<parameter name="address" type="text" required="true">
<label>Address</label>
<description>The velbus address of the device</description>
</parameter>
<parameter name="CH1" type="text">
<label>CH1 Name</label>
<description>The name of CH1.</description>
<default>CH1</default>
<advanced>true</advanced>
</parameter>
</config-description>
<config-description uri="thing-type:velbus:1channelDeviceWithDimspeed">
<parameter name="address" type="text" required="true">
<label>Address</label>
<description>The velbus address of the device</description>
</parameter>
<parameter name="CH1" type="text">
<label>CH1 Name</label>
<description>The name of CH1.</description>
<default>CH1</default>
<advanced>true</advanced>
</parameter>
<parameter name="dimspeed" type="integer" unit="s">
<label>Dimspeed</label>
<description>The time (in seconds) needed for dimming from 0 to 100%.</description>
<default>0</default>
<advanced>true</advanced>
</parameter>
</config-description>
<config-description uri="thing-type:velbus:2channelDevice">
<parameter name="address" type="text" required="true">
<label>Address</label>
<description>The velbus address of the device</description>
</parameter>
<parameter name="CH1" type="text">
<label>CH1 Name</label>
<description>The name of CH1.</description>
<default>CH1</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH2" type="text">
<label>CH2 Name</label>
<description>The name of CH2.</description>
<default>CH2</default>
<advanced>true</advanced>
</parameter>
</config-description>
<config-description uri="thing-type:velbus:4channelDevice">
<parameter name="address" type="text" required="true">
<label>Address</label>
<description>The velbus address of the device</description>
</parameter>
<parameter name="CH1" type="text">
<label>CH1 Name</label>
<description>The name of CH1.</description>
<default>CH1</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH2" type="text">
<label>CH2 Name</label>
<description>The name of CH2.</description>
<default>CH2</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH3" type="text">
<label>CH3 Name</label>
<description>The name of CH3.</description>
<default>CH3</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH4" type="text">
<label>CH4 Name</label>
<description>The name of CH4.</description>
<default>CH4</default>
<advanced>true</advanced>
</parameter>
</config-description>
<config-description uri="thing-type:velbus:4channelDeviceWithDimspeed">
<parameter name="address" type="text" required="true">
<label>Address</label>
<description>The velbus address of the device</description>
</parameter>
<parameter name="CH1" type="text">
<label>CH1 Name</label>
<description>The name of CH1.</description>
<default>CH1</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH2" type="text">
<label>CH2 Name</label>
<description>The name of CH2.</description>
<default>CH2</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH3" type="text">
<label>CH3 Name</label>
<description>The name of CH3.</description>
<default>CH3</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH4" type="text">
<label>CH4 Name</label>
<description>The name of CH4.</description>
<default>CH4</default>
<advanced>true</advanced>
</parameter>
<parameter name="dimspeed" type="integer" unit="s">
<label>Dimspeed</label>
<description>The time (in seconds) needed for dimming from 0 to 100%.</description>
<default>0</default>
<advanced>true</advanced>
</parameter>
</config-description>
<config-description uri="thing-type:velbus:5channelDevice">
<parameter name="address" type="text" required="true">
<label>Address</label>
<description>The velbus address of the device</description>
</parameter>
<parameter name="CH1" type="text">
<label>CH1 Name</label>
<description>The name of CH1.</description>
<default>CH1</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH2" type="text">
<label>CH2 Name</label>
<description>The name of CH2.</description>
<default>CH2</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH3" type="text">
<label>CH3 Name</label>
<description>The name of CH3.</description>
<default>CH3</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH4" type="text">
<label>CH4 Name</label>
<description>The name of CH4.</description>
<default>CH4</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH5" type="text">
<label>CH5 Name</label>
<description>The name of CH5.</description>
<default>CH5</default>
<advanced>true</advanced>
</parameter>
</config-description>
<config-description uri="thing-type:velbus:6channelDevice">
<parameter name="address" type="text" required="true">
<label>Address</label>
<description>The velbus address of the device</description>
</parameter>
<parameter name="CH1" type="text">
<label>CH1 Name</label>
<description>The name of CH1.</description>
<default>CH1</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH2" type="text">
<label>CH2 Name</label>
<description>The name of CH2.</description>
<default>CH2</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH3" type="text">
<label>CH3 Name</label>
<description>The name of CH3.</description>
<default>CH3</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH4" type="text">
<label>CH4 Name</label>
<description>The name of CH4.</description>
<default>CH4</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH5" type="text">
<label>CH5 Name</label>
<description>The name of CH5.</description>
<default>CH5</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH6" type="text">
<label>CH6 Name</label>
<description>The name of CH6.</description>
<default>CH6</default>
<advanced>true</advanced>
</parameter>
</config-description>
<config-description uri="thing-type:velbus:7channelDeviceWithCounters">
<parameter name="address" type="text" required="true">
<label>Address</label>
<description>The velbus address of the device</description>
</parameter>
<parameter name="refresh" type="integer" unit="s">
<label>Refresh Interval</label>
<description>Refresh interval for the counters (in seconds), default 300. If set to 0 or left empty, no refresh will
be scheduled.</description>
<default>300</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH1" type="text">
<label>CH1 Name</label>
<description>The name of CH1.</description>
<default>CH1</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH2" type="text">
<label>CH2 Name</label>
<description>The name of CH2.</description>
<default>CH2</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH3" type="text">
<label>CH3 Name</label>
<description>The name of CH3.</description>
<default>CH3</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH4" type="text">
<label>CH4 Name</label>
<description>The name of CH4.</description>
<default>CH4</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH5" type="text">
<label>CH5 Name</label>
<description>The name of CH5.</description>
<default>CH5</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH6" type="text">
<label>CH6 Name</label>
<description>The name of CH6.</description>
<default>CH6</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH7" type="text">
<label>CH7 Name</label>
<description>The name of CH7.</description>
<default>CH7</default>
<advanced>true</advanced>
</parameter>
<parameter name="counter1Unit" type="text">
<label>Counter 1 Unit</label>
<description>The unit for Counter 1.</description>
<default>kWh</default>
<options>
<option value="kWh">kWh</option>
<option value="liters">liters</option>
<option value="m³"></option>
</options>
<advanced>true</advanced>
</parameter>
<parameter name="counter1PulseMultiplier" type="decimal">
<label>Counter 1 Pulse Multiplier</label>
<description>The pulse multiplier for counter 1</description>
<default>1</default>
<options>
<option value="1">x1</option>
<option value="2.5">x2.5</option>
<option value="0.05">x0.05</option>
<option value="0.01">x0.01</option>
</options>
<advanced>true</advanced>
</parameter>
<parameter name="counter2Unit" type="text">
<label>Counter 2 Unit</label>
<description>The unit for Counter 2.</description>
<default>kWh</default>
<options>
<option value="kWh">kWh</option>
<option value="liters">liters</option>
<option value="m³"></option>
</options>
<advanced>true</advanced>
</parameter>
<parameter name="counter2PulseMultiplier" type="decimal">
<label>Counter 2 Pulse Multiplier</label>
<description>The pulse multiplier for counter 2</description>
<default>1</default>
<options>
<option value="1">x1</option>
<option value="2.5">x2.5</option>
<option value="0.05">x0.05</option>
<option value="0.01">x0.01</option>
</options>
<advanced>true</advanced>
</parameter>
<parameter name="counter3Unit" type="text">
<label>Counter 3 Unit</label>
<description>The unit for Counter 3.</description>
<default>kWh</default>
<options>
<option value="kWh">kWh</option>
<option value="liters">liters</option>
<option value="m³"></option>
</options>
<advanced>true</advanced>
</parameter>
<parameter name="counter3PulseMultiplier" type="decimal">
<label>Counter 3 Pulse Multiplier</label>
<description>The pulse multiplier for counter 3</description>
<default>1</default>
<options>
<option value="1">x1</option>
<option value="2.5">x2.5</option>
<option value="0.05">x0.05</option>
<option value="0.01">x0.01</option>
</options>
<advanced>true</advanced>
</parameter>
<parameter name="counter4Unit" type="text">
<label>Counter 4 Unit</label>
<description>The unit for Counter 4.</description>
<default>kWh</default>
<options>
<option value="kWh">kWh</option>
<option value="liters">liters</option>
<option value="m³"></option>
</options>
<advanced>true</advanced>
</parameter>
<parameter name="counter4PulseMultiplier" type="decimal">
<label>Counter 4 Pulse Multiplier</label>
<description>The pulse multiplier for counter 4</description>
<default>1</default>
<options>
<option value="1">x1</option>
<option value="2.5">x2.5</option>
<option value="0.05">x0.05</option>
<option value="0.01">x0.01</option>
</options>
<advanced>true</advanced>
</parameter>
</config-description>
<config-description uri="thing-type:velbus:7channelDeviceWithTemperatureSensor">
<parameter name="address" type="text" required="true">
<label>Address</label>
<description>The velbus address of the device</description>
</parameter>
<parameter name="refresh" type="integer" unit="s">
<label>Refresh Interval</label>
<description>Refresh interval for the temperature sensor (in seconds), default 300. If set to 0 or left empty, no
refresh will be scheduled.</description>
<default>300</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH1" type="text">
<label>CH1 Name</label>
<description>The name of CH1.</description>
<default>CH1</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH2" type="text">
<label>CH2 Name</label>
<description>The name of CH2.</description>
<default>CH2</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH3" type="text">
<label>CH3 Name</label>
<description>The name of CH3.</description>
<default>CH3</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH4" type="text">
<label>CH4 Name</label>
<description>The name of CH4.</description>
<default>CH4</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH5" type="text">
<label>CH5 Name</label>
<description>The name of CH5.</description>
<default>CH5</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH6" type="text">
<label>CH6 Name</label>
<description>The name of CH6.</description>
<default>CH6</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH7" type="text">
<label>CH7 Name</label>
<description>The name of CH7.</description>
<default>CH7</default>
<advanced>true</advanced>
</parameter>
</config-description>
<config-description uri="thing-type:velbus:8channelDevice">
<parameter name="address" type="text" required="true">
<label>Address</label>
<description>The velbus address of the device</description>
</parameter>
<parameter name="CH1" type="text">
<label>CH1 Name</label>
<description>The name of CH1.</description>
<default>CH1</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH2" type="text">
<label>CH2 Name</label>
<description>The name of CH2.</description>
<default>CH2</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH3" type="text">
<label>CH3 Name</label>
<description>The name of CH3.</description>
<default>CH3</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH4" type="text">
<label>CH4 Name</label>
<description>The name of CH4.</description>
<default>CH4</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH5" type="text">
<label>CH5 Name</label>
<description>The name of CH5.</description>
<default>CH5</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH6" type="text">
<label>CH6 Name</label>
<description>The name of CH6.</description>
<default>CH6</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH7" type="text">
<label>CH7 Name</label>
<description>The name of CH7.</description>
<default>CH7</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH8" type="text">
<label>CH8 Name</label>
<description>The name of CH8.</description>
<default>CH8</default>
<advanced>true</advanced>
</parameter>
</config-description>
<config-description uri="thing-type:velbus:9channelDeviceWithTemperatureSensor">
<parameter name="address" type="text" required="true">
<label>Address</label>
<description>The velbus address of the device</description>
</parameter>
<parameter name="refresh" type="integer" unit="s">
<label>Refresh Interval</label>
<description>Refresh interval for the temperature sensor (in seconds), default 300. If set to 0 or left empty, no
refresh will be scheduled.</description>
<default>300</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH1" type="text">
<label>CH1 Name</label>
<description>The name of CH1.</description>
<default>CH1</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH2" type="text">
<label>CH2 Name</label>
<description>The name of CH2.</description>
<default>CH2</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH3" type="text">
<label>CH3 Name</label>
<description>The name of CH3.</description>
<default>CH3</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH4" type="text">
<label>CH4 Name</label>
<description>The name of CH4.</description>
<default>CH4</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH5" type="text">
<label>CH5 Name</label>
<description>The name of CH5.</description>
<default>CH5</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH6" type="text">
<label>CH6 Name</label>
<description>The name of CH6.</description>
<default>CH6</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH7" type="text">
<label>CH7 Name</label>
<description>The name of CH7.</description>
<default>CH7</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH8" type="text">
<label>CH8 Name</label>
<description>The name of CH8.</description>
<default>CH8</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH9" type="text">
<label>CH9 Name</label>
<description>The name of CH9 (temperature sensor channel).</description>
<default>Temperature</default>
<advanced>true</advanced>
</parameter>
</config-description>
<config-description uri="thing-type:velbus:13channelDevice">
<parameter name="address" type="text" required="true">
<label>Address</label>
<description>The velbus address of the device</description>
</parameter>
<parameter name="refresh" type="integer" unit="s">
<label>Refresh Interval</label>
<description>Refresh interval for the sensors (in seconds), default 300. If set to 0 or left empty, no refresh will
be scheduled.</description>
<default>300</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH1" type="text">
<label>CH1 Name</label>
<description>The name of CH1.</description>
<default>CH1</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH2" type="text">
<label>CH2 Name</label>
<description>The name of CH2.</description>
<default>CH2</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH3" type="text">
<label>CH3 Name</label>
<description>The name of CH3.</description>
<default>CH3</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH4" type="text">
<label>CH4 Name</label>
<description>The name of CH4.</description>
<default>CH4</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH5" type="text">
<label>CH5 Name</label>
<description>The name of CH5.</description>
<default>CH5</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH6" type="text">
<label>CH6 Name</label>
<description>The name of CH6.</description>
<default>CH6</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH7" type="text">
<label>CH7 Name</label>
<description>The name of CH7.</description>
<default>CH7</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH8" type="text">
<label>CH8 Name</label>
<description>The name of CH8.</description>
<default>CH8</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH9" type="text">
<label>CH9 Name</label>
<description>The name of CH9.</description>
<default>CH9</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH10" type="text">
<label>CH10 Name</label>
<description>The name of CH10.</description>
<default>CH10</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH11" type="text">
<label>CH11 Name</label>
<description>The name of CH11.</description>
<default>CH11</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH12" type="text">
<label>CH12 Name</label>
<description>The name of CH12.</description>
<default>CH12</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH13" type="text">
<label>CH13 Name</label>
<description>The name of CH13.</description>
<default>CH13</default>
<advanced>true</advanced>
</parameter>
</config-description>
<config-description uri="thing-type:velbus:33channelDeviceWithTemperatureSensor">
<parameter name="address" type="text" required="true">
<label>Address</label>
<description>The velbus address of the device</description>
</parameter>
<parameter name="refresh" type="integer" unit="s">
<label>Refresh Interval</label>
<description>Refresh interval for the temperature sensor (in seconds), default 300. If set to 0 or left empty, no
refresh will be scheduled.</description>
<default>300</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH1" type="text">
<label>CH1 Name</label>
<description>The name of CH1.</description>
<default>CH1</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH2" type="text">
<label>CH2 Name</label>
<description>The name of CH2.</description>
<default>CH2</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH3" type="text">
<label>CH3 Name</label>
<description>The name of CH3.</description>
<default>CH3</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH4" type="text">
<label>CH4 Name</label>
<description>The name of CH4.</description>
<default>CH4</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH5" type="text">
<label>CH5 Name</label>
<description>The name of CH5.</description>
<default>CH5</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH6" type="text">
<label>CH6 Name</label>
<description>The name of CH6.</description>
<default>CH6</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH7" type="text">
<label>CH7 Name</label>
<description>The name of CH7.</description>
<default>CH7</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH8" type="text">
<label>CH8 Name</label>
<description>The name of CH8.</description>
<default>CH8</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH9" type="text">
<label>CH9 Name</label>
<description>The name of CH9.</description>
<default>CH9</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH10" type="text">
<label>CH10 Name</label>
<description>The name of CH10.</description>
<default>CH10</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH11" type="text">
<label>CH11 Name</label>
<description>The name of CH11.</description>
<default>CH11</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH12" type="text">
<label>CH12 Name</label>
<description>The name of CH12.</description>
<default>CH12</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH13" type="text">
<label>CH13 Name</label>
<description>The name of CH13.</description>
<default>CH13</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH14" type="text">
<label>CH14 Name</label>
<description>The name of CH14.</description>
<default>CH14</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH15" type="text">
<label>CH15 Name</label>
<description>The name of CH15.</description>
<default>CH15</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH16" type="text">
<label>CH16 Name</label>
<description>The name of CH16.</description>
<default>CH16</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH17" type="text">
<label>CH17 Name</label>
<description>The name of CH17.</description>
<default>CH17</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH18" type="text">
<label>CH18 Name</label>
<description>The name of CH18.</description>
<default>CH18</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH19" type="text">
<label>CH19 Name</label>
<description>The name of CH19.</description>
<default>CH19</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH20" type="text">
<label>CH20 Name</label>
<description>The name of CH20.</description>
<default>CH20</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH21" type="text">
<label>CH21 Name</label>
<description>The name of CH21.</description>
<default>CH21</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH22" type="text">
<label>CH22 Name</label>
<description>The name of CH22.</description>
<default>CH22</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH23" type="text">
<label>CH23 Name</label>
<description>The name of CH23.</description>
<default>CH23</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH24" type="text">
<label>CH24 Name</label>
<description>The name of CH24.</description>
<default>CH24</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH25" type="text">
<label>CH25 Name</label>
<description>The name of CH25.</description>
<default>CH25</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH26" type="text">
<label>CH26 Name</label>
<description>The name of CH26.</description>
<default>CH26</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH27" type="text">
<label>CH27 Name</label>
<description>The name of CH27.</description>
<default>CH27</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH28" type="text">
<label>CH28 Name</label>
<description>The name of CH28.</description>
<default>CH28</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH29" type="text">
<label>CH29 Name</label>
<description>The name of CH29.</description>
<default>CH29</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH30" type="text">
<label>CH30 Name</label>
<description>The name of CH30.</description>
<default>CH30</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH31" type="text">
<label>CH31 Name</label>
<description>The name of CH31.</description>
<default>CH31</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH32" type="text">
<label>CH32 Name</label>
<description>The name of CH32.</description>
<default>CH32</default>
<advanced>true</advanced>
</parameter>
<parameter name="CH33" type="text">
<label>CH33 Name</label>
<description>The name of CH33 (temperature sensor channel).</description>
<default>Temperature</default>
<advanced>true</advanced>
</parameter>
</config-description>
</config-description:config-descriptions>