]> git.basschouten.com Git - openhab-addons.git/blob
7ecd9167dfabeb70b319ab2482a58715a039e8c4
[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.nikohomecontrol.internal.discovery;
14
15 import static org.openhab.binding.nikohomecontrol.internal.NikoHomeControlBindingConstants.*;
16
17 import java.time.Instant;
18 import java.util.Map;
19 import java.util.concurrent.ScheduledFuture;
20 import java.util.concurrent.TimeUnit;
21
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.openhab.binding.nikohomecontrol.internal.handler.NikoHomeControlBridgeHandler;
25 import org.openhab.binding.nikohomecontrol.internal.protocol.NhcAction;
26 import org.openhab.binding.nikohomecontrol.internal.protocol.NhcEnergyMeter;
27 import org.openhab.binding.nikohomecontrol.internal.protocol.NhcThermostat;
28 import org.openhab.binding.nikohomecontrol.internal.protocol.NikoHomeControlCommunication;
29 import org.openhab.core.config.discovery.AbstractDiscoveryService;
30 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
31 import org.openhab.core.thing.ThingUID;
32 import org.openhab.core.thing.binding.ThingHandler;
33 import org.openhab.core.thing.binding.ThingHandlerService;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /**
38  * If a Niko Home Control bridge is added or if the user scans manually for things this
39  * {@link NikoHomeControlDiscoveryService} is used to return Niko Home Control Actions as things to the framework.
40  *
41  * @author Mark Herwege - Initial Contribution
42  */
43 @NonNullByDefault
44 public class NikoHomeControlDiscoveryService extends AbstractDiscoveryService implements ThingHandlerService {
45
46     private final Logger logger = LoggerFactory.getLogger(NikoHomeControlDiscoveryService.class);
47
48     private volatile @Nullable ScheduledFuture<?> nhcDiscoveryJob;
49
50     private static final int TIMEOUT_S = 5;
51     private static final int INITIAL_DELAY_S = 5; // initial delay for polling to allow time for initial request to NHC
52                                                   // controller to complete
53     private static final int REFRESH_INTERVAL_S = 60;
54
55     private @Nullable ThingUID bridgeUID;
56     private @Nullable NikoHomeControlBridgeHandler handler;
57
58     public NikoHomeControlDiscoveryService() {
59         super(SUPPORTED_THING_TYPES_UIDS, TIMEOUT_S, true);
60         logger.debug("device discovery service started");
61     }
62
63     @Override
64     public void activate() {
65         startBackgroundDiscovery();
66     }
67
68     @Override
69     public void deactivate() {
70         removeOlderResults(Instant.now().toEpochMilli());
71         super.deactivate();
72     }
73
74     /**
75      * Discovers devices connected to a Niko Home Control controller
76      */
77     public void discoverDevices() {
78         NikoHomeControlBridgeHandler bridgeHandler = handler;
79         if (bridgeHandler == null) {
80             return;
81         }
82
83         NikoHomeControlCommunication nhcComm = bridgeHandler.getCommunication();
84
85         if ((nhcComm == null) || !nhcComm.communicationActive()) {
86             logger.warn("not connected");
87             return;
88         }
89         logger.debug("getting devices on {}", bridgeHandler.getThing().getUID().getId());
90
91         Map<String, NhcAction> actions = nhcComm.getActions();
92
93         actions.forEach((actionId, nhcAction) -> {
94             String thingName = nhcAction.getName();
95             String thingLocation = nhcAction.getLocation();
96
97             switch (nhcAction.getType()) {
98                 case TRIGGER:
99                     addActionDevice(new ThingUID(THING_TYPE_PUSHBUTTON, bridgeHandler.getThing().getUID(), actionId),
100                             actionId, thingName, thingLocation);
101                     break;
102                 case RELAY:
103                     addActionDevice(new ThingUID(THING_TYPE_ON_OFF_LIGHT, bridgeHandler.getThing().getUID(), actionId),
104                             actionId, thingName, thingLocation);
105                     break;
106                 case DIMMER:
107                     addActionDevice(
108                             new ThingUID(THING_TYPE_DIMMABLE_LIGHT, bridgeHandler.getThing().getUID(), actionId),
109                             actionId, thingName, thingLocation);
110                     break;
111                 case ROLLERSHUTTER:
112                     addActionDevice(new ThingUID(THING_TYPE_BLIND, bridgeHandler.getThing().getUID(), actionId),
113                             actionId, thingName, thingLocation);
114                     break;
115                 default:
116                     logger.debug("unrecognized action type {} for {} {}", nhcAction.getType(), actionId, thingName);
117             }
118         });
119
120         Map<String, NhcThermostat> thermostats = nhcComm.getThermostats();
121
122         thermostats.forEach((thermostatId, nhcThermostat) -> {
123             String thingName = nhcThermostat.getName();
124             String thingLocation = nhcThermostat.getLocation();
125             addThermostatDevice(new ThingUID(THING_TYPE_THERMOSTAT, bridgeHandler.getThing().getUID(), thermostatId),
126                     thermostatId, thingName, thingLocation);
127         });
128
129         Map<String, NhcEnergyMeter> energyMeters = nhcComm.getEnergyMeters();
130
131         energyMeters.forEach((energyMeterId, nhcEnergyMeter) -> {
132             String thingName = nhcEnergyMeter.getName();
133             String thingLocation = nhcEnergyMeter.getLocation();
134             addEnergyMeterDevice(new ThingUID(THING_TYPE_ENERGYMETER, bridgeHandler.getThing().getUID(), energyMeterId),
135                     energyMeterId, thingName, thingLocation);
136         });
137     }
138
139     private void addActionDevice(ThingUID uid, String actionId, String thingName, @Nullable String thingLocation) {
140         DiscoveryResultBuilder discoveryResultBuilder = DiscoveryResultBuilder.create(uid).withBridge(bridgeUID)
141                 .withLabel(thingName).withProperty(CONFIG_ACTION_ID, actionId)
142                 .withRepresentationProperty(CONFIG_ACTION_ID);
143         if (thingLocation != null) {
144             discoveryResultBuilder.withProperty("Location", thingLocation);
145         }
146         thingDiscovered(discoveryResultBuilder.build());
147     }
148
149     private void addThermostatDevice(ThingUID uid, String thermostatId, String thingName,
150             @Nullable String thingLocation) {
151         DiscoveryResultBuilder discoveryResultBuilder = DiscoveryResultBuilder.create(uid).withBridge(bridgeUID)
152                 .withLabel(thingName).withProperty(CONFIG_THERMOSTAT_ID, thermostatId)
153                 .withRepresentationProperty(CONFIG_THERMOSTAT_ID);
154         if (thingLocation != null) {
155             discoveryResultBuilder.withProperty("Location", thingLocation);
156         }
157         thingDiscovered(discoveryResultBuilder.build());
158     }
159
160     private void addEnergyMeterDevice(ThingUID uid, String energyMeterId, String thingName,
161             @Nullable String thingLocation) {
162         DiscoveryResultBuilder discoveryResultBuilder = DiscoveryResultBuilder.create(uid).withBridge(bridgeUID)
163                 .withLabel(thingName).withProperty(CONFIG_ENERGYMETER_ID, energyMeterId)
164                 .withRepresentationProperty(CONFIG_ENERGYMETER_ID);
165         if (thingLocation != null) {
166             discoveryResultBuilder.withProperty("Location", thingLocation);
167         }
168         thingDiscovered(discoveryResultBuilder.build());
169     }
170
171     @Override
172     protected void startScan() {
173         discoverDevices();
174     }
175
176     @Override
177     protected synchronized void stopScan() {
178         super.stopScan();
179         removeOlderResults(getTimestampOfLastScan());
180     }
181
182     @Override
183     protected void startBackgroundDiscovery() {
184         logger.debug("Start device background discovery");
185         ScheduledFuture<?> job = nhcDiscoveryJob;
186         if (job == null || job.isCancelled()) {
187             nhcDiscoveryJob = scheduler.scheduleWithFixedDelay(this::discoverDevices, INITIAL_DELAY_S,
188                     REFRESH_INTERVAL_S, TimeUnit.SECONDS);
189         }
190     }
191
192     @Override
193     protected void stopBackgroundDiscovery() {
194         logger.debug("Stop device background discovery");
195         ScheduledFuture<?> job = nhcDiscoveryJob;
196         if (job != null && !job.isCancelled()) {
197             job.cancel(true);
198             nhcDiscoveryJob = null;
199         }
200     }
201
202     @Override
203     public void setThingHandler(@Nullable ThingHandler handler) {
204         if (handler instanceof NikoHomeControlBridgeHandler homeControlBridgeHandler) {
205             this.handler = homeControlBridgeHandler;
206             bridgeUID = handler.getThing().getUID();
207         }
208     }
209
210     @Override
211     public @Nullable ThingHandler getThingHandler() {
212         return handler;
213     }
214 }