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