]> git.basschouten.com Git - openhab-addons.git/blob
f9b7e45e0da1a534492f7cea83075347263f4775
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 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
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.openhab.binding.velbus.internal.VelbusClockAlarm;
24 import org.openhab.binding.velbus.internal.VelbusClockAlarmConfiguration;
25 import org.openhab.binding.velbus.internal.packets.VelbusPacket;
26 import org.openhab.binding.velbus.internal.packets.VelbusSetLocalClockAlarmPacket;
27 import org.openhab.core.library.types.DecimalType;
28 import org.openhab.core.library.types.OnOffType;
29 import org.openhab.core.library.types.StringType;
30 import org.openhab.core.thing.ChannelUID;
31 import org.openhab.core.thing.Thing;
32 import org.openhab.core.thing.ThingStatus;
33 import org.openhab.core.thing.ThingStatusDetail;
34 import org.openhab.core.thing.ThingTypeUID;
35 import org.openhab.core.types.Command;
36 import org.openhab.core.types.RefreshType;
37
38 /**
39  * The {@link VelbusSensorWithAlarmClockHandler} is responsible for handling commands, which are
40  * sent to one of the channels.
41  *
42  * @author Cedric Boon - Initial contribution
43  */
44 @NonNullByDefault
45 public class VelbusSensorWithAlarmClockHandler extends VelbusSensorHandler {
46     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(
47             Arrays.asList(THING_TYPE_VMB2PBN, THING_TYPE_VMB6PBN, THING_TYPE_VMB8PBU, THING_TYPE_VMBPIRC,
48                     THING_TYPE_VMBPIRM, THING_TYPE_VMBRFR8S, THING_TYPE_VMBVP1));
49     private static final HashMap<ThingTypeUID, Integer> ALARM_CONFIGURATION_MEMORY_ADDRESSES = new HashMap<ThingTypeUID, Integer>();
50
51     static {
52         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMB2PBN, 0x0093);
53         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMB4AN, 0x0046);
54         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMB6PBN, 0x0093);
55         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMB7IN, 0x0093);
56         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMB8PBU, 0x0093);
57         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBEL1, 0x0357);
58         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBEL2, 0x0357);
59         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBEL4, 0x0357);
60         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBELO, 0x0593);
61         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBPIRC, 0x0031);
62         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBPIRM, 0x0031);
63         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBPIRO, 0x0031);
64         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBMETEO, 0x0083);
65         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP1, 0x00A4);
66         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP1_2, 0x00A4);
67         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP2, 0x00A4);
68         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP2_2, 0x00A4);
69         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP4, 0x00A4);
70         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP4_2, 0x00A4);
71         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP4PIR, 0x00A4);
72         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGP4PIR_2, 0x00A4);
73         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGPO, 0x0284);
74         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGPOD, 0x0284);
75         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBGPOD_2, 0x0284);
76         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBRFR8S, 0x0093);
77         ALARM_CONFIGURATION_MEMORY_ADDRESSES.put(THING_TYPE_VMBVP1, 0x002B);
78     }
79
80     private static final byte ALARM_CONFIGURATION_MEMORY_SIZE = 0x09;
81     private static final byte ALARM_1_ENABLED_MASK = 0x01;
82     private static final byte ALARM_1_TYPE_MASK = 0x02;
83     private static final byte ALARM_2_ENABLED_MASK = 0x04;
84     private static final byte ALARM_2_TYPE_MASK = 0x08;
85
86     private static final StringType ALARM_TYPE_LOCAL = new StringType("LOCAL");
87     private static final StringType ALARM_TYPE_GLOBAL = new StringType("GLOBAL");
88
89     private final ChannelUID clockAlarm1Enabled = new ChannelUID(thing.getUID(), "clockAlarm", "clockAlarm1Enabled");
90     private final ChannelUID clockAlarm1Type = new ChannelUID(thing.getUID(), "clockAlarm", "clockAlarm1Type");
91     private final ChannelUID clockAlarm1WakeupHour = new ChannelUID(thing.getUID(), "clockAlarm",
92             "clockAlarm1WakeupHour");
93     private final ChannelUID clockAlarm1WakeupMinute = new ChannelUID(thing.getUID(), "clockAlarm",
94             "clockAlarm1WakeupMinute");
95     private final ChannelUID clockAlarm1BedtimeHour = new ChannelUID(thing.getUID(), "clockAlarm",
96             "clockAlarm1BedtimeHour");
97     private final ChannelUID clockAlarm1BedtimeMinute = new ChannelUID(thing.getUID(), "clockAlarm",
98             "clockAlarm1BedtimeMinute");
99     private final ChannelUID clockAlarm2Enabled = new ChannelUID(thing.getUID(), "clockAlarm", "clockAlarm2Enabled");
100     private final ChannelUID clockAlarm2Type = new ChannelUID(thing.getUID(), "clockAlarm", "clockAlarm2Type");
101     private final ChannelUID clockAlarm2WakeupHour = new ChannelUID(thing.getUID(), "clockAlarm",
102             "clockAlarm2WakeupHour");
103     private final ChannelUID clockAlarm2WakeupMinute = new ChannelUID(thing.getUID(), "clockAlarm",
104             "clockAlarm2WakeupMinute");
105     private final ChannelUID clockAlarm2BedtimeHour = new ChannelUID(thing.getUID(), "clockAlarm",
106             "clockAlarm2BedtimeHour");
107     private final ChannelUID clockAlarm2BedtimeMinute = new ChannelUID(thing.getUID(), "clockAlarm",
108             "clockAlarm2BedtimeMinute");
109
110     private int clockAlarmConfigurationMemoryAddress;
111     private VelbusClockAlarmConfiguration alarmClockConfiguration = new VelbusClockAlarmConfiguration();
112
113     public VelbusSensorWithAlarmClockHandler(Thing thing) {
114         this(thing, 0);
115     }
116
117     public VelbusSensorWithAlarmClockHandler(Thing thing, int numberOfSubAddresses) {
118         super(thing, numberOfSubAddresses);
119     }
120
121     @Override
122     public void initialize() {
123         super.initialize();
124
125         if (ALARM_CONFIGURATION_MEMORY_ADDRESSES.containsKey(thing.getThingTypeUID())) {
126             this.clockAlarmConfigurationMemoryAddress = ALARM_CONFIGURATION_MEMORY_ADDRESSES
127                     .get(thing.getThingTypeUID());
128         }
129     }
130
131     @Override
132     public void handleCommand(ChannelUID channelUID, Command command) {
133         super.handleCommand(channelUID, command);
134
135         VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
136         if (velbusBridgeHandler == null) {
137             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
138             return;
139         }
140
141         if (isAlarmClockChannel(channelUID) && command instanceof RefreshType) {
142             sendReadMemoryBlockPacket(velbusBridgeHandler, this.clockAlarmConfigurationMemoryAddress + 0);
143             sendReadMemoryBlockPacket(velbusBridgeHandler, this.clockAlarmConfigurationMemoryAddress + 4);
144             sendReadMemoryPacket(velbusBridgeHandler, this.clockAlarmConfigurationMemoryAddress + 8);
145         } else if (isAlarmClockChannel(channelUID)) {
146             byte alarmNumber = determineAlarmNumber(channelUID);
147             VelbusClockAlarm alarmClock = alarmClockConfiguration.getAlarmClock(alarmNumber);
148
149             if ((channelUID.equals(clockAlarm1Enabled) || channelUID.equals(clockAlarm2Enabled))
150                     && command instanceof OnOffType) {
151                 boolean enabled = command == OnOffType.ON;
152                 alarmClock.setEnabled(enabled);
153             } else if ((channelUID.equals(clockAlarm1Type) || channelUID.equals(clockAlarm2Type))
154                     && command instanceof StringType) {
155                 boolean isLocal = ((StringType) command).equals(ALARM_TYPE_LOCAL);
156                 alarmClock.setLocal(isLocal);
157             } else if (channelUID.equals(clockAlarm1WakeupHour)
158                     || channelUID.equals(clockAlarm2WakeupHour) && command instanceof DecimalType) {
159                 byte wakeupHour = ((DecimalType) command).byteValue();
160                 alarmClock.setWakeupHour(wakeupHour);
161             } else if (channelUID.equals(clockAlarm1WakeupMinute)
162                     || channelUID.equals(clockAlarm2WakeupMinute) && command instanceof DecimalType) {
163                 byte wakeupMinute = ((DecimalType) command).byteValue();
164                 alarmClock.setWakeupMinute(wakeupMinute);
165             } else if (channelUID.equals(clockAlarm1BedtimeHour)
166                     || channelUID.equals(clockAlarm2BedtimeHour) && command instanceof DecimalType) {
167                 byte bedTimeHour = ((DecimalType) command).byteValue();
168                 alarmClock.setBedtimeHour(bedTimeHour);
169             } else if (channelUID.equals(clockAlarm1BedtimeMinute)
170                     || channelUID.equals(clockAlarm2BedtimeMinute) && command instanceof DecimalType) {
171                 byte bedTimeMinute = ((DecimalType) command).byteValue();
172                 alarmClock.setBedtimeMinute(bedTimeMinute);
173             }
174
175             byte address = alarmClock.isLocal() ? getModuleAddress().getAddress() : 0x00;
176             VelbusSetLocalClockAlarmPacket packet = new VelbusSetLocalClockAlarmPacket(address, alarmNumber,
177                     alarmClock);
178             byte[] packetBytes = packet.getBytes();
179             velbusBridgeHandler.sendPacket(packetBytes);
180         } else {
181             logger.debug("The command '{}' is not supported by this handler.", command.getClass());
182         }
183     }
184
185     @Override
186     public void onPacketReceived(byte[] packet) {
187         super.onPacketReceived(packet);
188
189         logger.trace("onPacketReceived() was called");
190
191         if (packet[0] == VelbusPacket.STX && packet.length >= 5) {
192             byte command = packet[4];
193
194             if ((command == COMMAND_MEMORY_DATA_BLOCK && packet.length >= 11)
195                     || (command == COMMAND_MEMORY_DATA && packet.length >= 8)) {
196                 byte highMemoryAddress = packet[5];
197                 byte lowMemoryAddress = packet[6];
198                 int memoryAddress = ((highMemoryAddress & 0xff) << 8) | (lowMemoryAddress & 0xff);
199                 byte[] data = (command == COMMAND_MEMORY_DATA_BLOCK)
200                         ? new byte[] { packet[7], packet[8], packet[9], packet[10] }
201                         : new byte[] { packet[7] };
202
203                 for (int i = 0; i < data.length; i++) {
204
205                     if (isClockAlarmConfigurationByte(memoryAddress + i)) {
206                         setClockAlarmConfigurationByte(memoryAddress + i, data[i]);
207                     }
208                 }
209             } else if (command == COMMAND_MODULE_STATUS) {
210                 int clockAlarmAndProgramSelectionIndexInModuleStatus = this
211                         .getClockAlarmAndProgramSelectionIndexInModuleStatus();
212                 if (packet.length >= clockAlarmAndProgramSelectionIndexInModuleStatus + 1) {
213                     byte alarmAndProgramSelection = packet[clockAlarmAndProgramSelectionIndexInModuleStatus];
214
215                     boolean alarmClock1Enabled = (alarmAndProgramSelection & 0x04) > 0;
216                     boolean alarmClock1IsLocal = (alarmAndProgramSelection & 0x08) == 0;
217                     VelbusClockAlarm alarmClock1 = this.alarmClockConfiguration.getAlarmClock1();
218                     alarmClock1.setEnabled(alarmClock1Enabled);
219                     alarmClock1.setLocal(alarmClock1IsLocal);
220                     updateState(clockAlarm1Enabled, alarmClock1.isEnabled() ? OnOffType.ON : OnOffType.OFF);
221                     updateState(clockAlarm1Type, alarmClock1.isLocal() ? ALARM_TYPE_LOCAL : ALARM_TYPE_GLOBAL);
222
223                     boolean alarmClock2Enabled = (alarmAndProgramSelection & 0x10) > 0;
224                     boolean alarmClock2IsLocal = (alarmAndProgramSelection & 0x20) == 0;
225                     VelbusClockAlarm alarmClock2 = this.alarmClockConfiguration.getAlarmClock2();
226                     alarmClock2.setEnabled(alarmClock2Enabled);
227                     alarmClock2.setLocal(alarmClock2IsLocal);
228                     updateState(clockAlarm2Enabled, alarmClock2.isEnabled() ? OnOffType.ON : OnOffType.OFF);
229                     updateState(clockAlarm2Type, alarmClock2.isLocal() ? ALARM_TYPE_LOCAL : ALARM_TYPE_GLOBAL);
230                 }
231             }
232         }
233     }
234
235     public Boolean isClockAlarmConfigurationByte(int memoryAddress) {
236         return memoryAddress >= this.clockAlarmConfigurationMemoryAddress
237                 && memoryAddress < (this.clockAlarmConfigurationMemoryAddress + ALARM_CONFIGURATION_MEMORY_SIZE);
238     }
239
240     public void setClockAlarmConfigurationByte(int memoryAddress, byte data) {
241         VelbusClockAlarm alarmClock1 = this.alarmClockConfiguration.getAlarmClock1();
242         VelbusClockAlarm alarmClock2 = this.alarmClockConfiguration.getAlarmClock2();
243
244         switch (memoryAddress - this.clockAlarmConfigurationMemoryAddress) {
245             case 0:
246                 alarmClock1.setEnabled((data & ALARM_1_ENABLED_MASK) > 0);
247                 alarmClock1.setLocal((data & ALARM_1_TYPE_MASK) > 0);
248
249                 updateState(clockAlarm1Enabled, alarmClock1.isEnabled() ? OnOffType.ON : OnOffType.OFF);
250                 updateState(clockAlarm1Type, alarmClock1.isLocal() ? ALARM_TYPE_LOCAL : ALARM_TYPE_GLOBAL);
251
252                 alarmClock2.setEnabled((data & ALARM_2_ENABLED_MASK) > 0);
253                 alarmClock2.setLocal((data & ALARM_2_TYPE_MASK) > 0);
254
255                 updateState(clockAlarm2Enabled, alarmClock2.isEnabled() ? OnOffType.ON : OnOffType.OFF);
256                 updateState(clockAlarm2Type, alarmClock2.isLocal() ? ALARM_TYPE_LOCAL : ALARM_TYPE_GLOBAL);
257                 break;
258             case 1:
259                 alarmClock1.setWakeupHour(data);
260                 updateState(clockAlarm1WakeupHour, new DecimalType(alarmClock1.getWakeupHour()));
261                 break;
262             case 2:
263                 alarmClock1.setWakeupMinute(data);
264                 updateState(clockAlarm1WakeupMinute, new DecimalType(alarmClock1.getWakeupMinute()));
265                 break;
266             case 3:
267                 alarmClock1.setBedtimeHour(data);
268                 updateState(clockAlarm1BedtimeHour, new DecimalType(alarmClock1.getBedtimeHour()));
269                 break;
270             case 4:
271                 alarmClock1.setBedtimeMinute(data);
272                 updateState(clockAlarm1BedtimeMinute, new DecimalType(alarmClock1.getBedtimeMinute()));
273                 break;
274             case 5:
275                 alarmClock2.setWakeupHour(data);
276                 updateState(clockAlarm2WakeupHour, new DecimalType(alarmClock2.getWakeupHour()));
277                 break;
278             case 6:
279                 alarmClock2.setWakeupMinute(data);
280                 updateState(clockAlarm2WakeupMinute, new DecimalType(alarmClock2.getWakeupMinute()));
281                 break;
282             case 7:
283                 alarmClock2.setBedtimeHour(data);
284                 updateState(clockAlarm2BedtimeHour, new DecimalType(alarmClock2.getBedtimeHour()));
285                 break;
286             case 8:
287                 alarmClock2.setBedtimeMinute(data);
288                 updateState(clockAlarm2BedtimeMinute, new DecimalType(alarmClock2.getBedtimeMinute()));
289                 break;
290             default:
291                 throw new IllegalArgumentException("The memory address '" + memoryAddress
292                         + "' does not represent a clock alarm configuration for the thing '" + this.thing.getUID()
293                         + "'.");
294         }
295     }
296
297     protected boolean isAlarmClockChannel(ChannelUID channelUID) {
298         return channelUID.equals(clockAlarm1Enabled) || channelUID.equals(clockAlarm1Type)
299                 || channelUID.equals(clockAlarm1WakeupHour) || channelUID.equals(clockAlarm1WakeupMinute)
300                 || channelUID.equals(clockAlarm1BedtimeHour) || channelUID.equals(clockAlarm1BedtimeMinute)
301                 || channelUID.equals(clockAlarm2Enabled) || channelUID.equals(clockAlarm2Type)
302                 || channelUID.equals(clockAlarm2WakeupHour) || channelUID.equals(clockAlarm2WakeupMinute)
303                 || channelUID.equals(clockAlarm2BedtimeHour) || channelUID.equals(clockAlarm2BedtimeMinute);
304     }
305
306     protected byte determineAlarmNumber(ChannelUID channelUID) {
307         if (channelUID.equals(clockAlarm1Enabled) || channelUID.equals(clockAlarm1Type)
308                 || channelUID.equals(clockAlarm1WakeupHour) || channelUID.equals(clockAlarm1WakeupMinute)
309                 || channelUID.equals(clockAlarm1BedtimeHour) || channelUID.equals(clockAlarm1BedtimeMinute)) {
310             return 1;
311         } else if (channelUID.equals(clockAlarm2Enabled) || channelUID.equals(clockAlarm2Type)
312                 || channelUID.equals(clockAlarm2WakeupHour) || channelUID.equals(clockAlarm2WakeupMinute)
313                 || channelUID.equals(clockAlarm2BedtimeHour) || channelUID.equals(clockAlarm2BedtimeMinute)) {
314             return 2;
315         } else {
316             throw new IllegalArgumentException("The given channelUID is not an alarm clock channel: " + channelUID);
317         }
318     }
319
320     protected int getClockAlarmAndProgramSelectionIndexInModuleStatus() {
321         return 10;
322     }
323 }