]> git.basschouten.com Git - openhab-addons.git/blob
56cc8c25e90ac2f51319f0d7e13ce27f046ab330
[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.fronius.internal.handler;
14
15 import java.util.Optional;
16
17 import javax.measure.Unit;
18
19 import org.openhab.binding.fronius.internal.FroniusBaseDeviceConfiguration;
20 import org.openhab.binding.fronius.internal.FroniusBindingConstants;
21 import org.openhab.binding.fronius.internal.FroniusBridgeConfiguration;
22 import org.openhab.binding.fronius.internal.FroniusCommunicationException;
23 import org.openhab.binding.fronius.internal.api.InverterRealtimeBodyData;
24 import org.openhab.binding.fronius.internal.api.InverterRealtimeResponse;
25 import org.openhab.binding.fronius.internal.api.PowerFlowRealtimeInverter;
26 import org.openhab.binding.fronius.internal.api.PowerFlowRealtimeResponse;
27 import org.openhab.binding.fronius.internal.api.PowerFlowRealtimeSite;
28 import org.openhab.binding.fronius.internal.api.ValueUnit;
29 import org.openhab.core.library.types.DecimalType;
30 import org.openhab.core.library.types.QuantityType;
31 import org.openhab.core.library.unit.Units;
32 import org.openhab.core.thing.Thing;
33 import org.openhab.core.types.State;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /**
38  * The {@link FroniusSymoInverterHandler} is responsible for updating the data, which are
39  * sent to one of the channels.
40  *
41  * @author Thomas Rokohl - Initial contribution
42  * @author Peter Schraffl - Added device status and error status channels
43  * @author Thomas Kordelle - Added inverter power, battery state of charge and PV solar yield
44  * @author Jimmy Tanagra - Add powerflow autonomy, self consumption channels
45  */
46 public class FroniusSymoInverterHandler extends FroniusBaseThingHandler {
47
48     private final Logger logger = LoggerFactory.getLogger(FroniusSymoInverterHandler.class);
49     private InverterRealtimeResponse inverterRealtimeResponse;
50     private PowerFlowRealtimeResponse powerFlowResponse;
51     private FroniusBaseDeviceConfiguration config;
52
53     public FroniusSymoInverterHandler(Thing thing) {
54         super(thing);
55     }
56
57     @Override
58     protected String getDescription() {
59         return "Fronius Symo Inverter";
60     }
61
62     @Override
63     protected void handleRefresh(FroniusBridgeConfiguration bridgeConfiguration) throws FroniusCommunicationException {
64         updateData(bridgeConfiguration, config);
65         updateChannels();
66     }
67
68     @Override
69     public void initialize() {
70         config = getConfigAs(FroniusBaseDeviceConfiguration.class);
71         super.initialize();
72     }
73
74     /**
75      * Update the channel from the last data retrieved
76      *
77      * @param channelId the id identifying the channel to be updated
78      * @return the last retrieved data
79      */
80     @Override
81     protected State getValue(String channelId) {
82         final String[] fields = channelId.split("#");
83         if (fields.length < 1) {
84             return null;
85         }
86         final String fieldName = fields[0];
87
88         if (inverterRealtimeResponse != null) {
89             InverterRealtimeBodyData inverterData = inverterRealtimeResponse.getBody().getData();
90             switch (fieldName) {
91                 case FroniusBindingConstants.INVERTER_DATA_CHANNEL_PAC:
92                     return getQuantityOrZero(inverterData.getPac(), Units.WATT);
93                 case FroniusBindingConstants.INVERTER_DATA_CHANNEL_FAC:
94                     return getQuantityOrZero(inverterData.getFac(), Units.HERTZ);
95                 case FroniusBindingConstants.INVERTER_DATA_CHANNEL_IAC:
96                     return getQuantityOrZero(inverterData.getIac(), Units.AMPERE);
97                 case FroniusBindingConstants.INVERTER_DATA_CHANNEL_IDC:
98                     return getQuantityOrZero(inverterData.getIdc(), Units.AMPERE);
99                 case FroniusBindingConstants.INVERTER_DATA_CHANNEL_IDC2:
100                     return getQuantityOrZero(inverterData.getIdc2(), Units.AMPERE);
101                 case FroniusBindingConstants.INVERTER_DATA_CHANNEL_IDC3:
102                     return getQuantityOrZero(inverterData.getIdc3(), Units.AMPERE);
103                 case FroniusBindingConstants.INVERTER_DATA_CHANNEL_UAC:
104                     return getQuantityOrZero(inverterData.getUac(), Units.VOLT);
105                 case FroniusBindingConstants.INVERTER_DATA_CHANNEL_UDC:
106                     return getQuantityOrZero(inverterData.getUdc(), Units.VOLT);
107                 case FroniusBindingConstants.INVERTER_DATA_CHANNEL_UDC2:
108                     return getQuantityOrZero(inverterData.getUdc2(), Units.VOLT);
109                 case FroniusBindingConstants.INVERTER_DATA_CHANNEL_UDC3:
110                     return getQuantityOrZero(inverterData.getUdc3(), Units.VOLT);
111                 case FroniusBindingConstants.INVERTER_DATA_CHANNEL_PDC:
112                     return calculatePower(inverterData.getUdc(), inverterData.getIdc());
113                 case FroniusBindingConstants.INVERTER_DATA_CHANNEL_PDC2:
114                     return calculatePower(inverterData.getUdc2(), inverterData.getIdc2());
115                 case FroniusBindingConstants.INVERTER_DATA_CHANNEL_PDC3:
116                     return calculatePower(inverterData.getUdc3(), inverterData.getIdc3());
117                 case FroniusBindingConstants.INVERTER_DATA_CHANNEL_DAY_ENERGY:
118                     // Convert the unit to kWh for backwards compatibility with non-quantity type
119                     return getQuantityOrZero(inverterData.getDayEnergy(), Units.KILOWATT_HOUR).toUnit("kWh");
120                 case FroniusBindingConstants.INVERTER_DATA_CHANNEL_TOTAL:
121                     // Convert the unit to MWh for backwards compatibility with non-quantity type
122                     return getQuantityOrZero(inverterData.getTotalEnergy(), Units.MEGAWATT_HOUR).toUnit("MWh");
123                 case FroniusBindingConstants.INVERTER_DATA_CHANNEL_YEAR:
124                     // Convert the unit to MWh for backwards compatibility with non-quantity type
125                     return getQuantityOrZero(inverterData.getYearEnergy(), Units.MEGAWATT_HOUR).toUnit("MWh");
126                 case FroniusBindingConstants.INVERTER_DATA_CHANNEL_DEVICE_STATUS_ERROR_CODE:
127                     return new DecimalType(inverterData.getDeviceStatus().getErrorCode());
128                 case FroniusBindingConstants.INVERTER_DATA_CHANNEL_DEVICE_STATUS_STATUS_CODE:
129                     return new DecimalType(inverterData.getDeviceStatus().getStatusCode());
130                 default:
131                     break;
132             }
133         }
134
135         if (powerFlowResponse != null) {
136             PowerFlowRealtimeSite site = powerFlowResponse.getBody().getData().getSite();
137             switch (fieldName) {
138                 case FroniusBindingConstants.POWER_FLOW_P_GRID:
139                     return new QuantityType<>(site.getPgrid(), Units.WATT);
140                 case FroniusBindingConstants.POWER_FLOW_P_LOAD:
141                     return new QuantityType<>(site.getPload(), Units.WATT);
142                 case FroniusBindingConstants.POWER_FLOW_P_AKKU:
143                     return new QuantityType<>(site.getPakku(), Units.WATT);
144                 case FroniusBindingConstants.POWER_FLOW_P_PV:
145                     return new QuantityType<>(site.getPpv(), Units.WATT);
146                 case FroniusBindingConstants.POWER_FLOW_AUTONOMY:
147                     return new QuantityType<>(site.getRelAutonomy(), Units.PERCENT);
148                 case FroniusBindingConstants.POWER_FLOW_SELF_CONSUMPTION:
149                     return new QuantityType<>(site.getRelSelfConsumption(), Units.PERCENT);
150                 case FroniusBindingConstants.POWER_FLOW_INVERTER_1_POWER:
151                     return new QuantityType<>(getInverter("1").getP(), Units.WATT);
152                 case FroniusBindingConstants.POWER_FLOW_INVERTER_1_SOC:
153                     return new QuantityType<>(getInverter("1").getSoc(), Units.PERCENT);
154                 default:
155                     break;
156             }
157         }
158
159         return null;
160     }
161
162     /**
163      * get flow data for a specific inverter.
164      *
165      * @param number The inverter object of the given index
166      * @return a PowerFlowRealtimeInverter object.
167      */
168     private PowerFlowRealtimeInverter getInverter(final String number) {
169         return powerFlowResponse.getBody().getData().getInverters().get(number);
170     }
171
172     /**
173      * Return the value as QuantityType with the unit extracted from ValueUnit
174      * or a zero QuantityType with the given unit argument when value is null
175      * 
176      * @param value The ValueUnit data
177      * @param unit The default unit to use when value is null
178      * @return a QuantityType from the given value
179      */
180     private QuantityType<?> getQuantityOrZero(ValueUnit value, Unit unit) {
181         return Optional.ofNullable(value).map(val -> val.asQuantityType().toUnit(unit))
182                 .orElse(new QuantityType<>(0, unit));
183     }
184
185     /**
186      * Get new data
187      */
188     private void updateData(FroniusBridgeConfiguration bridgeConfiguration, FroniusBaseDeviceConfiguration config)
189             throws FroniusCommunicationException {
190         inverterRealtimeResponse = getRealtimeData(bridgeConfiguration.hostname, config.deviceId);
191         powerFlowResponse = getPowerFlowRealtime(bridgeConfiguration.hostname);
192     }
193
194     /**
195      * Make the PowerFlowRealtimeDataRequest
196      *
197      * @param ip address of the device
198      * @return {PowerFlowRealtimeResponse} the object representation of the json response
199      */
200     private PowerFlowRealtimeResponse getPowerFlowRealtime(String ip) throws FroniusCommunicationException {
201         String location = FroniusBindingConstants.getPowerFlowDataUrl(ip);
202         return collectDataFromUrl(PowerFlowRealtimeResponse.class, location);
203     }
204
205     /**
206      * Make the InverterRealtimeDataRequest
207      *
208      * @param ip address of the device
209      * @param deviceId of the device
210      * @return {InverterRealtimeResponse} the object representation of the json response
211      */
212     private InverterRealtimeResponse getRealtimeData(String ip, int deviceId) throws FroniusCommunicationException {
213         String location = FroniusBindingConstants.getInverterDataUrl(ip, deviceId);
214         return collectDataFromUrl(InverterRealtimeResponse.class, location);
215     }
216
217     /**
218      * Calculate the power value from the given voltage and current channels
219      * 
220      * @param voltage the voltage ValueUnit
221      * @param current the current ValueUnit
222      * @return {QuantityType<>} the power value calculated by multiplying voltage and current
223      */
224     private QuantityType<?> calculatePower(ValueUnit voltage, ValueUnit current) {
225         QuantityType<?> qtyVoltage = getQuantityOrZero(voltage, Units.VOLT);
226         QuantityType<?> qtyCurrent = getQuantityOrZero(current, Units.AMPERE);
227         return qtyVoltage.multiply(qtyCurrent).toUnit(Units.WATT);
228     }
229 }