]> git.basschouten.com Git - openhab-addons.git/blob
6e1eab2544310f7ba8d4d03570810116609f296b
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 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 VMBELPIR support, removes global alarm configuration from module (moved on bridge),
45  *         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<>(
50             Arrays.asList(THING_TYPE_VMB2PBN, THING_TYPE_VMB6PBN, THING_TYPE_VMB8PBU, THING_TYPE_VMBPIRC,
51                     THING_TYPE_VMBPIRM, THING_TYPE_VMBRFR8S, THING_TYPE_VMBVP1));
52     private static final HashMap<ThingTypeUID, Integer> ALARM_CONFIGURATION_MEMORY_ADDRESSES = new HashMap<ThingTypeUID, Integer>();
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     }
83
84     private static final byte ALARM_CONFIGURATION_MEMORY_SIZE = 0x09;
85     private static final byte ALARM_1_ENABLED_MASK = 0x01;
86     private static final byte ALARM_1_TYPE_MASK = 0x02;
87     private static final byte ALARM_2_ENABLED_MASK = 0x04;
88     private static final byte ALARM_2_TYPE_MASK = 0x08;
89
90     private static final StringType ALARM_TYPE_LOCAL = new StringType("LOCAL");
91     private static final StringType ALARM_TYPE_GLOBAL = new StringType("GLOBAL");
92
93     private final ChannelUID clockAlarm1Enabled = new ChannelUID(thing.getUID(), "clockAlarm", "clockAlarm1Enabled");
94     private final ChannelUID clockAlarm1Type = new ChannelUID(thing.getUID(), "clockAlarm", "clockAlarm1Type");
95     private final ChannelUID clockAlarm1WakeupHour = new ChannelUID(thing.getUID(), "clockAlarm",
96             "clockAlarm1WakeupHour");
97     private final ChannelUID clockAlarm1WakeupMinute = new ChannelUID(thing.getUID(), "clockAlarm",
98             "clockAlarm1WakeupMinute");
99     private final ChannelUID clockAlarm1BedtimeHour = new ChannelUID(thing.getUID(), "clockAlarm",
100             "clockAlarm1BedtimeHour");
101     private final ChannelUID clockAlarm1BedtimeMinute = new ChannelUID(thing.getUID(), "clockAlarm",
102             "clockAlarm1BedtimeMinute");
103     private final ChannelUID clockAlarm2Enabled = new ChannelUID(thing.getUID(), "clockAlarm", "clockAlarm2Enabled");
104     private final ChannelUID clockAlarm2Type = new ChannelUID(thing.getUID(), "clockAlarm", "clockAlarm2Type");
105     private final ChannelUID clockAlarm2WakeupHour = new ChannelUID(thing.getUID(), "clockAlarm",
106             "clockAlarm2WakeupHour");
107     private final ChannelUID clockAlarm2WakeupMinute = new ChannelUID(thing.getUID(), "clockAlarm",
108             "clockAlarm2WakeupMinute");
109     private final ChannelUID clockAlarm2BedtimeHour = new ChannelUID(thing.getUID(), "clockAlarm",
110             "clockAlarm2BedtimeHour");
111     private final ChannelUID clockAlarm2BedtimeMinute = new ChannelUID(thing.getUID(), "clockAlarm",
112             "clockAlarm2BedtimeMinute");
113
114     private int clockAlarmConfigurationMemoryAddress;
115     private VelbusClockAlarmConfiguration alarmClockConfiguration = new VelbusClockAlarmConfiguration();
116
117     private long lastUpdateAlarm1TimeMillis;
118     private long lastUpdateAlarm2TimeMillis;
119
120     public VelbusSensorWithAlarmClockHandler(Thing thing) {
121         this(thing, 0);
122     }
123
124     public VelbusSensorWithAlarmClockHandler(Thing thing, int numberOfSubAddresses) {
125         super(thing, numberOfSubAddresses);
126     }
127
128     @Override
129     public void initialize() {
130         super.initialize();
131
132         if (ALARM_CONFIGURATION_MEMORY_ADDRESSES.containsKey(thing.getThingTypeUID())) {
133             this.clockAlarmConfigurationMemoryAddress = ALARM_CONFIGURATION_MEMORY_ADDRESSES
134                     .get(thing.getThingTypeUID());
135         }
136     }
137
138     @Override
139     public void handleCommand(ChannelUID channelUID, Command command) {
140         super.handleCommand(channelUID, command);
141
142         VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
143         if (velbusBridgeHandler == null) {
144             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
145             return;
146         }
147
148         if (isAlarmClockChannel(channelUID) && command instanceof RefreshType) {
149             sendReadMemoryBlockPacket(velbusBridgeHandler, this.clockAlarmConfigurationMemoryAddress + 0);
150             sendReadMemoryBlockPacket(velbusBridgeHandler, this.clockAlarmConfigurationMemoryAddress + 4);
151             sendReadMemoryPacket(velbusBridgeHandler, this.clockAlarmConfigurationMemoryAddress + 8);
152         } else if (isAlarmClockChannel(channelUID)) {
153             byte alarmNumber = determineAlarmNumber(channelUID);
154             VelbusClockAlarm alarmClock = alarmClockConfiguration.getAlarmClock(alarmNumber);
155
156             alarmClock.setLocal(true);
157
158             switch (channelUID.getId()) {
159                 case CHANNEL_MODULE_CLOCK_ALARM1_TYPE:
160                 case CHANNEL_MODULE_CLOCK_ALARM2_TYPE: {
161                     if (command instanceof OnOffType) {
162                         // If AlarmType is not read only, it's an old implementation of the module, warn user and
163                         // discard the command
164                         logger.warn(
165                                 "Old implementation of thing '{}', still works, but it's better to remove and recreate the thing.",
166                                 getThing().getUID());
167                     }
168                     return;
169                 }
170                 case CHANNEL_MODULE_CLOCK_ALARM1_ENABLED:
171                 case CHANNEL_MODULE_CLOCK_ALARM2_ENABLED: {
172                     if (command instanceof OnOffType) {
173                         boolean enabled = command == OnOffType.ON;
174                         alarmClock.setEnabled(enabled);
175                     }
176                     break;
177                 }
178                 case CHANNEL_MODULE_CLOCK_ALARM1_WAKEUP_HOUR:
179                 case CHANNEL_MODULE_CLOCK_ALARM2_WAKEUP_HOUR: {
180                     if (command instanceof DecimalType) {
181                         byte wakeupHour = ((DecimalType) command).byteValue();
182                         alarmClock.setWakeupHour(wakeupHour);
183                     }
184                     break;
185                 }
186                 case CHANNEL_MODULE_CLOCK_ALARM1_WAKEUP_MINUTE:
187                 case CHANNEL_MODULE_CLOCK_ALARM2_WAKEUP_MINUTE: {
188                     if (command instanceof DecimalType) {
189                         byte wakeupMinute = ((DecimalType) command).byteValue();
190                         alarmClock.setWakeupMinute(wakeupMinute);
191                     }
192                     break;
193                 }
194                 case CHANNEL_MODULE_CLOCK_ALARM1_BEDTIME_HOUR:
195                 case CHANNEL_MODULE_CLOCK_ALARM2_BEDTIME_HOUR: {
196                     if (command instanceof DecimalType) {
197                         byte bedTimeHour = ((DecimalType) command).byteValue();
198                         alarmClock.setBedtimeHour(bedTimeHour);
199                     }
200                     break;
201                 }
202                 case CHANNEL_MODULE_CLOCK_ALARM1_BEDTIME_MINUTE:
203                 case CHANNEL_MODULE_CLOCK_ALARM2_BEDTIME_MINUTE: {
204                     if (command instanceof DecimalType) {
205                         byte bedTimeMinute = ((DecimalType) command).byteValue();
206                         alarmClock.setBedtimeMinute(bedTimeMinute);
207                     }
208                     break;
209                 }
210             }
211
212             if (alarmNumber == 1) {
213                 lastUpdateAlarm1TimeMillis = System.currentTimeMillis();
214             } else {
215                 lastUpdateAlarm2TimeMillis = System.currentTimeMillis();
216             }
217
218             VelbusSetLocalClockAlarmPacket packet = new VelbusSetLocalClockAlarmPacket(getModuleAddress().getAddress(),
219                     alarmNumber, alarmClock);
220             byte[] packetBytes = packet.getBytes();
221
222             // Schedule the send of the packet to see if there is another update in less than 10 secondes (reduce
223             // flooding of the bus)
224             scheduler.schedule(() -> {
225                 sendAlarmPacket(alarmNumber, packetBytes);
226             }, DELAY_SEND_CLOCK_ALARM_UPDATE, TimeUnit.MILLISECONDS);
227         } else {
228             logger.debug("The command '{}' is not supported by this handler.", command.getClass());
229         }
230     }
231
232     public synchronized void sendAlarmPacket(int alarmNumber, byte[] packetBytes) {
233         VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
234         if (velbusBridgeHandler == null) {
235             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
236             return;
237         }
238
239         long timeSinceLastUpdate;
240
241         if (alarmNumber == 1) {
242             timeSinceLastUpdate = System.currentTimeMillis() - lastUpdateAlarm1TimeMillis;
243         } else {
244             timeSinceLastUpdate = System.currentTimeMillis() - lastUpdateAlarm2TimeMillis;
245         }
246
247         // If a value of the alarm has been updated, discard this old update
248         if (timeSinceLastUpdate < DELAY_SEND_CLOCK_ALARM_UPDATE) {
249             return;
250         }
251
252         velbusBridgeHandler.sendPacket(packetBytes);
253     }
254
255     @Override
256     public void onPacketReceived(byte[] packet) {
257         super.onPacketReceived(packet);
258
259         logger.trace("onPacketReceived() was called");
260
261         if (packet[0] == VelbusPacket.STX && packet.length >= 5) {
262             byte command = packet[4];
263
264             if ((command == COMMAND_MEMORY_DATA_BLOCK && packet.length >= 11)
265                     || (command == COMMAND_MEMORY_DATA && packet.length >= 8)) {
266                 byte highMemoryAddress = packet[5];
267                 byte lowMemoryAddress = packet[6];
268                 int memoryAddress = ((highMemoryAddress & 0xff) << 8) | (lowMemoryAddress & 0xff);
269                 byte[] data = (command == COMMAND_MEMORY_DATA_BLOCK)
270                         ? new byte[] { packet[7], packet[8], packet[9], packet[10] }
271                         : new byte[] { packet[7] };
272
273                 for (int i = 0; i < data.length; i++) {
274
275                     if (isClockAlarmConfigurationByte(memoryAddress + i)) {
276                         setClockAlarmConfigurationByte(memoryAddress + i, data[i]);
277                     }
278                 }
279             } else if (command == COMMAND_MODULE_STATUS) {
280                 int clockAlarmAndProgramSelectionIndexInModuleStatus = this
281                         .getClockAlarmAndProgramSelectionIndexInModuleStatus();
282                 if (packet.length >= clockAlarmAndProgramSelectionIndexInModuleStatus + 1) {
283                     byte alarmAndProgramSelection = packet[clockAlarmAndProgramSelectionIndexInModuleStatus];
284
285                     boolean alarmClock1Enabled = (alarmAndProgramSelection & 0x04) > 0;
286                     boolean alarmClock1IsLocal = (alarmAndProgramSelection & 0x08) == 0;
287                     VelbusClockAlarm alarmClock1 = this.alarmClockConfiguration.getAlarmClock1();
288                     alarmClock1.setEnabled(alarmClock1Enabled);
289                     alarmClock1.setLocal(alarmClock1IsLocal);
290                     updateState(clockAlarm1Enabled, alarmClock1.isEnabled() ? OnOffType.ON : OnOffType.OFF);
291                     updateState(clockAlarm1Type, alarmClock1.isLocal() ? ALARM_TYPE_LOCAL : ALARM_TYPE_GLOBAL);
292
293                     boolean alarmClock2Enabled = (alarmAndProgramSelection & 0x10) > 0;
294                     boolean alarmClock2IsLocal = (alarmAndProgramSelection & 0x20) == 0;
295                     VelbusClockAlarm alarmClock2 = this.alarmClockConfiguration.getAlarmClock2();
296                     alarmClock2.setEnabled(alarmClock2Enabled);
297                     alarmClock2.setLocal(alarmClock2IsLocal);
298                     updateState(clockAlarm2Enabled, alarmClock2.isEnabled() ? OnOffType.ON : OnOffType.OFF);
299                     updateState(clockAlarm2Type, alarmClock2.isLocal() ? ALARM_TYPE_LOCAL : ALARM_TYPE_GLOBAL);
300                 }
301             }
302         }
303     }
304
305     public Boolean isClockAlarmConfigurationByte(int memoryAddress) {
306         return memoryAddress >= this.clockAlarmConfigurationMemoryAddress
307                 && memoryAddress < (this.clockAlarmConfigurationMemoryAddress + ALARM_CONFIGURATION_MEMORY_SIZE);
308     }
309
310     public void setClockAlarmConfigurationByte(int memoryAddress, byte data) {
311         VelbusClockAlarm alarmClock1 = this.alarmClockConfiguration.getAlarmClock1();
312         VelbusClockAlarm alarmClock2 = this.alarmClockConfiguration.getAlarmClock2();
313
314         switch (memoryAddress - this.clockAlarmConfigurationMemoryAddress) {
315             case 0:
316                 alarmClock1.setEnabled((data & ALARM_1_ENABLED_MASK) > 0);
317                 alarmClock1.setLocal((data & ALARM_1_TYPE_MASK) > 0);
318
319                 updateState(clockAlarm1Enabled, alarmClock1.isEnabled() ? OnOffType.ON : OnOffType.OFF);
320                 updateState(clockAlarm1Type, alarmClock1.isLocal() ? ALARM_TYPE_LOCAL : ALARM_TYPE_GLOBAL);
321
322                 alarmClock2.setEnabled((data & ALARM_2_ENABLED_MASK) > 0);
323                 alarmClock2.setLocal((data & ALARM_2_TYPE_MASK) > 0);
324
325                 updateState(clockAlarm2Enabled, alarmClock2.isEnabled() ? OnOffType.ON : OnOffType.OFF);
326                 updateState(clockAlarm2Type, alarmClock2.isLocal() ? ALARM_TYPE_LOCAL : ALARM_TYPE_GLOBAL);
327                 break;
328             case 1:
329                 alarmClock1.setWakeupHour(data);
330                 updateState(clockAlarm1WakeupHour, new DecimalType(alarmClock1.getWakeupHour()));
331                 break;
332             case 2:
333                 alarmClock1.setWakeupMinute(data);
334                 updateState(clockAlarm1WakeupMinute, new DecimalType(alarmClock1.getWakeupMinute()));
335                 break;
336             case 3:
337                 alarmClock1.setBedtimeHour(data);
338                 updateState(clockAlarm1BedtimeHour, new DecimalType(alarmClock1.getBedtimeHour()));
339                 break;
340             case 4:
341                 alarmClock1.setBedtimeMinute(data);
342                 updateState(clockAlarm1BedtimeMinute, new DecimalType(alarmClock1.getBedtimeMinute()));
343                 break;
344             case 5:
345                 alarmClock2.setWakeupHour(data);
346                 updateState(clockAlarm2WakeupHour, new DecimalType(alarmClock2.getWakeupHour()));
347                 break;
348             case 6:
349                 alarmClock2.setWakeupMinute(data);
350                 updateState(clockAlarm2WakeupMinute, new DecimalType(alarmClock2.getWakeupMinute()));
351                 break;
352             case 7:
353                 alarmClock2.setBedtimeHour(data);
354                 updateState(clockAlarm2BedtimeHour, new DecimalType(alarmClock2.getBedtimeHour()));
355                 break;
356             case 8:
357                 alarmClock2.setBedtimeMinute(data);
358                 updateState(clockAlarm2BedtimeMinute, new DecimalType(alarmClock2.getBedtimeMinute()));
359                 break;
360             default:
361                 throw new IllegalArgumentException("The memory address '" + memoryAddress
362                         + "' does not represent a clock alarm configuration for the thing '" + this.thing.getUID()
363                         + "'.");
364         }
365     }
366
367     protected boolean isAlarmClockChannel(ChannelUID channelUID) {
368         switch (channelUID.getId()) {
369             case CHANNEL_MODULE_CLOCK_ALARM1_ENABLED:
370             case CHANNEL_MODULE_CLOCK_ALARM1_TYPE:
371             case CHANNEL_MODULE_CLOCK_ALARM1_WAKEUP_HOUR:
372             case CHANNEL_MODULE_CLOCK_ALARM1_WAKEUP_MINUTE:
373             case CHANNEL_MODULE_CLOCK_ALARM1_BEDTIME_HOUR:
374             case CHANNEL_MODULE_CLOCK_ALARM1_BEDTIME_MINUTE:
375             case CHANNEL_MODULE_CLOCK_ALARM2_ENABLED:
376             case CHANNEL_MODULE_CLOCK_ALARM2_TYPE:
377             case CHANNEL_MODULE_CLOCK_ALARM2_WAKEUP_HOUR:
378             case CHANNEL_MODULE_CLOCK_ALARM2_WAKEUP_MINUTE:
379             case CHANNEL_MODULE_CLOCK_ALARM2_BEDTIME_HOUR:
380             case CHANNEL_MODULE_CLOCK_ALARM2_BEDTIME_MINUTE:
381                 return true;
382         }
383         return false;
384     }
385
386     protected byte determineAlarmNumber(ChannelUID channelUID) {
387         switch (channelUID.getId()) {
388             case CHANNEL_MODULE_CLOCK_ALARM1_ENABLED:
389             case CHANNEL_MODULE_CLOCK_ALARM1_TYPE:
390             case CHANNEL_MODULE_CLOCK_ALARM1_WAKEUP_HOUR:
391             case CHANNEL_MODULE_CLOCK_ALARM1_WAKEUP_MINUTE:
392             case CHANNEL_MODULE_CLOCK_ALARM1_BEDTIME_HOUR:
393             case CHANNEL_MODULE_CLOCK_ALARM1_BEDTIME_MINUTE:
394                 return 1;
395             case CHANNEL_MODULE_CLOCK_ALARM2_ENABLED:
396             case CHANNEL_MODULE_CLOCK_ALARM2_TYPE:
397             case CHANNEL_MODULE_CLOCK_ALARM2_WAKEUP_HOUR:
398             case CHANNEL_MODULE_CLOCK_ALARM2_WAKEUP_MINUTE:
399             case CHANNEL_MODULE_CLOCK_ALARM2_BEDTIME_HOUR:
400             case CHANNEL_MODULE_CLOCK_ALARM2_BEDTIME_MINUTE:
401                 return 2;
402         }
403
404         throw new IllegalArgumentException("The given channelUID is not an alarm clock channel: " + channelUID);
405     }
406
407     protected int getClockAlarmAndProgramSelectionIndexInModuleStatus() {
408         return 10;
409     }
410 }