]> git.basschouten.com Git - openhab-addons.git/blob
4343e844019de16c47353f8ea6cd4702c9691d68
[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.gardena.internal.handler;
14
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.concurrent.TimeUnit;
18
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.openhab.binding.gardena.internal.GardenaSmart;
22 import org.openhab.binding.gardena.internal.GardenaSmartEventListener;
23 import org.openhab.binding.gardena.internal.GardenaSmartImpl;
24 import org.openhab.binding.gardena.internal.config.GardenaConfig;
25 import org.openhab.binding.gardena.internal.discovery.GardenaDeviceDiscoveryService;
26 import org.openhab.binding.gardena.internal.exception.GardenaException;
27 import org.openhab.binding.gardena.internal.model.dto.Device;
28 import org.openhab.binding.gardena.internal.util.UidUtils;
29 import org.openhab.core.io.net.http.HttpClientFactory;
30 import org.openhab.core.io.net.http.WebSocketFactory;
31 import org.openhab.core.thing.Bridge;
32 import org.openhab.core.thing.Channel;
33 import org.openhab.core.thing.ChannelUID;
34 import org.openhab.core.thing.Thing;
35 import org.openhab.core.thing.ThingStatus;
36 import org.openhab.core.thing.ThingStatusDetail;
37 import org.openhab.core.thing.ThingUID;
38 import org.openhab.core.thing.binding.BaseBridgeHandler;
39 import org.openhab.core.thing.binding.ThingHandlerService;
40 import org.openhab.core.types.Command;
41 import org.openhab.core.types.RefreshType;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 /**
46  * The {@link GardenaAccountHandler} is the handler for a Gardena smart system access and connects it to the framework.
47  *
48  * @author Gerhard Riegler - Initial contribution
49  */
50 @NonNullByDefault
51 public class GardenaAccountHandler extends BaseBridgeHandler implements GardenaSmartEventListener {
52     private final Logger logger = LoggerFactory.getLogger(GardenaAccountHandler.class);
53     private final long REINITIALIZE_DELAY_SECONDS = 10;
54
55     private @Nullable GardenaDeviceDiscoveryService discoveryService;
56
57     private @Nullable GardenaSmart gardenaSmart;
58     private HttpClientFactory httpClientFactory;
59     private WebSocketFactory webSocketFactory;
60
61     public GardenaAccountHandler(Bridge bridge, HttpClientFactory httpClientFactory,
62             WebSocketFactory webSocketFactory) {
63         super(bridge);
64         this.httpClientFactory = httpClientFactory;
65         this.webSocketFactory = webSocketFactory;
66     }
67
68     @Override
69     public void initialize() {
70         logger.debug("Initializing Gardena account '{}'", getThing().getUID().getId());
71         initializeGardena();
72     }
73
74     public void setDiscoveryService(GardenaDeviceDiscoveryService discoveryService) {
75         this.discoveryService = discoveryService;
76     }
77
78     /**
79      * Initializes the GardenaSmart account.
80      */
81     private void initializeGardena() {
82         final GardenaAccountHandler instance = this;
83         scheduler.execute(() -> {
84             try {
85                 GardenaConfig gardenaConfig = getThing().getConfiguration().as(GardenaConfig.class);
86                 logger.debug("{}", gardenaConfig);
87
88                 String id = getThing().getUID().getId();
89                 gardenaSmart = new GardenaSmartImpl(id, gardenaConfig, instance, scheduler, httpClientFactory,
90                         webSocketFactory);
91                 final GardenaDeviceDiscoveryService discoveryService = this.discoveryService;
92                 if (discoveryService != null) {
93                     discoveryService.startScan(null);
94                     discoveryService.waitForScanFinishing();
95                 }
96                 updateStatus(ThingStatus.ONLINE);
97             } catch (GardenaException ex) {
98                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, ex.getMessage());
99                 disposeGardena();
100                 scheduleReinitialize();
101                 logger.warn("{}", ex.getMessage());
102             }
103         });
104     }
105
106     /**
107      * Schedules a reinitialization, if Gardena smart system account is not reachable.
108      */
109     private void scheduleReinitialize() {
110         scheduler.schedule(() -> {
111             if (getThing().getStatus() != ThingStatus.UNINITIALIZED) {
112                 initializeGardena();
113             }
114         }, REINITIALIZE_DELAY_SECONDS, TimeUnit.SECONDS);
115     }
116
117     @Override
118     public void dispose() {
119         super.dispose();
120         disposeGardena();
121     }
122
123     /**
124      * Disposes the GardenaSmart account.
125      */
126     private void disposeGardena() {
127         logger.debug("Disposing Gardena account '{}'", getThing().getUID().getId());
128         final GardenaDeviceDiscoveryService discoveryService = this.discoveryService;
129         if (discoveryService != null) {
130             discoveryService.stopScan();
131         }
132         final GardenaSmart gardenaSmart = this.gardenaSmart;
133         if (gardenaSmart != null) {
134             gardenaSmart.dispose();
135         }
136     }
137
138     /**
139      * Returns the Gardena smart system implementation.
140      */
141     public @Nullable GardenaSmart getGardenaSmart() {
142         return gardenaSmart;
143     }
144
145     @Override
146     public Collection<Class<? extends ThingHandlerService>> getServices() {
147         return Collections.singleton(GardenaDeviceDiscoveryService.class);
148     }
149
150     @Override
151     public void handleCommand(ChannelUID channelUID, Command command) {
152         if (RefreshType.REFRESH == command) {
153             logger.debug("Refreshing Gardena account '{}'", getThing().getUID().getId());
154             disposeGardena();
155             initializeGardena();
156         }
157     }
158
159     @Override
160     public void onDeviceUpdated(Device device) {
161         for (ThingUID thingUID : UidUtils.getThingUIDs(device, getThing())) {
162             final Thing gardenaThing;
163             final GardenaThingHandler gardenaThingHandler;
164             if ((gardenaThing = getThing().getThing(thingUID)) != null
165                     && (gardenaThingHandler = (GardenaThingHandler) gardenaThing.getHandler()) != null) {
166                 try {
167                     gardenaThingHandler.updateProperties(device);
168                     for (Channel channel : gardenaThing.getChannels()) {
169                         gardenaThingHandler.updateChannel(channel.getUID());
170                     }
171                     gardenaThingHandler.updateStatus(device);
172                 } catch (GardenaException ex) {
173                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, ex.getMessage());
174                 } catch (AccountHandlerNotAvailableException ignore) {
175                 }
176             }
177         }
178     }
179
180     @Override
181     public void onNewDevice(Device device) {
182         final GardenaDeviceDiscoveryService discoveryService = this.discoveryService;
183         if (discoveryService != null) {
184             discoveryService.deviceDiscovered(device);
185         }
186         onDeviceUpdated(device);
187     }
188
189     @Override
190     public void onError() {
191         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Connection lost");
192         disposeGardena();
193         scheduleReinitialize();
194     }
195 }