]> git.basschouten.com Git - openhab-addons.git/blob
3ae22ce65bb96e5184e553ba4f0b42e57cfab0cf
[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.discovery;
14
15 import static org.openhab.binding.velbus.internal.VelbusBindingConstants.*;
16
17 import java.util.Arrays;
18 import java.util.Date;
19 import java.util.HashMap;
20 import java.util.Map;
21
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.openhab.binding.velbus.internal.VelbusChannelIdentifier;
25 import org.openhab.binding.velbus.internal.VelbusFirstGenerationDeviceModuleAddress;
26 import org.openhab.binding.velbus.internal.VelbusModule;
27 import org.openhab.binding.velbus.internal.VelbusModuleAddress;
28 import org.openhab.binding.velbus.internal.VelbusPacketListener;
29 import org.openhab.binding.velbus.internal.handler.VelbusBridgeHandler;
30 import org.openhab.binding.velbus.internal.packets.VelbusPacket;
31 import org.openhab.binding.velbus.internal.packets.VelbusScanPacket;
32 import org.openhab.core.config.discovery.AbstractDiscoveryService;
33 import org.openhab.core.config.discovery.DiscoveryResult;
34 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
35 import org.openhab.core.thing.ThingUID;
36 import org.openhab.core.thing.binding.ThingHandler;
37 import org.openhab.core.thing.binding.ThingHandlerService;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 /**
42  * If the user scans manually for things this
43  * {@link VelbusThingDiscoveryService}
44  * is used to return Velbus Modules as things to the framework.
45  *
46  * @author Cedric Boon - Initial contribution
47  */
48 @NonNullByDefault
49 public class VelbusThingDiscoveryService extends AbstractDiscoveryService
50         implements ThingHandlerService, VelbusPacketListener {
51     private static final int SEARCH_TIME = 60;
52
53     private final Logger logger = LoggerFactory.getLogger(VelbusThingDiscoveryService.class);
54
55     private Map<Byte, VelbusModule> velbusModules = new HashMap<>();
56
57     private @Nullable VelbusBridgeHandler velbusBridgeHandler;
58
59     public VelbusThingDiscoveryService() {
60         super(SUPPORTED_THING_TYPES_UIDS, SEARCH_TIME);
61     }
62
63     @Override
64     public void deactivate() {
65         removeOlderResults(new Date().getTime());
66
67         final VelbusBridgeHandler velbusBridgeHandler = this.velbusBridgeHandler;
68         if (velbusBridgeHandler != null) {
69             velbusBridgeHandler.clearDefaultPacketListener();
70         }
71     }
72
73     @Override
74     protected void startScan() {
75         for (int i = 0x00; i <= 0xFF; i++) {
76             VelbusScanPacket packet = new VelbusScanPacket((byte) i);
77             byte[] packetBytes = packet.getBytes();
78
79             final VelbusBridgeHandler velbusBridgeHandler = this.velbusBridgeHandler;
80             if (velbusBridgeHandler != null) {
81                 velbusBridgeHandler.sendPacket(packetBytes);
82             }
83         }
84     }
85
86     @Override
87     public void onPacketReceived(byte[] packet) {
88         if (packet[0] == VelbusPacket.STX && packet.length >= 5) {
89             byte address = packet[2];
90             byte length = packet[3];
91             byte command = packet[4];
92
93             if (command == COMMAND_MODULE_TYPE && packet.length >= 10) {
94                 handleModuleTypeCommand(packet, address);
95             } else if (command == COMMAND_MODULE_NAME_PART1 & packet.length >= 4 + length) {
96                 handleChannelNameCommand(packet, address, length, 1);
97             } else if (command == COMMAND_MODULE_NAME_PART2 && packet.length >= 4 + length) {
98                 handleChannelNameCommand(packet, address, length, 2);
99             } else if (command == COMMAND_MODULE_NAME_PART3 && packet.length >= 4 + length) {
100                 handleChannelNameCommand(packet, address, length, 3);
101             } else if (command == COMMAND_SUBTYPE && packet.length >= 4 + length) {
102                 handleModuleSubtypeCommand(packet, address);
103             } else {
104                 logger.debug("Unknown command '{}' to address '{}'.", String.format("%02X", command),
105                         String.format("%02X", address));
106             }
107         }
108     }
109
110     private void handleModuleTypeCommand(byte[] packet, byte address) {
111         byte moduleType = packet[5];
112         byte highByteOfSerialNumber = packet[6];
113         byte lowByteOfSerialNumber = packet[7];
114         byte memoryMapVersion = packet[8];
115         byte buildYear = packet[9];
116         byte buildWeek = packet[10];
117
118         VelbusModule velbusModule = null;
119         switch (moduleType) {
120             case MODULE_TYPE_VMB1BL:
121                 velbusModule = new VelbusModule(new VelbusFirstGenerationDeviceModuleAddress(address), moduleType,
122                         highByteOfSerialNumber, lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek,
123                         THING_TYPE_VMB1BL, 1);
124                 break;
125             case MODULE_TYPE_VMB1BLS:
126                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
127                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1BLS, 1);
128                 break;
129             case MODULE_TYPE_VMB1DM:
130                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
131                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1DM, 1);
132                 break;
133             case MODULE_TYPE_VMB1LED:
134                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
135                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1LED, 1);
136                 break;
137             case MODULE_TYPE_VMB1RY:
138                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
139                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1RY, 1);
140                 break;
141             case MODULE_TYPE_VMB1RYNO:
142                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
143                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1RYNO, 5);
144                 break;
145             case MODULE_TYPE_VMB1RYNOS:
146                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
147                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1RYNOS, 5);
148                 break;
149             case MODULE_TYPE_VMB1RYS:
150                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
151                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1RYS, 5);
152                 break;
153             case MODULE_TYPE_VMB1TS:
154                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
155                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1TS, 1);
156                 break;
157             case MODULE_TYPE_VMB2BL:
158                 velbusModule = new VelbusModule(new VelbusFirstGenerationDeviceModuleAddress(address), moduleType,
159                         highByteOfSerialNumber, lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek,
160                         THING_TYPE_VMB2BL, 2);
161                 break;
162             case MODULE_TYPE_VMB2BLE:
163                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
164                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB2BLE, 2);
165                 break;
166             case MODULE_TYPE_VMB2PBN:
167                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
168                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB2PBN, 8);
169                 break;
170             case MODULE_TYPE_VMB4AN:
171                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
172                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4AN, 4);
173                 break;
174             case MODULE_TYPE_VMB4DC:
175                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
176                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4DC, 4);
177                 break;
178             case MODULE_TYPE_VMB4RY:
179                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
180                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4RY, 4);
181                 break;
182             case MODULE_TYPE_VMB4RYLD:
183                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
184                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4RYLD, 5);
185                 break;
186             case MODULE_TYPE_VMB4RYNO:
187                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
188                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4RYNO, 5);
189                 break;
190             case MODULE_TYPE_VMB6IN:
191                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
192                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB6IN, 6);
193                 break;
194             case MODULE_TYPE_VMB6PBN:
195                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
196                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB6PBN, 8);
197                 break;
198             case MODULE_TYPE_VMB7IN:
199                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
200                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB7IN, 8);
201                 break;
202             case MODULE_TYPE_VMB8IR:
203                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
204                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB8IR, 8);
205                 break;
206             case MODULE_TYPE_VMB8PB:
207                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
208                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB8PB, 8);
209                 break;
210             case MODULE_TYPE_VMB8PBU:
211                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
212                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB8PBU, 8);
213                 break;
214             case MODULE_TYPE_VMBDME:
215                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
216                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBDME, 1);
217                 break;
218             case MODULE_TYPE_VMBDMI:
219                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
220                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBDMI, 1);
221                 break;
222             case MODULE_TYPE_VMBDMIR:
223                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
224                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBDMIR, 1);
225                 break;
226             case MODULE_TYPE_VMBEL1:
227                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
228                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBEL1, 9);
229                 break;
230             case MODULE_TYPE_VMBEL2:
231                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
232                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBEL2, 9);
233                 break;
234             case MODULE_TYPE_VMBEL4:
235                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
236                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBEL4, 9);
237                 break;
238             case MODULE_TYPE_VMBELO:
239                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
240                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBELO, 33);
241                 break;
242             case MODULE_TYPE_VMBELPIR:
243                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
244                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBELPIR, 9);
245                 break;
246             case MODULE_TYPE_VMBGP1:
247                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
248                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP1, 9);
249                 break;
250             case MODULE_TYPE_VMBGP1_2:
251                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
252                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP1_2, 9);
253                 break;
254             case MODULE_TYPE_VMBGP2:
255                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
256                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP2, 9);
257                 break;
258             case MODULE_TYPE_VMBGP2_2:
259                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
260                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP2_2, 9);
261                 break;
262             case MODULE_TYPE_VMBGP4:
263                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
264                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP4, 9);
265                 break;
266             case MODULE_TYPE_VMBGP4_2:
267                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
268                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP4_2, 9);
269                 break;
270             case MODULE_TYPE_VMBGP4PIR:
271                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
272                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP4PIR, 9);
273                 break;
274             case MODULE_TYPE_VMBGP4PIR_2:
275                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
276                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP4PIR_2, 9);
277                 break;
278             case MODULE_TYPE_VMBGPO:
279                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
280                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGPO, 33);
281                 break;
282             case MODULE_TYPE_VMBGPOD:
283                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
284                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGPOD, 33);
285                 break;
286             case MODULE_TYPE_VMBGPOD_2:
287                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
288                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGPOD_2, 33);
289                 break;
290             case MODULE_TYPE_VMBMETEO:
291                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
292                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBMETEO, 13);
293                 break;
294             case MODULE_TYPE_VMBPIRC:
295                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
296                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBPIRC, 7);
297                 break;
298             case MODULE_TYPE_VMBPIRM:
299                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
300                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBPIRM, 7);
301                 break;
302             case MODULE_TYPE_VMBPIRO:
303                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
304                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBPIRO, 9);
305                 break;
306             case MODULE_TYPE_VMBRFR8S:
307                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
308                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBRFR8S, 8);
309                 break;
310             case MODULE_TYPE_VMBVP1:
311                 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
312                         lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBVP1, 8);
313                 break;
314         }
315
316         if (velbusModule != null) {
317             registerVelbusModule(address, velbusModule);
318         }
319     }
320
321     private void handleModuleSubtypeCommand(byte[] packet, byte address) {
322         if (velbusModules.containsKey(address)) {
323             VelbusModule velbusModule = velbusModules.get(address);
324
325             byte[] subAddresses = new byte[4];
326             System.arraycopy(packet, 8, subAddresses, 0, 4);
327
328             velbusModule.getModuleAddress().setSubAddresses(subAddresses);
329
330             for (int i = 0; i < subAddresses.length; i++) {
331                 if (subAddresses[i] != (byte) 0xFF) {
332                     velbusModules.put(subAddresses[i], velbusModule);
333                 }
334             }
335
336             notifyDiscoveredVelbusModule(velbusModule);
337         }
338     }
339
340     protected void registerVelbusModule(byte address, VelbusModule velbusModule) {
341         velbusModules.put(address, velbusModule);
342         notifyDiscoveredVelbusModule(velbusModule);
343         velbusModule.sendChannelNameRequests(velbusBridgeHandler);
344     }
345
346     private void handleChannelNameCommand(byte[] packet, byte address, byte length, int namePartNumber) {
347         if (velbusModules.containsKey(address)) {
348             VelbusModule velbusModule = velbusModules.get(address);
349
350             byte channel = packet[5];
351             byte[] namePart = Arrays.copyOfRange(packet, 6, 6 + length - 2);
352
353             VelbusChannelIdentifier velbusChannelIdentifier = new VelbusChannelIdentifier(address, channel);
354             velbusModule.setChannelName(velbusChannelIdentifier, namePartNumber, namePart);
355             notifyDiscoveredVelbusModule(velbusModule);
356         }
357     }
358
359     private void notifyDiscoveredVelbusModule(VelbusModule velbusModule) {
360         final VelbusBridgeHandler velbusBridgeHandler = this.velbusBridgeHandler;
361         if (velbusBridgeHandler != null) {
362             ThingUID bridgeUID = velbusBridgeHandler.getThing().getUID();
363
364             DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(velbusModule.getThingUID(bridgeUID))
365                     .withThingType(velbusModule.getThingTypeUID()).withProperties(velbusModule.getProperties())
366                     .withRepresentationProperty(ADDRESS).withBridge(bridgeUID).withLabel(velbusModule.getLabel())
367                     .build();
368
369             thingDiscovered(discoveryResult);
370         }
371     }
372
373     @Override
374     public void setThingHandler(@Nullable ThingHandler handler) {
375         if (handler instanceof VelbusBridgeHandler) {
376             final VelbusBridgeHandler velbusBridgeHandler = (VelbusBridgeHandler) handler;
377             this.velbusBridgeHandler = velbusBridgeHandler;
378             velbusBridgeHandler.setDefaultPacketListener(this);
379         }
380     }
381
382     @Override
383     public @Nullable ThingHandler getThingHandler() {
384         return this.velbusBridgeHandler;
385     }
386 }