diff --git a/bundles/org.openhab.binding.velbus/README.md b/bundles/org.openhab.binding.velbus/README.md index d6ae71b34a0..35c8ce41e0e 100644 --- a/bundles/org.openhab.binding.velbus/README.md +++ b/bundles/org.openhab.binding.velbus/README.md @@ -17,7 +17,7 @@ A Velbus configuration module (e.g. VMBRSUSB) or a network server (e.g. [VelServ The supported Velbus devices are: ``` -vmb1bl, vmb1bls, vmb1dm, vmb1led, vmb1ry, vmb1ryno, vmb1rynos, vmb1rys, vmb1ts, vmb2bl, vmb2ble, vmb2pbn, vmb4an, vmb4dc, vmb4ry, vmb4ryld, vmb4ryno, vmb6in, vmb6pbn, vmb7in, vmb8ir, vmb8pb, vmb8pbu, vmbdme, vmbdmi, vmbdmir, vmbel1, vmbel2, vmbel4, vmbelo, vmbgp1, vmbgp2, vmbgp4, vmbgp4pir, vmbgpo, vmbgpod, vmbmeteo, vmbpirc, vmbpirm, vmbpiro, vmbvp1 +vmb1bl, vmb1bls, vmb1dm, vmb1led, vmb1ry, vmb1ryno, vmb1rynos, vmb1rys, vmb1ts, vmb2bl, vmb2ble, vmb2pbn, vmb4an, vmb4dc, vmb4ry, vmb4ryld, vmb4ryno, vmb6in, vmb6pbn, vmb7in, vmb8ir, vmb8pb, vmb8pbu, vmbdme, vmbdmi, vmbdmir, vmbel1, vmbel2, vmbel4, vmbelo, vmbelpir, vmbgp1, vmbgp2, vmbgp4, vmbgp4pir, vmbgpo, vmbgpod, vmbmeteo, vmbpirc, vmbpirm, vmbpiro, vmbvp1 ``` The type of a specific device can be found in the configuration section for things in the UI. @@ -97,7 +97,7 @@ or nested in the bridge configuration: The following thing types are valid for configuration: ``` -vmb1bl, vmb1bls, vmb1dm, vmb1led, vmb1ry, vmb1ryno, vmb1rynos, vmb1rys, vmb1ts, vmb2bl, vmb2ble, vmb2pbn, vmb4an, vmb4dc, vmb4ry, vmb4ryld, vmb4ryno, vmb6in, vmb6pbn, vmb7in, vmb8ir, vmb8pb, vmb8pbu, vmbdme, vmbdmi, vmbdmir, vmbel1, vmbel2, vmbel4, vmbelo, vmbgp1, vmbgp2, vmbgp4, vmbgp4pir, vmbgpo, vmbgpod, vmbmeteo, vmbpirc, vmbpirm, vmbpiro, vmbvp1 +vmb1bl, vmb1bls, vmb1dm, vmb1led, vmb1ry, vmb1ryno, vmb1rynos, vmb1rys, vmb1ts, vmb2bl, vmb2ble, vmb2pbn, vmb4an, vmb4dc, vmb4ry, vmb4ryld, vmb4ryno, vmb6in, vmb6pbn, vmb7in, vmb8ir, vmb8pb, vmb8pbu, vmbdme, vmbdmi, vmbdmir, vmbel1, vmbel2, vmbel4, vmbelo, vmbelpir, vmbgp1, vmbgp2, vmbgp4, vmbgp4pir, vmbgpo, vmbgpod, vmbmeteo, vmbpirc, vmbpirm, vmbpiro, vmbvp1 ``` `thingId` is the hexadecimal Velbus address of the thing. @@ -120,7 +120,7 @@ Setting the refresh interval to 0 or leaving it empty will prevent the thing fro The following thing types support a sensor refresh interval: ``` -vmb1ts, vmb4an, vmbel1, vmbel2, vmbel4, vmbelo, vmbgp1, vmbgp2, vmbgp4, vmbgp4pir, vmbgpo, vmbgpod, vmbmeteo, vmbpirc, vmbpirm, vmbpiro +vmb1ts, vmb4an, vmbel1, vmbel2, vmbel4, vmbelo, vmbelpir, vmbgp1, vmbgp2, vmbgp4, vmbgp4pir, vmbgpo, vmbgpod, vmbmeteo, vmbpirc, vmbpirm, vmbpiro ``` The `vmb7in` thing type also supports a refresh interval. For this thing type, the refresh interval is the interval at which the counter values should be refreshed. @@ -192,14 +192,15 @@ Sending an ON command will switch the dimmer to the value stored when last turni For thing type `vmb4ry` 4 channels are available `CH1` ... `CH4`. OnOff command types are supported. -Thing types `vmbel1`, `vmbel2`, `vmbel4`, `vmbgp1`, `vmbgp2`, `vmbgp4`, `vmbgp4pir` and `vmbpiro` have 8 trigger channels `input:CH1` ... `input:CH8` and one temperature channel `input:CH9`. -Pressed and Long_Pressed command types are supported on channels `button#CH1` ... `button#CH8`. +Thing types `vmbel1`, `vmbel2`, `vmbel4`, `vmbelpir`, `vmbgp1`, `vmbgp2`, `vmbgp4`, `vmbgp4pir` and `vmbpiro` have 8 trigger channels `input:CH1` ... `input:CH8` and one temperature channel `input:CH9`. +Pressed and Long_Pressed command types are supported on channels `button#CH1` and `button#CH2` for the thing type `vmbelpir`. +Pressed and Long_Pressed command types are supported on channels `button#CH1` ... `button#CH8` for the thing types `vmbel1`, `vmbel2`, `vmbel4`, `vmbgp1`, `vmbgp2`, `vmbgp4`, `vmbgp4pir` and `vmbpiro`. The thing types `vmbel1` and `vmbgp1` have one channel to steer the button LED feedback `feedback:CH1`. The thing types `vmbel2` and `vmbgp2` have two channels to steer the button LED feedback `feedback:CH1` and `feedback:CH2`. The thing types `vmbel4`, `vmbgp4` and `vmbgp4pir` have four channels to steer the button LED feedback `feedback:CH1` ... `feedback:CH4`. The thing type `vmbpiro` has a channel `input:LIGHT` indicating the illuminance. -Thing types `vmbel1`, `vmbel2`, `vmbel4`, `vmbgp1`, `vmbgp2`, `vmbgp4` and `vmbgp4pir` have a number of channels to set the module's alarms: `clockAlarm:clockAlarm1Enabled`, `clockAlarm:clockAlarm1Type`, `clockAlarm:clockAlarm1WakeupHour`, `clockAlarm:clockAlarm1WakeupMinute`, `clockAlarm:clockAlarm1BedtimeHour`, `clockAlarm:clockAlarm1BedtimeMinute`, `clockAlarm:clockAlarm2Enabled`, `clockAlarm:clockAlarm2Type`, `clockAlarm:clockAlarm2WakeupHour`, `clockAlarm:clockAlarm2WakeupMinute`, `clockAlarm:clockAlarm2BedtimeHour` and `clockAlarm:clockAlarm2BedtimeMinute`. -Thing types `vmbel1`, `vmbel2`, `vmbel4`, `vmbgp1`, `vmbgp2`, `vmbgp4` and `vmbgp4pir` also have a number of channels to set the module's thermostat (`thermostat:currentTemperatureSetpoint`, `thermostat:heatingModeComfortTemperatureSetpoint`, `thermostat:heatingModeDayTemperatureSetpoint`, `thermostat:heatingModeNightTemperatureSetpoint`, `thermostat:heatingModeAntiFrostTemperatureSetpoint`, `thermostat:coolingModeComfortTemperatureSetpoint`, `thermostat:coolingModeDayTemperatureSetpoint`, `thermostat:coolingModeNightTemperatureSetpoint`, `thermostat:coolingModeSafeTemperatureSetpoint`, `operatingMode` and `thermostat:mode`) and thermostat trigger channels: `thermostat:heater`, `thermostat:boost`, `thermostat:pump`, `thermostat:cooler`, `thermostat:alarm1`, `thermostat:alarm2`, `thermostat:alarm3`, `thermostat:alarm4`. +Thing types `vmbel1`, `vmbel2`, `vmbel4`, `vmbelpir`, `vmbgp1`, `vmbgp2`, `vmbgp4` and `vmbgp4pir` have a number of channels to set the module's alarms: `clockAlarm:clockAlarm1Enabled`, `clockAlarm:clockAlarm1Type`, `clockAlarm:clockAlarm1WakeupHour`, `clockAlarm:clockAlarm1WakeupMinute`, `clockAlarm:clockAlarm1BedtimeHour`, `clockAlarm:clockAlarm1BedtimeMinute`, `clockAlarm:clockAlarm2Enabled`, `clockAlarm:clockAlarm2Type`, `clockAlarm:clockAlarm2WakeupHour`, `clockAlarm:clockAlarm2WakeupMinute`, `clockAlarm:clockAlarm2BedtimeHour` and `clockAlarm:clockAlarm2BedtimeMinute`. +Thing types `vmbel1`, `vmbel2`, `vmbel4`, `vmbelpir`, `vmbgp1`, `vmbgp2`, `vmbgp4` and `vmbgp4pir` also have a number of channels to set the module's thermostat (`thermostat:currentTemperatureSetpoint`, `thermostat:heatingModeComfortTemperatureSetpoint`, `thermostat:heatingModeDayTemperatureSetpoint`, `thermostat:heatingModeNightTemperatureSetpoint`, `thermostat:heatingModeAntiFrostTemperatureSetpoint`, `thermostat:coolingModeComfortTemperatureSetpoint`, `thermostat:coolingModeDayTemperatureSetpoint`, `thermostat:coolingModeNightTemperatureSetpoint`, `thermostat:coolingModeSafeTemperatureSetpoint`, `operatingMode` and `thermostat:mode`) and thermostat trigger channels: `thermostat:heater`, `thermostat:boost`, `thermostat:pump`, `thermostat:cooler`, `thermostat:alarm1`, `thermostat:alarm2`, `thermostat:alarm3`, `thermostat:alarm4`. Thing types `vmbelo`, `vmbgpo` and `vmbgpod` have 32 trigger channels `input:CH1` ... `input:CH32` and one temperature channel `input:CH33`. Pressed and Long_Pressed command types are supported on channels `button#CH1` ... `button#CH32`. diff --git a/bundles/org.openhab.binding.velbus/src/main/java/org/openhab/binding/velbus/internal/VelbusBindingConstants.java b/bundles/org.openhab.binding.velbus/src/main/java/org/openhab/binding/velbus/internal/VelbusBindingConstants.java index 1f8dc13a3ee..df98433e5da 100644 --- a/bundles/org.openhab.binding.velbus/src/main/java/org/openhab/binding/velbus/internal/VelbusBindingConstants.java +++ b/bundles/org.openhab.binding.velbus/src/main/java/org/openhab/binding/velbus/internal/VelbusBindingConstants.java @@ -66,6 +66,7 @@ public class VelbusBindingConstants { 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_VMBELPIR = new ThingTypeUID(BINDING_ID, "vmbelpir"); 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"); @@ -94,8 +95,8 @@ public class VelbusBindingConstants { 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_VMBEL2, THING_TYPE_VMBEL4, THING_TYPE_VMBELO, THING_TYPE_VMBELPIR, 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, THING_TYPE_VMBVP1))); @@ -142,6 +143,7 @@ public class VelbusBindingConstants { 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_VMBELPIR = 0x38; 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; @@ -224,4 +226,31 @@ public class VelbusBindingConstants { public static final String CHANNEL = "CH"; public static final String SUB_ADDRESS = "subaddress"; public static final String DIMSPEED = "dimspeed"; + + // Channels ids + public static final String CHANNEL_BRIDGE_CLOCK_ALARM1_ENABLED = "bridgeClockAlarm#clockAlarm1Enabled"; + public static final String CHANNEL_BRIDGE_CLOCK_ALARM1_WAKEUP_HOUR = "bridgeClockAlarm#clockAlarm1WakeupHour"; + public static final String CHANNEL_BRIDGE_CLOCK_ALARM1_WAKEUP_MINUTE = "bridgeClockAlarm#clockAlarm1WakeupMinute"; + public static final String CHANNEL_BRIDGE_CLOCK_ALARM1_BEDTIME_HOUR = "bridgeClockAlarm#clockAlarm1BedtimeHour"; + public static final String CHANNEL_BRIDGE_CLOCK_ALARM1_BEDTIME_MINUTE = "bridgeClockAlarm#clockAlarm1BedtimeMinute"; + public static final String CHANNEL_BRIDGE_CLOCK_ALARM2_ENABLED = "bridgeClockAlarm#clockAlarm2Enabled"; + public static final String CHANNEL_BRIDGE_CLOCK_ALARM2_WAKEUP_HOUR = "bridgeClockAlarm#clockAlarm2WakeupHour"; + public static final String CHANNEL_BRIDGE_CLOCK_ALARM2_WAKEUP_MINUTE = "bridgeClockAlarm#clockAlarm2WakeupMinute"; + public static final String CHANNEL_BRIDGE_CLOCK_ALARM2_BEDTIME_HOUR = "bridgeClockAlarm#clockAlarm2BedtimeHour"; + public static final String CHANNEL_BRIDGE_CLOCK_ALARM2_BEDTIME_MINUTE = "bridgeClockAlarm#clockAlarm2BedtimeMinute"; + public static final String CHANNEL_MODULE_CLOCK_ALARM1_ENABLED = "clockAlarm#clockAlarm1Enabled"; + public static final String CHANNEL_MODULE_CLOCK_ALARM1_TYPE = "clockAlarm#clockAlarm1Type"; + public static final String CHANNEL_MODULE_CLOCK_ALARM1_WAKEUP_HOUR = "clockAlarm#clockAlarm1WakeupHour"; + public static final String CHANNEL_MODULE_CLOCK_ALARM1_WAKEUP_MINUTE = "clockAlarm#clockAlarm1WakeupMinute"; + public static final String CHANNEL_MODULE_CLOCK_ALARM1_BEDTIME_HOUR = "clockAlarm#clockAlarm1BedtimeHour"; + public static final String CHANNEL_MODULE_CLOCK_ALARM1_BEDTIME_MINUTE = "clockAlarm#clockAlarm1BedtimeMinute"; + public static final String CHANNEL_MODULE_CLOCK_ALARM2_ENABLED = "clockAlarm#clockAlarm2Enabled"; + public static final String CHANNEL_MODULE_CLOCK_ALARM2_TYPE = "clockAlarm#clockAlarm2Type"; + public static final String CHANNEL_MODULE_CLOCK_ALARM2_WAKEUP_HOUR = "clockAlarm#clockAlarm2WakeupHour"; + public static final String CHANNEL_MODULE_CLOCK_ALARM2_WAKEUP_MINUTE = "clockAlarm#clockAlarm2WakeupMinute"; + public static final String CHANNEL_MODULE_CLOCK_ALARM2_BEDTIME_HOUR = "clockAlarm#clockAlarm2BedtimeHour"; + public static final String CHANNEL_MODULE_CLOCK_ALARM2_BEDTIME_MINUTE = "clockAlarm#clockAlarm2BedtimeMinute"; + + // Delay + public static final Integer DELAY_SEND_CLOCK_ALARM_UPDATE = 10000; } diff --git a/bundles/org.openhab.binding.velbus/src/main/java/org/openhab/binding/velbus/internal/discovery/VelbusThingDiscoveryService.java b/bundles/org.openhab.binding.velbus/src/main/java/org/openhab/binding/velbus/internal/discovery/VelbusThingDiscoveryService.java index 15b80c8826b..3ae22ce65bb 100644 --- a/bundles/org.openhab.binding.velbus/src/main/java/org/openhab/binding/velbus/internal/discovery/VelbusThingDiscoveryService.java +++ b/bundles/org.openhab.binding.velbus/src/main/java/org/openhab/binding/velbus/internal/discovery/VelbusThingDiscoveryService.java @@ -239,6 +239,10 @@ public class VelbusThingDiscoveryService extends AbstractDiscoveryService velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber, lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBELO, 33); break; + case MODULE_TYPE_VMBELPIR: + velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber, + lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBELPIR, 9); + break; case MODULE_TYPE_VMBGP1: velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber, lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP1, 9); diff --git a/bundles/org.openhab.binding.velbus/src/main/java/org/openhab/binding/velbus/internal/handler/VelbusBridgeHandler.java b/bundles/org.openhab.binding.velbus/src/main/java/org/openhab/binding/velbus/internal/handler/VelbusBridgeHandler.java index d3c5cfb8171..d20d706fe74 100644 --- a/bundles/org.openhab.binding.velbus/src/main/java/org/openhab/binding/velbus/internal/handler/VelbusBridgeHandler.java +++ b/bundles/org.openhab.binding.velbus/src/main/java/org/openhab/binding/velbus/internal/handler/VelbusBridgeHandler.java @@ -12,6 +12,8 @@ */ package org.openhab.binding.velbus.internal.handler; +import static org.openhab.binding.velbus.internal.VelbusBindingConstants.*; + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -27,13 +29,18 @@ import java.util.concurrent.TimeUnit; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.velbus.internal.VelbusClockAlarm; +import org.openhab.binding.velbus.internal.VelbusClockAlarmConfiguration; 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.VelbusSetLocalClockAlarmPacket; import org.openhab.binding.velbus.internal.packets.VelbusSetRealtimeClockPacket; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.OnOffType; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.ThingStatus; @@ -49,6 +56,8 @@ import org.slf4j.LoggerFactory; * the framework. * * @author Cedric Boon - Initial contribution + * @author Daniel Rosengarten - Add global alarm configuration from bridge (removed from modules), reduces bus flooding + * on alarm value update */ @NonNullByDefault public abstract class VelbusBridgeHandler extends BaseBridgeHandler { @@ -68,6 +77,11 @@ public abstract class VelbusBridgeHandler extends BaseBridgeHandler { private boolean listenerStopped; + private VelbusClockAlarmConfiguration alarmClockConfiguration = new VelbusClockAlarmConfiguration(); + + private long lastUpdateAlarm1TimeMillis; + private long lastUpdateAlarm2TimeMillis; + public VelbusBridgeHandler(Bridge velbusBridge) { super(velbusBridge); } @@ -141,7 +155,90 @@ public abstract class VelbusBridgeHandler extends BaseBridgeHandler { @Override public void handleCommand(ChannelUID channelUID, Command command) { - // There is nothing to handle in the bridge handler + if (isAlarmClockChannel(channelUID)) { + byte alarmNumber = determineAlarmNumber(channelUID); + VelbusClockAlarm alarmClock = alarmClockConfiguration.getAlarmClock(alarmNumber); + + alarmClock.setLocal(false); + + switch (channelUID.getId()) { + case CHANNEL_BRIDGE_CLOCK_ALARM1_ENABLED: + case CHANNEL_BRIDGE_CLOCK_ALARM2_ENABLED: { + if (command instanceof OnOffType) { + boolean enabled = command == OnOffType.ON; + alarmClock.setEnabled(enabled); + } + break; + } + case CHANNEL_BRIDGE_CLOCK_ALARM1_WAKEUP_HOUR: + case CHANNEL_BRIDGE_CLOCK_ALARM2_WAKEUP_HOUR: { + if (command instanceof DecimalType) { + byte wakeupHour = ((DecimalType) command).byteValue(); + alarmClock.setWakeupHour(wakeupHour); + } + break; + } + case CHANNEL_BRIDGE_CLOCK_ALARM1_WAKEUP_MINUTE: + case CHANNEL_BRIDGE_CLOCK_ALARM2_WAKEUP_MINUTE: { + if (command instanceof DecimalType) { + byte wakeupMinute = ((DecimalType) command).byteValue(); + alarmClock.setWakeupMinute(wakeupMinute); + } + break; + } + case CHANNEL_BRIDGE_CLOCK_ALARM1_BEDTIME_HOUR: + case CHANNEL_BRIDGE_CLOCK_ALARM2_BEDTIME_HOUR: { + if (command instanceof DecimalType) { + byte bedTimeHour = ((DecimalType) command).byteValue(); + alarmClock.setBedtimeHour(bedTimeHour); + } + break; + } + case CHANNEL_BRIDGE_CLOCK_ALARM1_BEDTIME_MINUTE: + case CHANNEL_BRIDGE_CLOCK_ALARM2_BEDTIME_MINUTE: { + if (command instanceof DecimalType) { + byte bedTimeMinute = ((DecimalType) command).byteValue(); + alarmClock.setBedtimeMinute(bedTimeMinute); + } + break; + } + } + + if (alarmNumber == 1) { + lastUpdateAlarm1TimeMillis = System.currentTimeMillis(); + } else { + lastUpdateAlarm2TimeMillis = System.currentTimeMillis(); + } + + VelbusSetLocalClockAlarmPacket packet = new VelbusSetLocalClockAlarmPacket((byte) 0x00, alarmNumber, + alarmClock); + byte[] packetBytes = packet.getBytes(); + + // Schedule the send of the packet to see if there is another update in less than 10 secondes (reduce + // flooding of the bus) + scheduler.schedule(() -> { + sendAlarmPacket(alarmNumber, packetBytes); + }, DELAY_SEND_CLOCK_ALARM_UPDATE, TimeUnit.MILLISECONDS); + } else { + logger.debug("The command '{}' is not supported by this handler.", command.getClass()); + } + } + + public synchronized void sendAlarmPacket(int alarmNumber, byte[] packetBytes) { + long timeSinceLastUpdate; + + if (alarmNumber == 1) { + timeSinceLastUpdate = System.currentTimeMillis() - lastUpdateAlarm1TimeMillis; + } else { + timeSinceLastUpdate = System.currentTimeMillis() - lastUpdateAlarm2TimeMillis; + } + + // If a value of the alarm has been updated, discard this old update + if (timeSinceLastUpdate < DELAY_SEND_CLOCK_ALARM_UPDATE) { + return; + } + + sendPacket(packetBytes); } public synchronized void sendPacket(byte[] packet) { @@ -282,4 +379,40 @@ public abstract class VelbusBridgeHandler extends BaseBridgeHandler { public void unregisterRelayStatusListener(byte address) { packetListeners.remove(Byte.valueOf(address)); } + + protected boolean isAlarmClockChannel(ChannelUID channelUID) { + switch (channelUID.getId()) { + case CHANNEL_BRIDGE_CLOCK_ALARM1_ENABLED: + case CHANNEL_BRIDGE_CLOCK_ALARM1_WAKEUP_HOUR: + case CHANNEL_BRIDGE_CLOCK_ALARM1_WAKEUP_MINUTE: + case CHANNEL_BRIDGE_CLOCK_ALARM1_BEDTIME_HOUR: + case CHANNEL_BRIDGE_CLOCK_ALARM1_BEDTIME_MINUTE: + case CHANNEL_BRIDGE_CLOCK_ALARM2_ENABLED: + case CHANNEL_BRIDGE_CLOCK_ALARM2_WAKEUP_HOUR: + case CHANNEL_BRIDGE_CLOCK_ALARM2_WAKEUP_MINUTE: + case CHANNEL_BRIDGE_CLOCK_ALARM2_BEDTIME_HOUR: + case CHANNEL_BRIDGE_CLOCK_ALARM2_BEDTIME_MINUTE: + return true; + } + return false; + } + + protected byte determineAlarmNumber(ChannelUID channelUID) { + switch (channelUID.getId()) { + case CHANNEL_BRIDGE_CLOCK_ALARM1_ENABLED: + case CHANNEL_BRIDGE_CLOCK_ALARM1_WAKEUP_HOUR: + case CHANNEL_BRIDGE_CLOCK_ALARM1_WAKEUP_MINUTE: + case CHANNEL_BRIDGE_CLOCK_ALARM1_BEDTIME_HOUR: + case CHANNEL_BRIDGE_CLOCK_ALARM1_BEDTIME_MINUTE: + return 1; + case CHANNEL_BRIDGE_CLOCK_ALARM2_ENABLED: + case CHANNEL_BRIDGE_CLOCK_ALARM2_WAKEUP_HOUR: + case CHANNEL_BRIDGE_CLOCK_ALARM2_WAKEUP_MINUTE: + case CHANNEL_BRIDGE_CLOCK_ALARM2_BEDTIME_HOUR: + case CHANNEL_BRIDGE_CLOCK_ALARM2_BEDTIME_MINUTE: + return 2; + } + + throw new IllegalArgumentException("The given channelUID is not an alarm clock channel: " + channelUID); + } } diff --git a/bundles/org.openhab.binding.velbus/src/main/java/org/openhab/binding/velbus/internal/handler/VelbusSensorWithAlarmClockHandler.java b/bundles/org.openhab.binding.velbus/src/main/java/org/openhab/binding/velbus/internal/handler/VelbusSensorWithAlarmClockHandler.java index 2c989912650..6e1eab25443 100644 --- a/bundles/org.openhab.binding.velbus/src/main/java/org/openhab/binding/velbus/internal/handler/VelbusSensorWithAlarmClockHandler.java +++ b/bundles/org.openhab.binding.velbus/src/main/java/org/openhab/binding/velbus/internal/handler/VelbusSensorWithAlarmClockHandler.java @@ -18,6 +18,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.TimeUnit; import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.velbus.internal.VelbusClockAlarm; @@ -40,6 +41,8 @@ import org.openhab.core.types.RefreshType; * sent to one of the channels. * * @author Cedric Boon - Initial contribution + * @author Daniel Rosengarten - Add VMBELPIR support, removes global alarm configuration from module (moved on bridge), + * reduces bus flooding on alarm value update */ @NonNullByDefault public class VelbusSensorWithAlarmClockHandler extends VelbusSensorHandler { @@ -58,6 +61,7 @@ public class VelbusSensorWithAlarmClockHandler extends VelbusSensorHandler { 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_VMBELPIR, 0x030F); 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); @@ -110,6 +114,9 @@ public class VelbusSensorWithAlarmClockHandler extends VelbusSensorHandler { private int clockAlarmConfigurationMemoryAddress; private VelbusClockAlarmConfiguration alarmClockConfiguration = new VelbusClockAlarmConfiguration(); + private long lastUpdateAlarm1TimeMillis; + private long lastUpdateAlarm2TimeMillis; + public VelbusSensorWithAlarmClockHandler(Thing thing) { this(thing, 0); } @@ -146,42 +153,105 @@ public class VelbusSensorWithAlarmClockHandler extends VelbusSensorHandler { 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); + alarmClock.setLocal(true); + + switch (channelUID.getId()) { + case CHANNEL_MODULE_CLOCK_ALARM1_TYPE: + case CHANNEL_MODULE_CLOCK_ALARM2_TYPE: { + if (command instanceof OnOffType) { + // If AlarmType is not read only, it's an old implementation of the module, warn user and + // discard the command + logger.warn( + "Old implementation of thing '{}', still works, but it's better to remove and recreate the thing.", + getThing().getUID()); + } + return; + } + case CHANNEL_MODULE_CLOCK_ALARM1_ENABLED: + case CHANNEL_MODULE_CLOCK_ALARM2_ENABLED: { + if (command instanceof OnOffType) { + boolean enabled = command == OnOffType.ON; + alarmClock.setEnabled(enabled); + } + break; + } + case CHANNEL_MODULE_CLOCK_ALARM1_WAKEUP_HOUR: + case CHANNEL_MODULE_CLOCK_ALARM2_WAKEUP_HOUR: { + if (command instanceof DecimalType) { + byte wakeupHour = ((DecimalType) command).byteValue(); + alarmClock.setWakeupHour(wakeupHour); + } + break; + } + case CHANNEL_MODULE_CLOCK_ALARM1_WAKEUP_MINUTE: + case CHANNEL_MODULE_CLOCK_ALARM2_WAKEUP_MINUTE: { + if (command instanceof DecimalType) { + byte wakeupMinute = ((DecimalType) command).byteValue(); + alarmClock.setWakeupMinute(wakeupMinute); + } + break; + } + case CHANNEL_MODULE_CLOCK_ALARM1_BEDTIME_HOUR: + case CHANNEL_MODULE_CLOCK_ALARM2_BEDTIME_HOUR: { + if (command instanceof DecimalType) { + byte bedTimeHour = ((DecimalType) command).byteValue(); + alarmClock.setBedtimeHour(bedTimeHour); + } + break; + } + case CHANNEL_MODULE_CLOCK_ALARM1_BEDTIME_MINUTE: + case CHANNEL_MODULE_CLOCK_ALARM2_BEDTIME_MINUTE: { + if (command instanceof DecimalType) { + byte bedTimeMinute = ((DecimalType) command).byteValue(); + alarmClock.setBedtimeMinute(bedTimeMinute); + } + break; + } } - byte address = alarmClock.isLocal() ? getModuleAddress().getAddress() : 0x00; - VelbusSetLocalClockAlarmPacket packet = new VelbusSetLocalClockAlarmPacket(address, alarmNumber, - alarmClock); + if (alarmNumber == 1) { + lastUpdateAlarm1TimeMillis = System.currentTimeMillis(); + } else { + lastUpdateAlarm2TimeMillis = System.currentTimeMillis(); + } + + VelbusSetLocalClockAlarmPacket packet = new VelbusSetLocalClockAlarmPacket(getModuleAddress().getAddress(), + alarmNumber, alarmClock); byte[] packetBytes = packet.getBytes(); - velbusBridgeHandler.sendPacket(packetBytes); + + // Schedule the send of the packet to see if there is another update in less than 10 secondes (reduce + // flooding of the bus) + scheduler.schedule(() -> { + sendAlarmPacket(alarmNumber, packetBytes); + }, DELAY_SEND_CLOCK_ALARM_UPDATE, TimeUnit.MILLISECONDS); } else { logger.debug("The command '{}' is not supported by this handler.", command.getClass()); } } + public synchronized void sendAlarmPacket(int alarmNumber, byte[] packetBytes) { + VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler(); + if (velbusBridgeHandler == null) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE); + return; + } + + long timeSinceLastUpdate; + + if (alarmNumber == 1) { + timeSinceLastUpdate = System.currentTimeMillis() - lastUpdateAlarm1TimeMillis; + } else { + timeSinceLastUpdate = System.currentTimeMillis() - lastUpdateAlarm2TimeMillis; + } + + // If a value of the alarm has been updated, discard this old update + if (timeSinceLastUpdate < DELAY_SEND_CLOCK_ALARM_UPDATE) { + return; + } + + velbusBridgeHandler.sendPacket(packetBytes); + } + @Override public void onPacketReceived(byte[] packet) { super.onPacketReceived(packet); @@ -295,26 +365,43 @@ public class VelbusSensorWithAlarmClockHandler extends VelbusSensorHandler { } 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); + switch (channelUID.getId()) { + case CHANNEL_MODULE_CLOCK_ALARM1_ENABLED: + case CHANNEL_MODULE_CLOCK_ALARM1_TYPE: + case CHANNEL_MODULE_CLOCK_ALARM1_WAKEUP_HOUR: + case CHANNEL_MODULE_CLOCK_ALARM1_WAKEUP_MINUTE: + case CHANNEL_MODULE_CLOCK_ALARM1_BEDTIME_HOUR: + case CHANNEL_MODULE_CLOCK_ALARM1_BEDTIME_MINUTE: + case CHANNEL_MODULE_CLOCK_ALARM2_ENABLED: + case CHANNEL_MODULE_CLOCK_ALARM2_TYPE: + case CHANNEL_MODULE_CLOCK_ALARM2_WAKEUP_HOUR: + case CHANNEL_MODULE_CLOCK_ALARM2_WAKEUP_MINUTE: + case CHANNEL_MODULE_CLOCK_ALARM2_BEDTIME_HOUR: + case CHANNEL_MODULE_CLOCK_ALARM2_BEDTIME_MINUTE: + return true; + } + return false; } 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); + switch (channelUID.getId()) { + case CHANNEL_MODULE_CLOCK_ALARM1_ENABLED: + case CHANNEL_MODULE_CLOCK_ALARM1_TYPE: + case CHANNEL_MODULE_CLOCK_ALARM1_WAKEUP_HOUR: + case CHANNEL_MODULE_CLOCK_ALARM1_WAKEUP_MINUTE: + case CHANNEL_MODULE_CLOCK_ALARM1_BEDTIME_HOUR: + case CHANNEL_MODULE_CLOCK_ALARM1_BEDTIME_MINUTE: + return 1; + case CHANNEL_MODULE_CLOCK_ALARM2_ENABLED: + case CHANNEL_MODULE_CLOCK_ALARM2_TYPE: + case CHANNEL_MODULE_CLOCK_ALARM2_WAKEUP_HOUR: + case CHANNEL_MODULE_CLOCK_ALARM2_WAKEUP_MINUTE: + case CHANNEL_MODULE_CLOCK_ALARM2_BEDTIME_HOUR: + case CHANNEL_MODULE_CLOCK_ALARM2_BEDTIME_MINUTE: + return 2; } + + throw new IllegalArgumentException("The given channelUID is not an alarm clock channel: " + channelUID); } protected int getClockAlarmAndProgramSelectionIndexInModuleStatus() { diff --git a/bundles/org.openhab.binding.velbus/src/main/java/org/openhab/binding/velbus/internal/handler/VelbusVMBELHandler.java b/bundles/org.openhab.binding.velbus/src/main/java/org/openhab/binding/velbus/internal/handler/VelbusVMBELHandler.java index ebb1a842b03..17d2d24cdab 100644 --- a/bundles/org.openhab.binding.velbus/src/main/java/org/openhab/binding/velbus/internal/handler/VelbusVMBELHandler.java +++ b/bundles/org.openhab.binding.velbus/src/main/java/org/openhab/binding/velbus/internal/handler/VelbusVMBELHandler.java @@ -28,11 +28,12 @@ import org.openhab.core.thing.ThingTypeUID; * sent to one of the channels. * * @author Cedric Boon - Initial contribution + * @author Daniel Rosengarten - Add VMBELPIR support */ @NonNullByDefault public class VelbusVMBELHandler extends VelbusThermostatHandler { public static final Set SUPPORTED_THING_TYPES = new HashSet<>( - Arrays.asList(THING_TYPE_VMBEL1, THING_TYPE_VMBEL2, THING_TYPE_VMBEL4)); + Arrays.asList(THING_TYPE_VMBEL1, THING_TYPE_VMBEL2, THING_TYPE_VMBEL4, THING_TYPE_VMBELPIR)); public VelbusVMBELHandler(Thing thing) { super(thing, 4, new ChannelUID(thing.getUID(), "input", "CH9")); diff --git a/bundles/org.openhab.binding.velbus/src/main/resources/OH-INF/i18n/velbus.properties b/bundles/org.openhab.binding.velbus/src/main/resources/OH-INF/i18n/velbus.properties index 198396a3a61..e53696cff1f 100644 --- a/bundles/org.openhab.binding.velbus/src/main/resources/OH-INF/i18n/velbus.properties +++ b/bundles/org.openhab.binding.velbus/src/main/resources/OH-INF/i18n/velbus.properties @@ -69,6 +69,8 @@ thing-type.velbus.vmbel4.label = VMBEL4 thing-type.velbus.vmbel4.description = Edge-lit four touch buttons module thing-type.velbus.vmbelo.label = VMBELO thing-type.velbus.vmbelo.description = Edge-lit touch panel with Oled display +thing-type.velbus.vmbelpir.label = VMBELPIR +thing-type.velbus.vmbelpir.description = Edge-lit Motion detector with one touch button thing-type.velbus.vmbgp1-2.label = VMBGP1-2 thing-type.velbus.vmbgp1-2.description = Glass control module with 1 touch key (Edition 2) thing-type.velbus.vmbgp1.label = VMBGP1 @@ -415,6 +417,8 @@ channel-group-type.velbus.1channelFeedbackModule.label = Feedback channel-group-type.velbus.1channelFeedbackModule.description = This is a generic module with 1 feedback channel. channel-group-type.velbus.1channelInputModuleWithTemperatureSensor.label = Input with Temperature Sensor channel-group-type.velbus.1channelInputModuleWithTemperatureSensor.description = This is a generic module with 8 input channels and a temperature sensor. +channel-group-type.velbus.2channelButtonModule.label = Button +channel-group-type.velbus.2channelButtonModule.description = This is a generic module with 2 button channels. channel-group-type.velbus.2channelFeedbackModule.label = Feedback channel-group-type.velbus.2channelFeedbackModule.description = This is a generic module with 2 feedback channels. channel-group-type.velbus.32channelButtonModule.label = Button @@ -449,7 +453,19 @@ channel-group-type.velbus.9channelInputModuleWithTemperatureAndLightSensor.label channel-group-type.velbus.9channelInputModuleWithTemperatureAndLightSensor.description = This is a generic module with 8 input channels, a temperature sensor and a light sensor. channel-group-type.velbus.9channelInputModuleWithTemperatureSensor.label = Input with Temperature Sensor channel-group-type.velbus.9channelInputModuleWithTemperatureSensor.description = This is a generic module with 8 input channels and a temperature sensor. -channel-group-type.velbus.clockAlarm.label = Clock Alarm +channel-group-type.velbus.bridgeClockAlarm.label = Global Clock Alarm +channel-group-type.velbus.bridgeClockAlarm.description = This is a clock alarm with two configurable alarms that can be programmed with a wake up time and a bed time. +channel-group-type.velbus.bridgeClockAlarm.channel.clockAlarm1BedtimeHour.label = Clock Alarm 1 Bedtime Hour +channel-group-type.velbus.bridgeClockAlarm.channel.clockAlarm1BedtimeMinute.label = Clock Alarm 1 Bedtime Minute +channel-group-type.velbus.bridgeClockAlarm.channel.clockAlarm1Enabled.label = Clock Alarm 1 Enabled +channel-group-type.velbus.bridgeClockAlarm.channel.clockAlarm1WakeupHour.label = Clock Alarm 1 Wakeup Hour +channel-group-type.velbus.bridgeClockAlarm.channel.clockAlarm1WakeupMinute.label = Clock Alarm 1 Wakeup Minute +channel-group-type.velbus.bridgeClockAlarm.channel.clockAlarm2BedtimeHour.label = Clock Alarm 2 Bedtime Hour +channel-group-type.velbus.bridgeClockAlarm.channel.clockAlarm2BedtimeMinute.label = Clock Alarm 2 Bedtime Minute +channel-group-type.velbus.bridgeClockAlarm.channel.clockAlarm2Enabled.label = Clock Alarm 2 Enabled +channel-group-type.velbus.bridgeClockAlarm.channel.clockAlarm2WakeupHour.label = Clock Alarm 2 Wakeup Hour +channel-group-type.velbus.bridgeClockAlarm.channel.clockAlarm2WakeupMinute.label = Clock Alarm 2 Wakeup Minute +channel-group-type.velbus.clockAlarm.label = Local Clock Alarm channel-group-type.velbus.clockAlarm.description = This is a clock alarm with two configurable alarms that can be programmed with a wake up time and a bed time. channel-group-type.velbus.clockAlarm.channel.clockAlarm1BedtimeHour.label = Clock Alarm 1 Bedtime Hour channel-group-type.velbus.clockAlarm.channel.clockAlarm1BedtimeMinute.label = Clock Alarm 1 Bedtime Minute diff --git a/bundles/org.openhab.binding.velbus/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.velbus/src/main/resources/OH-INF/thing/thing-types.xml index b7e7096d6be..b5fc0463451 100644 --- a/bundles/org.openhab.binding.velbus/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.velbus/src/main/resources/OH-INF/thing/thing-types.xml @@ -7,12 +7,18 @@ This bridge represents a Velbus Serial-interface + + + This bridge represents a Velbus connection over TCP/IP + + + @@ -531,6 +537,25 @@ + + + + + + + + Edge-lit Motion detector with one touch button + + + + + + + + + + + @@ -884,7 +909,7 @@ String Type (local/global) of the alarm clock in Velbus - + @@ -1292,6 +1317,16 @@ + + + + This is a generic module with 2 button channels. + + + + + + @@ -1444,8 +1479,46 @@ + + + This is a clock alarm with two configurable alarms that can be programmed with a wake up time and a bed + time. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + This is a clock alarm with two configurable alarms that can be programmed with a wake up time and a bed time.