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