# Fronius Binding
-This binding uses the [Fronius Solar API V1](https://www.fronius.com/en/photovoltaics/products/all-products/system-monitoring/open-interfaces/fronius-solar-api-json-) to obtain data from a Fronius devices.
+This binding uses the [Fronius Solar API V1](https://www.fronius.com/en/photovoltaics/products/all-products/system-monitoring/open-interfaces/fronius-solar-api-json-) to obtain data from Fronius devices.
+It supports Fronius inverters and Fronius Smart Meter. Tested with a Fronius Symo 8.2-3-M and Fronius Smart Meter 63A.
## Supported Things
-Support Fronius Galvo, Fronius Symo inverters and other Fronius inverters in combination with the Fronius Datamanager 1.0 / 2.0 or Fronius Datalogger.
-You can add multiple inverters that depend on the same datalogger with different device ids. (Default 1)
+| Thing Type | Description |
+| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `bridge` | The Bridge |
+| `powerinverter` | Fronius Galvo, Symo and other Fronius inverters in combination with the Fronius Datamanager 1.0 / 2.0 or Fronius Datalogger. You can add multiple inverters that depend on the same datalogger with different device ids. (Default 1) |
+| `meter` | Fronius Smart Meter. You can add multiple smart meters with different device ids. (The default id = 0) |
## Discovery
## Binding Configuration
-The binding has no configuration options, all configuration is done at `bridge` or `powerinverter` level.
+The binding has no configuration options, all configuration is done at `bridge`, `powerinverter` or `meter` level.
## Thing Configuration
### Bridge Thing Configuration
-| Parameter | Description |
-|-----------------|------------------------------------------------------ |
-| hostname | The hostname or IP address of your Fronius Datalogger |
-| refreshInterval | Refresh interval in seconds |
+| Parameter | Description |
+| ----------------- | ----------------------------------------------------- |
+| `hostname` | The hostname or IP address of your Fronius Datalogger |
+| `refreshInterval` | Refresh interval in seconds |
### Powerinverter Thing Configuration
-| Parameter | Description |
-|-----------------|------------------------------------------------------ |
-| deviceId | The identifier of your device (Default: 1) |
+| Parameter | Description |
+| ---------- | ------------------------------------------ |
+| `deviceId` | The identifier of your device (Default: 1) |
+
+### Meter Thing Configuration
+
+| Parameter | Description |
+| ---------- | ----------------------------------------------- |
+| `deviceId` | The identifier of your smart meter (Default: 0) |
## Channels
-| Channel ID | Item Type | Description |
-|------------|--------------|------------------------- |
-| inverterdatachanneldayenergy | Number | Energy generated on current day |
-| inverterdatachannelpac | Number | AC powery |
-| inverterdatachanneltotal | Number | Energy generated overall |
-| inverterdatachannelyear | Number | Energy generated in current year |
-| inverterdatachannelfac | Number | AC frequency |
-| inverterdatachanneliac | Number | AC current |
-| inverterdatachannelidc | Number | DC current |
-| inverterdatachanneluac | Number | AC voltage |
-| inverterdatachanneludc | Number | DC voltage |
-| inverterdatadevicestatuserrorcode | Number | Device error code |
-| inverterdatadevicestatusstatuscode | Number | Device status code<br />`0` - `6` Startup<br />`7` Running <br />`8` Standby<br />`9` Bootloading<br />`10` Error |
-| powerflowchannelpgrid | Number | Power + from grid, - to grid |
-| powerflowchannelpload | Number | Power + generator, - consumer |
-| powerflowchannelpakku | Number | Power + charge, - discharge |
+### Channels for `powerinverter` Thing
+
+| Channel ID | Item Type | Description |
+| ------------------------------------ | --------- | ----------------------------------------------------------------------------------------------------------------- |
+| `inverterdatachanneldayenergy` | Number | Energy generated on current day |
+| `inverterdatachannelpac` | Number | AC power |
+| `inverterdatachanneltotal` | Number | Energy generated overall |
+| `inverterdatachannelyear` | Number | Energy generated in current year |
+| `inverterdatachannelfac` | Number | AC frequency |
+| `inverterdatachanneliac` | Number | AC current |
+| `inverterdatachannelidc` | Number | DC current |
+| `inverterdatachanneluac` | Number | AC voltage |
+| `inverterdatachanneludc` | Number | DC voltage |
+| `inverterdatadevicestatuserrorcode` | Number | Device error code |
+| `inverterdatadevicestatusstatuscode` | Number | Device status code<br />`0` - `6` Startup<br />`7` Running <br />`8` Standby<br />`9` Bootloading<br />`10` Error |
+| `powerflowchannelpgrid` | Number | Power + from grid, - to grid |
+| `powerflowchannelpload` | Number | Power + generator, - consumer |
+| `powerflowchannelpakku` | Number | Power + charge, - discharge |
+
+### Channels for `meter` Thing
+
+| Channel ID | Item Type | Description |
+| ----------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `enable` | Number | 1 = enabled, 0 = disabled |
+| `location` | Number | 0 = grid interconnection point (primary meter)<br/> 1 = load (primary meter) <br />3 = external generator (secondary meters)(multiple)<br />256-511 = subloads (secondary meters)(unique). Refer to Fronius Solar API. |
+| `currentacphase1` | Number:ElectricCurrent | AC Current on Phase 1 |
+| `currentacphase2` | Number:ElectricCurrent | AC Current on Phase 2 |
+| `currentacphase3` | Number:ElectricCurrent | AC Current on Phase 3 |
+| `voltageacphase1` | Number:ElectricPotential | AC Voltage on Phase 1 |
+| `voltageacphase2` | Number:ElectricPotential | AC Voltage on Phase 2 |
+| `voltageacphase3` | Number:ElectricPotential | AC Voltage on Phase 3 |
+| `powerrealphase1` | Number:Power | Real Power on Phase 1 |
+| `powerrealphase2` | Number:Power | Real Power on Phase 2 |
+| `powerrealphase3` | Number:Power | Real Power on Phase 3 |
+| `powerfactorphase1` | Number | Power Factor on Phase 1 |
+| `powerfactorphase2` | Number | Power Factor on Phase 2 |
+| `powerfactorphase3` | Number | Power Factor on Phase 3 |
+| `energyrealsumconsumed` | Number:Energy | Real Energy consumed |
+| `energyrealsumproduced` | Number:Energy | Real Energy produced |
+| |
+
+
+
+
+## Properties
+
+The `meter` thing has the following properties:
+
+| Property | Description |
+| -------- | ------------------------------ |
+| `model` | The model name of the meter |
+| `serial` | The serial number of the meter |
## Full Example
```
Bridge fronius:bridge:mybridge [hostname="192.168.66.148", refreshInterval=5] {
Thing powerinverter myinverter [deviceId=1]
+ Thing meter mymeter [deviceId=0]
}
```
demo.items:
```
-Number AC_Powery { channel="fronius:powerinverter:mybridge:myinverter:inverterdatachannelpac" }
+Number AC_Power { channel="fronius:powerinverter:mybridge:myinverter:inverterdatachannelpac" }
Number Day_Energy { channel="fronius:powerinverter:mybridge:myinverter:inverterdatachanneldayenergy" }
Number Total_Energy { channel="fronius:powerinverter:mybridge:myinverter:inverterdatachanneltotal" }
Number Year_Energy { channel="fronius:powerinverter:mybridge:myinverter:inverterdatachannelyear" }
Number Grid_Power { channel="fronius:powerinverter:mybridge:myinverter:powerflowchannelpgrid" }
Number Load_Power { channel="fronius:powerinverter:mybridge:myinverter:powerflowchannelpload" }
Number Battery_Power { channel="fronius:powerinverter:mybridge:myinverter:powerflowchannelpakku" }
-```
-Tested with a Fronius Symo 8.2-3-M
+Number Meter_Enable { channel="fronius:meter:mybridge:mymeter:enable" }
+Number Meter_Location { channel="fronius:meter:mybridge:mymeter:location" }
+Number:ElectricCurrent Meter_CurrentPhase1 { channel="fronius:meter:mybridge:mymeter:currentacphase1" }
+Number:ElectricCurrent Meter_CurrentPhase2 { channel="fronius:meter:mybridge:mymeter:currentacphase2" }
+Number:ElectricCurrent Meter_CurrentPhase3 { channel="fronius:meter:mybridge:mymeter:currentacphase3" }
+Number:Voltage Meter_VoltagePhase1 { channel="fronius:meter:mybridge:mymeter:voltageacphase1" }
+Number:Voltage Meter_VoltagePhase2 { channel="fronius:meter:mybridge:mymeter:voltageacphase2" }
+Number:Voltage Meter_VoltagePhase3 { channel="fronius:meter:mybridge:mymeter:voltageacphase3" }
+Number:Power Meter_PowerPhase1 { channel="fronius:meter:mybridge:mymeter:powerrealphase1" }
+Number:Power Meter_PowerPhase2 { channel="fronius:meter:mybridge:mymeter:powerrealphase2" }
+Number:Power Meter_PowerPhase3 { channel="fronius:meter:mybridge:mymeter:powerrealphase3" }
+Number Meter_PowerFactorPhase1 { channel="fronius:meter:mybridge:mymeter:powerfactorphase1" }
+Number Meter_PowerFactorPhase2 { channel="fronius:meter:mybridge:mymeter:powerfactorphase2" }
+Number Meter_PowerFactorPhase3 { channel="fronius:meter:mybridge:mymeter:powerfactorphase3" }
+Number:Energy Meter_EnergyConsumed { channel="fronius:meter:mybridge:mymeter:energyrealsumconsumed" }
+Number:Energy Meter_EnergyProduced { channel="fronius:meter:mybridge:mymeter:energyrealsumproduced" }
+```
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_INVERTER = new ThingTypeUID(BINDING_ID, "powerinverter");
public static final ThingTypeUID THING_TYPE_BRIDGE = new ThingTypeUID(BINDING_ID, "bridge");
+ public static final ThingTypeUID THING_TYPE_METER = new ThingTypeUID(BINDING_ID, "meter");
// List of all Channel ids
public static final String InverterDataChannelDayEnergy = "inverterdatachanneldayenergy";
public static final String PowerFlowpGrid = "powerflowchannelpgrid";
public static final String PowerFlowpLoad = "powerflowchannelpload";
public static final String PowerFlowpAkku = "powerflowchannelpakku";
+ public static final String MeterModel = "model";
+ public static final String MeterSerial = "serial";
+ public static final String MeterEnable = "enable";
+ public static final String MeterLocation = "location";
+ public static final String MeterCurrentAcPhase1 = "currentacphase1";
+ public static final String MeterCurrentAcPhase2 = "currentacphase2";
+ public static final String MeterCurrentAcPhase3 = "currentacphase3";
+ public static final String MeterVoltageAcPhase1 = "voltageacphase1";
+ public static final String MeterVoltageAcPhase2 = "voltageacphase2";
+ public static final String MeterVoltageAcPhase3 = "voltageacphase3";
+ public static final String MeterPowerPhase1 = "powerrealphase1";
+ public static final String MeterPowerPhase2 = "powerrealphase2";
+ public static final String MeterPowerPhase3 = "powerrealphase3";
+ public static final String MeterPowerFactorPhase1 = "powerfactorphase1";
+ public static final String MeterPowerFactorPhase2 = "powerfactorphase2";
+ public static final String MeterPowerFactorPhase3 = "powerfactorphase3";
+ public static final String MeterEnergyRealSumConsumed = "energyrealsumconsumed";
+ public static final String MeterEnergyRealSumProduced = "energyrealsumproduced";
// List of all Urls
public static final String INVERTER_REALTIME_DATA_URL = "http://%IP%/solar_api/v1/GetInverterRealtimeData.cgi?Scope=Device&DeviceId=%DEVICEID%&DataCollection=CommonInverterData";
public static final String POWERFLOW_REALTIME_DATA = "http://%IP%/solar_api/v1/GetPowerFlowRealtimeData.fcgi";
+ public static final String METER_REALTIME_DATA_URL = "http://%IP%/solar_api/v1/GetMeterRealtimeData.cgi?Scope=Device&DeviceId=%DEVICEID%&DataCollection=MeterRealtimeData";
}
import java.util.Set;
import org.openhab.binding.fronius.internal.handler.FroniusBridgeHandler;
+import org.openhab.binding.fronius.internal.handler.FroniusMeterHandler;
import org.openhab.binding.fronius.internal.handler.FroniusSymoInverterHandler;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
{
add(THING_TYPE_INVERTER);
add(THING_TYPE_BRIDGE);
+ add(THING_TYPE_METER);
}
};
return new FroniusSymoInverterHandler(thing);
} else if (thingTypeUID.equals(THING_TYPE_BRIDGE)) {
return new FroniusBridgeHandler((Bridge) thing);
+ } else if (thingTypeUID.equals(THING_TYPE_METER)) {
+ return new FroniusMeterHandler(thing);
}
return null;
}
--- /dev/null
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.fronius.internal.api;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * The {@link MeterRealtimeBody} is responsible for storing
+ * the "body" node of the JSON response
+ *
+ * @author Jimmy Tanagra - Initial contribution
+ */
+public class MeterRealtimeBodyDTO {
+ @SerializedName("Data")
+ private MeterRealtimeBodyDataDTO data;
+
+ public MeterRealtimeBodyDataDTO getData() {
+ if (data == null) {
+ data = new MeterRealtimeBodyDataDTO();
+ }
+ return data;
+ }
+
+ public void setData(MeterRealtimeBodyDataDTO data) {
+ this.data = data;
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.fronius.internal.api;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * The {@link MeterRealtimeBodyData} is responsible for storing
+ * the "data" node of the JSON response
+ *
+ * @author Jimmy Tanagra - Initial contribution
+ */
+public class MeterRealtimeBodyDataDTO {
+ @SerializedName("Current_AC_Phase_1")
+ private double currentACPhase1;
+ @SerializedName("Current_AC_Phase_2")
+ private double currentACPhase2;
+ @SerializedName("Current_AC_Phase_3")
+ private double currentACPhase3;
+ @SerializedName("Details")
+ private MeterRealtimeDetailsDTO details;
+ @SerializedName("Enable")
+ private int enable;
+ @SerializedName("EnergyReactive_VArAC_Sum_Consumed")
+ private int energyReactiveVArACSumConsumed;
+ @SerializedName("EnergyReactive_VArAC_Sum_Produced")
+ private int energyReactiveVArACSumProduced;
+ @SerializedName("EnergyReal_WAC_Minus_Absolute")
+ private int energyRealWACMinusAbsolute;
+ @SerializedName("EnergyReal_WAC_Plus_Absolute")
+ private int energyRealWACPlusAbsolute;
+ @SerializedName("EnergyReal_WAC_Sum_Consumed")
+ private int energyRealWACSumConsumed;
+ @SerializedName("EnergyReal_WAC_Sum_Produced")
+ private int energyRealWACSumProduced;
+ @SerializedName("Frequency_Phase_Average")
+ private double frequencyPhaseAverage;
+ @SerializedName("Meter_Location_Current")
+ private int meterLocationCurrent;
+ @SerializedName("PowerApparent_S_Phase_1")
+ private double powerApparentSPhase1;
+ @SerializedName("PowerApparent_S_Phase_2")
+ private double powerApparentSPhase2;
+ @SerializedName("PowerApparent_S_Phase_3")
+ private double powerApparentSPhase3;
+ @SerializedName("PowerApparent_S_Sum")
+ private int powerApparentSSum;
+ @SerializedName("PowerFactor_Phase_1")
+ private double powerFactorPhase1;
+ @SerializedName("PowerFactor_Phase_2")
+ private double powerFactorPhase2;
+ @SerializedName("PowerFactor_Phase_3")
+ private double powerFactorPhase3;
+ @SerializedName("PowerFactor_Sum")
+ private double powerFactorSum;
+ @SerializedName("PowerReactive_Q_Phase_1")
+ private double powerReactiveQPhase1;
+ @SerializedName("PowerReactive_Q_Phase_2")
+ private double powerReactiveQPhase2;
+ @SerializedName("PowerReactive_Q_Phase_3")
+ private double powerReactiveQPhase3;
+ @SerializedName("PowerReactive_Q_Sum")
+ private double powerReactiveQSum;
+ @SerializedName("PowerReal_P_Phase_1")
+ private double powerRealPPhase1;
+ @SerializedName("PowerReal_P_Phase_2")
+ private double powerRealPPhase2;
+ @SerializedName("PowerReal_P_Phase_3")
+ private double powerRealPPhase3;
+ @SerializedName("PowerReal_P_Sum")
+ private double powerRealPSum;
+ @SerializedName("TimeStamp")
+ private int timeStamp;
+ @SerializedName("Visible")
+ private int visible;
+ @SerializedName("Voltage_AC_PhaseToPhase_12")
+ private double voltageACPhaseToPhase12;
+ @SerializedName("Voltage_AC_PhaseToPhase_23")
+ private double voltageACPhaseToPhase23;
+ @SerializedName("Voltage_AC_PhaseToPhase_31")
+ private double voltageACPhaseToPhase31;
+ @SerializedName("Voltage_AC_Phase_1")
+ private double voltageACPhase1;
+ @SerializedName("Voltage_AC_Phase_2")
+ private double voltageACPhase2;
+ @SerializedName("Voltage_AC_Phase_3")
+ private double voltageACPhase3;
+
+ public double getCurrentACPhase1() {
+ return currentACPhase1;
+ }
+
+ public void setCurrentACPhase1(double currentACPhase1) {
+ this.currentACPhase1 = currentACPhase1;
+ }
+
+ public double getCurrentACPhase2() {
+ return currentACPhase2;
+ }
+
+ public void setCurrentACPhase2(double currentACPhase2) {
+ this.currentACPhase2 = currentACPhase2;
+ }
+
+ public double getCurrentACPhase3() {
+ return currentACPhase3;
+ }
+
+ public void setCurrentACPhase3(double currentACPhase3) {
+ this.currentACPhase3 = currentACPhase3;
+ }
+
+ public MeterRealtimeDetailsDTO getDetails() {
+ if (details == null) {
+ details = new MeterRealtimeDetailsDTO();
+ }
+ return details;
+ }
+
+ public void setDetails(MeterRealtimeDetailsDTO details) {
+ this.details = details;
+ }
+
+ public int getEnable() {
+ return enable;
+ }
+
+ public void setEnable(int enable) {
+ this.enable = enable;
+ }
+
+ public int getEnergyReactiveVArACSumConsumed() {
+ return energyReactiveVArACSumConsumed;
+ }
+
+ public void setEnergyReactiveVArACSumConsumed(int energyReactiveVArACSumConsumed) {
+ this.energyReactiveVArACSumConsumed = energyReactiveVArACSumConsumed;
+ }
+
+ public int getEnergyReactiveVArACSumProduced() {
+ return energyReactiveVArACSumProduced;
+ }
+
+ public void setEnergyReactiveVArACSumProduced(int energyReactiveVArACSumProduced) {
+ this.energyReactiveVArACSumProduced = energyReactiveVArACSumProduced;
+ }
+
+ public int getEnergyRealWACMinusAbsolute() {
+ return energyRealWACMinusAbsolute;
+ }
+
+ public void setEnergyRealWACMinusAbsolute(int energyRealWACMinusAbsolute) {
+ this.energyRealWACMinusAbsolute = energyRealWACMinusAbsolute;
+ }
+
+ public int getEnergyRealWACPlusAbsolute() {
+ return energyRealWACPlusAbsolute;
+ }
+
+ public void setEnergyRealWACPlusAbsolute(int energyRealWACPlusAbsolute) {
+ this.energyRealWACPlusAbsolute = energyRealWACPlusAbsolute;
+ }
+
+ public int getEnergyRealWACSumConsumed() {
+ return energyRealWACSumConsumed;
+ }
+
+ public void setEnergyRealWACSumConsumed(int energyRealWACSumConsumed) {
+ this.energyRealWACSumConsumed = energyRealWACSumConsumed;
+ }
+
+ public int getEnergyRealWACSumProduced() {
+ return energyRealWACSumProduced;
+ }
+
+ public void setEnergyRealWACSumProduced(int energyRealWACSumProduced) {
+ this.energyRealWACSumProduced = energyRealWACSumProduced;
+ }
+
+ public double getFrequencyPhaseAverage() {
+ return frequencyPhaseAverage;
+ }
+
+ public void setFrequencyPhaseAverage(double frequencyPhaseAverage) {
+ this.frequencyPhaseAverage = frequencyPhaseAverage;
+ }
+
+ public int getMeterLocationCurrent() {
+ return meterLocationCurrent;
+ }
+
+ public void setMeterLocationCurrent(int meterLocationCurrent) {
+ this.meterLocationCurrent = meterLocationCurrent;
+ }
+
+ public double getPowerApparentSPhase1() {
+ return powerApparentSPhase1;
+ }
+
+ public void setPowerApparentSPhase1(double powerApparentSPhase1) {
+ this.powerApparentSPhase1 = powerApparentSPhase1;
+ }
+
+ public double getPowerApparentSPhase2() {
+ return powerApparentSPhase2;
+ }
+
+ public void setPowerApparentSPhase2(double powerApparentSPhase2) {
+ this.powerApparentSPhase2 = powerApparentSPhase2;
+ }
+
+ public double getPowerApparentSPhase3() {
+ return powerApparentSPhase3;
+ }
+
+ public void setPowerApparentSPhase3(double powerApparentSPhase3) {
+ this.powerApparentSPhase3 = powerApparentSPhase3;
+ }
+
+ public int getPowerApparentSSum() {
+ return powerApparentSSum;
+ }
+
+ public void setPowerApparentSSum(int powerApparentSSum) {
+ this.powerApparentSSum = powerApparentSSum;
+ }
+
+ public double getPowerFactorPhase1() {
+ return powerFactorPhase1;
+ }
+
+ public void setPowerFactorPhase1(double powerFactorPhase1) {
+ this.powerFactorPhase1 = powerFactorPhase1;
+ }
+
+ public double getPowerFactorPhase2() {
+ return powerFactorPhase2;
+ }
+
+ public void setPowerFactorPhase2(double powerFactorPhase2) {
+ this.powerFactorPhase2 = powerFactorPhase2;
+ }
+
+ public double getPowerFactorPhase3() {
+ return powerFactorPhase3;
+ }
+
+ public void setPowerFactorPhase3(double powerFactorPhase3) {
+ this.powerFactorPhase3 = powerFactorPhase3;
+ }
+
+ public double getPowerFactorSum() {
+ return powerFactorSum;
+ }
+
+ public void setPowerFactorSum(double powerFactorSum) {
+ this.powerFactorSum = powerFactorSum;
+ }
+
+ public double getPowerReactiveQPhase1() {
+ return powerReactiveQPhase1;
+ }
+
+ public void setPowerReactiveQPhase1(double powerReactiveQPhase1) {
+ this.powerReactiveQPhase1 = powerReactiveQPhase1;
+ }
+
+ public double getPowerReactiveQPhase2() {
+ return powerReactiveQPhase2;
+ }
+
+ public void setPowerReactiveQPhase2(double powerReactiveQPhase2) {
+ this.powerReactiveQPhase2 = powerReactiveQPhase2;
+ }
+
+ public double getPowerReactiveQPhase3() {
+ return powerReactiveQPhase3;
+ }
+
+ public void setPowerReactiveQPhase3(double powerReactiveQPhase3) {
+ this.powerReactiveQPhase3 = powerReactiveQPhase3;
+ }
+
+ public double getPowerReactiveQSum() {
+ return powerReactiveQSum;
+ }
+
+ public void setPowerReactiveQSum(double powerReactiveQSum) {
+ this.powerReactiveQSum = powerReactiveQSum;
+ }
+
+ public double getPowerRealPPhase1() {
+ return powerRealPPhase1;
+ }
+
+ public void setPowerRealPPhase1(double powerRealPPhase1) {
+ this.powerRealPPhase1 = powerRealPPhase1;
+ }
+
+ public double getPowerRealPPhase2() {
+ return powerRealPPhase2;
+ }
+
+ public void setPowerRealPPhase2(double powerRealPPhase2) {
+ this.powerRealPPhase2 = powerRealPPhase2;
+ }
+
+ public double getPowerRealPPhase3() {
+ return powerRealPPhase3;
+ }
+
+ public void setPowerRealPPhase3(double powerRealPPhase3) {
+ this.powerRealPPhase3 = powerRealPPhase3;
+ }
+
+ public double getPowerRealPSum() {
+ return powerRealPSum;
+ }
+
+ public void setPowerRealPSum(double powerRealPSum) {
+ this.powerRealPSum = powerRealPSum;
+ }
+
+ public int getTimeStamp() {
+ return timeStamp;
+ }
+
+ public void setTimeStamp(int timeStamp) {
+ this.timeStamp = timeStamp;
+ }
+
+ public int getVisible() {
+ return visible;
+ }
+
+ public void setVisible(int visible) {
+ this.visible = visible;
+ }
+
+ public double getVoltageACPhaseToPhase12() {
+ return voltageACPhaseToPhase12;
+ }
+
+ public void setVoltageACPhaseToPhase12(double voltageACPhaseToPhase12) {
+ this.voltageACPhaseToPhase12 = voltageACPhaseToPhase12;
+ }
+
+ public double getVoltageACPhaseToPhase23() {
+ return voltageACPhaseToPhase23;
+ }
+
+ public void setVoltageACPhaseToPhase23(double voltageACPhaseToPhase23) {
+ this.voltageACPhaseToPhase23 = voltageACPhaseToPhase23;
+ }
+
+ public double getVoltageACPhaseToPhase31() {
+ return voltageACPhaseToPhase31;
+ }
+
+ public void setVoltageACPhaseToPhase31(double voltageACPhaseToPhase31) {
+ this.voltageACPhaseToPhase31 = voltageACPhaseToPhase31;
+ }
+
+ public double getVoltageACPhase1() {
+ return voltageACPhase1;
+ }
+
+ public void setVoltageACPhase1(double voltageACPhase1) {
+ this.voltageACPhase1 = voltageACPhase1;
+ }
+
+ public double getVoltageACPhase2() {
+ return voltageACPhase2;
+ }
+
+ public void setVoltageACPhase2(double voltageACPhase2) {
+ this.voltageACPhase2 = voltageACPhase2;
+ }
+
+ public double getVoltageACPhase3() {
+ return voltageACPhase3;
+ }
+
+ public void setVoltageACPhase3(double voltageACPhase3) {
+ this.voltageACPhase3 = voltageACPhase3;
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.fronius.internal.api;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * The {@link MeterRealtimeDetails} is responsible for storing
+ * the "body" node of the JSON response
+ *
+ * @author Jimmy Tanagra - Initial contribution
+ */
+public class MeterRealtimeDetailsDTO {
+ @SerializedName("Manufacturer")
+ private String manufacturer;
+ @SerializedName("Model")
+ private String model;
+ @SerializedName("Serial")
+ private String serial;
+
+ public String getManufacturer() {
+ return manufacturer;
+ }
+
+ public void setManufacturer(String manufacturer) {
+ this.manufacturer = manufacturer;
+ }
+
+ public String getModel() {
+ return model;
+ }
+
+ public void setModel(String model) {
+ this.model = model;
+ }
+
+ public String getSerial() {
+ return serial;
+ }
+
+ public void setSerial(String serial) {
+ this.serial = serial;
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.fronius.internal.api;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * The {@link MeterRealtimeResponse} is responsible for storing
+ * the response from the powerflowrealtime api
+ *
+ * @author Jimmy Tanagra - Initial contribution
+ */
+public class MeterRealtimeResponseDTO extends BaseFroniusResponse {
+ @SerializedName("Body")
+ private MeterRealtimeBodyDTO body;
+
+ public MeterRealtimeBodyDTO getBody() {
+ if (body == null) {
+ body = new MeterRealtimeBodyDTO();
+ }
+ return body;
+ }
+
+ public void setBody(MeterRealtimeBodyDTO body) {
+ this.body = body;
+ }
+}
*/
package org.openhab.binding.fronius.internal.handler;
+import java.io.IOException;
import java.math.BigDecimal;
import org.openhab.binding.fronius.internal.FroniusBridgeConfiguration;
+import org.openhab.binding.fronius.internal.api.BaseFroniusResponse;
import org.openhab.binding.fronius.internal.api.ValueUnit;
+import org.openhab.core.io.net.http.HttpUtil;
import org.openhab.core.library.types.DecimalType;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
+import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.gson.Gson;
+import com.google.gson.JsonSyntaxException;
+
/**
* Basic Handler class for all Fronius services.
*
*/
public abstract class FroniusBaseThingHandler extends BaseThingHandler {
+ private static final int API_TIMEOUT = 5000;
private final Logger logger = LoggerFactory.getLogger(FroniusBaseThingHandler.class);
private final String serviceDescription;
private FroniusBridgeHandler bridgeHandler;
+ private final Gson gson;
public FroniusBaseThingHandler(Thing thing) {
super(thing);
+ gson = new Gson();
serviceDescription = getDescription();
}
state = new DecimalType((double) value);
} else if (value instanceof ValueUnit) {
state = new DecimalType(((ValueUnit) value).getValue());
+ } else if (value instanceof String) {
+ state = new StringType((String) value);
+ } else if (value instanceof QuantityType) {
+ state = (QuantityType) value;
} else {
logger.warn("Update channel {}: Unsupported value type {}", channelId, value.getClass().getSimpleName());
}
* @param bridgeConfiguration the connected bridge configuration
*/
public abstract void refresh(FroniusBridgeConfiguration bridgeConfiguration);
+
+ /**
+ *
+ * @param type response class type
+ * @param url to request
+ * @return the object representation of the json response
+ */
+ protected <T extends BaseFroniusResponse> T collectDataFormUrl(Class<T> type, String url) {
+ T result = null;
+ boolean resultOk = false;
+ String errorMsg = null;
+
+ try {
+ logger.debug("URL = {}", url);
+ String response = HttpUtil.executeUrl("GET", url, API_TIMEOUT);
+
+ if (response != null) {
+ logger.debug("aqiResponse = {}", response);
+ result = gson.fromJson(response, type);
+ }
+
+ if (result == null) {
+ errorMsg = "no data returned";
+ } else {
+ if (result.getHead().getStatus().getCode() == 0) {
+ resultOk = true;
+ } else {
+ errorMsg = result.getHead().getStatus().getReason();
+ }
+ }
+ if (!resultOk) {
+ logger.debug("Error in fronius response: {}", errorMsg);
+ }
+ } catch (JsonSyntaxException e) {
+ errorMsg = "Invalid JSON data received";
+ logger.debug("Error running fronius request: {}", errorMsg);
+ } catch (IOException | IllegalStateException e) {
+ errorMsg = e.getMessage();
+ logger.debug("Error running fronius request: {}", errorMsg);
+ }
+
+ // Update the thing status
+ if (resultOk) {
+ updateStatus(ThingStatus.ONLINE);
+ } else {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, errorMsg);
+ }
+ return resultOk ? result : null;
+ }
}
--- /dev/null
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.fronius.internal.handler;
+
+import java.util.Map;
+
+import org.apache.commons.lang.StringUtils;
+import org.openhab.binding.fronius.internal.FroniusBaseDeviceConfiguration;
+import org.openhab.binding.fronius.internal.FroniusBindingConstants;
+import org.openhab.binding.fronius.internal.FroniusBridgeConfiguration;
+import org.openhab.binding.fronius.internal.api.MeterRealtimeBodyDataDTO;
+import org.openhab.binding.fronius.internal.api.MeterRealtimeResponseDTO;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.unit.Units;
+import org.openhab.core.thing.Thing;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link FroniusMeterHandler} is responsible for updating the data, which are
+ * sent to one of the channels.
+ *
+ * @author Jimmy Tanagra - Initial contribution
+ */
+public class FroniusMeterHandler extends FroniusBaseThingHandler {
+
+ private final Logger logger = LoggerFactory.getLogger(FroniusMeterHandler.class);
+ private MeterRealtimeBodyDataDTO meterRealtimeBodyData;
+ private FroniusBaseDeviceConfiguration config;
+
+ public FroniusMeterHandler(Thing thing) {
+ super(thing);
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Fronius Smart Meter";
+ }
+
+ @Override
+ public void refresh(FroniusBridgeConfiguration bridgeConfiguration) {
+ updateData(bridgeConfiguration, config);
+ updateChannels();
+ updateProperties();
+ }
+
+ @Override
+ public void initialize() {
+ config = getConfigAs(FroniusBaseDeviceConfiguration.class);
+ super.initialize();
+ }
+
+ /**
+ * Update the channel from the last data retrieved
+ *
+ * @param channelId the id identifying the channel to be updated
+ * @return the last retrieved data
+ */
+ @Override
+ protected Object getValue(String channelId) {
+ if (meterRealtimeBodyData == null) {
+ return null;
+ }
+
+ String[] fields = StringUtils.split(channelId, "#");
+ String fieldName = fields[0];
+
+ switch (fieldName) {
+ case FroniusBindingConstants.MeterEnable:
+ return meterRealtimeBodyData.getEnable();
+ case FroniusBindingConstants.MeterLocation:
+ return meterRealtimeBodyData.getMeterLocationCurrent();
+ case FroniusBindingConstants.MeterCurrentAcPhase1:
+ return new QuantityType(meterRealtimeBodyData.getCurrentACPhase1(), Units.AMPERE);
+ case FroniusBindingConstants.MeterCurrentAcPhase2:
+ return new QuantityType(meterRealtimeBodyData.getCurrentACPhase2(), Units.AMPERE);
+ case FroniusBindingConstants.MeterCurrentAcPhase3:
+ return new QuantityType(meterRealtimeBodyData.getCurrentACPhase3(), Units.AMPERE);
+ case FroniusBindingConstants.MeterVoltageAcPhase1:
+ return new QuantityType(meterRealtimeBodyData.getVoltageACPhase1(), Units.VOLT);
+ case FroniusBindingConstants.MeterVoltageAcPhase2:
+ return new QuantityType(meterRealtimeBodyData.getVoltageACPhase2(), Units.VOLT);
+ case FroniusBindingConstants.MeterVoltageAcPhase3:
+ return new QuantityType(meterRealtimeBodyData.getVoltageACPhase3(), Units.VOLT);
+ case FroniusBindingConstants.MeterPowerPhase1:
+ return new QuantityType(meterRealtimeBodyData.getPowerRealPPhase1(), Units.WATT);
+ case FroniusBindingConstants.MeterPowerPhase2:
+ return new QuantityType(meterRealtimeBodyData.getPowerRealPPhase2(), Units.WATT);
+ case FroniusBindingConstants.MeterPowerPhase3:
+ return new QuantityType(meterRealtimeBodyData.getPowerRealPPhase3(), Units.WATT);
+ case FroniusBindingConstants.MeterPowerFactorPhase1:
+ return meterRealtimeBodyData.getPowerFactorPhase1();
+ case FroniusBindingConstants.MeterPowerFactorPhase2:
+ return meterRealtimeBodyData.getPowerFactorPhase2();
+ case FroniusBindingConstants.MeterPowerFactorPhase3:
+ return meterRealtimeBodyData.getPowerFactorPhase3();
+ case FroniusBindingConstants.MeterEnergyRealSumConsumed:
+ return new QuantityType(meterRealtimeBodyData.getEnergyRealWACSumConsumed(), Units.WATT_HOUR);
+ case FroniusBindingConstants.MeterEnergyRealSumProduced:
+ return new QuantityType(meterRealtimeBodyData.getEnergyRealWACSumProduced(), Units.WATT_HOUR);
+ }
+
+ return null;
+ }
+
+ private void updateProperties() {
+ if (meterRealtimeBodyData == null) {
+ return;
+ }
+
+ Map<String, String> properties = editProperties();
+
+ properties.put(FroniusBindingConstants.MeterModel, meterRealtimeBodyData.getDetails().getModel());
+ properties.put(FroniusBindingConstants.MeterSerial, meterRealtimeBodyData.getDetails().getSerial());
+
+ updateProperties(properties);
+ }
+
+ /**
+ * Get new data
+ */
+ private void updateData(FroniusBridgeConfiguration bridgeConfiguration, FroniusBaseDeviceConfiguration config) {
+ MeterRealtimeResponseDTO meterRealtimeResponse = getMeterRealtimeData(bridgeConfiguration.hostname,
+ config.deviceId);
+ if (meterRealtimeResponse == null) {
+ meterRealtimeBodyData = null;
+ } else {
+ meterRealtimeBodyData = meterRealtimeResponse.getBody().getData();
+ }
+ }
+
+ /**
+ * Make the MeterRealtimeData request
+ *
+ * @param ip address of the device
+ * @param deviceId of the device
+ * @return {MeterRealtimeResponse} the object representation of the json response
+ */
+ private MeterRealtimeResponseDTO getMeterRealtimeData(String ip, int deviceId) {
+ String location = FroniusBindingConstants.METER_REALTIME_DATA_URL.replace("%IP%", StringUtils.trimToEmpty(ip));
+ location = location.replace("%DEVICEID%", Integer.toString(deviceId));
+ return collectDataFormUrl(MeterRealtimeResponseDTO.class, location);
+ }
+}
*/
package org.openhab.binding.fronius.internal.handler;
-import java.io.IOException;
-
import org.apache.commons.lang.StringUtils;
import org.openhab.binding.fronius.internal.FroniusBaseDeviceConfiguration;
import org.openhab.binding.fronius.internal.FroniusBindingConstants;
import org.openhab.binding.fronius.internal.FroniusBridgeConfiguration;
-import org.openhab.binding.fronius.internal.api.BaseFroniusResponse;
import org.openhab.binding.fronius.internal.api.InverterRealtimeResponse;
import org.openhab.binding.fronius.internal.api.PowerFlowRealtimeResponse;
import org.openhab.binding.fronius.internal.api.ValueUnit;
-import org.openhab.core.io.net.http.HttpUtil;
import org.openhab.core.thing.Thing;
-import org.openhab.core.thing.ThingStatus;
-import org.openhab.core.thing.ThingStatusDetail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.gson.Gson;
-import com.google.gson.JsonSyntaxException;
-
/**
* The {@link FroniusSymoInverterHandler} is responsible for updating the data, which are
* sent to one of the channels.
*/
public class FroniusSymoInverterHandler extends FroniusBaseThingHandler {
- private static final int API_TIMEOUT = 5000;
private final Logger logger = LoggerFactory.getLogger(FroniusSymoInverterHandler.class);
private InverterRealtimeResponse inverterRealtimeResponse;
private PowerFlowRealtimeResponse powerFlowResponse;
private FroniusBaseDeviceConfiguration config;
- private final Gson gson;
public FroniusSymoInverterHandler(Thing thing) {
super(thing);
- gson = new Gson();
}
@Override
powerFlowResponse = getPowerFlowRealtime(bridgeConfiguration.hostname);
}
- /**
- *
- * @param type response class type
- * @param url to request
- * @return the object representation of the json response
- */
- private <T extends BaseFroniusResponse> T collectDataFormUrl(Class<T> type, String url) {
- T result = null;
- boolean resultOk = false;
- String errorMsg = null;
-
- try {
- logger.debug("URL = {}", url);
- String response = HttpUtil.executeUrl("GET", url, API_TIMEOUT);
-
- if (response != null) {
- logger.debug("aqiResponse = {}", response);
- result = gson.fromJson(response, type);
- }
-
- if (result == null) {
- errorMsg = "no data returned";
- } else {
- if (result.getHead().getStatus().getCode() == 0) {
- resultOk = true;
- } else {
- errorMsg = result.getHead().getStatus().getReason();
- }
- }
- if (!resultOk) {
- logger.debug("Error in fronius response: {}", errorMsg);
- }
- } catch (JsonSyntaxException e) {
- errorMsg = "Configuration is incorrect";
- logger.debug("Error running fronius request: {}", errorMsg);
- } catch (IOException | IllegalStateException e) {
- logger.debug("Error running fronius request: {}", e.getMessage());
- }
-
- // Update the thing status
- if (resultOk) {
- updateStatus(ThingStatus.ONLINE);
- } else {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, errorMsg);
- }
- return resultOk ? result : null;
- }
-
/**
* Make the PowerFlowRealtimeDataRequest
*
</config-description>
</thing-type>
+ <!-- Meter Thing Type -->
+ <thing-type id="meter">
+ <supported-bridge-type-refs>
+ <bridge-type-ref id="bridge"/>
+ </supported-bridge-type-refs>
+ <label>Fronius Smart Meter</label>
+ <description>Fronius Smart Meter</description>
+
+ <channels>
+ <channel id="enable" typeId="meter_enable"/>
+ <channel id="location" typeId="meter_location"/>
+ <channel id="currentacphase1" typeId="meter_ac_current">
+ <label>AC Current Phase 1</label>
+ </channel>
+ <channel id="currentacphase2" typeId="meter_ac_current">
+ <label>AC Current Phase 2</label>
+ </channel>
+ <channel id="currentacphase3" typeId="meter_ac_current">
+ <label>AC Current Phase 3</label>
+ </channel>
+ <channel id="voltageacphase1" typeId="meter_ac_voltage">
+ <label>AC Voltage Phase 1</label>
+ </channel>
+ <channel id="voltageacphase2" typeId="meter_ac_voltage">
+ <label>AC Voltage Phase 2</label>
+ </channel>
+ <channel id="voltageacphase3" typeId="meter_ac_voltage">
+ <label>AC Voltage Phase 3</label>
+ </channel>
+ <channel id="powerrealphase1" typeId="meter_powerreal">
+ <label>Real Power Phase 1</label>
+ </channel>
+ <channel id="powerrealphase2" typeId="meter_powerreal">
+ <label>Real Power Phase 2</label>
+ </channel>
+ <channel id="powerrealphase3" typeId="meter_powerreal">
+ <label>Real Power Phase 3</label>
+ </channel>
+ <channel id="powerfactorphase1" typeId="meter_powerfactor">
+ <label>Power Factor Phase 1</label>
+ </channel>
+ <channel id="powerfactorphase2" typeId="meter_powerfactor">
+ <label>Power Factor Phase 2</label>
+ </channel>
+ <channel id="powerfactorphase3" typeId="meter_powerfactor">
+ <label>Power Factor Phase 3</label>
+ </channel>
+ <channel id="energyrealsumconsumed" typeId="meter_energy">
+ <label>Real Energy Consumed</label>
+ </channel>
+ <channel id="energyrealsumproduced" typeId="meter_energy">
+ <label>Real Energy Produced</label>
+ </channel>
+ </channels>
+
+ <properties>
+ <property name="model"/>
+ <property name="serial"/>
+ </properties>
+
+ <config-description>
+ <parameter name="deviceId" type="integer">
+ <label>Device ID</label>
+ <description>Specific device identifier</description>
+ <default>0</default>
+ </parameter>
+ </config-description>
+ </thing-type>
+
<channel-type id="day_energy">
<item-type>Number</item-type>
<label>Day Energy</label>
<description>Battery Power ( + charge, - discharge )</description>
<state pattern="%.2f W" readOnly="true"></state>
</channel-type>
+
+
+ <channel-type id="meter_enable" advanced="true">
+ <item-type>Number</item-type>
+ <label>Enabled</label>
+ <description>Enabled</description>
+ <state readOnly="true"></state>
+ </channel-type>
+ <channel-type id="meter_location" advanced="true">
+ <item-type>Number</item-type>
+ <label>Location</label>
+ <description>Meter location code</description>
+ <state readOnly="true"></state>
+ </channel-type>
+ <channel-type id="meter_ac_current">
+ <item-type>Number:ElectricCurrent</item-type>
+ <label>AC Current</label>
+ <description></description>
+ <state pattern="%.2f %unit%" readOnly="true"></state>
+ </channel-type>
+ <channel-type id="meter_ac_voltage">
+ <item-type>Number:ElectricPotential</item-type>
+ <label>AC Voltage</label>
+ <description></description>
+ <state pattern="%.2f %unit%" readOnly="true"></state>
+ </channel-type>
+ <channel-type id="meter_powerreal">
+ <item-type>Number:Power</item-type>
+ <label>Power</label>
+ <description></description>
+ <state pattern="%.2f %unit%" readOnly="true"></state>
+ </channel-type>
+ <channel-type id="meter_powerfactor">
+ <item-type>Number</item-type>
+ <label>Power Factor</label>
+ <description></description>
+ <state pattern="%.2f" readOnly="true"></state>
+ </channel-type>
+ <channel-type id="meter_energy">
+ <item-type>Number:Energy</item-type>
+ <label>Energy</label>
+ <description></description>
+ <state pattern="%.2f %unit%" readOnly="true"></state>
+ </channel-type>
+
</thing:thing-descriptions>