]> git.basschouten.com Git - openhab-addons.git/blob
4bb99486a22066183b003036c4b00e2f2225f9bb
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 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.AbstractThingHandlerDiscoveryService;
30 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
31 import org.openhab.core.thing.ThingUID;
32 import org.osgi.service.component.annotations.Component;
33 import org.osgi.service.component.annotations.ServiceScope;
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 @Component(scope = ServiceScope.PROTOTYPE, service = NikoHomeControlDiscoveryService.class)
44 @NonNullByDefault
45 public class NikoHomeControlDiscoveryService
46         extends AbstractThingHandlerDiscoveryService<NikoHomeControlBridgeHandler> {
47     private final Logger logger = LoggerFactory.getLogger(NikoHomeControlDiscoveryService.class);
48
49     private volatile @Nullable ScheduledFuture<?> nhcDiscoveryJob;
50
51     private static final int TIMEOUT_S = 5;
52     private static final int INITIAL_DELAY_S = 5; // initial delay for polling to allow time for initial request to NHC
53                                                   // controller to complete
54     private static final int REFRESH_INTERVAL_S = 60;
55
56     private @Nullable ThingUID bridgeUID;
57
58     public NikoHomeControlDiscoveryService() {
59         super(NikoHomeControlBridgeHandler.class, SUPPORTED_THING_TYPES_UIDS, TIMEOUT_S, true);
60         logger.debug("device discovery service started");
61     }
62
63     @Override
64     public void dispose() {
65         super.dispose();
66         removeOlderResults(Instant.now().toEpochMilli());
67     }
68
69     /**
70      * Discovers devices connected to a Niko Home Control controller
71      */
72     public void discoverDevices() {
73         NikoHomeControlCommunication nhcComm = thingHandler.getCommunication();
74
75         if ((nhcComm == null) || !nhcComm.communicationActive()) {
76             logger.warn("not connected");
77             return;
78         }
79         logger.debug("getting devices on {}", thingHandler.getThing().getUID().getId());
80
81         Map<String, NhcAction> actions = nhcComm.getActions();
82
83         actions.forEach((actionId, nhcAction) -> {
84             String thingName = nhcAction.getName();
85             String thingLocation = nhcAction.getLocation();
86
87             switch (nhcAction.getType()) {
88                 case TRIGGER:
89                     addActionDevice(new ThingUID(THING_TYPE_PUSHBUTTON, thingHandler.getThing().getUID(), actionId),
90                             actionId, thingName, thingLocation);
91                     break;
92                 case RELAY:
93                     addActionDevice(new ThingUID(THING_TYPE_ON_OFF_LIGHT, thingHandler.getThing().getUID(), actionId),
94                             actionId, thingName, thingLocation);
95                     break;
96                 case DIMMER:
97                     addActionDevice(new ThingUID(THING_TYPE_DIMMABLE_LIGHT, thingHandler.getThing().getUID(), actionId),
98                             actionId, thingName, thingLocation);
99                     break;
100                 case ROLLERSHUTTER:
101                     addActionDevice(new ThingUID(THING_TYPE_BLIND, thingHandler.getThing().getUID(), actionId),
102                             actionId, thingName, thingLocation);
103                     break;
104                 default:
105                     logger.debug("unrecognized action type {} for {} {}", nhcAction.getType(), actionId, thingName);
106             }
107         });
108
109         Map<String, NhcThermostat> thermostats = nhcComm.getThermostats();
110
111         thermostats.forEach((thermostatId, nhcThermostat) -> {
112             String thingName = nhcThermostat.getName();
113             String thingLocation = nhcThermostat.getLocation();
114             addThermostatDevice(new ThingUID(THING_TYPE_THERMOSTAT, thingHandler.getThing().getUID(), thermostatId),
115                     thermostatId, thingName, thingLocation);
116         });
117
118         Map<String, NhcEnergyMeter> energyMeters = nhcComm.getEnergyMeters();
119
120         energyMeters.forEach((energyMeterId, nhcEnergyMeter) -> {
121             String thingName = nhcEnergyMeter.getName();
122             String thingLocation = nhcEnergyMeter.getLocation();
123             addEnergyMeterDevice(new ThingUID(THING_TYPE_ENERGYMETER, thingHandler.getThing().getUID(), energyMeterId),
124                     energyMeterId, thingName, thingLocation);
125         });
126     }
127
128     private void addActionDevice(ThingUID uid, String actionId, String thingName, @Nullable String thingLocation) {
129         DiscoveryResultBuilder discoveryResultBuilder = DiscoveryResultBuilder.create(uid).withBridge(bridgeUID)
130                 .withLabel(thingName).withProperty(CONFIG_ACTION_ID, actionId)
131                 .withRepresentationProperty(CONFIG_ACTION_ID);
132         if (thingLocation != null) {
133             discoveryResultBuilder.withProperty("Location", thingLocation);
134         }
135         thingDiscovered(discoveryResultBuilder.build());
136     }
137
138     private void addThermostatDevice(ThingUID uid, String thermostatId, String thingName,
139             @Nullable String thingLocation) {
140         DiscoveryResultBuilder discoveryResultBuilder = DiscoveryResultBuilder.create(uid).withBridge(bridgeUID)
141                 .withLabel(thingName).withProperty(CONFIG_THERMOSTAT_ID, thermostatId)
142                 .withRepresentationProperty(CONFIG_THERMOSTAT_ID);
143         if (thingLocation != null) {
144             discoveryResultBuilder.withProperty("Location", thingLocation);
145         }
146         thingDiscovered(discoveryResultBuilder.build());
147     }
148
149     private void addEnergyMeterDevice(ThingUID uid, String energyMeterId, String thingName,
150             @Nullable String thingLocation) {
151         DiscoveryResultBuilder discoveryResultBuilder = DiscoveryResultBuilder.create(uid).withBridge(bridgeUID)
152                 .withLabel(thingName).withProperty(CONFIG_ENERGYMETER_ID, energyMeterId)
153                 .withRepresentationProperty(CONFIG_ENERGYMETER_ID);
154         if (thingLocation != null) {
155             discoveryResultBuilder.withProperty("Location", thingLocation);
156         }
157         thingDiscovered(discoveryResultBuilder.build());
158     }
159
160     @Override
161     protected void startScan() {
162         discoverDevices();
163     }
164
165     @Override
166     protected synchronized void stopScan() {
167         super.stopScan();
168         removeOlderResults(getTimestampOfLastScan());
169     }
170
171     @Override
172     protected void startBackgroundDiscovery() {
173         logger.debug("Start device background discovery");
174         ScheduledFuture<?> job = nhcDiscoveryJob;
175         if (job == null || job.isCancelled()) {
176             nhcDiscoveryJob = scheduler.scheduleWithFixedDelay(this::discoverDevices, INITIAL_DELAY_S,
177                     REFRESH_INTERVAL_S, TimeUnit.SECONDS);
178         }
179     }
180
181     @Override
182     protected void stopBackgroundDiscovery() {
183         logger.debug("Stop device background discovery");
184         ScheduledFuture<?> job = nhcDiscoveryJob;
185         if (job != null && !job.isCancelled()) {
186             job.cancel(true);
187             nhcDiscoveryJob = null;
188         }
189     }
190
191     @Override
192     public void initialize() {
193         bridgeUID = thingHandler.getThing().getUID();
194         super.initialize();
195     }
196 }