]> git.basschouten.com Git - openhab-addons.git/blob
c0b75fca44e5abc1fb408059e3f86fb1e8de23a6
[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.juicenet.internal.handler;
14
15 import static org.openhab.binding.juicenet.internal.JuiceNetBindingConstants.*;
16
17 import java.util.Collection;
18 import java.util.Collections;
19 import java.util.List;
20 import java.util.Objects;
21 import java.util.concurrent.ScheduledFuture;
22 import java.util.concurrent.TimeUnit;
23
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.eclipse.jetty.client.HttpClient;
27 import org.openhab.binding.juicenet.internal.api.JuiceNetApi;
28 import org.openhab.binding.juicenet.internal.api.JuiceNetApiException;
29 import org.openhab.binding.juicenet.internal.api.dto.JuiceNetApiDevice;
30 import org.openhab.binding.juicenet.internal.config.JuiceNetBridgeConfiguration;
31 import org.openhab.binding.juicenet.internal.discovery.JuiceNetDiscoveryService;
32 import org.openhab.core.config.core.Configuration;
33 import org.openhab.core.thing.Bridge;
34 import org.openhab.core.thing.ChannelUID;
35 import org.openhab.core.thing.Thing;
36 import org.openhab.core.thing.ThingStatus;
37 import org.openhab.core.thing.ThingStatusDetail;
38 import org.openhab.core.thing.binding.BaseBridgeHandler;
39 import org.openhab.core.thing.binding.ThingHandler;
40 import org.openhab.core.thing.binding.ThingHandlerService;
41 import org.openhab.core.types.Command;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 /**
46  * The {@link JuiceNetBridgeHandler} is responsible for handling commands, which are
47  * sent to one of the channels.
48  *
49  * @author Jeff James - Initial contribution
50  */
51 @NonNullByDefault
52 public class JuiceNetBridgeHandler extends BaseBridgeHandler {
53
54     private final Logger logger = LoggerFactory.getLogger(JuiceNetBridgeHandler.class);
55
56     private JuiceNetBridgeConfiguration config = new JuiceNetBridgeConfiguration();
57     private final JuiceNetApi api;
58
59     public JuiceNetApi getApi() {
60         return api;
61     }
62
63     private @Nullable ScheduledFuture<?> pollingJob;
64     private @Nullable JuiceNetDiscoveryService discoveryService;
65
66     public JuiceNetBridgeHandler(Bridge bridge, HttpClient httpClient) {
67         super(bridge);
68
69         this.api = new JuiceNetApi(httpClient, getThing().getUID());
70     }
71
72     @Override
73     public void handleCommand(ChannelUID channelUID, Command command) {
74     }
75
76     @Override
77     public void initialize() {
78         config = getConfigAs(JuiceNetBridgeConfiguration.class);
79
80         logger.trace("Bridge initialized: {}", Objects.requireNonNull(getThing()).getUID());
81
82         api.setApiToken(config.apiToken);
83
84         updateStatus(ThingStatus.UNKNOWN);
85         // Bridge will go online after the first successful API call in iterateApiDevices. iterateApiDevices will be
86         // called when a child device attempts to goOnline and needs to retrieve the api token
87
88         pollingJob = scheduler.scheduleWithFixedDelay(this::pollDevices, 10, config.refreshInterval, TimeUnit.SECONDS);
89
90         // Call here in order to discover any devices.
91         iterateApiDevices();
92     }
93
94     @Override
95     public void dispose() {
96         logger.debug("Handler disposed.");
97         ScheduledFuture<?> pollingJob = this.pollingJob;
98         if (pollingJob != null) {
99             pollingJob.cancel(true);
100             this.pollingJob = null;
101         }
102     }
103
104     public void setDiscoveryService(JuiceNetDiscoveryService discoveryService) {
105         this.discoveryService = discoveryService;
106     }
107
108     @Override
109     public void childHandlerInitialized(ThingHandler childHandler, Thing childThing) {
110         // Call here to set the Api Token for any newly initialized Child devices
111         iterateApiDevices();
112     }
113
114     /**
115      * Get the services registered for this bridge. Provides the discovery service.
116      */
117     @Override
118     public Collection<Class<? extends ThingHandlerService>> getServices() {
119         return Collections.singleton(JuiceNetDiscoveryService.class);
120     }
121
122     public void handleApiException(Exception e) {
123         if (e instanceof JuiceNetApiException) {
124             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, e.toString());
125         } else if (e instanceof InterruptedException) {
126             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, e.toString());
127             Thread.currentThread().interrupt();
128         } else {
129             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.NONE, e.toString());
130         }
131     }
132
133     @Nullable
134     public Thing getThingById(String id) {
135         List<Thing> childThings = getThing().getThings();
136
137         for (Thing childThing : childThings) {
138             Configuration configuration = childThing.getConfiguration();
139
140             String childId = configuration.get(PARAMETER_UNIT_ID).toString();
141
142             if (childId.equals(id)) {
143                 return childThing;
144             }
145         }
146
147         return null;
148     }
149
150     // This function will query the list of devices from the API and then set the name/token in the child handlers. If a
151     // child does not exist, it will notify the Discovery service. If it is successful, it will ensure the bridge status
152     // is updated
153     // to ONLINE.
154     public void iterateApiDevices() {
155         List<JuiceNetApiDevice> listDevices;
156
157         try {
158             listDevices = api.queryDeviceList();
159         } catch (JuiceNetApiException | InterruptedException e) {
160             handleApiException(e);
161             return;
162         }
163
164         if (getThing().getStatus() != ThingStatus.ONLINE) {
165             updateStatus(ThingStatus.ONLINE);
166         }
167
168         JuiceNetDiscoveryService discoveryService = this.discoveryService;
169         for (JuiceNetApiDevice dev : listDevices) {
170             Thing childThing = getThingById(dev.unitId);
171             if (childThing == null) {
172                 if (discoveryService != null) {
173                     discoveryService.notifyDiscoveryDevice(dev.unitId, dev.name);
174                 }
175             } else {
176                 JuiceNetDeviceHandler childHandler = (JuiceNetDeviceHandler) childThing.getHandler();
177                 if (childHandler != null) {
178                     childHandler.setNameAndToken(dev.name, dev.token);
179                 }
180             }
181         }
182     }
183
184     private void pollDevices() {
185         List<Thing> things = getThing().getThings();
186
187         for (Thing t : things) {
188             if (!t.getThingTypeUID().equals(DEVICE_THING_TYPE)) {
189                 continue;
190             }
191
192             JuiceNetDeviceHandler handler = (JuiceNetDeviceHandler) t.getHandler();
193             if (handler == null) {
194                 logger.trace("no handler for thing: {}", t.getUID());
195                 continue;
196             }
197
198             handler.queryDeviceStatusAndInfo();
199         }
200     }
201 }