2 * Copyright (c) 2010-2020 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.config.discovery.DiscoveryService;
36 import org.openhab.core.thing.ThingUID;
37 import org.openhab.core.thing.binding.ThingHandler;
38 import org.openhab.core.thing.binding.ThingHandlerService;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
43 * If the user scans manually for things this
44 * {@link VelbusThingDiscoveryService}
45 * is used to return Velbus Modules as things to the framework.
47 * @author Cedric Boon - Initial contribution
50 public class VelbusThingDiscoveryService extends AbstractDiscoveryService
51 implements DiscoveryService, ThingHandlerService, VelbusPacketListener {
52 private static final int SEARCH_TIME = 60;
54 private final Logger logger = LoggerFactory.getLogger(VelbusThingDiscoveryService.class);
56 private Map<Byte, VelbusModule> velbusModules = new HashMap<>();
58 private @Nullable VelbusBridgeHandler velbusBridgeHandler;
60 public VelbusThingDiscoveryService() {
61 super(SUPPORTED_THING_TYPES_UIDS, SEARCH_TIME);
65 public void deactivate() {
66 removeOlderResults(new Date().getTime());
68 final VelbusBridgeHandler velbusBridgeHandler = this.velbusBridgeHandler;
69 if (velbusBridgeHandler != null) {
70 velbusBridgeHandler.clearDefaultPacketListener();
75 protected void startScan() {
76 for (int i = 0x00; i <= 0xFF; i++) {
77 VelbusScanPacket packet = new VelbusScanPacket((byte) i);
78 byte[] packetBytes = packet.getBytes();
80 final VelbusBridgeHandler velbusBridgeHandler = this.velbusBridgeHandler;
81 if (velbusBridgeHandler != null) {
82 velbusBridgeHandler.sendPacket(packetBytes);
88 public void onPacketReceived(byte[] packet) {
89 if (packet[0] == VelbusPacket.STX && packet.length >= 5) {
90 byte address = packet[2];
91 byte length = packet[3];
92 byte command = packet[4];
94 if (command == COMMAND_MODULE_TYPE && packet.length >= 10) {
95 handleModuleTypeCommand(packet, address);
96 } else if (command == COMMAND_MODULE_NAME_PART1 & packet.length >= 4 + length) {
97 handleChannelNameCommand(packet, address, length, 1);
98 } else if (command == COMMAND_MODULE_NAME_PART2 && packet.length >= 4 + length) {
99 handleChannelNameCommand(packet, address, length, 2);
100 } else if (command == COMMAND_MODULE_NAME_PART3 && packet.length >= 4 + length) {
101 handleChannelNameCommand(packet, address, length, 3);
102 } else if (command == COMMAND_SUBTYPE && packet.length >= 4 + length) {
103 handleModuleSubtypeCommand(packet, address);
105 logger.debug("Unknown command '{}' to address '{}'.", String.format("%02X", command),
106 String.format("%02X", address));
111 private void handleModuleTypeCommand(byte[] packet, byte address) {
112 byte moduleType = packet[5];
113 byte highByteOfSerialNumber = packet[6];
114 byte lowByteOfSerialNumber = packet[7];
115 byte memoryMapVersion = packet[8];
116 byte buildYear = packet[9];
117 byte buildWeek = packet[10];
119 VelbusModule velbusModule = null;
120 switch (moduleType) {
121 case MODULE_TYPE_VMB1BL:
122 velbusModule = new VelbusModule(new VelbusFirstGenerationDeviceModuleAddress(address), moduleType,
123 highByteOfSerialNumber, lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek,
124 THING_TYPE_VMB1BL, 1);
126 case MODULE_TYPE_VMB1BLS:
127 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
128 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1BLS, 1);
130 case MODULE_TYPE_VMB1DM:
131 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
132 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1DM, 1);
134 case MODULE_TYPE_VMB1LED:
135 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
136 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1LED, 1);
138 case MODULE_TYPE_VMB1RY:
139 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
140 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1RY, 1);
142 case MODULE_TYPE_VMB1RYNO:
143 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
144 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1RYNO, 5);
146 case MODULE_TYPE_VMB1RYNOS:
147 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
148 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1RYNOS, 5);
150 case MODULE_TYPE_VMB1RYS:
151 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
152 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1RYS, 5);
154 case MODULE_TYPE_VMB1TS:
155 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
156 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB1TS, 1);
158 case MODULE_TYPE_VMB2BL:
159 velbusModule = new VelbusModule(new VelbusFirstGenerationDeviceModuleAddress(address), moduleType,
160 highByteOfSerialNumber, lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek,
161 THING_TYPE_VMB2BL, 2);
163 case MODULE_TYPE_VMB2BLE:
164 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
165 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB2BLE, 2);
167 case MODULE_TYPE_VMB2PBN:
168 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
169 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB2PBN, 8);
171 case MODULE_TYPE_VMB4AN:
172 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
173 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4AN, 4);
175 case MODULE_TYPE_VMB4DC:
176 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
177 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4DC, 4);
179 case MODULE_TYPE_VMB4RY:
180 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
181 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4RY, 4);
183 case MODULE_TYPE_VMB4RYLD:
184 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
185 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4RYLD, 5);
187 case MODULE_TYPE_VMB4RYNO:
188 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
189 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB4RYNO, 5);
191 case MODULE_TYPE_VMB6IN:
192 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
193 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB6IN, 6);
195 case MODULE_TYPE_VMB6PBN:
196 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
197 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB6PBN, 8);
199 case MODULE_TYPE_VMB7IN:
200 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
201 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB7IN, 8);
203 case MODULE_TYPE_VMB8IR:
204 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
205 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB8IR, 8);
207 case MODULE_TYPE_VMB8PB:
208 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
209 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB8PB, 8);
211 case MODULE_TYPE_VMB8PBU:
212 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
213 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMB8PBU, 8);
215 case MODULE_TYPE_VMBDME:
216 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
217 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBDME, 1);
219 case MODULE_TYPE_VMBDMI:
220 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
221 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBDMI, 1);
223 case MODULE_TYPE_VMBDMIR:
224 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
225 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBDMIR, 1);
227 case MODULE_TYPE_VMBEL1:
228 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
229 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBEL1, 9);
231 case MODULE_TYPE_VMBEL2:
232 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
233 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBEL2, 9);
235 case MODULE_TYPE_VMBEL4:
236 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
237 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBEL4, 9);
239 case MODULE_TYPE_VMBELO:
240 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
241 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBELO, 33);
243 case MODULE_TYPE_VMBGP1:
244 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
245 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP1, 9);
247 case MODULE_TYPE_VMBGP1_2:
248 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
249 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP1_2, 9);
251 case MODULE_TYPE_VMBGP2:
252 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
253 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP2, 9);
255 case MODULE_TYPE_VMBGP2_2:
256 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
257 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP2_2, 9);
259 case MODULE_TYPE_VMBGP4:
260 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
261 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP4, 9);
263 case MODULE_TYPE_VMBGP4_2:
264 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
265 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP4_2, 9);
267 case MODULE_TYPE_VMBGP4PIR:
268 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
269 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP4PIR, 9);
271 case MODULE_TYPE_VMBGP4PIR_2:
272 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
273 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGP4PIR_2, 9);
275 case MODULE_TYPE_VMBGPO:
276 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
277 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGPO, 33);
279 case MODULE_TYPE_VMBGPOD:
280 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
281 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGPOD, 33);
283 case MODULE_TYPE_VMBGPOD_2:
284 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 4), moduleType, highByteOfSerialNumber,
285 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBGPOD_2, 33);
287 case MODULE_TYPE_VMBMETEO:
288 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
289 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBMETEO, 13);
291 case MODULE_TYPE_VMBPIRC:
292 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
293 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBPIRC, 7);
295 case MODULE_TYPE_VMBPIRM:
296 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
297 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBPIRM, 7);
299 case MODULE_TYPE_VMBPIRO:
300 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
301 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBPIRO, 9);
303 case MODULE_TYPE_VMBRFR8S:
304 velbusModule = new VelbusModule(new VelbusModuleAddress(address, 0), moduleType, highByteOfSerialNumber,
305 lowByteOfSerialNumber, memoryMapVersion, buildYear, buildWeek, THING_TYPE_VMBRFR8S, 8);
309 if (velbusModule != null) {
310 registerVelbusModule(address, velbusModule);
314 private void handleModuleSubtypeCommand(byte[] packet, byte address) {
315 if (velbusModules.containsKey(address)) {
316 VelbusModule velbusModule = velbusModules.get(address);
318 byte[] subAddresses = new byte[4];
319 System.arraycopy(packet, 8, subAddresses, 0, 4);
321 velbusModule.getModuleAddress().setSubAddresses(subAddresses);
323 for (int i = 0; i < subAddresses.length; i++) {
324 if (subAddresses[i] != (byte) 0xFF) {
325 velbusModules.put(subAddresses[i], velbusModule);
329 notifyDiscoveredVelbusModule(velbusModule);
333 protected void registerVelbusModule(byte address, VelbusModule velbusModule) {
334 velbusModules.put(address, velbusModule);
335 notifyDiscoveredVelbusModule(velbusModule);
336 velbusModule.sendChannelNameRequests(velbusBridgeHandler);
339 private void handleChannelNameCommand(byte[] packet, byte address, byte length, int namePartNumber) {
340 if (velbusModules.containsKey(address)) {
341 VelbusModule velbusModule = velbusModules.get(address);
343 byte channel = packet[5];
344 byte[] namePart = Arrays.copyOfRange(packet, 6, 6 + length - 2);
346 VelbusChannelIdentifier velbusChannelIdentifier = new VelbusChannelIdentifier(address, channel);
347 velbusModule.setChannelName(velbusChannelIdentifier, namePartNumber, namePart);
348 notifyDiscoveredVelbusModule(velbusModule);
352 private void notifyDiscoveredVelbusModule(VelbusModule velbusModule) {
353 final VelbusBridgeHandler velbusBridgeHandler = this.velbusBridgeHandler;
354 if (velbusBridgeHandler != null) {
355 ThingUID bridgeUID = velbusBridgeHandler.getThing().getUID();
357 DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(velbusModule.getThingUID(bridgeUID))
358 .withThingType(velbusModule.getThingTypeUID()).withProperties(velbusModule.getProperties())
359 .withRepresentationProperty(ADDRESS).withBridge(bridgeUID).withLabel(velbusModule.getLabel())
362 thingDiscovered(discoveryResult);
367 public void setThingHandler(@Nullable ThingHandler handler) {
368 if (handler instanceof VelbusBridgeHandler) {
369 final VelbusBridgeHandler velbusBridgeHandler = (VelbusBridgeHandler) handler;
370 this.velbusBridgeHandler = velbusBridgeHandler;
371 velbusBridgeHandler.setDefaultPacketListener(this);
376 public @Nullable ThingHandler getThingHandler() {
377 return this.velbusBridgeHandler;