2 * Copyright (c) 2010-2024 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.openhab.binding.velbus.internal.VelbusChannelIdentifier;
24 import org.openhab.binding.velbus.internal.VelbusFirstGenerationDeviceModuleAddress;
25 import org.openhab.binding.velbus.internal.VelbusModule;
26 import org.openhab.binding.velbus.internal.VelbusModuleAddress;
27 import org.openhab.binding.velbus.internal.VelbusPacketListener;
28 import org.openhab.binding.velbus.internal.handler.VelbusBridgeHandler;
29 import org.openhab.binding.velbus.internal.packets.VelbusPacket;
30 import org.openhab.binding.velbus.internal.packets.VelbusScanPacket;
31 import org.openhab.core.config.discovery.AbstractThingHandlerDiscoveryService;
32 import org.openhab.core.config.discovery.DiscoveryResult;
33 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
34 import org.openhab.core.thing.ThingUID;
35 import org.osgi.service.component.annotations.Component;
36 import org.osgi.service.component.annotations.ServiceScope;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
41 * If the user scans manually for things this
42 * {@link VelbusThingDiscoveryService}
43 * is used to return Velbus Modules as things to the framework.
45 * @author Cedric Boon - Initial contribution
47 @Component(scope = ServiceScope.PROTOTYPE, service = VelbusThingDiscoveryService.class)
49 public class VelbusThingDiscoveryService extends AbstractThingHandlerDiscoveryService<VelbusBridgeHandler>
50 implements 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 public VelbusThingDiscoveryService() {
58 super(VelbusBridgeHandler.class, SUPPORTED_THING_TYPES_UIDS, SEARCH_TIME);
62 public void dispose() {
64 removeOlderResults(new Date().getTime());
65 thingHandler.clearDefaultPacketListener();
69 protected void startScan() {
70 for (int i = 0x00; i <= 0xFF; i++) {
71 VelbusScanPacket packet = new VelbusScanPacket((byte) i);
72 byte[] packetBytes = packet.getBytes();
74 thingHandler.sendPacket(packetBytes);
79 public void onPacketReceived(byte[] packet) {
80 if (packet[0] == VelbusPacket.STX && packet.length >= 5) {
81 byte address = packet[2];
82 byte length = packet[3];
83 byte command = packet[4];
85 if (command == COMMAND_MODULE_TYPE && packet.length >= 10) {
86 handleModuleTypeCommand(packet, address);
87 } else if (command == COMMAND_MODULE_NAME_PART1 & packet.length >= 4 + length) {
88 handleChannelNameCommand(packet, address, length, 1);
89 } else if (command == COMMAND_MODULE_NAME_PART2 && packet.length >= 4 + length) {
90 handleChannelNameCommand(packet, address, length, 2);
91 } else if (command == COMMAND_MODULE_NAME_PART3 && packet.length >= 4 + length) {
92 handleChannelNameCommand(packet, address, length, 3);
93 } else if (command == COMMAND_SUBTYPE && packet.length >= 4 + length) {
94 handleModuleSubtypeCommand(packet, address);
96 logger.debug("Unknown command '{}' to address '{}'.", String.format("%02X", command),
97 String.format("%02X", address));
102 private void handleModuleTypeCommand(byte[] packet, byte address) {
103 byte moduleType = packet[5];
104 byte highByteOfSerialNumber = packet[6];
105 byte lowByteOfSerialNumber = packet[7];
106 byte memoryMapVersion = packet[8];
107 byte buildYear = packet[9];
108 byte buildWeek = packet[10];
110 VelbusModule velbusModule = null;
111 switch (moduleType) {
112 case MODULE_TYPE_VMB1BL:
113 velbusModule = new VelbusModule(new VelbusFirstGenerationDeviceModuleAddress(address), moduleType,
114 highByteOfSerialNumber, lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek,
115 THING_TYPE_VMB1BL, 1);
117 case MODULE_TYPE_VMB1BLS:
118 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
119 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1BLS, 1);
121 case MODULE_TYPE_VMB1DM:
122 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
123 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1DM, 1);
125 case MODULE_TYPE_VMB1LED:
126 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
127 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1LED, 1);
129 case MODULE_TYPE_VMB1RY:
130 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
131 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1RY, 1);
133 case MODULE_TYPE_VMB1RYNO:
134 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
135 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1RYNO, 5);
137 case MODULE_TYPE_VMB1RYNOS:
138 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
139 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1RYNOS, 5);
141 case MODULE_TYPE_VMB1RYS:
142 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
143 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1RYS, 5);
145 case MODULE_TYPE_VMB1TS:
146 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
147 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1TS, 1);
149 case MODULE_TYPE_VMB2BL:
150 velbusModule = new VelbusModule(new VelbusFirstGenerationDeviceModuleAddress(address), moduleType,
151 highByteOfSerialNumber, lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek,
152 THING_TYPE_VMB2BL, 2);
154 case MODULE_TYPE_VMB2BLE:
155 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
156 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB2BLE, 2);
158 case MODULE_TYPE_VMB2PBN:
159 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
160 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB2PBN, 8);
162 case MODULE_TYPE_VMB4AN:
163 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
164 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4AN, 4);
166 case MODULE_TYPE_VMB4DC:
167 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
168 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4DC, 4);
170 case MODULE_TYPE_VMB4RY:
171 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
172 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4RY, 4);
174 case MODULE_TYPE_VMB4RYLD:
175 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
176 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4RYLD, 5);
178 case MODULE_TYPE_VMB4RYNO:
179 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
180 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4RYNO, 5);
182 case MODULE_TYPE_VMB6IN:
183 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
184 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB6IN, 6);
186 case MODULE_TYPE_VMB6PBN:
187 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
188 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB6PBN, 8);
190 case MODULE_TYPE_VMB7IN:
191 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
192 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB7IN, 8);
194 case MODULE_TYPE_VMB8IR:
195 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
196 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB8IR, 8);
198 case MODULE_TYPE_VMB8PB:
199 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
200 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB8PB, 8);
202 case MODULE_TYPE_VMB8PBU:
203 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
204 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB8PBU, 8);
206 case MODULE_TYPE_VMBDME:
207 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
208 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBDME, 1);
210 case MODULE_TYPE_VMBDMI:
211 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
212 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBDMI, 1);
214 case MODULE_TYPE_VMBDMIR:
215 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
216 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBDMIR, 1);
218 case MODULE_TYPE_VMBEL1:
219 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
220 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBEL1, 9);
222 case MODULE_TYPE_VMBEL2:
223 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
224 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBEL2, 9);
226 case MODULE_TYPE_VMBEL4:
227 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
228 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBEL4, 9);
230 case MODULE_TYPE_VMBELO:
231 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
232 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBELO, 33);
234 case MODULE_TYPE_VMBELPIR:
235 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
236 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBELPIR, 9);
238 case MODULE_TYPE_VMBGP1:
239 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
240 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP1, 9);
242 case MODULE_TYPE_VMBGP1_2:
243 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
244 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP1_2, 9);
246 case MODULE_TYPE_VMBGP2:
247 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
248 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP2, 9);
250 case MODULE_TYPE_VMBGP2_2:
251 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
252 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP2_2, 9);
254 case MODULE_TYPE_VMBGP4:
255 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
256 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP4, 9);
258 case MODULE_TYPE_VMBGP4_2:
259 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
260 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP4_2, 9);
262 case MODULE_TYPE_VMBGP4PIR:
263 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
264 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP4PIR, 9);
266 case MODULE_TYPE_VMBGP4PIR_2:
267 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
268 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP4PIR_2, 9);
270 case MODULE_TYPE_VMBGPO:
271 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
272 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGPO, 33);
274 case MODULE_TYPE_VMBGPOD:
275 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
276 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGPOD, 33);
278 case MODULE_TYPE_VMBGPOD_2:
279 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
280 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGPOD_2, 33);
282 case MODULE_TYPE_VMBMETEO:
283 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
284 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBMETEO, 13);
286 case MODULE_TYPE_VMBPIRC:
287 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
288 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBPIRC, 7);
290 case MODULE_TYPE_VMBPIRM:
291 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
292 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBPIRM, 7);
294 case MODULE_TYPE_VMBPIRO:
295 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
296 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBPIRO, 9);
298 case MODULE_TYPE_VMBRFR8S:
299 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
300 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBRFR8S, 8);
302 case MODULE_TYPE_VMBVP1:
303 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
304 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBVP1, 8);
306 case MODULE_TYPE_VMBKP:
307 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
308 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBKP, 8);
310 case MODULE_TYPE_VMBIN:
311 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
312 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBIN, 8);
314 case MODULE_TYPE_VMB4PB:
315 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
316 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4PB, 8);
320 if (velbusModule != null) {
321 registerVelbusModule(address, velbusModule);
325 private void handleModuleSubtypeCommand(byte[] packet, byte address) {
326 if (velbusModules.containsKey(address)) {
327 VelbusModule velbusModule = velbusModules.get(address);
329 byte[] subAddresses = new byte[4];
330 System.arraycopy(packet, 8, subAddresses, 0, 4);
332 velbusModule.getModuleAddress().setSubAddresses(subAddresses);
334 for (int i = 0; i < subAddresses.length; i++) {
335 if (subAddresses[i] != (byte) 0xFF) {
336 velbusModules.put(subAddresses[i], velbusModule);
340 notifyDiscoveredVelbusModule(velbusModule);
344 protected void registerVelbusModule(byte address, VelbusModule velbusModule) {
345 velbusModules.put(address, velbusModule);
346 notifyDiscoveredVelbusModule(velbusModule);
347 velbusModule.sendChannelNameRequests(thingHandler);
350 private void handleChannelNameCommand(byte[] packet, byte address, byte length, int namePartNumber) {
351 if (velbusModules.containsKey(address)) {
352 VelbusModule velbusModule = velbusModules.get(address);
354 byte channel = packet[5];
355 byte[] namePart = Arrays.copyOfRange(packet, 6, 6 + length - 2);
357 VelbusChannelIdentifier velbusChannelIdentifier = new VelbusChannelIdentifier(address, channel);
358 velbusModule.setChannelName(velbusChannelIdentifier, namePartNumber, namePart);
359 notifyDiscoveredVelbusModule(velbusModule);
363 private void notifyDiscoveredVelbusModule(VelbusModule velbusModule) {
364 ThingUID bridgeUID = thingHandler.getThing().getUID();
366 DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(velbusModule.getThingUID(bridgeUID))
367 .withThingType(velbusModule.getThingTypeUID()).withProperties(velbusModule.getProperties())
368 .withRepresentationProperty(ADDRESS).withBridge(bridgeUID).withLabel(velbusModule.getLabel()).build();
370 thingDiscovered(discoveryResult);
374 public void initialize() {
375 thingHandler.setDefaultPacketListener(this);