]> git.basschouten.com Git - openhab-addons.git/blob
aadd8621dee33d725c02a2a59d82ff95805d6392
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.velbus.internal.handler;
14
15 import static org.openhab.binding.velbus.internal.VelbusBindingConstants.*;
16
17 import java.util.Arrays;
18 import java.util.HashMap;
19 import java.util.HashSet;
20 import java.util.Set;
21 import java.util.concurrent.TimeUnit;
22
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.openhab.binding.velbus.internal.VelbusClockAlarm;
25 import org.openhab.binding.velbus.internal.VelbusClockAlarmConfiguration;
26 import org.openhab.binding.velbus.internal.packets.VelbusPacket;
27 import org.openhab.binding.velbus.internal.packets.VelbusSetLocalClockAlarmPacket;
28 import org.openhab.core.library.types.DecimalType;
29 import org.openhab.core.library.types.OnOffType;
30 import org.openhab.core.library.types.StringType;
31 import org.openhab.core.thing.ChannelUID;
32 import org.openhab.core.thing.Thing;
33 import org.openhab.core.thing.ThingStatus;
34 import org.openhab.core.thing.ThingStatusDetail;
35 import org.openhab.core.thing.ThingTypeUID;
36 import org.openhab.core.types.Command;
37 import org.openhab.core.types.RefreshType;
38
39 /**
40  * The {@link VelbusSensorWithAlarmClockHandler} is responsible for handling commands, which are
41  * sent to one of the channels.
42  *
43  * @author Cedric Boon - Initial contribution
44  * @author Daniel Rosengarten - Add new module support, removes global alarm configuration from module (moved on
45  *         bridge), reduces bus flooding on alarm value update
46  */
47 @NonNullByDefault
48 public class VelbusSensorWithAlarmClockHandler extends VelbusSensorHandler {
49     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(Arrays.asList(THING_TYPE_VMB2PBN,
50             THING_TYPE_VMB6PBN, THING_TYPE_VMB8PBU, THING_TYPE_VMBPIRC, THING_TYPE_VMBPIRM, THING_TYPE_VMBRFR8S,
51             THING_TYPE_VMBVP1, THING_TYPE_VMBKP, THING_TYPE_VMBIN, THING_TYPE_VMB4PB));
52     private static final HashMap<ThingTypeUID, Integer> ALARM_CONFIGURATION_MEMORY_ADDRESSES = new HashMap<>();
53
54     static {
55         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMB2PBN, 0x0093);
56         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMB4AN, 0x0046);
57         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMB6PBN, 0x0093);
58         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMB7IN, 0x0093);
59         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMB8PBU, 0x0093);
60         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBEL1, 0x0357);
61         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBEL2, 0x0357);
62         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBEL4, 0x0357);
63         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBELO, 0x0593);
64         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBELPIR, 0x030F);
65         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBPIRC, 0x0031);
66         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBPIRM, 0x0031);
67         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBPIRO, 0x0031);
68         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBMETEO, 0x0083);
69         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP1, 0x00A4);
70         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP1_2, 0x00A4);
71         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP2, 0x00A4);
72         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP2_2, 0x00A4);
73         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP4, 0x00A4);
74         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP4_2, 0x00A4);
75         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP4PIR, 0x00A4);
76         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP4PIR_2, 0x00A4);
77         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGPO, 0x0284);
78         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGPOD, 0x0284);
79         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGPOD_2, 0x0284);
80         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBRFR8S, 0x0093);
81         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBVP1, 0x002B);
82         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBKP, 0x00A7);
83         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBIN, 0x00A7);
84         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMB4PB, 0x00A7);
85     }
86
87     private static final byte ALARM_CONFIGURATION_MEMORY_SIZE = 0x09;
88     private static final byte ALARM_1_ENABLED_MASK = 0x01;
89     private static final byte ALARM_1_TYPE_MASK = 0x02;
90     private static final byte ALARM_2_ENABLED_MASK = 0x04;
91     private static final byte ALARM_2_TYPE_MASK = 0x08;
92
93     private static final StringType ALARM_TYPE_LOCAL = new StringType("LOCAL");
94     private static final StringType ALARM_TYPE_GLOBAL = new StringType("GLOBAL");
95
96     private final ChannelUID clockAlarm1Enabled = new ChannelUID(thing.getUID(), "clockAlarm", "clockAlarm1Enabled");
97     private final ChannelUID clockAlarm1Type = new ChannelUID(thing.getUID(), "clockAlarm", "clockAlarm1Type");
98     private final ChannelUID clockAlarm1WakeupHour = new ChannelUID(thing.getUID(), "clockAlarm",
99             "clockAlarm1WakeupHour");
100     private final ChannelUID clockAlarm1WakeupMinute = new ChannelUID(thing.getUID(), "clockAlarm",
101             "clockAlarm1WakeupMinute");
102     private final ChannelUID clockAlarm1BedtimeHour = new ChannelUID(thing.getUID(), "clockAlarm",
103             "clockAlarm1BedtimeHour");
104     private final ChannelUID clockAlarm1BedtimeMinute = new ChannelUID(thing.getUID(), "clockAlarm",
105             "clockAlarm1BedtimeMinute");
106     private final ChannelUID clockAlarm2Enabled = new ChannelUID(thing.getUID(), "clockAlarm", "clockAlarm2Enabled");
107     private final ChannelUID clockAlarm2Type = new ChannelUID(thing.getUID(), "clockAlarm", "clockAlarm2Type");
108     private final ChannelUID clockAlarm2WakeupHour = new ChannelUID(thing.getUID(), "clockAlarm",
109             "clockAlarm2WakeupHour");
110     private final ChannelUID clockAlarm2WakeupMinute = new ChannelUID(thing.getUID(), "clockAlarm",
111             "clockAlarm2WakeupMinute");
112     private final ChannelUID clockAlarm2BedtimeHour = new ChannelUID(thing.getUID(), "clockAlarm",
113             "clockAlarm2BedtimeHour");
114     private final ChannelUID clockAlarm2BedtimeMinute = new ChannelUID(thing.getUID(), "clockAlarm",
115             "clockAlarm2BedtimeMinute");
116
117     private int clockAlarmConfigurationMemoryAddress;
118     private VelbusClockAlarmConfiguration alarmClockConfiguration = new VelbusClockAlarmConfiguration();
119
120     private long lastUpdateAlarm1TimeMillis;
121     private long lastUpdateAlarm2TimeMillis;
122
123     public VelbusSensorWithAlarmClockHandler(Thing thing) {
124         this(thing, 0);
125     }
126
127     public VelbusSensorWithAlarmClockHandler(Thing thing, int numberOfSubAddresses) {
128         super(thing, numberOfSubAddresses);
129     }
130
131     @Override
132     public void initialize() {
133         super.initialize();
134
135         if (ALARM_CONFIGURATION_MEMORY_ADDRESSES.containsKey(thing.getThingTypeUID())) {
136             this.clockAlarmConfigurationMemoryAddress = ALARM_CONFIGURATION_MEMORY_ADDRESSES
137                     .get(thing.getThingTypeUID());
138         }
139     }
140
141     @Override
142     public void handleCommand(ChannelUID channelUID, Command command) {
143         super.handleCommand(channelUID, command);
144
145         VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
146         if (velbusBridgeHandler == null) {
147             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
148             return;
149         }
150
151         if (isAlarmClockChannel(channelUID) && command instanceof RefreshType) {
152             sendReadMemoryBlockPacket(velbusBridgeHandler, this.clockAlarmConfigurationMemoryAddress + 0);
153             sendReadMemoryBlockPacket(velbusBridgeHandler, this.clockAlarmConfigurationMemoryAddress + 4);
154             sendReadMemoryPacket(velbusBridgeHandler, this.clockAlarmConfigurationMemoryAddress + 8);
155         } else if (isAlarmClockChannel(channelUID)) {
156             byte alarmNumber = determineAlarmNumber(channelUID);
157             VelbusClockAlarm alarmClock = alarmClockConfiguration.getAlarmClock(alarmNumber);
158
159             alarmClock.setLocal(true);
160
161             switch (channelUID.getId()) {
162                 case CHANNEL_MODULE_CLOCK_ALARM1_TYPE:
163                 case CHANNEL_MODULE_CLOCK_ALARM2_TYPE: {
164                     if (command instanceof OnOffType) {
165                         // If AlarmType is not read only, it's an old implementation of the module, warn user and
166                         // discard the command
167                         logger.warn(
168                                 "Old implementation of thing '{}', still works, but it's better to remove and recreate the thing.",
169                                 getThing().getUID());
170                     }
171                     return;
172                 }
173                 case CHANNEL_MODULE_CLOCK_ALARM1_ENABLED:
174                 case CHANNEL_MODULE_CLOCK_ALARM2_ENABLED: {
175                     if (command instanceof OnOffType) {
176                         boolean enabled = command == OnOffType.ON;
177                         alarmClock.setEnabled(enabled);
178                     }
179                     break;
180                 }
181                 case CHANNEL_MODULE_CLOCK_ALARM1_WAKEUP_HOUR:
182                 case CHANNEL_MODULE_CLOCK_ALARM2_WAKEUP_HOUR: {
183                     if (command instanceof DecimalType decimalCommand) {
184                         byte wakeupHour = decimalCommand.byteValue();
185                         alarmClock.setWakeupHour(wakeupHour);
186                     }
187                     break;
188                 }
189                 case CHANNEL_MODULE_CLOCK_ALARM1_WAKEUP_MINUTE:
190                 case CHANNEL_MODULE_CLOCK_ALARM2_WAKEUP_MINUTE: {
191                     if (command instanceof DecimalType decimalCommand) {
192                         byte wakeupMinute = decimalCommand.byteValue();
193                         alarmClock.setWakeupMinute(wakeupMinute);
194                     }
195                     break;
196                 }
197                 case CHANNEL_MODULE_CLOCK_ALARM1_BEDTIME_HOUR:
198                 case CHANNEL_MODULE_CLOCK_ALARM2_BEDTIME_HOUR: {
199                     if (command instanceof DecimalType decimalCommand) {
200                         byte bedTimeHour = decimalCommand.byteValue();
201                         alarmClock.setBedtimeHour(bedTimeHour);
202                     }
203                     break;
204                 }
205                 case CHANNEL_MODULE_CLOCK_ALARM1_BEDTIME_MINUTE:
206                 case CHANNEL_MODULE_CLOCK_ALARM2_BEDTIME_MINUTE: {
207                     if (command instanceof DecimalType decimalCommand) {
208                         byte bedTimeMinute = decimalCommand.byteValue();
209                         alarmClock.setBedtimeMinute(bedTimeMinute);
210                     }
211                     break;
212                 }
213             }
214
215             if (alarmNumber == 1) {
216                 lastUpdateAlarm1TimeMillis = System.currentTimeMillis();
217             } else {
218                 lastUpdateAlarm2TimeMillis = System.currentTimeMillis();
219             }
220
221             VelbusSetLocalClockAlarmPacket packet = new VelbusSetLocalClockAlarmPacket(getModuleAddress().getAddress(),
222                     alarmNumber, alarmClock);
223             byte[] packetBytes = packet.getBytes();
224
225             // Schedule the send of the packet to see if there is another update in less than 10 secondes (reduce
226             // flooding of the bus)
227             scheduler.schedule(() -> {
228                 sendAlarmPacket(alarmNumber, packetBytes);
229             }, DELAY_SEND_CLOCK_ALARM_UPDATE, TimeUnit.MILLISECONDS);
230         } else {
231             logger.debug("The command '{}' is not supported by this handler.", command.getClass());
232         }
233     }
234
235     public synchronized void sendAlarmPacket(int alarmNumber, byte[] packetBytes) {
236         VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
237         if (velbusBridgeHandler == null) {
238             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
239             return;
240         }
241
242         long timeSinceLastUpdate;
243
244         if (alarmNumber == 1) {
245             timeSinceLastUpdate = System.currentTimeMillis() - lastUpdateAlarm1TimeMillis;
246         } else {
247             timeSinceLastUpdate = System.currentTimeMillis() - lastUpdateAlarm2TimeMillis;
248         }
249
250         // If a value of the alarm has been updated, discard this old update
251         if (timeSinceLastUpdate < DELAY_SEND_CLOCK_ALARM_UPDATE) {
252             return;
253         }
254
255         velbusBridgeHandler.sendPacket(packetBytes);
256     }
257
258     @Override
259     public void onPacketReceived(byte[] packet) {
260         super.onPacketReceived(packet);
261
262         logger.trace("onPacketReceived() was called");
263
264         if (packet[0] == VelbusPacket.STX && packet.length >= 5) {
265             byte command = packet[4];
266
267             if ((command == COMMAND_MEMORY_DATA_BLOCK && packet.length >= 11)
268                     || (command == COMMAND_MEMORY_DATA && packet.length >= 8)) {
269                 byte highMemoryAddress = packet[5];
270                 byte lowMemoryAddress = packet[6];
271                 int memoryAddress = ((highMemoryAddress & 0xff) << 8) | (lowMemoryAddress & 0xff);
272                 byte[] data = (command == COMMAND_MEMORY_DATA_BLOCK)
273                         ? new byte[] { packet[7], packet[8], packet[9], packet[10] }
274                         : new byte[] { packet[7] };
275
276                 for (int i = 0; i < data.length; i++) {
277
278                     if (isClockAlarmConfigurationByte(memoryAddress + i)) {
279                         setClockAlarmConfigurationByte(memoryAddress + i, data[i]);
280                     }
281                 }
282             } else if (command == COMMAND_MODULE_STATUS) {
283                 int clockAlarmAndProgramSelectionIndexInModuleStatus = this
284                         .getClockAlarmAndProgramSelectionIndexInModuleStatus();
285                 if (packet.length >= clockAlarmAndProgramSelectionIndexInModuleStatus + 1) {
286                     byte alarmAndProgramSelection = packet[clockAlarmAndProgramSelectionIndexInModuleStatus];
287
288                     boolean alarmClock1Enabled = (alarmAndProgramSelection & 0x04) > 0;
289                     boolean alarmClock1IsLocal = (alarmAndProgramSelection & 0x08) == 0;
290                     VelbusClockAlarm alarmClock1 = this.alarmClockConfiguration.getAlarmClock1();
291                     alarmClock1.setEnabled(alarmClock1Enabled);
292                     alarmClock1.setLocal(alarmClock1IsLocal);
293                     updateState(clockAlarm1Enabled, OnOffType.from(alarmClock1.isEnabled()));
294                     updateState(clockAlarm1Type, alarmClock1.isLocal() ? ALARM_TYPE_LOCAL : ALARM_TYPE_GLOBAL);
295
296                     boolean alarmClock2Enabled = (alarmAndProgramSelection & 0x10) > 0;
297                     boolean alarmClock2IsLocal = (alarmAndProgramSelection & 0x20) == 0;
298                     VelbusClockAlarm alarmClock2 = this.alarmClockConfiguration.getAlarmClock2();
299                     alarmClock2.setEnabled(alarmClock2Enabled);
300                     alarmClock2.setLocal(alarmClock2IsLocal);
301                     updateState(clockAlarm2Enabled, OnOffType.from(alarmClock2.isEnabled()));
302                     updateState(clockAlarm2Type, alarmClock2.isLocal() ? ALARM_TYPE_LOCAL : ALARM_TYPE_GLOBAL);
303                 }
304             }
305         }
306     }
307
308     public Boolean isClockAlarmConfigurationByte(int memoryAddress) {
309         return memoryAddress >= this.clockAlarmConfigurationMemoryAddress
310                 && memoryAddress < (this.clockAlarmConfigurationMemoryAddress + ALARM_CONFIGURATION_MEMORY_SIZE);
311     }
312
313     public void setClockAlarmConfigurationByte(int memoryAddress, byte data) {
314         VelbusClockAlarm alarmClock1 = this.alarmClockConfiguration.getAlarmClock1();
315         VelbusClockAlarm alarmClock2 = this.alarmClockConfiguration.getAlarmClock2();
316
317         switch (memoryAddress - this.clockAlarmConfigurationMemoryAddress) {
318             case 0:
319                 alarmClock1.setEnabled((data & ALARM_1_ENABLED_MASK) > 0);
320                 alarmClock1.setLocal((data & ALARM_1_TYPE_MASK) > 0);
321
322                 updateState(clockAlarm1Enabled, OnOffType.from(alarmClock1.isEnabled()));
323                 updateState(clockAlarm1Type, alarmClock1.isLocal() ? ALARM_TYPE_LOCAL : ALARM_TYPE_GLOBAL);
324
325                 alarmClock2.setEnabled((data & ALARM_2_ENABLED_MASK) > 0);
326                 alarmClock2.setLocal((data & ALARM_2_TYPE_MASK) > 0);
327
328                 updateState(clockAlarm2Enabled, OnOffType.from(alarmClock2.isEnabled()));
329                 updateState(clockAlarm2Type, alarmClock2.isLocal() ? ALARM_TYPE_LOCAL : ALARM_TYPE_GLOBAL);
330                 break;
331             case 1:
332                 alarmClock1.setWakeupHour(data);
333                 updateState(clockAlarm1WakeupHour, new DecimalType(alarmClock1.getWakeupHour()));
334                 break;
335             case 2:
336                 alarmClock1.setWakeupMinute(data);
337                 updateState(clockAlarm1WakeupMinute, new DecimalType(alarmClock1.getWakeupMinute()));
338                 break;
339             case 3:
340                 alarmClock1.setBedtimeHour(data);
341                 updateState(clockAlarm1BedtimeHour, new DecimalType(alarmClock1.getBedtimeHour()));
342                 break;
343             case 4:
344                 alarmClock1.setBedtimeMinute(data);
345                 updateState(clockAlarm1BedtimeMinute, new DecimalType(alarmClock1.getBedtimeMinute()));
346                 break;
347             case 5:
348                 alarmClock2.setWakeupHour(data);
349                 updateState(clockAlarm2WakeupHour, new DecimalType(alarmClock2.getWakeupHour()));
350                 break;
351             case 6:
352                 alarmClock2.setWakeupMinute(data);
353                 updateState(clockAlarm2WakeupMinute, new DecimalType(alarmClock2.getWakeupMinute()));
354                 break;
355             case 7:
356                 alarmClock2.setBedtimeHour(data);
357                 updateState(clockAlarm2BedtimeHour, new DecimalType(alarmClock2.getBedtimeHour()));
358                 break;
359             case 8:
360                 alarmClock2.setBedtimeMinute(data);
361                 updateState(clockAlarm2BedtimeMinute, new DecimalType(alarmClock2.getBedtimeMinute()));
362                 break;
363             default:
364                 throw new IllegalArgumentException("The memory address '" + memoryAddress
365                         + "' does not represent a clock alarm configuration for the thing '" + this.thing.getUID()
366                         + "'.");
367         }
368     }
369
370     protected boolean isAlarmClockChannel(ChannelUID channelUID) {
371         switch (channelUID.getId()) {
372             case CHANNEL_MODULE_CLOCK_ALARM1_ENABLED:
373             case CHANNEL_MODULE_CLOCK_ALARM1_TYPE:
374             case CHANNEL_MODULE_CLOCK_ALARM1_WAKEUP_HOUR:
375             case CHANNEL_MODULE_CLOCK_ALARM1_WAKEUP_MINUTE:
376             case CHANNEL_MODULE_CLOCK_ALARM1_BEDTIME_HOUR:
377             case CHANNEL_MODULE_CLOCK_ALARM1_BEDTIME_MINUTE:
378             case CHANNEL_MODULE_CLOCK_ALARM2_ENABLED:
379             case CHANNEL_MODULE_CLOCK_ALARM2_TYPE:
380             case CHANNEL_MODULE_CLOCK_ALARM2_WAKEUP_HOUR:
381             case CHANNEL_MODULE_CLOCK_ALARM2_WAKEUP_MINUTE:
382             case CHANNEL_MODULE_CLOCK_ALARM2_BEDTIME_HOUR:
383             case CHANNEL_MODULE_CLOCK_ALARM2_BEDTIME_MINUTE:
384                 return true;
385         }
386         return false;
387     }
388
389     protected byte determineAlarmNumber(ChannelUID channelUID) {
390         switch (channelUID.getId()) {
391             case CHANNEL_MODULE_CLOCK_ALARM1_ENABLED:
392             case CHANNEL_MODULE_CLOCK_ALARM1_TYPE:
393             case CHANNEL_MODULE_CLOCK_ALARM1_WAKEUP_HOUR:
394             case CHANNEL_MODULE_CLOCK_ALARM1_WAKEUP_MINUTE:
395             case CHANNEL_MODULE_CLOCK_ALARM1_BEDTIME_HOUR:
396             case CHANNEL_MODULE_CLOCK_ALARM1_BEDTIME_MINUTE:
397                 return 1;
398             case CHANNEL_MODULE_CLOCK_ALARM2_ENABLED:
399             case CHANNEL_MODULE_CLOCK_ALARM2_TYPE:
400             case CHANNEL_MODULE_CLOCK_ALARM2_WAKEUP_HOUR:
401             case CHANNEL_MODULE_CLOCK_ALARM2_WAKEUP_MINUTE:
402             case CHANNEL_MODULE_CLOCK_ALARM2_BEDTIME_HOUR:
403             case CHANNEL_MODULE_CLOCK_ALARM2_BEDTIME_MINUTE:
404                 return 2;
405         }
406
407         throw new IllegalArgumentException("The given channelUID is not an alarm clock channel: " + channelUID);
408     }
409
410     protected int getClockAlarmAndProgramSelectionIndexInModuleStatus() {
411         return 10;
412     }
413 }