2 * Copyright (c) 2010-2022 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.velbus.internal.discovery;
15 import static org.openhab.binding.velbus.internal.VelbusBindingConstants.*;
17 import java.util.Arrays;
18 import java.util.Date;
19 import java.util.HashMap;
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;
42 * If the user scans manually for things this
43 * {@link VelbusThingDiscoveryService}
44 * is used to return Velbus Modules as things to the framework.
46 * @author Cedric Boon - Initial contribution
49 public class VelbusThingDiscoveryService extends AbstractDiscoveryService
50 implements ThingHandlerService, VelbusPacketListener {
51 private static final int SEARCH_TIME = 60;
53 private final Logger logger = LoggerFactory.getLogger(VelbusThingDiscoveryService.class);
55 private Map<Byte, VelbusModule> velbusModules = new HashMap<>();
57 private @Nullable VelbusBridgeHandler velbusBridgeHandler;
59 public VelbusThingDiscoveryService() {
60 super(SUPPORTED_THING_TYPES_UIDS, SEARCH_TIME);
64 public void deactivate() {
65 removeOlderResults(new Date().getTime());
67 final VelbusBridgeHandler velbusBridgeHandler = this.velbusBridgeHandler;
68 if (velbusBridgeHandler != null) {
69 velbusBridgeHandler.clearDefaultPacketListener();
74 protected void startScan() {
75 for (int i = 0x00; i <= 0xFF; i++) {
76 VelbusScanPacket packet = new VelbusScanPacket((byte) i);
77 byte[] packetBytes = packet.getBytes();
79 final VelbusBridgeHandler velbusBridgeHandler = this.velbusBridgeHandler;
80 if (velbusBridgeHandler != null) {
81 velbusBridgeHandler.sendPacket(packetBytes);
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];
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);
104 logger.debug("Unknown command '{}' to address '{}'.", String.format("%02X", command),
105 String.format("%02X", address));
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];
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);
125 case MODULE_TYPE_VMB1BLS:
126 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
127 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1BLS, 1);
129 case MODULE_TYPE_VMB1DM:
130 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
131 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1DM, 1);
133 case MODULE_TYPE_VMB1LED:
134 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
135 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1LED, 1);
137 case MODULE_TYPE_VMB1RY:
138 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
139 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1RY, 1);
141 case MODULE_TYPE_VMB1RYNO:
142 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
143 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1RYNO, 5);
145 case MODULE_TYPE_VMB1RYNOS:
146 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
147 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1RYNOS, 5);
149 case MODULE_TYPE_VMB1RYS:
150 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
151 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1RYS, 5);
153 case MODULE_TYPE_VMB1TS:
154 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
155 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1TS, 1);
157 case MODULE_TYPE_VMB2BL:
158 velbusModule = new VelbusModule(new VelbusFirstGenerationDeviceModuleAddress(address), moduleType,
159 highByteOfSerialNumber, lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek,
160 THING_TYPE_VMB2BL, 2);
162 case MODULE_TYPE_VMB2BLE:
163 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
164 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB2BLE, 2);
166 case MODULE_TYPE_VMB2PBN:
167 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
168 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB2PBN, 8);
170 case MODULE_TYPE_VMB4AN:
171 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
172 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4AN, 4);
174 case MODULE_TYPE_VMB4DC:
175 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
176 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4DC, 4);
178 case MODULE_TYPE_VMB4RY:
179 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
180 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4RY, 4);
182 case MODULE_TYPE_VMB4RYLD:
183 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
184 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4RYLD, 5);
186 case MODULE_TYPE_VMB4RYNO:
187 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
188 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4RYNO, 5);
190 case MODULE_TYPE_VMB6IN:
191 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
192 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB6IN, 6);
194 case MODULE_TYPE_VMB6PBN:
195 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
196 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB6PBN, 8);
198 case MODULE_TYPE_VMB7IN:
199 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
200 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB7IN, 8);
202 case MODULE_TYPE_VMB8IR:
203 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
204 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB8IR, 8);
206 case MODULE_TYPE_VMB8PB:
207 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
208 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB8PB, 8);
210 case MODULE_TYPE_VMB8PBU:
211 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
212 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB8PBU, 8);
214 case MODULE_TYPE_VMBDME:
215 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
216 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBDME, 1);
218 case MODULE_TYPE_VMBDMI:
219 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
220 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBDMI, 1);
222 case MODULE_TYPE_VMBDMIR:
223 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
224 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBDMIR, 1);
226 case MODULE_TYPE_VMBEL1:
227 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
228 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBEL1, 9);
230 case MODULE_TYPE_VMBEL2:
231 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
232 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBEL2, 9);
234 case MODULE_TYPE_VMBEL4:
235 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
236 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBEL4, 9);
238 case MODULE_TYPE_VMBELO:
239 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
240 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBELO, 33);
242 case MODULE_TYPE_VMBELPIR:
243 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
244 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBELPIR, 9);
246 case MODULE_TYPE_VMBGP1:
247 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
248 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP1, 9);
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);
254 case MODULE_TYPE_VMBGP2:
255 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
256 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP2, 9);
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);
262 case MODULE_TYPE_VMBGP4:
263 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
264 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP4, 9);
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);
270 case MODULE_TYPE_VMBGP4PIR:
271 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
272 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP4PIR, 9);
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);
278 case MODULE_TYPE_VMBGPO:
279 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
280 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGPO, 33);
282 case MODULE_TYPE_VMBGPOD:
283 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
284 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGPOD, 33);
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);
290 case MODULE_TYPE_VMBMETEO:
291 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
292 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBMETEO, 13);
294 case MODULE_TYPE_VMBPIRC:
295 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
296 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBPIRC, 7);
298 case MODULE_TYPE_VMBPIRM:
299 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
300 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBPIRM, 7);
302 case MODULE_TYPE_VMBPIRO:
303 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
304 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBPIRO, 9);
306 case MODULE_TYPE_VMBRFR8S:
307 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
308 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBRFR8S, 8);
310 case MODULE_TYPE_VMBVP1:
311 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
312 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBVP1, 8);
316 if (velbusModule != null) {
317 registerVelbusModule(address, velbusModule);
321 private void handleModuleSubtypeCommand(byte[] packet, byte address) {
322 if (velbusModules.containsKey(address)) {
323 VelbusModule velbusModule = velbusModules.get(address);
325 byte[] subAddresses = new byte[4];
326 System.arraycopy(packet, 8, subAddresses, 0, 4);
328 velbusModule.getModuleAddress().setSubAddresses(subAddresses);
330 for (int i = 0; i < subAddresses.length; i++) {
331 if (subAddresses[i] != (byte) 0xFF) {
332 velbusModules.put(subAddresses[i], velbusModule);
336 notifyDiscoveredVelbusModule(velbusModule);
340 protected void registerVelbusModule(byte address, VelbusModule velbusModule) {
341 velbusModules.put(address, velbusModule);
342 notifyDiscoveredVelbusModule(velbusModule);
343 velbusModule.sendChannelNameRequests(velbusBridgeHandler);
346 private void handleChannelNameCommand(byte[] packet, byte address, byte length, int namePartNumber) {
347 if (velbusModules.containsKey(address)) {
348 VelbusModule velbusModule = velbusModules.get(address);
350 byte channel = packet[5];
351 byte[] namePart = Arrays.copyOfRange(packet, 6, 6 + length - 2);
353 VelbusChannelIdentifier velbusChannelIdentifier = new VelbusChannelIdentifier(address, channel);
354 velbusModule.setChannelName(velbusChannelIdentifier, namePartNumber, namePart);
355 notifyDiscoveredVelbusModule(velbusModule);
359 private void notifyDiscoveredVelbusModule(VelbusModule velbusModule) {
360 final VelbusBridgeHandler velbusBridgeHandler = this.velbusBridgeHandler;
361 if (velbusBridgeHandler != null) {
362 ThingUID bridgeUID = velbusBridgeHandler.getThing().getUID();
364 DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(velbusModule.getThingUID(bridgeUID))
365 .withThingType(velbusModule.getThingTypeUID()).withProperties(velbusModule.getProperties())
366 .withRepresentationProperty(ADDRESS).withBridge(bridgeUID).withLabel(velbusModule.getLabel())
369 thingDiscovered(discoveryResult);
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);
383 public @Nullable ThingHandler getThingHandler() {
384 return this.velbusBridgeHandler;