]> git.basschouten.com Git - openhab-addons.git/blob
850049dfccc64cf04eeeb35dd8a3c47eaf464c95
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.airvisualnode.internal.discovery;
14
15 import java.io.IOException;
16 import java.net.UnknownHostException;
17 import java.util.Collections;
18 import java.util.concurrent.ScheduledFuture;
19 import java.util.concurrent.TimeUnit;
20 import java.util.regex.Matcher;
21 import java.util.regex.Pattern;
22
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.openhab.binding.airvisualnode.internal.AirVisualNodeBindingConstants;
26 import org.openhab.binding.airvisualnode.internal.config.AirVisualNodeConfig;
27 import org.openhab.core.config.discovery.AbstractDiscoveryService;
28 import org.openhab.core.config.discovery.DiscoveryResult;
29 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
30 import org.openhab.core.config.discovery.DiscoveryService;
31 import org.openhab.core.thing.ThingUID;
32 import org.osgi.service.component.annotations.Component;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 import jcifs.netbios.NbtAddress;
37 import jcifs.smb.SmbFile;
38
39 /**
40  * Autodiscovery for AirVisual Node by searching for a host advertised with the NetBIOS name 'AVISUAL-<SerialNumber>'.
41  *
42  * @author Victor Antonovich - Initial contribution
43  */
44 @NonNullByDefault
45 @Component(service = DiscoveryService.class)
46 public class AirVisualNodeDiscoveryService extends AbstractDiscoveryService {
47
48     private final Logger logger = LoggerFactory.getLogger(AirVisualNodeDiscoveryService.class);
49     private static final int REFRESH_MINUTES = 5;
50
51     public static final String AVISUAL_WORKGROUP_NAME = "MSHOME";
52
53     private static final Pattern AVISUAL_NAME_PATTERN = Pattern.compile("^AVISUAL-([^/]+)$");
54
55     private @Nullable ScheduledFuture<?> backgroundDiscoveryFuture;
56
57     public AirVisualNodeDiscoveryService() {
58         super(Collections.singleton(AirVisualNodeBindingConstants.THING_TYPE_AVNODE), 600, true);
59     }
60
61     @Override
62     protected void startScan() {
63         logger.debug("Starting scan");
64         scheduler.execute(this::scan);
65     }
66
67     @Override
68     protected void startBackgroundDiscovery() {
69         logger.debug("Starting background discovery");
70         ScheduledFuture<?> localDiscoveryFuture = backgroundDiscoveryFuture;
71         if (localDiscoveryFuture == null || localDiscoveryFuture.isCancelled()) {
72             backgroundDiscoveryFuture = scheduler.scheduleWithFixedDelay(this::scan, 0, REFRESH_MINUTES,
73                     TimeUnit.MINUTES);
74         }
75     }
76
77     @Override
78     protected void stopBackgroundDiscovery() {
79         logger.debug("Stopping background discovery");
80
81         ScheduledFuture<?> localDiscoveryFuture = backgroundDiscoveryFuture;
82         if (localDiscoveryFuture != null) {
83             localDiscoveryFuture.cancel(true);
84             backgroundDiscoveryFuture = null;
85         }
86     }
87
88     private void scan() {
89         // Get all workgroup members
90         SmbFile[] workgroupMembers;
91         try {
92             String workgroupUrl = "smb://" + AVISUAL_WORKGROUP_NAME + "/";
93             workgroupMembers = new SmbFile(workgroupUrl).listFiles();
94         } catch (IOException e) {
95             logger.debug("IOException while trying to get workgroup member list", e);
96             return;
97         }
98
99         // Check found workgroup members for the Node devices
100         for (SmbFile s : workgroupMembers) {
101             String serverName = s.getServer();
102
103             // Check workgroup member for the Node device name match
104             Matcher m = AVISUAL_NAME_PATTERN.matcher(serverName);
105             if (!m.find()) {
106                 // Workgroup member server name doesn't match the Node device name pattern
107                 continue;
108             }
109
110             // Extract the Node serial number from device name
111             String nodeSerialNumber = m.group(1);
112
113             if (nodeSerialNumber != null) {
114                 logger.debug("Extracting the Node serial number failed");
115                 return;
116             }
117             // The Node Thing UID is serial number converted to lower case
118             ThingUID thingUID = new ThingUID(AirVisualNodeBindingConstants.THING_TYPE_AVNODE,
119                     nodeSerialNumber.toLowerCase());
120
121             try {
122                 // Get the Node address by name
123                 NbtAddress nodeNbtAddress = NbtAddress.getByName(serverName);
124                 if (nodeNbtAddress == null) {
125                     // The Node address not found by some reason, skip it
126                     continue;
127                 }
128
129                 // Create discovery result
130                 String nodeAddress = nodeNbtAddress.getInetAddress().getHostAddress();
131                 if (nodeAddress != null) {
132                     DiscoveryResult result = DiscoveryResultBuilder.create(thingUID)
133                             .withProperty(AirVisualNodeConfig.ADDRESS, nodeAddress)
134                             .withRepresentationProperty(AirVisualNodeConfig.ADDRESS)
135                             .withLabel("AirVisual Node (" + nodeSerialNumber + ")").build();
136                     thingDiscovered(result);
137                 } else {
138                     logger.debug("Getting the node address from the host failed");
139                 }
140             } catch (UnknownHostException e) {
141                 logger.debug("The Node address resolving failed ", e);
142             }
143
144         }
145     }
146 }