added migrated 2.x add-ons

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer
2020-09-21 01:58:32 +02:00
parent bbf1a7fd29
commit 6df6783b60
11662 changed files with 1302875 additions and 11 deletions

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.fronius-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
<feature name="openhab-binding-fronius" description="Fronius Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.fronius/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,23 @@
/**
* 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;
/**
* The {@link FroniusBaseDeviceConfiguration} is the class used to match the
* thing configuration.
*
* @author Thomas Rokohl - Initial contribution
*/
public class FroniusBaseDeviceConfiguration {
public Integer deviceId;
}

View File

@@ -0,0 +1,53 @@
/**
* 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;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link FroniusBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Thomas Rokohl - Initial contribution
* @author Peter Schraffl - Added device status and error status channels
*/
@NonNullByDefault
public class FroniusBindingConstants {
private static final String BINDING_ID = "fronius";
// 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");
// List of all Channel ids
public static final String InverterDataChannelDayEnergy = "inverterdatachanneldayenergy";
public static final String InverterDataChannelPac = "inverterdatachannelpac";
public static final String InverterDataChannelTotal = "inverterdatachanneltotal";
public static final String InverterDataChannelYear = "inverterdatachannelyear";
public static final String InverterDataChannelFac = "inverterdatachannelfac";
public static final String InverterDataChannelIac = "inverterdatachanneliac";
public static final String InverterDataChannelIdc = "inverterdatachannelidc";
public static final String InverterDataChannelUac = "inverterdatachanneluac";
public static final String InverterDataChannelUdc = "inverterdatachanneludc";
public static final String InverterDataChannelDeviceStatusErrorCode = "inverterdatadevicestatuserrorcode";
public static final String InverterDataChannelDeviceStatusStatusCode = "inverterdatadevicestatusstatuscode";
public static final String PowerFlowpGrid = "powerflowchannelpgrid";
public static final String PowerFlowpLoad = "powerflowchannelpload";
public static final String PowerFlowpAkku = "powerflowchannelpakku";
// 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";
}

View File

@@ -0,0 +1,24 @@
/**
* 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;
/**
* The {@link FroniusBridgeConfiguration} is the class used to match the
* bridge configuration.
*
* @author Thomas Rokohl - Initial contribution
*/
public class FroniusBridgeConfiguration {
public String hostname;
public Integer refreshInterval;
}

View File

@@ -0,0 +1,64 @@
/**
* 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;
import static org.openhab.binding.fronius.internal.FroniusBindingConstants.*;
import java.util.HashSet;
import java.util.Set;
import org.openhab.binding.fronius.internal.handler.FroniusBridgeHandler;
import org.openhab.binding.fronius.internal.handler.FroniusSymoInverterHandler;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Component;
/**
* The {@link FroniusHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Thomas Rokohl - Initial contribution
*/
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.fronius")
public class FroniusHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = new HashSet<ThingTypeUID>() {
private static final long serialVersionUID = 1L;
{
add(THING_TYPE_INVERTER);
add(THING_TYPE_BRIDGE);
}
};
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
protected ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (thingTypeUID.equals(THING_TYPE_INVERTER)) {
return new FroniusSymoInverterHandler(thing);
} else if (thingTypeUID.equals(THING_TYPE_BRIDGE)) {
return new FroniusBridgeHandler((Bridge) thing);
}
return null;
}
}

View File

@@ -0,0 +1,36 @@
/**
* 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;
/**
* base class for a response-object from the API
*
* @author Thomas Rokohl - Initial contribution
*/
public class BaseFroniusResponse {
@SerializedName("Head")
private Head head;
public Head getHead() {
if (head == null) {
head = new Head();
}
return head;
}
public void setHead(Head head) {
this.head = head;
}
}

View File

@@ -0,0 +1,84 @@
/**
* 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 DeviceStatus} is responsible for storing
* the "devicestatus" node
*
* @author Thomas Rokohl - Initial contribution
*/
public class DeviceStatus {
@SerializedName("StatusCode")
private int statusCode;
@SerializedName("MgmtTimerRemainingTime")
private int mgmtTimerRemainingTime;
@SerializedName("ErrorCode")
private int errorCode;
@SerializedName("LEDColor")
private int ledColor;
@SerializedName("LEDState")
private int ledState;
@SerializedName("StateToReset")
private boolean stateToReset;
public int getStatusCode() {
return statusCode;
}
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}
public int getMgmtTimerRemainingTime() {
return mgmtTimerRemainingTime;
}
public void setMgmtTimerRemainingTime(int mgmtTimerRemainingTime) {
this.mgmtTimerRemainingTime = mgmtTimerRemainingTime;
}
public int getErrorCode() {
return errorCode;
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
public int getLedColor() {
return ledColor;
}
public void setLedColor(int ledColor) {
this.ledColor = ledColor;
}
public int getLedState() {
return ledState;
}
public void setLedState(int ledState) {
this.ledState = ledState;
}
public boolean isStateToReset() {
return stateToReset;
}
public void setStateToReset(boolean stateToReset) {
this.stateToReset = stateToReset;
}
}

View File

@@ -0,0 +1,68 @@
/**
* 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 Head} is responsible for storing
* the "head" node of the JSON response from the Fronius Solar APIs (V1)
*
* The contents of the response object will vary depending on the preceding request but it always contains a common
* response header and a request body.
*
* @author Thomas Rokohl - Initial contribution
*/
public class Head {
@SerializedName("RequestArguments")
private HeadRequestArguments requestArguments;
@SerializedName("Status")
private HeadStatus status;
@SerializedName("Timestamp")
private String timestamp;
public HeadRequestArguments getRequestArguments() {
if (requestArguments == null) {
requestArguments = new HeadRequestArguments();
}
return requestArguments;
}
public void setRequestArguments(HeadRequestArguments requestArguments) {
this.requestArguments = requestArguments;
}
public HeadStatus getStatus() {
if (status == null) {
status = new HeadStatus();
status.setCode(255);
status.setReason("undefined runtime error");
}
return status;
}
public void setStatus(HeadStatus status) {
this.status = status;
}
public String getTimestamp() {
if (timestamp == null) {
timestamp = "";
}
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
}

View File

@@ -0,0 +1,76 @@
/**
* 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 HeadRequestArguments} is responsible for storing
* the "RequestArguments" node from the {@link Head}
*
* @author Thomas Rokohl - Initial contribution
*/
public class HeadRequestArguments {
@SerializedName("DataCollection")
private String dataCollection;
@SerializedName("DeviceClass")
private String deviceClass;
@SerializedName("DeviceId")
private String deviceId;
@SerializedName("Scope")
private String scope;
public String getDataCollection() {
if (null == dataCollection) {
dataCollection = "";
}
return dataCollection;
}
public void setDataCollection(String dataCollection) {
this.dataCollection = dataCollection;
}
public String getDeviceClass() {
if (null == deviceClass) {
deviceClass = "";
}
return deviceClass;
}
public void setDeviceClass(String deviceClass) {
this.deviceClass = deviceClass;
}
public String getDeviceId() {
if (null == deviceId) {
deviceId = "";
}
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getScope() {
if (null == scope) {
scope = "";
}
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
}

View File

@@ -0,0 +1,60 @@
/**
* 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 HeadStatus} is responsible for storing
* the "status" node from the {@link Head}
*
* @author Thomas Rokohl - Initial contribution
*/
public class HeadStatus {
@SerializedName("Code")
private int code;
@SerializedName("Reason")
private String reason;
@SerializedName("UserMessage")
private String userMessage;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getReason() {
if (reason == null) {
reason = "";
}
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
public String getUserMessage() {
if (userMessage == null) {
userMessage = "";
}
return userMessage;
}
public void setUserMessage(String userMessage) {
this.userMessage = userMessage;
}
}

View File

@@ -0,0 +1,37 @@
/**
* 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 InverterRealtimeBody} is responsible for storing
* the "body" node of the JSON response
*
* @author Thomas Rokohl - Initial contribution
*/
public class InverterRealtimeBody {
@SerializedName("Data")
private InverterRealtimeBodyData data;
public InverterRealtimeBodyData getData() {
if (data == null) {
data = new InverterRealtimeBodyData();
}
return data;
}
public void setData(InverterRealtimeBodyData data) {
this.data = data;
}
}

View File

@@ -0,0 +1,128 @@
/**
* 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 InverterRealtimeBodyData} is responsible for storing
* the "data" node of the JSON response
*
* @author Thomas Rokohl - Initial contribution
*/
public class InverterRealtimeBodyData {
@SerializedName("DAY_ENERGY")
private ValueUnit dayEnergy;
@SerializedName("FAC")
private ValueUnit fac;
@SerializedName("IAC")
private ValueUnit iac;
@SerializedName("IDC")
private ValueUnit idc;
@SerializedName("PAC")
private ValueUnit pac;
@SerializedName("TOTAL_ENERGY")
private ValueUnit totalEnergy;
@SerializedName("UAC")
private ValueUnit uac;
@SerializedName("UDC")
private ValueUnit udc;
@SerializedName("YEAR_ENERGY")
private ValueUnit yearEnergy;
@SerializedName("DeviceStatus")
private DeviceStatus deviceStatus;
public ValueUnit getDayEnergy() {
return dayEnergy;
}
public void setDayEnergy(ValueUnit dayEnergy) {
this.dayEnergy = dayEnergy;
}
public ValueUnit getPac() {
return pac;
}
public void setPac(ValueUnit pac) {
this.pac = pac;
}
public ValueUnit getTotalEnergy() {
return totalEnergy;
}
public void setTotalEnergy(ValueUnit totalEnergy) {
this.totalEnergy = totalEnergy;
}
public ValueUnit getYearEnergy() {
return yearEnergy;
}
public void setYearEnergy(ValueUnit yearEnergy) {
this.yearEnergy = yearEnergy;
}
public DeviceStatus getDeviceStatus() {
if (deviceStatus == null) {
deviceStatus = new DeviceStatus();
}
return deviceStatus;
}
public void setDeviceStatus(DeviceStatus deviceStatus) {
this.deviceStatus = deviceStatus;
}
public ValueUnit getFac() {
return fac;
}
public void setFac(ValueUnit fac) {
this.fac = fac;
}
public ValueUnit getIac() {
return iac;
}
public void setIac(ValueUnit iac) {
this.iac = iac;
}
public ValueUnit getIdc() {
return idc;
}
public void setIdc(ValueUnit idc) {
this.idc = idc;
}
public ValueUnit getUac() {
return uac;
}
public void setUac(ValueUnit uac) {
this.uac = uac;
}
public ValueUnit getUdc() {
return udc;
}
public void setUdc(ValueUnit udc) {
this.udc = udc;
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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 InverterRealtimeResponse} is responsible for storing
* the response from the realtime api
*
* @author Thomas Rokohl - Initial contribution
*/
public class InverterRealtimeResponse extends BaseFroniusResponse {
@SerializedName("Body")
private InverterRealtimeBody body;
public InverterRealtimeBody getBody() {
if (body == null) {
body = new InverterRealtimeBody();
}
return body;
}
public void setBody(InverterRealtimeBody body) {
this.body = body;
}
}

View File

@@ -0,0 +1,37 @@
/**
* 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 PowerFlowRealtimeBody} is responsible for storing
* the "body" node of the JSON response
*
* @author Thomas Rokohl - Initial contribution
*/
public class PowerFlowRealtimeBody {
@SerializedName("Data")
private PowerFlowRealtimeBodyData data;
public PowerFlowRealtimeBodyData getData() {
if (data == null) {
data = new PowerFlowRealtimeBodyData();
}
return data;
}
public void setData(PowerFlowRealtimeBodyData data) {
this.data = data;
}
}

View File

@@ -0,0 +1,55 @@
/**
* 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 java.util.HashMap;
import java.util.Map;
import com.google.gson.annotations.SerializedName;
/**
* The {@link PowerFlowRealtimeBodyData} is responsible for storing
* the "data" node of the JSON response
*
* @author Thomas Rokohl - Initial contribution
*/
public class PowerFlowRealtimeBodyData {
@SerializedName("Site")
private PowerFlowRealtimeSite site;
@SerializedName("Inverters")
private Map<String, PowerFlowRealtimeInverter> inverters;
public Map<String, PowerFlowRealtimeInverter> getInverters() {
if (inverters == null) {
inverters = new HashMap<>();
}
return inverters;
}
public void setInverters(Map<String, PowerFlowRealtimeInverter> inverters) {
this.inverters = inverters;
}
public PowerFlowRealtimeSite getSite() {
if (site == null) {
site = new PowerFlowRealtimeSite();
}
return site;
}
public void setSite(PowerFlowRealtimeSite site) {
this.site = site;
}
}

View File

@@ -0,0 +1,75 @@
/**
* 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 PowerFlowRealtimeInverter} is responsible for storing
* the "inverter" node of the JSON response
*
* @author Thomas Rokohl - Initial contribution
*/
public class PowerFlowRealtimeInverter {
@SerializedName("DT")
private double dt;
@SerializedName("P")
private double p;
@SerializedName("E_Day")
private double eDay;
@SerializedName("E_Year")
private double eYear;
@SerializedName("E_Total")
private double eTotal;
public double getDt() {
return dt;
}
public void setDt(double dt) {
this.dt = dt;
}
public double getP() {
return p;
}
public void setP(double p) {
this.p = p;
}
public double geteDay() {
return eDay;
}
public void seteDay(double eDay) {
this.eDay = eDay;
}
public double geteYear() {
return eYear;
}
public void seteYear(double eYear) {
this.eYear = eYear;
}
public double geteTotal() {
return eTotal;
}
public void seteTotal(double eTotal) {
this.eTotal = eTotal;
}
}

View File

@@ -0,0 +1,37 @@
/**
* 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 PowerFlowRealtimeResponse} is responsible for storing
* the response from the powerflowrealtime api
*
* @author Thomas Rokohl - Initial contribution
*/
public class PowerFlowRealtimeResponse extends BaseFroniusResponse {
@SerializedName("Body")
private PowerFlowRealtimeBody body;
public PowerFlowRealtimeBody getBody() {
if (body == null) {
body = new PowerFlowRealtimeBody();
}
return body;
}
public void setBody(PowerFlowRealtimeBody body) {
this.body = body;
}
}

View File

@@ -0,0 +1,138 @@
/**
* 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 PowerFlowRealtimeSite} is responsible for storing
* the "site" node
*
* @author Thomas Rokohl - Initial contribution
*/
public class PowerFlowRealtimeSite {
@SerializedName("Mode")
private String mode;
@SerializedName("P_Grid")
private double pgrid;
@SerializedName("P_Load")
private double pload;
@SerializedName("P_Akku")
private double pakku;
@SerializedName("P_PV")
private double ppv;
@SerializedName("rel_SelfConsumption")
private double relSelfConsumption;
@SerializedName("rel_Autonomy")
private double relAutonomy;
@SerializedName("E_Day")
private double eDay;
@SerializedName("E_Year")
private double eYear;
@SerializedName("E_Total")
private double eTotal;
@SerializedName("Meter_Location")
private String meterLocation;
public String getMode() {
if (mode == null) {
mode = "";
}
return mode;
}
public void setMode(String mode) {
this.mode = mode;
}
public double getPgrid() {
return pgrid;
}
public void setPgrid(double pgrid) {
this.pgrid = pgrid;
}
public double getPload() {
return pload;
}
public void setPload(double pload) {
this.pload = pload;
}
public double getPakku() {
return pakku;
}
public void setPakku(double pakku) {
this.pakku = pakku;
}
public double getPpv() {
return ppv;
}
public void setPpv(double ppv) {
this.ppv = ppv;
}
public double getRelSelfConsumption() {
return relSelfConsumption;
}
public void setRelSelfConsumption(double relSelfConsumption) {
this.relSelfConsumption = relSelfConsumption;
}
public double getRelAutonomy() {
return relAutonomy;
}
public void setRelAutonomy(double relAutonomy) {
this.relAutonomy = relAutonomy;
}
public double geteDay() {
return eDay;
}
public void seteDay(double eDay) {
this.eDay = eDay;
}
public double geteYear() {
return eYear;
}
public void seteYear(double eYear) {
this.eYear = eYear;
}
public double geteTotal() {
return eTotal;
}
public void seteTotal(double eTotal) {
this.eTotal = eTotal;
}
public String getMeterLocation() {
return meterLocation;
}
public void setMeterLocation(String meterLocation) {
this.meterLocation = meterLocation;
}
}

View File

@@ -0,0 +1,50 @@
/**
* 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 org.openhab.binding.fronius.internal.math.KilowattConverter;
import com.google.gson.annotations.SerializedName;
/**
* The {@link InverterRealtimeResponse} is responsible for storing
* a value
*
* @author Thomas Rokohl - Initial contribution
*/
public class ValueUnit {
@SerializedName("Value")
private double value;
@SerializedName("Unit")
private String unit;
public double getValue() {
return value;
}
public void setValue(double value) {
this.value = value;
}
public String getUnit() {
if (unit == null) {
unit = "";
}
return unit;
}
public void setUnit(String unit) {
this.setValue(KilowattConverter.convertTo(this.getValue(), this.getUnit(), unit));
this.unit = unit;
}
}

View File

@@ -0,0 +1,152 @@
/**
* 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.math.BigDecimal;
import org.openhab.binding.fronius.internal.FroniusBridgeConfiguration;
import org.openhab.binding.fronius.internal.api.ValueUnit;
import org.openhab.core.library.types.DecimalType;
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.binding.BaseThingHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Basic Handler class for all Fronius services.
*
* @author Gerrit Beine - Initial contribution
* @author Thomas Rokohl - Refactoring to merge the concepts
*/
public abstract class FroniusBaseThingHandler extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(FroniusBaseThingHandler.class);
private final String serviceDescription;
private FroniusBridgeHandler bridgeHandler;
public FroniusBaseThingHandler(Thing thing) {
super(thing);
serviceDescription = getDescription();
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
updateChannel(channelUID.getId());
}
}
@Override
public void initialize() {
if (getFroniusBridgeHandler() == null) {
logger.debug("Initializing {} Service is only supported within a bridge", serviceDescription);
updateStatus(ThingStatus.OFFLINE);
return;
}
logger.debug("Initializing {} Service", serviceDescription);
getFroniusBridgeHandler().registerService(this);
}
private synchronized FroniusBridgeHandler getFroniusBridgeHandler() {
if (this.bridgeHandler == null) {
Bridge bridge = getBridge();
if (bridge == null) {
return null;
}
ThingHandler handler = bridge.getHandler();
if (handler instanceof FroniusBridgeHandler) {
this.bridgeHandler = (FroniusBridgeHandler) handler;
} else {
return null;
}
}
return this.bridgeHandler;
}
/**
* Update all Channels
*/
protected void updateChannels() {
for (Channel channel : getThing().getChannels()) {
updateChannel(channel.getUID().getId());
}
}
/**
* Update the channel from the last data
*
* @param channelId the id identifying the channel to be updated
*/
protected void updateChannel(String channelId) {
if (!isLinked(channelId)) {
return;
}
Object value = getValue(channelId);
if (value == null) {
logger.debug("Value retrieved for channel '{}' was null. Can't update.", channelId);
return;
}
State state = null;
if (value instanceof BigDecimal) {
state = new DecimalType((BigDecimal) value);
} else if (value instanceof Integer) {
state = new DecimalType(BigDecimal.valueOf(((Integer) value).longValue()));
} else if (value instanceof Double) {
state = new DecimalType((double) value);
} else if (value instanceof ValueUnit) {
state = new DecimalType(((ValueUnit) value).getValue());
} else {
logger.warn("Update channel {}: Unsupported value type {}", channelId, value.getClass().getSimpleName());
}
logger.debug("Update channel {} with state {} ({})", channelId, (state == null) ? "null" : state.toString(),
value.getClass().getSimpleName());
// Update the channel
if (state != null) {
updateState(channelId, state);
}
}
/**
* return an internal description for logging
*
* @return the description of the thing
*/
protected abstract String getDescription();
/**
* get the "new" associated value for a channelId
*
* @param channelId the id identifying the channel
* @return the "new" associated value
*/
protected abstract Object getValue(String channelId);
/**
* do whatever a thing must do to update the values
* this function is called from the bridge in a given interval
*
* @param bridgeConfiguration the connected bridge configuration
*/
public abstract void refresh(FroniusBridgeConfiguration bridgeConfiguration);
}

View File

@@ -0,0 +1,122 @@
/**
* 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.io.IOException;
import java.net.InetAddress;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang.StringUtils;
import org.openhab.binding.fronius.internal.FroniusBridgeConfiguration;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Bridge for Fronius devices.
*
* @author Gerrit Beine - Initial contribution
* @author Thomas Rokohl - Refactoring to merge the concepts.
* Check if host is reachable.
*/
public class FroniusBridgeHandler extends BaseBridgeHandler {
private final Logger logger = LoggerFactory.getLogger(FroniusBridgeHandler.class);
private static final int DEFAULT_REFRESH_PERIOD = 10;
private final Set<FroniusBaseThingHandler> services = new HashSet<>();
private ScheduledFuture<?> refreshJob;
public FroniusBridgeHandler(Bridge bridge) {
super(bridge);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
}
public void registerService(final FroniusBaseThingHandler service) {
this.services.add(service);
}
@Override
public void initialize() {
final FroniusBridgeConfiguration config = getConfigAs(FroniusBridgeConfiguration.class);
boolean validConfig = true;
String errorMsg = null;
if (StringUtils.trimToNull(config.hostname) == null) {
errorMsg = "Parameter 'hostname' is mandatory and must be configured";
validConfig = false;
}
if (config.refreshInterval != null && config.refreshInterval <= 0) {
errorMsg = "Parameter 'refresh' must be at least 1 second";
validConfig = false;
}
if (validConfig) {
startAutomaticRefresh(config);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, errorMsg);
}
}
@Override
public void dispose() {
if (refreshJob != null) {
refreshJob.cancel(true);
}
services.clear();
}
/**
* Start the job refreshing the data
*/
private void startAutomaticRefresh(FroniusBridgeConfiguration config) {
if (refreshJob == null || refreshJob.isCancelled()) {
Runnable runnable = () -> {
boolean online = false;
try {
InetAddress inet;
inet = InetAddress.getByName(config.hostname);
if (inet.isReachable(5000)) {
online = true;
}
} catch (IOException e) {
logger.debug("Connection Error: {}", e.getMessage());
return;
}
if (!online) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
"hostname or ip is not reachable");
} else {
updateStatus(ThingStatus.ONLINE);
for (FroniusBaseThingHandler service : services) {
service.refresh(config);
}
}
};
int delay = (config.refreshInterval != null) ? config.refreshInterval.intValue() : DEFAULT_REFRESH_PERIOD;
refreshJob = scheduler.scheduleWithFixedDelay(runnable, 0, delay, TimeUnit.SECONDS);
}
}
}

View File

@@ -0,0 +1,219 @@
/**
* 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.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.
*
* @author Thomas Rokohl - Initial contribution
* @author Peter Schraffl - Added device status and error status 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
protected String getDescription() {
return "Fronius Symo Inverter";
}
@Override
public void refresh(FroniusBridgeConfiguration bridgeConfiguration) {
updateData(bridgeConfiguration, config);
updateChannels();
}
@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) {
String[] fields = StringUtils.split(channelId, "#");
String fieldName = fields[0];
if (inverterRealtimeResponse == null) {
return null;
}
switch (fieldName) {
case FroniusBindingConstants.InverterDataChannelDayEnergy:
ValueUnit day = inverterRealtimeResponse.getBody().getData().getDayEnergy();
if (day != null) {
day.setUnit("kWh");
}
return day;
case FroniusBindingConstants.InverterDataChannelPac:
return inverterRealtimeResponse.getBody().getData().getPac();
case FroniusBindingConstants.InverterDataChannelTotal:
ValueUnit total = inverterRealtimeResponse.getBody().getData().getTotalEnergy();
if (total != null) {
total.setUnit("MWh");
}
return total;
case FroniusBindingConstants.InverterDataChannelYear:
ValueUnit year = inverterRealtimeResponse.getBody().getData().getYearEnergy();
if (year != null) {
year.setUnit("MWh");
}
return year;
case FroniusBindingConstants.InverterDataChannelFac:
return inverterRealtimeResponse.getBody().getData().getFac();
case FroniusBindingConstants.InverterDataChannelIac:
return inverterRealtimeResponse.getBody().getData().getIac();
case FroniusBindingConstants.InverterDataChannelIdc:
return inverterRealtimeResponse.getBody().getData().getIdc();
case FroniusBindingConstants.InverterDataChannelUac:
return inverterRealtimeResponse.getBody().getData().getUac();
case FroniusBindingConstants.InverterDataChannelUdc:
return inverterRealtimeResponse.getBody().getData().getUdc();
case FroniusBindingConstants.InverterDataChannelDeviceStatusErrorCode:
return inverterRealtimeResponse.getBody().getData().getDeviceStatus().getErrorCode();
case FroniusBindingConstants.InverterDataChannelDeviceStatusStatusCode:
return inverterRealtimeResponse.getBody().getData().getDeviceStatus().getStatusCode();
}
if (powerFlowResponse == null) {
return null;
}
switch (fieldName) {
case FroniusBindingConstants.PowerFlowpGrid:
return powerFlowResponse.getBody().getData().getSite().getPgrid();
case FroniusBindingConstants.PowerFlowpLoad:
return powerFlowResponse.getBody().getData().getSite().getPload();
case FroniusBindingConstants.PowerFlowpAkku:
return powerFlowResponse.getBody().getData().getSite().getPakku();
}
return null;
}
/**
* Get new data
*/
private void updateData(FroniusBridgeConfiguration bridgeConfiguration, FroniusBaseDeviceConfiguration config) {
inverterRealtimeResponse = getRealtimeData(bridgeConfiguration.hostname, config.deviceId);
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
*
* @param ip address of the device
* @return {PowerFlowRealtimeResponse} the object representation of the json response
*/
private PowerFlowRealtimeResponse getPowerFlowRealtime(String ip) {
String location = FroniusBindingConstants.POWERFLOW_REALTIME_DATA.replace("%IP%", StringUtils.trimToEmpty(ip));
return collectDataFormUrl(PowerFlowRealtimeResponse.class, location);
}
/**
* Make the InverterRealtimeDataRequest
*
* @param ip address of the device
* @param deviceId of the device
* @return {InverterRealtimeResponse} the object representation of the json response
*/
private InverterRealtimeResponse getRealtimeData(String ip, int deviceId) {
String location = FroniusBindingConstants.INVERTER_REALTIME_DATA_URL.replace("%IP%",
StringUtils.trimToEmpty(ip));
location = location.replace("%DEVICEID%", Integer.toString(deviceId));
return collectDataFormUrl(InverterRealtimeResponse.class, location);
}
}

View File

@@ -0,0 +1,33 @@
/**
* 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.math;
/**
* Helper class for unit conversions
*
* @author Thomas Rokohl - Initial contribution
*
*/
public class KilowattConverter {
public static double getConvertFactor(String fromUnit, String toUnit) {
String adjustedFromUnit = fromUnit.replace("Wh", "");
String adjustedtoUnit = toUnit.replace("Wh", "");
return SiPrefixFactors.getFactorToBaseUnit(adjustedFromUnit) * 1
/ SiPrefixFactors.getFactorToBaseUnit(adjustedtoUnit);
}
public static double convertTo(double value, String fromUnit, String toUnit) {
return value * getConvertFactor(fromUnit, toUnit);
}
}

View File

@@ -0,0 +1,62 @@
/**
* 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.math;
/**
* Helper class for unit conversions
*
* @author Thomas Rokohl - Initial contribution
*
*/
public class SiPrefixFactors {
/**
* return the relative factor to the base unit
* k == 1000, M = 1000000 ...
* Not completely!!! Rank from n to T
*
* @param prefix of the unit
* @return relative factor to the base unit
*/
public static double getFactorToBaseUnit(String prefix) {
if (prefix.isEmpty()) {
return 1;
}
switch (prefix) {
case "T":
return 1000000000000d;
case "G":
return 1000000000;
case "M":
return 1000000;
case "k":
return 1000;
case "h":
return 100;
case "da":
return 10;
case "d":
return 0.1;
case "c":
return 0.01;
case "m":
return 0.001;
case "µ":
return 0.000001;
case "n":
return 0.000000001;
}
return 1;
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="fronius" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
<name>Fronius Binding</name>
<description>Binding for Fronius inverters.</description>
<author>Thomas Rokohl, Gerrit Beine</author>
</binding:binding>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="fronius"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<bridge-type id="bridge">
<label>Fronius Bridge</label>
<description>A bridge to connect Fronius devices</description>
<config-description>
<parameter name="hostname" type="text" required="true" groupName="network">
<context>network-address</context>
<label>Hostname</label>
<description>The hostname or IP address of the Fronius gateway/device</description>
</parameter>
<parameter name="refreshInterval" type="integer" min="2">
<label>Refresh Interval</label>
<description>Specifies the refresh interval in seconds.</description>
<default>10</default>
</parameter>
</config-description>
</bridge-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,130 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="fronius"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<!-- Powerinverter Thing Type -->
<thing-type id="powerinverter">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Fronius Symo Inverter</label>
<description>Fronius Symo power inverter</description>
<channels>
<channel id="inverterdatachannelpac" typeId="pac"/>
<channel id="inverterdatachanneldayenergy" typeId="day_energy"/>
<channel id="inverterdatachanneltotal" typeId="total_energy"/>
<channel id="inverterdatachannelyear" typeId="year_energy"/>
<channel id="inverterdatachannelfac" typeId="fac"/>
<channel id="inverterdatachanneliac" typeId="iac"/>
<channel id="inverterdatachannelidc" typeId="idc"/>
<channel id="inverterdatachanneluac" typeId="uac"/>
<channel id="inverterdatachanneludc" typeId="udc"/>
<channel id="inverterdatadevicestatuserrorcode" typeId="devicestatus_errorcode"/>
<channel id="inverterdatadevicestatusstatuscode" typeId="devicestatus_statuscode"/>
<channel id="powerflowchannelpgrid" typeId="pGrid"/>
<channel id="powerflowchannelpload" typeId="pLoad"/>
<channel id="powerflowchannelpakku" typeId="pAkku"/>
</channels>
<config-description>
<parameter name="deviceId" type="integer">
<label>Device ID</label>
<description>Specific device identifier</description>
<default>1</default>
</parameter>
</config-description>
</thing-type>
<channel-type id="day_energy">
<item-type>Number</item-type>
<label>Day Energy</label>
<description>Energy generated on current day</description>
<state pattern="%.2f kWh" readOnly="true"></state>
</channel-type>
<channel-type id="pac">
<item-type>Number</item-type>
<label>AC Power</label>
<description>AC power</description>
<state pattern="%f W" readOnly="true"></state>
</channel-type>
<channel-type id="total_energy">
<item-type>Number</item-type>
<label>Total Energy</label>
<description>Energy generated overall</description>
<state pattern="%.3f MWh" readOnly="true"></state>
</channel-type>
<channel-type id="year_energy">
<item-type>Number</item-type>
<label>Year Energy</label>
<description>Energy generated in current year</description>
<state pattern="%.3f MWh" readOnly="true"></state>
</channel-type>
<channel-type id="fac">
<item-type>Number</item-type>
<label>AC Frequency</label>
<description>AC frequency</description>
<state pattern="%.2f Hz" readOnly="true"></state>
</channel-type>
<channel-type id="iac">
<item-type>Number</item-type>
<label>AC Current</label>
<description>AC current</description>
<state pattern="%.2f A" readOnly="true"></state>
</channel-type>
<channel-type id="idc">
<item-type>Number</item-type>
<label>DC Current</label>
<description>DC current</description>
<state pattern="%.2f A" readOnly="true"></state>
</channel-type>
<channel-type id="uac">
<item-type>Number</item-type>
<label>AC Voltage</label>
<description>AC voltage</description>
<state pattern="%.1f V" readOnly="true"></state>
</channel-type>
<channel-type id="udc">
<item-type>Number</item-type>
<label>DC Voltage</label>
<description>DC voltage</description>
<state pattern="%.1f V" readOnly="true"></state>
</channel-type>
<channel-type id="devicestatus_errorcode">
<item-type>Number</item-type>
<label>Error Code</label>
<description>Current device error code</description>
<state pattern="%d" readOnly="true"></state>
</channel-type>
<channel-type id="devicestatus_statuscode">
<item-type>Number</item-type>
<label>Status Code</label>
<description>Current device status code</description>
<state pattern="%d" readOnly="true"></state>
</channel-type>
<channel-type id="pGrid">
<item-type>Number</item-type>
<label>Grid Power</label>
<description>Grid Power ( + from grid, - to grid )</description>
<state pattern="%.2f W" readOnly="true"></state>
</channel-type>
<channel-type id="pLoad">
<item-type>Number</item-type>
<label>Load Power</label>
<description>Load Power ( + generator, - consumer )</description>
<state pattern="%.2f W" readOnly="true"></state>
</channel-type>
<channel-type id="pAkku">
<item-type>Number</item-type>
<label>Battery Power</label>
<description>Battery Power ( + charge, - discharge )</description>
<state pattern="%.2f W" readOnly="true"></state>
</channel-type>
</thing:thing-descriptions>