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.solax.internal;
15 import java.io.IOException;
16 import java.time.ZonedDateTime;
17 import java.util.concurrent.ScheduledFuture;
18 import java.util.concurrent.TimeUnit;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.openhab.binding.solax.internal.connectivity.LocalHttpConnector;
23 import org.openhab.binding.solax.internal.connectivity.rawdata.LocalConnectRawDataBean;
24 import org.openhab.binding.solax.internal.model.InverterData;
25 import org.openhab.core.library.types.DateTimeType;
26 import org.openhab.core.library.types.QuantityType;
27 import org.openhab.core.library.types.StringType;
28 import org.openhab.core.library.unit.SIUnits;
29 import org.openhab.core.library.unit.Units;
30 import org.openhab.core.thing.ChannelUID;
31 import org.openhab.core.thing.Thing;
32 import org.openhab.core.thing.ThingStatus;
33 import org.openhab.core.thing.ThingStatusDetail;
34 import org.openhab.core.thing.binding.BaseThingHandler;
35 import org.openhab.core.types.Command;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
39 import com.google.gson.JsonParseException;
42 * The {@link SolaxLocalAccessHandler} is responsible for handling commands, which are
43 * sent to one of the channels.
45 * @author Konstantin Polihronov - Initial contribution
48 public class SolaxLocalAccessHandler extends BaseThingHandler {
50 private final Logger logger = LoggerFactory.getLogger(SolaxLocalAccessHandler.class);
52 private static final int INITIAL_SCHEDULE_DELAY_SECONDS = 5;
54 private @NonNullByDefault({}) LocalHttpConnector localHttpConnector;
56 private @Nullable ScheduledFuture<?> schedule;
58 public SolaxLocalAccessHandler(Thing thing) {
63 public void initialize() {
64 updateStatus(ThingStatus.UNKNOWN);
66 SolaxConfiguration config = getConfigAs(SolaxConfiguration.class);
67 localHttpConnector = new LocalHttpConnector(config.password, config.hostname);
68 int refreshInterval = config.refreshInterval;
69 TimeUnit timeUnit = TimeUnit.SECONDS;
71 logger.debug("Scheduling regular interval retrieval every {} {}", refreshInterval, timeUnit);
72 schedule = scheduler.scheduleWithFixedDelay(this::retrieveData, INITIAL_SCHEDULE_DELAY_SECONDS, refreshInterval,
76 private void retrieveData() {
78 String rawJsonData = localHttpConnector.retrieveData();
79 logger.debug("Raw data retrieved = {}", rawJsonData);
81 if (rawJsonData != null && !rawJsonData.isEmpty()) {
82 updateData(rawJsonData);
84 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
85 SolaxBindingConstants.I18N_KEY_OFFLINE_COMMUNICATION_ERROR_JSON_CANNOT_BE_RETRIEVED);
87 } catch (IOException e) {
88 logger.debug("Exception received while attempting to retrieve data via HTTP", e);
89 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
93 private void updateData(String rawJsonData) {
95 LocalConnectRawDataBean inverterParsedData = parseJson(rawJsonData);
96 updateThing(inverterParsedData);
97 } catch (JsonParseException e) {
98 logger.debug("Unable to deserialize from JSON.", e);
99 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
103 private void updateThing(LocalConnectRawDataBean inverterParsedData) {
104 transferInverterDataToChannels(inverterParsedData);
106 if (getThing().getStatus() != ThingStatus.ONLINE) {
107 updateStatus(ThingStatus.ONLINE);
111 private LocalConnectRawDataBean parseJson(String rawJsonData) {
112 LocalConnectRawDataBean inverterParsedData = LocalConnectRawDataBean.fromJson(rawJsonData);
113 logger.debug("Received a new inverter data object. Data = {}", inverterParsedData.toStringDetailed());
114 return inverterParsedData;
117 private void transferInverterDataToChannels(InverterData data) {
118 updateProperty(Thing.PROPERTY_SERIAL_NUMBER, data.getWifiSerial());
119 updateProperty(SolaxBindingConstants.PROPERTY_INVERTER_TYPE, data.getInverterType().name());
121 updateState(SolaxBindingConstants.INVERTER_OUTPUT_POWER,
122 new QuantityType<>(data.getInverterOutputPower(), Units.WATT));
123 updateState(SolaxBindingConstants.INVERTER_OUTPUT_CURRENT,
124 new QuantityType<>(data.getInverterCurrent(), Units.AMPERE));
125 updateState(SolaxBindingConstants.INVERTER_OUTPUT_VOLTAGE,
126 new QuantityType<>(data.getInverterVoltage(), Units.VOLT));
127 updateState(SolaxBindingConstants.INVERTER_OUTPUT_FREQUENCY,
128 new QuantityType<>(data.getInverterFrequency(), Units.HERTZ));
130 updateState(SolaxBindingConstants.INVERTER_PV1_POWER, new QuantityType<>(data.getPV1Power(), Units.WATT));
131 updateState(SolaxBindingConstants.INVERTER_PV1_CURRENT, new QuantityType<>(data.getPV1Current(), Units.AMPERE));
132 updateState(SolaxBindingConstants.INVERTER_PV1_VOLTAGE, new QuantityType<>(data.getPV1Voltage(), Units.VOLT));
134 updateState(SolaxBindingConstants.INVERTER_PV2_POWER, new QuantityType<>(data.getPV2Power(), Units.WATT));
135 updateState(SolaxBindingConstants.INVERTER_PV2_CURRENT, new QuantityType<>(data.getPV2Current(), Units.AMPERE));
136 updateState(SolaxBindingConstants.INVERTER_PV2_VOLTAGE, new QuantityType<>(data.getPV2Voltage(), Units.VOLT));
138 updateState(SolaxBindingConstants.INVERTER_PV_TOTAL_POWER,
139 new QuantityType<>(data.getPVTotalPower(), Units.WATT));
140 updateState(SolaxBindingConstants.INVERTER_PV_TOTAL_CURRENT,
141 new QuantityType<>(data.getPVTotalCurrent(), Units.AMPERE));
143 updateState(SolaxBindingConstants.BATTERY_POWER, new QuantityType<>(data.getBatteryPower(), Units.WATT));
144 updateState(SolaxBindingConstants.BATTERY_CURRENT, new QuantityType<>(data.getBatteryCurrent(), Units.AMPERE));
145 updateState(SolaxBindingConstants.BATTERY_VOLTAGE, new QuantityType<>(data.getBatteryVoltage(), Units.VOLT));
146 updateState(SolaxBindingConstants.BATTERY_TEMPERATURE,
147 new QuantityType<>(data.getBatteryTemperature(), SIUnits.CELSIUS));
148 updateState(SolaxBindingConstants.BATTERY_STATE_OF_CHARGE,
149 new QuantityType<>(data.getBatterySoC(), Units.PERCENT));
151 updateState(SolaxBindingConstants.FEED_IN_POWER, new QuantityType<>(data.getFeedInPower(), Units.WATT));
153 updateState(SolaxBindingConstants.TIMESTAMP, new DateTimeType(ZonedDateTime.now()));
154 updateState(SolaxBindingConstants.RAW_DATA, new StringType(data.getRawData()));
158 public void handleCommand(ChannelUID channelUID, Command command) {
159 // Nothing to do here as of now. Maybe implement a REFRESH command in the future.
163 public void dispose() {
165 ScheduledFuture<?> schedule = this.schedule;
166 if (schedule != null) {
167 schedule.cancel(true);
168 this.schedule = null;