2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.juicenet.internal.handler;
15 import static org.openhab.binding.juicenet.internal.JuiceNetBindingConstants.*;
17 import java.util.Collection;
18 import java.util.List;
19 import java.util.Objects;
21 import java.util.concurrent.ScheduledFuture;
22 import java.util.concurrent.TimeUnit;
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;
46 * The {@link JuiceNetBridgeHandler} is responsible for handling commands, which are
47 * sent to one of the channels.
49 * @author Jeff James - Initial contribution
52 public class JuiceNetBridgeHandler extends BaseBridgeHandler {
54 private final Logger logger = LoggerFactory.getLogger(JuiceNetBridgeHandler.class);
56 private JuiceNetBridgeConfiguration config = new JuiceNetBridgeConfiguration();
57 private final JuiceNetApi api;
59 public JuiceNetApi getApi() {
63 private @Nullable ScheduledFuture<?> pollingJob;
64 private @Nullable JuiceNetDiscoveryService discoveryService;
66 public JuiceNetBridgeHandler(Bridge bridge, HttpClient httpClient) {
69 this.api = new JuiceNetApi(httpClient, getThing().getUID());
73 public void handleCommand(ChannelUID channelUID, Command command) {
77 public void initialize() {
78 config = getConfigAs(JuiceNetBridgeConfiguration.class);
80 logger.trace("Bridge initialized: {}", Objects.requireNonNull(getThing()).getUID());
82 api.setApiToken(config.apiToken);
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
88 pollingJob = scheduler.scheduleWithFixedDelay(this::pollDevices, 10, config.refreshInterval, TimeUnit.SECONDS);
90 // Call here in order to discover any devices.
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;
104 public void setDiscoveryService(JuiceNetDiscoveryService discoveryService) {
105 this.discoveryService = discoveryService;
109 public void childHandlerInitialized(ThingHandler childHandler, Thing childThing) {
110 // Call here to set the Api Token for any newly initialized Child devices
115 * Get the services registered for this bridge. Provides the discovery service.
118 public Collection<Class<? extends ThingHandlerService>> getServices() {
119 return Set.of(JuiceNetDiscoveryService.class);
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();
129 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.NONE, e.toString());
134 public Thing getThingById(String id) {
135 List<Thing> childThings = getThing().getThings();
137 for (Thing childThing : childThings) {
138 Configuration configuration = childThing.getConfiguration();
140 String childId = configuration.get(PARAMETER_UNIT_ID).toString();
142 if (childId.equals(id)) {
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
154 public void iterateApiDevices() {
155 List<JuiceNetApiDevice> listDevices;
158 listDevices = api.queryDeviceList();
159 } catch (JuiceNetApiException | InterruptedException e) {
160 handleApiException(e);
164 if (getThing().getStatus() != ThingStatus.ONLINE) {
165 updateStatus(ThingStatus.ONLINE);
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);
176 JuiceNetDeviceHandler childHandler = (JuiceNetDeviceHandler) childThing.getHandler();
177 if (childHandler != null) {
178 childHandler.setNameAndToken(dev.name, dev.token);
184 private void pollDevices() {
185 List<Thing> things = getThing().getThings();
187 for (Thing t : things) {
188 if (!t.getThingTypeUID().equals(DEVICE_THING_TYPE)) {
192 JuiceNetDeviceHandler handler = (JuiceNetDeviceHandler) t.getHandler();
193 if (handler == null) {
194 logger.trace("no handler for thing: {}", t.getUID());
198 handler.queryDeviceStatusAndInfo();