]> git.basschouten.com Git - openhab-addons.git/blob
f7e4215655f99cb896ce975f458d36f687e3ef36
[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.solarwatt.internal.discovery;
14
15 import static org.openhab.binding.solarwatt.internal.SolarwattBindingConstants.*;
16
17 import java.util.HashMap;
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.solarwatt.internal.domain.model.BatteryConverter;
25 import org.openhab.binding.solarwatt.internal.domain.model.Device;
26 import org.openhab.binding.solarwatt.internal.domain.model.EVStation;
27 import org.openhab.binding.solarwatt.internal.domain.model.GridFlow;
28 import org.openhab.binding.solarwatt.internal.domain.model.Inverter;
29 import org.openhab.binding.solarwatt.internal.domain.model.Location;
30 import org.openhab.binding.solarwatt.internal.domain.model.PVPlant;
31 import org.openhab.binding.solarwatt.internal.domain.model.PowerMeter;
32 import org.openhab.binding.solarwatt.internal.handler.EnergyManagerHandler;
33 import org.openhab.core.config.discovery.AbstractDiscoveryService;
34 import org.openhab.core.config.discovery.DiscoveryResult;
35 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
36 import org.openhab.core.config.discovery.DiscoveryService;
37 import org.openhab.core.thing.ThingStatus;
38 import org.openhab.core.thing.ThingTypeUID;
39 import org.openhab.core.thing.ThingUID;
40 import org.openhab.core.thing.binding.ThingHandler;
41 import org.openhab.core.thing.binding.ThingHandlerService;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 /**
46  * Discovery service to discover devices attached to the energy manager.
47  *
48  * @author Sven Carstens - Initial contribution
49  */
50 @NonNullByDefault
51 public class SolarwattDevicesDiscoveryService extends AbstractDiscoveryService
52         implements ThingHandlerService, DiscoveryService {
53
54     private static final int TIMEOUT_SECONDS = 20;
55
56     private final Logger logger = LoggerFactory.getLogger(SolarwattDevicesDiscoveryService.class);
57     private @Nullable EnergyManagerHandler energyManagerHandler;
58
59     /**
60      * Job which will do the background scanning
61      */
62     private final EnergymanagerScan scanningRunnable;
63
64     /**
65      * Schedule for scanning
66      */
67     private @Nullable ScheduledFuture<?> scanningJob;
68
69     public SolarwattDevicesDiscoveryService() {
70         super(TIMEOUT_SECONDS);
71         this.scanningRunnable = new EnergymanagerScan();
72
73         this.activate(null);
74     }
75
76     @Override
77     public void setThingHandler(final @Nullable ThingHandler handler) {
78         if (handler instanceof EnergyManagerHandler) {
79             this.energyManagerHandler = (EnergyManagerHandler) handler;
80         }
81     }
82
83     @Override
84     public @Nullable ThingHandler getThingHandler() {
85         return this.energyManagerHandler;
86     }
87
88     @Override
89     public void deactivate() {
90         this.stopBackgroundDiscovery();
91     }
92
93     @Override
94     protected void startBackgroundDiscovery() {
95         ScheduledFuture<?> localScanningJob = this.scanningJob;
96         if (localScanningJob == null || localScanningJob.isCancelled()) {
97             this.scanningJob = this.scheduler.scheduleWithFixedDelay(this.scanningRunnable, 5, 5 * 60,
98                     TimeUnit.SECONDS);
99         }
100     }
101
102     @Override
103     protected void stopBackgroundDiscovery() {
104         ScheduledFuture<?> localScanningJob = this.scanningJob;
105         if (localScanningJob != null && !localScanningJob.isCancelled()) {
106             localScanningJob.cancel(true);
107             this.scanningJob = null;
108         }
109     }
110
111     @Override
112     protected synchronized void startScan() {
113         this.removeOlderResults(this.getTimestampOfLastScan());
114         final EnergyManagerHandler localEnergyManagerHandler = this.energyManagerHandler;
115
116         if (localEnergyManagerHandler == null
117                 || localEnergyManagerHandler.getThing().getStatus() != ThingStatus.ONLINE) {
118             this.logger.warn("Energymanager handler not available: {}", localEnergyManagerHandler);
119             return;
120         }
121         this.scanForDeviceThings();
122     }
123
124     /**
125      * Scans for device things.
126      *
127      * Walks through the list of devices and adds discovery results for the supported devices.
128      */
129     private void scanForDeviceThings() {
130         EnergyManagerHandler localEnergyManagerHandler = this.energyManagerHandler;
131         if (localEnergyManagerHandler != null) {
132             final Map<String, Device> devices = localEnergyManagerHandler.getDevices();
133
134             final ThingUID bridgeUID = localEnergyManagerHandler.getThing().getUID();
135
136             if (devices == null) {
137                 this.logger.warn("No device data for solarwatt devices in discovery for energy manager {}.", bridgeUID);
138             } else {
139                 devices.forEach((key, entry) -> {
140                     if (entry instanceof BatteryConverter) {
141                         this.discover(bridgeUID, entry, THING_TYPE_BATTERYCONVERTER);
142                     } else if (entry instanceof Inverter) {
143                         this.discover(bridgeUID, entry, THING_TYPE_INVERTER);
144                     } else if (entry instanceof PowerMeter) {
145                         this.discover(bridgeUID, entry, THING_TYPE_POWERMETER);
146                     } else if (entry instanceof EVStation) {
147                         this.discover(bridgeUID, entry, THING_TYPE_EVSTATION);
148                     } else if (entry instanceof Location) {
149                         this.discover(bridgeUID, entry, THING_TYPE_LOCATION);
150                     } else if (entry instanceof PVPlant) {
151                         this.discover(bridgeUID, entry, THING_TYPE_PVPLANT);
152                     } else if (entry instanceof GridFlow) {
153                         this.discover(bridgeUID, entry, THING_TYPE_GRIDFLOW);
154                     }
155                 });
156             }
157         }
158     }
159
160     /**
161      * Create a discovery result and add to result.
162      *
163      * @param bridgeID to which this device belongs
164      * @param entry describing the device
165      * @param typeUID for matching thing
166      */
167     private void discover(final ThingUID bridgeID, final Device entry, final ThingTypeUID typeUID) {
168         final ThingUID thingUID = new ThingUID(typeUID, bridgeID, this.rewriteGuid(entry.getGuid()));
169         final Map<String, Object> properties = new HashMap<>(5);
170
171         properties.put(THING_PROPERTIES_GUID, entry.getGuid());
172         final DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withBridge(bridgeID)
173                 .withRepresentationProperty(THING_PROPERTIES_GUID).withProperties(properties)
174                 .withLabel("Solarwatt " + entry.getLabel()).build();
175         this.thingDiscovered(discoveryResult);
176     }
177
178     /**
179      * Rewrite energy manager guids to be acceptable to openhab.
180      *
181      * @param emGuid from energy manager
182      * @return guid for openhab
183      */
184     private String rewriteGuid(String emGuid) {
185         return emGuid.replaceAll(":", "-");
186     }
187
188     public class EnergymanagerScan implements Runnable {
189         @Override
190         public void run() {
191             SolarwattDevicesDiscoveryService.this.startScan();
192         }
193     }
194 }