]> git.basschouten.com Git - openhab-addons.git/blob
9ac3e1fa5d405d9d756bb63b5fbc4f619fd839a4
[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.Map;
18 import java.util.concurrent.Future;
19 import java.util.concurrent.TimeUnit;
20 import java.util.concurrent.atomic.AtomicReference;
21
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.openhab.binding.easee.internal.AtomicReferenceTrait;
25 import org.openhab.binding.easee.internal.EaseeBindingConstants;
26 import org.openhab.binding.easee.internal.Utils;
27 import org.openhab.binding.easee.internal.command.EaseeCommand;
28 import org.openhab.binding.easee.internal.command.charger.ChangeConfiguration;
29 import org.openhab.binding.easee.internal.command.charger.Charger;
30 import org.openhab.binding.easee.internal.command.charger.ChargerState;
31 import org.openhab.binding.easee.internal.command.charger.GetConfiguration;
32 import org.openhab.binding.easee.internal.command.charger.LatestChargingSession;
33 import org.openhab.binding.easee.internal.command.charger.SendCommand;
34 import org.openhab.binding.easee.internal.command.charger.SendCommandPauseResume;
35 import org.openhab.binding.easee.internal.command.charger.SendCommandStartStop;
36 import org.openhab.binding.easee.internal.config.EaseeConfiguration;
37 import org.openhab.binding.easee.internal.connector.CommunicationStatus;
38 import org.openhab.core.thing.Bridge;
39 import org.openhab.core.thing.Channel;
40 import org.openhab.core.thing.Thing;
41 import org.openhab.core.thing.ThingStatus;
42 import org.openhab.core.thing.ThingStatusDetail;
43 import org.openhab.core.thing.binding.BaseThingHandler;
44 import org.openhab.core.types.Command;
45 import org.openhab.core.types.State;
46 import org.openhab.core.types.UnDefType;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 import com.google.gson.JsonObject;
51
52 /**
53  * The {@link EaseeChargerHandler} is responsible for handling commands, which are
54  * sent to one of the channels.
55  *
56  * @author Alexander Friese - initial contribution
57  */
58 @NonNullByDefault
59 public class EaseeChargerHandler extends BaseThingHandler implements EaseeThingHandler, AtomicReferenceTrait {
60     private final Logger logger = LoggerFactory.getLogger(EaseeChargerHandler.class);
61
62     /**
63      * Schedule for polling live data
64      */
65     private final AtomicReference<@Nullable Future<?>> dataPollingJobReference;
66
67     public EaseeChargerHandler(Thing thing) {
68         super(thing);
69         this.dataPollingJobReference = new AtomicReference<>(null);
70     }
71
72     @Override
73     public void initialize() {
74         logger.debug("About to initialize Charger");
75         String chargerId = getConfig().get(EaseeBindingConstants.THING_CONFIG_ID).toString();
76         logger.debug("Easee Charger initialized with id: {}", chargerId);
77
78         updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, STATUS_WAITING_FOR_BRIDGE);
79         startPolling();
80
81         enqueueCommand(new Charger(this, chargerId, this::updateProperties));
82     }
83
84     private void updateProperties(CommunicationStatus status, JsonObject charger) {
85         Map<String, String> properties = editProperties();
86
87         String backPlateId = Utils.getAsString(charger.getAsJsonObject(JSON_KEY_BACK_PLATE), JSON_KEY_GENERIC_ID);
88         String masterBackPlateId = Utils.getAsString(charger.getAsJsonObject(JSON_KEY_BACK_PLATE),
89                 JSON_KEY_MASTER_BACK_PLATE_ID);
90         if (backPlateId != null && masterBackPlateId != null) {
91             if (backPlateId.equals(masterBackPlateId)) {
92                 properties.put(THING_CONFIG_IS_MASTER, GENERIC_YES);
93             } else {
94                 properties.put(THING_CONFIG_IS_MASTER, GENERIC_NO);
95             }
96             properties.put(THING_CONFIG_BACK_PLATE_ID, backPlateId);
97             properties.put(THING_CONFIG_MASTER_BACK_PLATE_ID, masterBackPlateId);
98         }
99         String chargerName = Utils.getAsString(charger, JSON_KEY_GENERIC_NAME);
100         if (chargerName != null) {
101             properties.put(JSON_KEY_GENERIC_NAME, chargerName);
102         }
103         String circuitId = Utils.getAsString(charger.getAsJsonObject(JSON_KEY_BACK_PLATE), JSON_KEY_CIRCUIT_ID);
104         if (circuitId != null) {
105             properties.put(JSON_KEY_CIRCUIT_ID, circuitId);
106         }
107
108         updateProperties(properties);
109     }
110
111     /**
112      * Start the polling.
113      */
114     private void startPolling() {
115         updateJobReference(dataPollingJobReference, scheduler.scheduleWithFixedDelay(this::pollingRun,
116                 POLLING_INITIAL_DELAY, getBridgeConfiguration().getDataPollingInterval(), TimeUnit.SECONDS));
117     }
118
119     /**
120      * Poll the Easee Cloud API one time.
121      */
122     void pollingRun() {
123         String chargerId = getConfig().get(EaseeBindingConstants.THING_CONFIG_ID).toString();
124         logger.debug("polling charger data for {}", chargerId);
125
126         ChargerState state = new ChargerState(this, chargerId);
127         state.registerResultProcessor(this::updateStatusInfo);
128         enqueueCommand(state);
129
130         // proceed if charger is online
131         if (getThing().getStatus() == ThingStatus.ONLINE) {
132             enqueueCommand(new GetConfiguration(this, chargerId));
133             enqueueCommand(new LatestChargingSession(this, chargerId));
134         }
135     }
136
137     /**
138      * updates status depending on online information received from the API.
139      *
140      * @param status
141      * @param jsonObject
142      */
143     private void updateStatusInfo(CommunicationStatus status, JsonObject jsonObject) {
144         Boolean isOnline = Utils.getAsBool(jsonObject, JSON_KEY_ONLINE);
145
146         if (isOnline == null) {
147             super.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, STATUS_NO_VALID_DATA);
148         } else if (isOnline) {
149             super.updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
150         } else {
151             super.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, STATUS_NO_CONNECTION);
152         }
153     }
154
155     /**
156      * Disposes the thing.
157      */
158     @Override
159     public void dispose() {
160         logger.debug("Handler disposed.");
161         cancelJobReference(dataPollingJobReference);
162     }
163
164     /**
165      * will update all channels provided in the map
166      */
167     @Override
168     public void updateChannelStatus(Map<Channel, State> values) {
169         logger.debug("Handling charger channel update.");
170
171         for (Channel channel : values.keySet()) {
172             if (getThing().getChannels().contains(channel)) {
173                 State value = values.get(channel);
174                 if (value != null) {
175                     logger.debug("Channel is to be updated: {}: {}", channel.getUID().getAsString(), value);
176                     updateState(channel.getUID(), value);
177                 } else {
178                     logger.debug("Value is null or not provided by Easee Cloud (channel: {})",
179                             channel.getUID().getAsString());
180                     updateState(channel.getUID(), UnDefType.UNDEF);
181                 }
182             } else {
183                 logger.debug("Could not identify channel: {} for model {}", channel.getUID().getAsString(),
184                         getThing().getThingTypeUID().getAsString());
185             }
186         }
187     }
188
189     @Override
190     public void enqueueCommand(EaseeCommand command) {
191         EaseeBridgeHandler bridgeHandler = getBridgeHandler();
192         if (bridgeHandler != null) {
193             bridgeHandler.enqueueCommand(command);
194         } else {
195             // this should not happen
196             logger.warn("no bridge handler found");
197         }
198     }
199
200     private @Nullable EaseeBridgeHandler getBridgeHandler() {
201         Bridge bridge = getBridge();
202         return bridge == null ? null : ((EaseeBridgeHandler) bridge.getHandler());
203     }
204
205     @Override
206     public EaseeConfiguration getBridgeConfiguration() {
207         EaseeBridgeHandler bridgeHandler = getBridgeHandler();
208         return bridgeHandler == null ? new EaseeConfiguration() : bridgeHandler.getBridgeConfiguration();
209     }
210
211     @Override
212     public EaseeCommand buildEaseeCommand(Command command, Channel channel) {
213         String chargerId = getConfig().get(EaseeBindingConstants.THING_CONFIG_ID).toString();
214
215         switch (Utils.getWriteCommand(channel)) {
216             case COMMAND_CHANGE_CONFIGURATION:
217                 return new ChangeConfiguration(this, chargerId, channel, command);
218             case COMMAND_SEND_COMMAND:
219                 return new SendCommand(this, chargerId, channel, command);
220             case COMMAND_SEND_COMMAND_START_STOP:
221                 return new SendCommandStartStop(this, chargerId, channel, command);
222             case COMMAND_SEND_COMMAND_PAUSE_RESUME:
223                 return new SendCommandPauseResume(this, chargerId, channel, command);
224             default:
225                 // this should not happen
226                 logger.error("write command '{}' not found for channel '{}'", command.toString(),
227                         channel.getUID().getIdWithoutGroup());
228                 throw new UnsupportedOperationException(
229                         "write command not found for channel: " + channel.getUID().getIdWithoutGroup());
230         }
231     }
232
233     @Override
234     public Logger getLogger() {
235         return logger;
236     }
237 }