]> git.basschouten.com Git - openhab-addons.git/blob
ef007fe58eeab53cf27647f8831671cea24796a9
[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.easee.internal.handler;
14
15 import static org.openhab.binding.easee.internal.EaseeBindingConstants.*;
16
17 import java.util.Collection;
18 import java.util.Collections;
19 import java.util.HashMap;
20 import java.util.Map;
21 import java.util.concurrent.Future;
22 import java.util.concurrent.TimeUnit;
23 import java.util.concurrent.atomic.AtomicReference;
24
25 import org.eclipse.jdt.annotation.NonNullByDefault;
26 import org.eclipse.jdt.annotation.Nullable;
27 import org.eclipse.jetty.client.HttpClient;
28 import org.openhab.binding.easee.internal.AtomicReferenceTrait;
29 import org.openhab.binding.easee.internal.EaseeBindingConstants;
30 import org.openhab.binding.easee.internal.Utils;
31 import org.openhab.binding.easee.internal.command.EaseeCommand;
32 import org.openhab.binding.easee.internal.command.site.GetSite;
33 import org.openhab.binding.easee.internal.command.site.SiteState;
34 import org.openhab.binding.easee.internal.config.EaseeConfiguration;
35 import org.openhab.binding.easee.internal.connector.CommunicationStatus;
36 import org.openhab.binding.easee.internal.connector.WebInterface;
37 import org.openhab.binding.easee.internal.discovery.EaseeSiteDiscoveryService;
38 import org.openhab.core.config.discovery.DiscoveryService;
39 import org.openhab.core.thing.Bridge;
40 import org.openhab.core.thing.ThingStatus;
41 import org.openhab.core.thing.ThingStatusDetail;
42 import org.openhab.core.thing.binding.BaseBridgeHandler;
43 import org.openhab.core.thing.binding.ThingHandlerService;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 import com.google.gson.JsonObject;
48
49 /**
50  * The {@link EaseeSiteHandler} is responsible for handling commands, which are
51  * sent to one of the channels.
52  *
53  * @author Alexander Friese - initial contribution
54  */
55 @NonNullByDefault
56 public class EaseeSiteHandler extends BaseBridgeHandler implements EaseeBridgeHandler, AtomicReferenceTrait {
57     private final Logger logger = LoggerFactory.getLogger(EaseeSiteHandler.class);
58
59     /**
60      * Schedule for polling live data
61      */
62     private final AtomicReference<@Nullable Future<?>> dataPollingJobReference;
63
64     private @Nullable DiscoveryService discoveryService;
65
66     /**
67      * Interface object for querying the Easee web interface
68      */
69     private WebInterface webInterface;
70
71     public EaseeSiteHandler(Bridge bridge, HttpClient httpClient) {
72         super(bridge);
73         this.dataPollingJobReference = new AtomicReference<>(null);
74         this.webInterface = new WebInterface(scheduler, this, httpClient, super::updateStatus);
75     }
76
77     @Override
78     public void initialize() {
79         logger.debug("About to initialize Easee Site");
80         EaseeConfiguration config = getBridgeConfiguration();
81         logger.debug("Easee Site initialized with configuration: {}", config.toString());
82
83         updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, STATUS_WAITING_FOR_LOGIN);
84         webInterface.start();
85         startPolling();
86
87         enqueueCommand(new GetSite(this, this::updateProperties));
88     }
89
90     private void updateProperties(CommunicationStatus status, JsonObject jsonObject) {
91         Map<String, String> properties = editProperties();
92         String name = Utils.getAsString(jsonObject, JSON_KEY_GENERIC_NAME);
93         if (name != null) {
94             properties.put(JSON_KEY_GENERIC_NAME, name);
95         }
96         String siteKey = Utils.getAsString(jsonObject, JSON_KEY_SITE_KEY);
97         if (siteKey != null) {
98             properties.put(JSON_KEY_SITE_KEY, siteKey);
99         }
100         updateProperties(properties);
101     }
102
103     /**
104      * Start the polling.
105      */
106     private void startPolling() {
107         updateJobReference(dataPollingJobReference, scheduler.scheduleWithFixedDelay(this::pollingRun,
108                 POLLING_INITIAL_DELAY, getBridgeConfiguration().getDataPollingInterval(), TimeUnit.SECONDS));
109     }
110
111     /**
112      * Poll the Easee Cloud API one time.
113      */
114     void pollingRun() {
115         String siteId = getConfig().get(EaseeBindingConstants.THING_CONFIG_SITE_ID).toString();
116         logger.debug("polling site data for {}", siteId);
117
118         SiteState state = new SiteState(this, siteId, getChildChargerHandlers(), this::updateOnlineStatus);
119         enqueueCommand(state);
120
121         // proceed if site is online
122         if (getThing().getStatus() == ThingStatus.ONLINE) {
123             // add further polling commands here
124         }
125     }
126
127     /**
128      * creates a map containing all child chargers/masterchargers identified by their unique id.
129      *
130      * @return the map created
131      */
132     private Map<String, EaseeChargerHandler> getChildChargerHandlers() {
133         Map<String, EaseeChargerHandler> chargerHandlers = new HashMap<>();
134
135         getThing().getThings().stream().filter(x -> x.getThingTypeUID().equals(THING_TYPE_CHARGER)
136                 || x.getThingTypeUID().equals(THING_TYPE_MASTER_CHARGER)).forEach(y -> {
137                     EaseeChargerHandler handler = (EaseeChargerHandler) y.getHandler();
138                     if (handler != null) {
139                         chargerHandlers.put(handler.getId(), handler);
140                     }
141                 });
142         return chargerHandlers;
143     }
144
145     /**
146      * result processor to handle online status updates
147      *
148      * @param status of command execution
149      * @param jsonObject json respone result
150      */
151     protected final void updateOnlineStatus(CommunicationStatus status, JsonObject jsonObject) {
152         String msg = Utils.getAsString(jsonObject, JSON_KEY_ERROR_TITLE);
153         if (msg == null || msg.isBlank()) {
154             msg = status.getMessage();
155         }
156
157         switch (status.getHttpCode()) {
158             case OK:
159             case ACCEPTED:
160                 super.updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
161                 break;
162             default:
163                 super.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, msg);
164         }
165     }
166
167     /**
168      * Disposes the bridge.
169      */
170     @Override
171     public void dispose() {
172         logger.debug("Handler disposed.");
173         cancelJobReference(dataPollingJobReference);
174         webInterface.dispose();
175     }
176
177     @Override
178     public EaseeConfiguration getBridgeConfiguration() {
179         return this.getConfigAs(EaseeConfiguration.class);
180     }
181
182     @Override
183     public Collection<Class<? extends ThingHandlerService>> getServices() {
184         return Collections.singleton(EaseeSiteDiscoveryService.class);
185     }
186
187     public void setDiscoveryService(EaseeSiteDiscoveryService discoveryService) {
188         this.discoveryService = discoveryService;
189     }
190
191     @Override
192     public void startDiscovery() {
193         DiscoveryService discoveryService = this.discoveryService;
194         if (discoveryService != null) {
195             discoveryService.startScan(null);
196         }
197     }
198
199     @Override
200     public void enqueueCommand(EaseeCommand command) {
201         webInterface.enqueueCommand(command);
202     }
203
204     @Override
205     public Logger getLogger() {
206         return logger;
207     }
208 }