2 * Copyright (c) 2010-2024 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.solax.internal.handlers;
15 import java.io.IOException;
16 import java.time.ZoneId;
17 import java.util.concurrent.ScheduledFuture;
18 import java.util.concurrent.TimeUnit;
19 import java.util.concurrent.locks.ReentrantLock;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.binding.solax.internal.SolaxBindingConstants;
24 import org.openhab.binding.solax.internal.SolaxConfiguration;
25 import org.openhab.binding.solax.internal.connectivity.SolaxConnector;
26 import org.openhab.binding.solax.internal.exceptions.SolaxUpdateException;
27 import org.openhab.core.i18n.TimeZoneProvider;
28 import org.openhab.core.i18n.TranslationProvider;
29 import org.openhab.core.thing.ChannelUID;
30 import org.openhab.core.thing.Thing;
31 import org.openhab.core.thing.ThingStatus;
32 import org.openhab.core.thing.ThingStatusDetail;
33 import org.openhab.core.thing.binding.BaseThingHandler;
34 import org.openhab.core.types.Command;
35 import org.openhab.core.types.RefreshType;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
40 * The {@link SolaxCloudHandler} is responsible for handling commands, which are
41 * sent to one of the channels.
43 * @author Konstantin Polihronov - Initial contribution
46 public abstract class AbstractSolaxHandler extends BaseThingHandler {
48 private final Logger logger = LoggerFactory.getLogger(AbstractSolaxHandler.class);
50 private static final int INITIAL_SCHEDULE_DELAY_SECONDS = 0;
52 private @NonNullByDefault({}) SolaxConnector connector;
54 private @Nullable ScheduledFuture<?> schedule;
56 private final ReentrantLock retrieveDataCallLock = new ReentrantLock();
58 protected final TranslationProvider i18nProvider;
60 protected final ZoneId timeZone;
62 public AbstractSolaxHandler(Thing thing, TranslationProvider i18nProvider, TimeZoneProvider timeZoneProvider) {
64 this.i18nProvider = i18nProvider;
65 this.timeZone = timeZoneProvider.getTimeZone();
69 public void initialize() {
70 updateStatus(ThingStatus.UNKNOWN);
72 SolaxConfiguration config = getConfigAs(SolaxConfiguration.class);
73 connector = createConnector(config);
74 int refreshInterval = config.refreshInterval;
75 TimeUnit timeUnit = TimeUnit.SECONDS;
77 logger.debug("Scheduling regular interval retrieval every {} {}", refreshInterval, timeUnit);
78 schedule = scheduler.scheduleWithFixedDelay(this::retrieveData, INITIAL_SCHEDULE_DELAY_SECONDS, refreshInterval,
82 private void retrieveData() {
83 if (retrieveDataCallLock.tryLock()) {
85 String rawJsonData = connector.retrieveData();
86 logger.debug("Raw data retrieved = {}", rawJsonData);
88 if (rawJsonData != null && !rawJsonData.isEmpty()) {
89 updateFromData(rawJsonData);
90 if (getThing().getStatus() != ThingStatus.ONLINE) {
91 updateStatus(ThingStatus.ONLINE);
94 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
95 SolaxBindingConstants.I18N_KEY_OFFLINE_COMMUNICATION_ERROR_JSON_CANNOT_BE_RETRIEVED);
97 } catch (IOException e) {
98 logger.debug("Exception received while attempting to retrieve data via HTTP", e);
99 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
100 } catch (SolaxUpdateException e) {
101 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
103 retrieveDataCallLock.unlock();
106 logger.debug("Unable to retrieve data because a request is already in progress.");
111 public void handleCommand(ChannelUID channelUID, Command command) {
112 if (command instanceof RefreshType) {
113 scheduler.execute(this::retrieveData);
115 logger.debug("Binding {} only supports refresh command", SolaxBindingConstants.BINDING_ID);
120 public void dispose() {
125 protected void cancelSchedule() {
126 ScheduledFuture<?> schedule = this.schedule;
127 if (schedule != null) {
128 logger.debug("Cancelling schedule {}", schedule);
129 schedule.cancel(true);
130 this.schedule = null;
134 protected abstract SolaxConnector createConnector(SolaxConfiguration config);
136 protected abstract void updateFromData(String rawJsonData) throws SolaxUpdateException;