[velbus] New module VMBELPIR + Improvement clock alarms management (#12390)

* [velbus] Add new functionality PRESSED and LONG PRESSED and fix bug

New functionnality :
Add the the possibility to simulate the PRESSED and LONG PRESSED message of an input.

Module supported with button simulation :
VMB1RYS (button : CH6)
VMB6IN (buttons : CH1 ... CH6)
VMB2PBN, VMB6PBN, VMB7IN, VMB8IR, VMB8PB, VMB8PBU, VMBEL1, VMBEL2, VMBEL4, VMBGP1, VMBGP1-2, VMBGP2, VMBGP2-2, VMBGP4, VMBGP4-2, VMBGP4PIR, VMBGP4PIR-2 (buttons : CH1 ... CH8)
VMBELO, VMBGPOD, VMBGPOD-2 (buttons : CH1 ... CH32)

Fix bug :

The channels names were not correctly assigned to the thing properties. The last channel had the default name, not the one retrieved from the module.

* Add trigger on channel when using button simulation

Remove uneeded  Thread.sleep in code.
Trigger the events PRESSED, LONG_PRESSED, RELEASED on the linked trigger channel when using the button simulation.

* Fix redundant superinterface DiscoveryService

Redundant superinterface DiscoveryService for the type VelbusThingDiscoveryService, already defined by AbstractDiscoveryService.

* Fix bug #11521

Typo in the Counter Channel name for VMB7IN.

* [velbus] Add VMBELPIR module

* [velbus] Updates clock alarms management

Changes the clocks alarm management :
- Global alarms are now set from the bridge thing.
- Local alarms are still set from the module thing, but the alarm type channels on modules are now readonly.

Reduces the flooding of the bus by adding a delay of 10 seconds before sending the update on the bus :
- Removes the send on the bus after each update of a clock alarm value.
- Sends only the values of the last update after 10 seconds.

Signed-off-by: Daniel Rosengarten <github@praetorians.be>
This commit is contained in:
Daniel Rosengarten 2022-03-27 23:21:17 +02:00 committed by GitHub
parent cd1bf9c950
commit 53bb6f48ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 402 additions and 58 deletions

View File

@ -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`.

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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) {
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);
} 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) {
}
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);
} else if (channelUID.equals(clockAlarm1WakeupMinute)
|| channelUID.equals(clockAlarm2WakeupMinute) && command instanceof DecimalType) {
}
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);
} else if (channelUID.equals(clockAlarm1BedtimeHour)
|| channelUID.equals(clockAlarm2BedtimeHour) && command instanceof DecimalType) {
}
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);
} else if (channelUID.equals(clockAlarm1BedtimeMinute)
|| channelUID.equals(clockAlarm2BedtimeMinute) && command instanceof DecimalType) {
}
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)) {
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;
} else if (channelUID.equals(clockAlarm2Enabled) || channelUID.equals(clockAlarm2Type)
|| channelUID.equals(clockAlarm2WakeupHour) || channelUID.equals(clockAlarm2WakeupMinute)
|| channelUID.equals(clockAlarm2BedtimeHour) || channelUID.equals(clockAlarm2BedtimeMinute)) {
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;
} else {
throw new IllegalArgumentException("The given channelUID is not an alarm clock channel: " + channelUID);
}
throw new IllegalArgumentException("The given channelUID is not an alarm clock channel: " + channelUID);
}
protected int getClockAlarmAndProgramSelectionIndexInModuleStatus() {

View File

@ -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<ThingTypeUID> 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"));

View File

@ -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

View File

@ -7,12 +7,18 @@
<bridge-type id="bridge">
<label>Velbus Serial Bridge</label>
<description>This bridge represents a Velbus Serial-interface</description>
<channel-groups>
<channel-group id="bridgeClockAlarm" typeId="clockAlarm"/>
</channel-groups>
<config-description-ref uri="bridge-type:velbus:bridge"/>
</bridge-type>
<bridge-type id="networkbridge">
<label>Velbus Network Bridge</label>
<description>This bridge represents a Velbus connection over TCP/IP</description>
<channel-groups>
<channel-group id="bridgeClockAlarm" typeId="clockAlarm"/>
</channel-groups>
<config-description-ref uri="bridge-type:velbus:networkbridge"/>
</bridge-type>
@ -531,6 +537,25 @@
<config-description-ref uri="thing-type:velbus:33channelDeviceWithTemperatureSensor"/>
</thing-type>
<thing-type id="vmbelpir">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
<bridge-type-ref id="networkbridge"/>
</supported-bridge-type-refs>
<label>VMBELPIR</label>
<description>Edge-lit Motion detector with one touch button</description>
<channel-groups>
<channel-group id="input" typeId="9channelInputModuleWithTemperatureSensor"/>
<channel-group id="button" typeId="2channelButtonModule"/>
<channel-group id="feedback" typeId="1channelFeedbackModule"/>
<channel-group id="thermostat" typeId="thermostat"/>
<channel-group id="clockAlarm" typeId="clockAlarm"/>
</channel-groups>
<config-description-ref uri="thing-type:velbus:9channelDeviceWithTemperatureSensor"/>
</thing-type>
<thing-type id="vmbgp1">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
@ -884,7 +909,7 @@
<item-type>String</item-type>
<label>Alarm Type</label>
<description>Type (local/global) of the alarm clock in Velbus</description>
<state>
<state readOnly="true">
<options>
<option value="LOCAL">Local</option>
<option value="GLOBAL">Global</option>
@ -1292,6 +1317,16 @@
<channel id="CH32" typeId="ledFeedback"/>
</channels>
</channel-group-type>
<channel-group-type id="2channelButtonModule">
<label>Button</label>
<description>
This is a generic module with 2 button channels.
</description>
<channels>
<channel id="CH1" typeId="button-channel"/>
<channel id="CH2" typeId="button-channel"/>
</channels>
</channel-group-type>
<channel-group-type id="6channelButtonModule">
<label>Button</label>
<description>
@ -1444,8 +1479,46 @@
<channel id="CH13" typeId="windspeed"/>
</channels>
</channel-group-type>
<channel-group-type id="bridgeClockAlarm">
<label>Global Clock Alarm</label>
<description>This is a clock alarm with two configurable alarms that can be programmed with a wake up time and a bed
time.
</description>
<channels>
<channel id="clockAlarm1Enabled" typeId="switch">
<label>Clock Alarm 1 Enabled</label>
</channel>
<channel id="clockAlarm1WakeupHour" typeId="hour">
<label>Clock Alarm 1 Wakeup Hour</label>
</channel>
<channel id="clockAlarm1WakeupMinute" typeId="minute">
<label>Clock Alarm 1 Wakeup Minute</label>
</channel>
<channel id="clockAlarm1BedtimeHour" typeId="hour">
<label>Clock Alarm 1 Bedtime Hour</label>
</channel>
<channel id="clockAlarm1BedtimeMinute" typeId="minute">
<label>Clock Alarm 1 Bedtime Minute</label>
</channel>
<channel id="clockAlarm2Enabled" typeId="switch">
<label>Clock Alarm 2 Enabled</label>
</channel>
<channel id="clockAlarm2WakeupHour" typeId="hour">
<label>Clock Alarm 2 Wakeup Hour</label>
</channel>
<channel id="clockAlarm2WakeupMinute" typeId="minute">
<label>Clock Alarm 2 Wakeup Minute</label>
</channel>
<channel id="clockAlarm2BedtimeHour" typeId="hour">
<label>Clock Alarm 2 Bedtime Hour</label>
</channel>
<channel id="clockAlarm2BedtimeMinute" typeId="minute">
<label>Clock Alarm 2 Bedtime Minute</label>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="clockAlarm">
<label>Clock Alarm</label>
<label>Local Clock Alarm</label>
<description>This is a clock alarm with two configurable alarms that can be programmed with a wake up time and a bed
time.
</description>