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.solaredge.internal.model;
15 import static org.openhab.binding.solaredge.internal.SolarEdgeBindingConstants.*;
19 import javax.measure.Quantity;
20 import javax.measure.Unit;
21 import javax.measure.quantity.Energy;
22 import javax.measure.quantity.Power;
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.openhab.binding.solaredge.internal.model.AggregateDataResponsePrivateApi.Value;
27 import org.openhab.binding.solaredge.internal.model.AggregateDataResponsePrivateApi.ValueAndPercent;
28 import org.openhab.binding.solaredge.internal.model.AggregateDataResponsePublicApi.MeterTelemetry;
29 import org.openhab.core.library.types.DecimalType;
30 import org.openhab.core.library.types.QuantityType;
31 import org.openhab.core.library.types.StringType;
32 import org.openhab.core.library.unit.MetricPrefix;
33 import org.openhab.core.library.unit.Units;
34 import org.openhab.core.thing.Channel;
35 import org.openhab.core.types.State;
36 import org.openhab.core.types.UnDefType;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
41 * common interface for all data response classes
43 * @author Alexander Friese - initial contribution
46 abstract class AbstractDataResponseTransformer {
47 static final String UNIT_WH = "Wh";
48 static final String UNIT_KWH = "kWh";
49 static final String UNIT_MWH = "MWh";
50 static final String UNIT_W = "W";
51 static final String UNIT_KW = "kW";
52 static final String UNIT_MW = "MW";
57 private final Logger logger = LoggerFactory.getLogger(AbstractDataResponseTransformer.class);
60 * determines the unit, also handles wrong spelling of kWh (which is spelled with capital K by API)
65 private final @Nullable Unit<Energy> determineEnergyUnit(@Nullable String unit) {
67 if (unit.equals(UNIT_WH)) {
68 return Units.WATT_HOUR;
69 } else if (unit.toLowerCase().equals(UNIT_KWH.toLowerCase())) {
70 return MetricPrefix.KILO(Units.WATT_HOUR);
71 } else if (unit.equals(UNIT_MWH)) {
72 return MetricPrefix.MEGA(Units.WATT_HOUR);
75 logger.debug("Could not determine energy unit: '{}'", unit);
80 * determines the unit, also handles wrong spelling of kW (which is spelled with capital K by API)
85 private final @Nullable Unit<Power> determinePowerUnit(@Nullable String unit) {
87 if (unit.equals(UNIT_W)) {
89 } else if (unit.toLowerCase().equals(UNIT_KW.toLowerCase())) {
90 return MetricPrefix.KILO(Units.WATT);
91 } else if (unit.equals(UNIT_MW)) {
92 return MetricPrefix.MEGA(Units.WATT);
95 logger.debug("Could not determine power unit: '{}'", unit);
100 * converts the value to QuantityType and puts it into the targetMap. If no value or unit is provided
101 * UnDefType.UNDEF will be used
103 * @param targetMap result will be put into this map
104 * @param channel channel to assign the value
105 * @param value the value to convert
106 * @param unit the unit to be used
108 private final <T extends Quantity<T>> void putQuantityType(Map<Channel, State> targetMap, Channel channel,
109 @Nullable Double value, @Nullable Unit<T> unit) {
110 State result = UnDefType.UNDEF;
112 if (value != null && unit != null) {
113 result = new QuantityType<>(value, unit);
114 logger.debug("Channel {} transformed to QuantityType ({} {}) -> {}", channel.getUID().getId(), value, unit,
117 logger.debug("Channel {}: no value/unit provided", channel.getUID().getId());
119 targetMap.put(channel, result);
123 * converts the value to {@code QuantityType<Power>} and puts it into the targetMap. If no value or unit is
124 * provided, UnDefType.UNDEF will be used
126 * @param targetMap result will be put into this map
127 * @param channel channel to assign the value
128 * @param value the value to convert
129 * @param unitAsString unit as string
131 protected final void putPowerType(Map<Channel, State> targetMap, @Nullable Channel channel, @Nullable Double value,
132 @Nullable String unitAsString) {
133 if (channel != null) {
134 Unit<Power> unit = determinePowerUnit(unitAsString);
135 putQuantityType(targetMap, channel, value, unit);
140 * converts the value to {@code QuantityType<Energy>} and puts it into the targetMap. If no value or unit is
141 * provided UnDefType.UNDEF will be used
143 * @param targetMap result will be put into this map
144 * @param channel channel to assign the value
145 * @param value the value to convert
146 * @param unitAsString as string
148 protected final void putEnergyType(Map<Channel, State> targetMap, @Nullable Channel channel, @Nullable Double value,
149 @Nullable String unitAsString) {
150 if (channel != null) {
151 Unit<Energy> unit = determineEnergyUnit(unitAsString);
152 putQuantityType(targetMap, channel, value, unit);
157 * converts the value to {@code QuantityType<Energy>} and puts it into the targetMap. If no value or unit is
158 * provided, UnDefType.UNDEF will be used
160 * @param targetMap result will be put into this map
161 * @param channel channel to assign the value
162 * @param value the value to convert
164 protected final void putEnergyType(Map<Channel, State> targetMap, @Nullable Channel channel, Value value) {
165 putEnergyType(targetMap, channel, value.value, value.unit);
169 * converts the meter value to {@code QuantityType<Energy>} and puts it into the targetMap. If multiple meter value
170 * are provided a sum will be calculated. If no
171 * unit can be determined UnDefType.UNDEF will be used
173 * @param targetMap result will be put into this map
174 * @param channel channel to assign the value
175 * @param values one or more meter values
177 protected final void putEnergyType(Map<Channel, State> targetMap, @Nullable Channel channel, @Nullable String unit,
178 MeterTelemetry... values) {
180 for (MeterTelemetry value : values) {
181 Double innerValue = value.value;
182 if (innerValue != null) {
186 putEnergyType(targetMap, channel, sum, unit);
190 * put value as StringType into targetMap.
192 * @param targetMap result will be put into this map
193 * @param channel channel to assign the value
194 * @param value the value
196 protected final void putStringType(Map<Channel, State> targetMap, @Nullable Channel channel,
197 @Nullable String value) {
198 if (channel != null) {
199 State result = UnDefType.UNDEF;
202 result = new StringType(value);
203 logger.debug("Channel {} transformed to StringType ({}) -> {}", channel.getUID().getId(), value,
207 logger.debug("Channel {}: no value provided.", channel);
209 targetMap.put(channel, result);
214 * put value as PercentType into targetMap.
216 * @param targetMap result will be put into this map
217 * @param channel channel to assign the value
218 * @param value the value to convert
219 * @param factor to be applied (usually 1 or 100)
221 protected final void putPercentType(Map<Channel, State> targetMap, @Nullable Channel channel,
222 @Nullable Double value, int factor) {
223 if (channel != null) {
224 State result = UnDefType.UNDEF;
227 result = new QuantityType<>(value * factor, Units.PERCENT);
229 logger.debug("Channel {}: no value provided.", channel.getUID().getAsString());
231 targetMap.put(channel, result);
236 * put value as PercentType into targetMap.
238 * @param targetMap result will be put into this map
239 * @param channel channel to assign the value
240 * @param value the value to convert
242 protected final void putPercentType(Map<Channel, State> targetMap, @Nullable Channel channel,
243 @Nullable Double value) {
244 putPercentType(targetMap, channel, value, 1);
248 * put value as PercentType into targetMap.
250 * @param targetMap result will be put into this map
251 * @param channel channel to assign the value
252 * @param value the value to convert
254 protected final void putPercentType(Map<Channel, State> targetMap, @Nullable Channel channel,
255 ValueAndPercent value) {
256 putPercentType(targetMap, channel, value.percentage, 100);
260 * calculates percentage and puts it into the targetmap
262 * @param targetMap result will be put into this map
263 * @param channel channel to assign the value
264 * @param dividendAsState
265 * @param divisorAsState
267 protected final void putPercentType(Map<Channel, State> targetMap, @Nullable Channel channel,
268 @Nullable State dividendAsState, @Nullable State divisorAsState) {
269 Double percent = null;
271 if (dividendAsState != null && divisorAsState != null) {
272 DecimalType dividendAsDecimalType = dividendAsState.as(DecimalType.class);
273 DecimalType divisorAsDecimalType = divisorAsState.as(DecimalType.class);
275 if (dividendAsDecimalType != null && divisorAsDecimalType != null) {
276 double dividend = dividendAsDecimalType.doubleValue();
277 double divisor = divisorAsDecimalType.doubleValue();
278 if (dividend >= 0.0 && divisor > 0.0) {
279 percent = dividend / divisor * 100;
284 putPercentType(targetMap, channel, percent);
288 * converts the aggregate period to the correpsonding channel group.
293 protected String convertPeriodToGroup(AggregatePeriod period) {
294 String group = "undefined";
297 group = CHANNEL_GROUP_AGGREGATE_DAY;
300 group = CHANNEL_GROUP_AGGREGATE_WEEK;
303 group = CHANNEL_GROUP_AGGREGATE_MONTH;
306 group = CHANNEL_GROUP_AGGREGATE_YEAR;