]> git.basschouten.com Git - openhab-addons.git/blob
7461b29c50b6e2ce6f378afe522a5f36a0cc96f5
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 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_POWER:
151                     return new QuantityType<>(getInverter(config.deviceId).getP(), Units.WATT);
152                 case FroniusBindingConstants.POWER_FLOW_INVERTER_SOC:
153                     return new QuantityType<>(getInverter(config.deviceId).getSoc(), Units.PERCENT);
154
155                 // Kept for backwards compatibility
156                 case FroniusBindingConstants.POWER_FLOW_INVERTER_1_POWER:
157                     return new QuantityType<>(getInverter(1).getP(), Units.WATT);
158                 case FroniusBindingConstants.POWER_FLOW_INVERTER_1_SOC:
159                     return new QuantityType<>(getInverter(1).getSoc(), Units.PERCENT);
160                 default:
161                     break;
162             }
163         }
164
165         return null;
166     }
167
168     /**
169      * get flow data for a specific inverter.
170      *
171      * @param number The inverter object of the given index
172      * @return a PowerFlowRealtimeInverter object.
173      */
174     private PowerFlowRealtimeInverter getInverter(final int number) {
175         return powerFlowResponse.getBody().getData().getInverters().get(Integer.toString(number));
176     }
177
178     /**
179      * Return the value as QuantityType with the unit extracted from ValueUnit
180      * or a zero QuantityType with the given unit argument when value is null
181      * 
182      * @param value The ValueUnit data
183      * @param unit The default unit to use when value is null
184      * @return a QuantityType from the given value
185      */
186     private QuantityType<?> getQuantityOrZero(ValueUnit value, Unit unit) {
187         return Optional.ofNullable(value).map(val -> val.asQuantityType().toUnit(unit))
188                 .orElse(new QuantityType<>(0, unit));
189     }
190
191     /**
192      * Get new data
193      */
194     private void updateData(FroniusBridgeConfiguration bridgeConfiguration, FroniusBaseDeviceConfiguration config)
195             throws FroniusCommunicationException {
196         inverterRealtimeResponse = getRealtimeData(bridgeConfiguration.hostname, config.deviceId);
197         powerFlowResponse = getPowerFlowRealtime(bridgeConfiguration.hostname);
198     }
199
200     /**
201      * Make the PowerFlowRealtimeDataRequest
202      *
203      * @param ip address of the device
204      * @return {PowerFlowRealtimeResponse} the object representation of the json response
205      */
206     private PowerFlowRealtimeResponse getPowerFlowRealtime(String ip) throws FroniusCommunicationException {
207         String location = FroniusBindingConstants.getPowerFlowDataUrl(ip);
208         return collectDataFromUrl(PowerFlowRealtimeResponse.class, location);
209     }
210
211     /**
212      * Make the InverterRealtimeDataRequest
213      *
214      * @param ip address of the device
215      * @param deviceId of the device
216      * @return {InverterRealtimeResponse} the object representation of the json response
217      */
218     private InverterRealtimeResponse getRealtimeData(String ip, int deviceId) throws FroniusCommunicationException {
219         String location = FroniusBindingConstants.getInverterDataUrl(ip, deviceId);
220         return collectDataFromUrl(InverterRealtimeResponse.class, location);
221     }
222
223     /**
224      * Calculate the power value from the given voltage and current channels
225      * 
226      * @param voltage the voltage ValueUnit
227      * @param current the current ValueUnit
228      * @return {QuantityType<>} the power value calculated by multiplying voltage and current
229      */
230     private QuantityType<?> calculatePower(ValueUnit voltage, ValueUnit current) {
231         QuantityType<?> qtyVoltage = getQuantityOrZero(voltage, Units.VOLT);
232         QuantityType<?> qtyCurrent = getQuantityOrZero(current, Units.AMPERE);
233         return qtyVoltage.multiply(qtyCurrent).toUnit(Units.WATT);
234     }
235 }