diff --git a/CODEOWNERS b/CODEOWNERS
index 2393601417b..dc0594108b3 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -290,6 +290,7 @@
/bundles/org.openhab.binding.solarwatt/ @sven-carstens
/bundles/org.openhab.binding.somfymylink/ @loungeflyz
/bundles/org.openhab.binding.somfytahoma/ @octa22
+/bundles/org.openhab.binding.sonnen/ @chingon007
/bundles/org.openhab.binding.sonos/ @kgoderis @lolodomo
/bundles/org.openhab.binding.sonyaudio/ @freke
/bundles/org.openhab.binding.sonyprojector/ @lolodomo
diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml
index 4e06be80604..109c762a36f 100644
--- a/bom/openhab-addons/pom.xml
+++ b/bom/openhab-addons/pom.xml
@@ -1441,6 +1441,11 @@
org.openhab.binding.somfytahoma${project.version}
+
+ org.openhab.addons.bundles
+ org.openhab.binding.sonnen
+ ${project.version}
+ org.openhab.addons.bundlesorg.openhab.binding.sonos
diff --git a/bundles/org.openhab.binding.sonnen/NOTICE b/bundles/org.openhab.binding.sonnen/NOTICE
new file mode 100644
index 00000000000..38d625e3492
--- /dev/null
+++ b/bundles/org.openhab.binding.sonnen/NOTICE
@@ -0,0 +1,13 @@
+This content is produced and maintained by the openHAB project.
+
+* Project home: https://www.openhab.org
+
+== Declared Project Licenses
+
+This program and the accompanying materials are made available under the terms
+of the Eclipse Public License 2.0 which is available at
+https://www.eclipse.org/legal/epl-2.0/.
+
+== Source Code
+
+https://github.com/openhab/openhab-addons
diff --git a/bundles/org.openhab.binding.sonnen/README.md b/bundles/org.openhab.binding.sonnen/README.md
new file mode 100644
index 00000000000..0e30d5f84bb
--- /dev/null
+++ b/bundles/org.openhab.binding.sonnen/README.md
@@ -0,0 +1,64 @@
+# Sonnen Binding
+
+The binding for sonnen communicates with a sonnen battery.
+More information about the sonnen battery can be found [here](https://sonnen.de/).
+
+## Supported Things
+
+| Thing Type | Description |
+|---------------|--------------------------------|
+| sonnenbattery | Monitoring of a sonnen battery |
+
+
+## Thing Configuration
+
+Only the parameter `hostIP` is required; this is the IP address of the sonnen battery in your local network.
+
+
+## Channels
+
+The following channels are yet supported:
+
+
+| Channel | Type | Access| Description|
+|---------|-------|-------|------------|
+|batteryChargingState|Switch|read|Indicates if the Battery is charging at that moment|
+|batteryCharging|Number:Energy|read|Indicates the actual current charging the Battery. Otherwise 0.|
+|batteryDischargingState|Switch|read|Indicates if the Battery is discharging at that moment|
+|batteryDischarging|Number:Energy|read|Indicates the actual current discharging the Battery. Otherwise 0.|
+|batteryFeedIn|Number:Energy|read|Indicates the actual charging current of the Battery in watt|
+|batteryDischarging|Number:Energy|read|Indicates the actual current discharging the Battery in watt|
+|consumption|Number:Energy|read|Indicates the actual consumption of the consumer in watt|
+|gridFeedIn|Number:Energy|read|Indicates the actual current feeding to the Grid in watt.0 if nothing is feeded|
+|gridConsumption|Number:Energy|read|Indicates the actual current consumption from the Grid in watt.0 if nothing is received|
+|solarProduction|Number:Energy|read|Indicates the actual production of the Solar system in watt|
+|batteryLevel|Number|read|Indicates the actual Battery Level in % from 0 - 100|
+|flowConsumptionBatteryState|Switch|read|Indicates if there is a current flow from Battery towards Consumption|
+|flowConsumptionGridState|Switch|read|Indicates if there is a current flow from Grid towards Consumption|
+|flowConsumptionProductionState|Switch|read|Indicates if there is a current flow from Solar Production towards Consumption|
+|flowGridBatteryState|Switch|read|Indicates if there is a current flow from Grid towards Battery|
+|flowProductionBatteryState|Switch|read|Indicates if there is a current flow from Production towards Battery|
+|flowProductionGridState|Switch|read|Indicates if there is a current flow from Production towards Grid|
+
+## Full Example
+
+example.things:
+
+```
+Thing sonnen:sonnenbattery:myBattery "Sonnen Battery" [ hostIP="192.168.0.10"]
+```
+
+example.items:
+
+```
+Number:Energy Consumption { channel="sonnen:sonnenbattery:myBattery:consumption" }
+Number:Energy GridFeeding { channel="sonnen:sonnenbattery:myBattery:gridFeedIn" }
+Number BatteryLevel { channel="sonnen:sonnenbattery:myBattery:batteryLevel" }
+Switch FlowConsumptionBattery { channel="sonnen:sonnenbattery:myBattery:flowConsumptionBattery" }
+```
+
+## Tested Hardware
+
+The binding was successfully tested with the following sonnen battery:
+
+- sonnnen eco 8.0 SW Version: 1.6.10.1221979
diff --git a/bundles/org.openhab.binding.sonnen/pom.xml b/bundles/org.openhab.binding.sonnen/pom.xml
new file mode 100644
index 00000000000..baffc8c2e78
--- /dev/null
+++ b/bundles/org.openhab.binding.sonnen/pom.xml
@@ -0,0 +1,17 @@
+
+
+
+ 4.0.0
+
+
+ org.openhab.addons.bundles
+ org.openhab.addons.reactor.bundles
+ 3.3.0-SNAPSHOT
+
+
+ org.openhab.binding.sonnen
+
+ openHAB Add-ons :: Bundles :: Sonnen Binding
+
+
diff --git a/bundles/org.openhab.binding.sonnen/src/main/feature/feature.xml b/bundles/org.openhab.binding.sonnen/src/main/feature/feature.xml
new file mode 100644
index 00000000000..3a439f43c25
--- /dev/null
+++ b/bundles/org.openhab.binding.sonnen/src/main/feature/feature.xml
@@ -0,0 +1,9 @@
+
+
+ mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features
+
+
+ openhab-runtime-base
+ mvn:org.openhab.addons.bundles/org.openhab.binding.sonnen/${project.version}
+
+
diff --git a/bundles/org.openhab.binding.sonnen/src/main/java/org/openhab/binding/sonnen/internal/SonnenBindingConstants.java b/bundles/org.openhab.binding.sonnen/src/main/java/org/openhab/binding/sonnen/internal/SonnenBindingConstants.java
new file mode 100644
index 00000000000..09b80a1b042
--- /dev/null
+++ b/bundles/org.openhab.binding.sonnen/src/main/java/org/openhab/binding/sonnen/internal/SonnenBindingConstants.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2010-2022 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.sonnen.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.thing.ThingTypeUID;
+
+/**
+ * The {@link SonnenBindingConstants} class defines common constants, which are
+ * used across the whole binding.
+ *
+ * @author Christian Feininger - Initial contribution
+ */
+@NonNullByDefault
+public class SonnenBindingConstants {
+
+ private static final String BINDING_ID = "sonnen";
+
+ // List of all Thing Type UIDs
+ public static final ThingTypeUID THING_TYPE_BATTERY = new ThingTypeUID(BINDING_ID, "sonnenbattery");
+
+ // List of all Channel ids
+ public static final String CHANNELBATTERYCHARGINGSTATE = "batteryChargingState";
+ public static final String CHANNELBATTERYDISCHARGINGSTATE = "batteryDischargingState";
+ public static final String CHANNELBATTERYCHARGING = "batteryCharging";
+ public static final String CHANNELBATTERYDISCHARGING = "batteryDischarging";
+ public static final String CHANNELCONSUMPTION = "consumption";
+ public static final String CHANNELGRIDFEEDIN = "gridFeedIn";
+ public static final String CHANNELGRIDCONSUMPTION = "gridConsumption";
+ public static final String CHANNELSOLARPRODUCTION = "solarProduction";
+ public static final String CHANNELBATTERYLEVEL = "batteryLevel";
+ public static final String CHANNELFLOWCONSUMPTIONBATTERYSTATE = "flowConsumptionBatteryState";
+ public static final String CHANNELFLOWCONSUMPTIONGRIDSTATE = "flowConsumptionGridState";
+ public static final String CHANNELFLOWCONSUMPTIONPRODUCTIONSTATE = "flowConsumptionProductionState";
+ public static final String CHANNELFLOWGRIDBATTERYSTATE = "flowGridBatteryState";
+ public static final String CHANNELFLOWPRODUCTIONBATTERYSTATE = "flowProductionBatteryState";
+ public static final String CHANNELFLOWPRODUCTIONGRIDSTATE = "flowProductionGridState";
+}
diff --git a/bundles/org.openhab.binding.sonnen/src/main/java/org/openhab/binding/sonnen/internal/SonnenConfiguration.java b/bundles/org.openhab.binding.sonnen/src/main/java/org/openhab/binding/sonnen/internal/SonnenConfiguration.java
new file mode 100644
index 00000000000..ffcdf1b51c1
--- /dev/null
+++ b/bundles/org.openhab.binding.sonnen/src/main/java/org/openhab/binding/sonnen/internal/SonnenConfiguration.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2010-2022 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.sonnen.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * The {@link SonnenConfiguration} class contains fields mapping thing configuration parameters.
+ *
+ * @author Christian Feininger - Initial contribution
+ */
+@NonNullByDefault
+public class SonnenConfiguration {
+
+ public @Nullable String hostIP = null;
+ public int refreshInterval = 30;
+}
diff --git a/bundles/org.openhab.binding.sonnen/src/main/java/org/openhab/binding/sonnen/internal/SonnenHandler.java b/bundles/org.openhab.binding.sonnen/src/main/java/org/openhab/binding/sonnen/internal/SonnenHandler.java
new file mode 100644
index 00000000000..657a5f936ec
--- /dev/null
+++ b/bundles/org.openhab.binding.sonnen/src/main/java/org/openhab/binding/sonnen/internal/SonnenHandler.java
@@ -0,0 +1,261 @@
+/**
+ * Copyright (c) 2010-2022 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.sonnen.internal;
+
+import static org.openhab.binding.sonnen.internal.SonnenBindingConstants.*;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import javax.measure.quantity.Dimensionless;
+import javax.measure.quantity.Power;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.binding.sonnen.internal.communication.SonnenJSONCommunication;
+import org.openhab.binding.sonnen.internal.communication.SonnenJsonDataDTO;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.unit.Units;
+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.types.Command;
+import org.openhab.core.types.RefreshType;
+import org.openhab.core.types.State;
+import org.openhab.core.types.UnDefType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link SonnenHandler} is responsible for handling commands, which are
+ * sent to one of the channels.
+ *
+ * @author Christian Feininger - Initial contribution
+ */
+@NonNullByDefault
+public class SonnenHandler extends BaseThingHandler {
+
+ private final Logger logger = LoggerFactory.getLogger(SonnenHandler.class);
+
+ private SonnenConfiguration config = new SonnenConfiguration();
+
+ private @Nullable ScheduledFuture> refreshJob;
+
+ private SonnenJSONCommunication serviceCommunication;
+
+ private boolean automaticRefreshing = false;
+
+ private Map linkedChannels = new HashMap<>();
+
+ public SonnenHandler(Thing thing) {
+ super(thing);
+ serviceCommunication = new SonnenJSONCommunication();
+ }
+
+ @Override
+ public void initialize() {
+ logger.debug("Initializing sonnen handler for thing {}", getThing().getUID());
+ config = getConfigAs(SonnenConfiguration.class);
+ if (config.refreshInterval < 0 || config.refreshInterval > 1000) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
+ "Parameter 'refresh Rate' msut be in the range 0-1000!");
+ return;
+ }
+ if (config.hostIP == null) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "IP Address must be configured!");
+ return;
+ }
+
+ serviceCommunication.setConfig(config);
+ updateStatus(ThingStatus.UNKNOWN);
+ scheduler.submit(() -> {
+ if (updateBatteryData()) {
+ for (Channel channel : getThing().getChannels()) {
+ if (isLinked(channel.getUID().getId())) {
+ channelLinked(channel.getUID());
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Calls the service to update the battery data
+ *
+ * @return true if the update succeeded, false otherwise
+ */
+ private boolean updateBatteryData() {
+ String error = serviceCommunication.refreshBatteryConnection();
+ if (error.isEmpty()) {
+ if (!ThingStatus.ONLINE.equals(getThing().getStatus())) {
+ updateStatus(ThingStatus.ONLINE);
+ }
+ } else {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, error);
+ }
+ return error.isEmpty();
+ }
+
+ private void verifyLinkedChannel(String channelID) {
+ if (isLinked(channelID) && !linkedChannels.containsKey(channelID)) {
+ linkedChannels.put(channelID, true);
+ }
+ }
+
+ @Override
+ public void dispose() {
+ stopAutomaticRefresh();
+ linkedChannels.clear();
+ automaticRefreshing = false;
+ }
+
+ private void stopAutomaticRefresh() {
+ ScheduledFuture> job = refreshJob;
+ if (job != null) {
+ job.cancel(true);
+ }
+ refreshJob = null;
+ }
+
+ /**
+ * Start the job refreshing the oven status
+ */
+ private void startAutomaticRefresh() {
+ ScheduledFuture> job = refreshJob;
+ if (job == null || job.isCancelled()) {
+ refreshJob = scheduler.scheduleWithFixedDelay(this::refreshChannels, 0, config.refreshInterval,
+ TimeUnit.SECONDS);
+ }
+ }
+
+ private void refreshChannels() {
+ updateBatteryData();
+ for (Channel channel : getThing().getChannels()) {
+ updateChannel(channel.getUID().getId());
+ }
+ }
+
+ @Override
+ public void channelLinked(ChannelUID channelUID) {
+ if (!automaticRefreshing) {
+ logger.debug("Start automatic refreshing");
+ startAutomaticRefresh();
+ automaticRefreshing = true;
+ }
+ verifyLinkedChannel(channelUID.getId());
+ updateChannel(channelUID.getId());
+ }
+
+ @Override
+ public void channelUnlinked(ChannelUID channelUID) {
+ linkedChannels.remove(channelUID.getId());
+ if (linkedChannels.isEmpty()) {
+ automaticRefreshing = false;
+ stopAutomaticRefresh();
+ logger.debug("Stop automatic refreshing");
+ }
+ }
+
+ private void updateChannel(String channelId) {
+ if (isLinked(channelId)) {
+ State state = null;
+ SonnenJsonDataDTO data = serviceCommunication.getBatteryData();
+ if (data != null) {
+ switch (channelId) {
+ case CHANNELBATTERYDISCHARGINGSTATE:
+ update(OnOffType.from(data.isBatteryDischarging()), channelId);
+ break;
+ case CHANNELBATTERYCHARGINGSTATE:
+ update(OnOffType.from(data.isBatteryCharging()), channelId);
+ break;
+ case CHANNELCONSUMPTION:
+ state = new QuantityType(data.getConsumptionHouse(), Units.WATT);
+ update(state, channelId);
+ break;
+ case CHANNELBATTERYDISCHARGING:
+ state = new QuantityType(data.getbatteryCurrent() > 0 ? data.getbatteryCurrent() : 0,
+ Units.WATT);
+ update(state, channelId);
+ break;
+ case CHANNELBATTERYCHARGING:
+ state = new QuantityType(
+ data.getbatteryCurrent() <= 0 ? (data.getbatteryCurrent() * -1) : 0, Units.WATT);
+ update(state, channelId);
+ break;
+ case CHANNELGRIDFEEDIN:
+ state = new QuantityType(data.getGridValue() > 0 ? data.getGridValue() : 0, Units.WATT);
+ update(state, channelId);
+ break;
+ case CHANNELGRIDCONSUMPTION:
+ state = new QuantityType(data.getGridValue() <= 0 ? (data.getGridValue() * -1) : 0,
+ Units.WATT);
+ update(state, channelId);
+ break;
+ case CHANNELSOLARPRODUCTION:
+ state = new QuantityType(data.getSolarProduction(), Units.WATT);
+ update(state, channelId);
+ break;
+ case CHANNELBATTERYLEVEL:
+ state = new QuantityType(data.getBatteryChargingLevel(), Units.PERCENT);
+ update(state, channelId);
+ break;
+ case CHANNELFLOWCONSUMPTIONBATTERYSTATE:
+ update(OnOffType.from(data.isFlowConsumptionBattery()), channelId);
+ break;
+ case CHANNELFLOWCONSUMPTIONGRIDSTATE:
+ update(OnOffType.from(data.isFlowConsumptionGrid()), channelId);
+ break;
+ case CHANNELFLOWCONSUMPTIONPRODUCTIONSTATE:
+ update(OnOffType.from(data.isFlowConsumptionProduction()), channelId);
+ break;
+ case CHANNELFLOWGRIDBATTERYSTATE:
+ update(OnOffType.from(data.isFlowGridBattery()), channelId);
+ break;
+ case CHANNELFLOWPRODUCTIONBATTERYSTATE:
+ update(OnOffType.from(data.isFlowProductionBattery()), channelId);
+ break;
+ case CHANNELFLOWPRODUCTIONGRIDSTATE:
+ update(OnOffType.from(data.isFlowProductionGrid()), channelId);
+ break;
+ }
+ } else {
+ update(null, channelId);
+ }
+ }
+ }
+
+ /**
+ * Updates the State of the given channel
+ *
+ * @param state Given state
+ * @param channelId the refereed channelID
+ */
+ private void update(@Nullable State state, String channelId) {
+ logger.debug("Update channel {} with state {}", channelId, (state == null) ? "null" : state.toString());
+ updateState(channelId, state != null ? state : UnDefType.UNDEF);
+ }
+
+ @Override
+ public void handleCommand(ChannelUID channelUID, Command command) {
+ if (command == RefreshType.REFRESH) {
+ updateBatteryData();
+ updateChannel(channelUID.getId());
+ }
+ }
+}
diff --git a/bundles/org.openhab.binding.sonnen/src/main/java/org/openhab/binding/sonnen/internal/SonnenHandlerFactory.java b/bundles/org.openhab.binding.sonnen/src/main/java/org/openhab/binding/sonnen/internal/SonnenHandlerFactory.java
new file mode 100644
index 00000000000..ab8c968756a
--- /dev/null
+++ b/bundles/org.openhab.binding.sonnen/src/main/java/org/openhab/binding/sonnen/internal/SonnenHandlerFactory.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2010-2022 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.sonnen.internal;
+
+import static org.openhab.binding.sonnen.internal.SonnenBindingConstants.THING_TYPE_BATTERY;
+
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+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 SonnenHandlerFactory} is responsible for creating things and thing
+ * handlers.
+ *
+ * @author Christian Feininger - Initial contribution
+ */
+@NonNullByDefault
+@Component(configurationPid = "binding.sonnen", service = ThingHandlerFactory.class)
+public class SonnenHandlerFactory extends BaseThingHandlerFactory {
+
+ private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_BATTERY);
+
+ @Override
+ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
+ return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
+ }
+
+ @Override
+ protected @Nullable ThingHandler createHandler(Thing thing) {
+ ThingTypeUID thingTypeUID = thing.getThingTypeUID();
+
+ if (THING_TYPE_BATTERY.equals(thingTypeUID)) {
+ return new SonnenHandler(thing);
+ }
+
+ return null;
+ }
+}
diff --git a/bundles/org.openhab.binding.sonnen/src/main/java/org/openhab/binding/sonnen/internal/communication/SonnenJSONCommunication.java b/bundles/org.openhab.binding.sonnen/src/main/java/org/openhab/binding/sonnen/internal/communication/SonnenJSONCommunication.java
new file mode 100644
index 00000000000..0d8482db234
--- /dev/null
+++ b/bundles/org.openhab.binding.sonnen/src/main/java/org/openhab/binding/sonnen/internal/communication/SonnenJSONCommunication.java
@@ -0,0 +1,88 @@
+/**
+ * Copyright (c) 2010-2022 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.sonnen.internal.communication;
+
+import java.io.IOException;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.binding.sonnen.internal.SonnenConfiguration;
+import org.openhab.core.io.net.http.HttpUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonSyntaxException;
+
+/**
+ * This class handles the JSON communication with the sonnen battery
+ *
+ * @author Christian Feininger - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class SonnenJSONCommunication {
+
+ private final Logger logger = LoggerFactory.getLogger(SonnenJSONCommunication.class);
+ private SonnenConfiguration config;
+
+ private Gson gson;
+ private @Nullable SonnenJsonDataDTO batteryData;
+
+ public SonnenJSONCommunication() {
+ gson = new Gson();
+ config = new SonnenConfiguration();
+ }
+
+ /**
+ * Refreshes the battery connection.
+ *
+ * @return an empty string if no error occurred, the error message otherwise.
+ */
+ public String refreshBatteryConnection() {
+ String result = "";
+ String urlStr = "http://" + config.hostIP + "/api/v1/status";
+
+ try {
+ String response = HttpUtil.executeUrl("GET", urlStr, 10000);
+ logger.debug("BatteryData = {}", response);
+ if (response == null) {
+ throw new IOException("HttpUtil.executeUrl returned null");
+ }
+ batteryData = gson.fromJson(response, SonnenJsonDataDTO.class);
+ } catch (IOException | JsonSyntaxException e) {
+ logger.debug("Error processiong Get request {}: {}", urlStr, e.getMessage());
+ result = "Cannot find service on given IP " + config.hostIP + ". Please verify the IP address!";
+ batteryData = null;
+ }
+ return result;
+ }
+
+ /**
+ * Set the config for service to communicate
+ *
+ * @param config2
+ */
+ public void setConfig(SonnenConfiguration config2) {
+ this.config = config2;
+ }
+
+ /**
+ * Returns the actual stored Battery Data
+ *
+ * @return JSON Data from the Battery or null if request failed
+ */
+ public @Nullable SonnenJsonDataDTO getBatteryData() {
+ return this.batteryData;
+ }
+}
diff --git a/bundles/org.openhab.binding.sonnen/src/main/java/org/openhab/binding/sonnen/internal/communication/SonnenJsonDataDTO.java b/bundles/org.openhab.binding.sonnen/src/main/java/org/openhab/binding/sonnen/internal/communication/SonnenJsonDataDTO.java
new file mode 100644
index 00000000000..84c2dae5df6
--- /dev/null
+++ b/bundles/org.openhab.binding.sonnen/src/main/java/org/openhab/binding/sonnen/internal/communication/SonnenJsonDataDTO.java
@@ -0,0 +1,141 @@
+/**
+ * Copyright (c) 2010-2022 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.sonnen.internal.communication;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * The {@link SonnenJsonDataDTO} is the Java class used to map the JSON
+ * response to a Oven request.
+ *
+ * @author Christian Feininger - Initial contribution
+ */
+public class SonnenJsonDataDTO {
+ @SerializedName("BatteryCharging")
+ boolean batteryCharging;
+ @SerializedName("BatteryDischarging")
+ boolean batteryDischarging;
+ @SerializedName("Consumption_W")
+ int consumptionHouse;
+ @SerializedName("GridFeedIn_W")
+ int gridValue;
+ @SerializedName("Production_W")
+ int solarProduction;
+ @SerializedName("USOC")
+ int batteryChargingLevel;
+ @SerializedName("FlowConsumptionBattery")
+ boolean flowConsumptionBattery;
+ @SerializedName("FlowConsumptionGrid")
+ boolean flowConsumptionGrid;
+ @SerializedName("FlowConsumptionProduction")
+ boolean flowConsumptionProduction;
+ @SerializedName("FlowGridBattery")
+ boolean flowGridBattery;
+ @SerializedName("FlowProductionBattery")
+ boolean flowProductionBattery;
+ @SerializedName("FlowProductionGrid")
+ boolean flowProductionGrid;
+ @SerializedName("Pac_total_W")
+ int batteryCurrent;
+
+ /**
+ * @return the batteryCurrent
+ */
+ public int getbatteryCurrent() {
+ return batteryCurrent;
+ }
+
+ /**
+ * @return the batteryCharging
+ */
+ public boolean isBatteryCharging() {
+ return batteryCharging;
+ }
+
+ /**
+ * @return the batteryDischarging
+ */
+ public boolean isBatteryDischarging() {
+ return batteryDischarging;
+ }
+
+ /**
+ * @return the consumptionHouse
+ */
+ public int getConsumptionHouse() {
+ return consumptionHouse;
+ }
+
+ /**
+ * @return the gridValue. Negative value indicates receiving from Grid. Positive value indicates feeding to Grid.
+ */
+ public int getGridValue() {
+ return gridValue;
+ }
+
+ /**
+ * @return the solarProduction
+ */
+ public int getSolarProduction() {
+ return solarProduction;
+ }
+
+ /**
+ * @return the batteryChargingLevel
+ */
+ public int getBatteryChargingLevel() {
+ return batteryChargingLevel;
+ }
+
+ /**
+ * @return the flowConsumptionBattery
+ */
+ public boolean isFlowConsumptionBattery() {
+ return flowConsumptionBattery;
+ }
+
+ /**
+ * @return the flowConsumptionGrid
+ */
+ public boolean isFlowConsumptionGrid() {
+ return flowConsumptionGrid;
+ }
+
+ /**
+ * @return the flowConsumptionProduction
+ */
+ public boolean isFlowConsumptionProduction() {
+ return flowConsumptionProduction;
+ }
+
+ /**
+ * @return the flowGridBattery
+ */
+ public boolean isFlowGridBattery() {
+ return flowGridBattery;
+ }
+
+ /**
+ * @return the flowProductionBattery
+ */
+ public boolean isFlowProductionBattery() {
+ return flowProductionBattery;
+ }
+
+ /**
+ * @return the flowProductionGrid
+ */
+ public boolean isFlowProductionGrid() {
+ return flowProductionGrid;
+ }
+}
diff --git a/bundles/org.openhab.binding.sonnen/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.sonnen/src/main/resources/OH-INF/binding/binding.xml
new file mode 100644
index 00000000000..a24ce4e0cec
--- /dev/null
+++ b/bundles/org.openhab.binding.sonnen/src/main/resources/OH-INF/binding/binding.xml
@@ -0,0 +1,9 @@
+
+
+
+ Sonnen Binding
+ This binding communicates with a solar battery from sonnen.
+
+
diff --git a/bundles/org.openhab.binding.sonnen/src/main/resources/OH-INF/i18n/sonnen.properties b/bundles/org.openhab.binding.sonnen/src/main/resources/OH-INF/i18n/sonnen.properties
new file mode 100644
index 00000000000..d7687f61741
--- /dev/null
+++ b/bundles/org.openhab.binding.sonnen/src/main/resources/OH-INF/i18n/sonnen.properties
@@ -0,0 +1,47 @@
+# binding
+
+binding.sonnen.name = Sonnen Binding
+binding.sonnen.description = This binding communicates with a solar battery from sonnen.
+
+# thing types
+
+thing-type.sonnen.sonnenbattery.label = Sonnen Battery
+thing-type.sonnen.sonnenbattery.description = Monitoring of a sonnen battery.
+
+# thing types config
+
+thing-type.config.sonnen.sonnenbattery.hostIP.label = IP Address
+thing-type.config.sonnen.sonnenbattery.hostIP.description = Please add the IP Address of your sonnen battery.
+thing-type.config.sonnen.sonnenbattery.refreshInterval.label = Refresh Interval
+thing-type.config.sonnen.sonnenbattery.refreshInterval.description = How often in seconds the sonnen battery should schedule a refresh after a channel is linked to an item. Valid input is 0 - 1000.
+
+# channel types
+
+channel-type.sonnen.batteryCharging.label = Battery Charging
+channel-type.sonnen.batteryCharging.description = Indicates the actual current charging the Battery. Otherwise 0.
+channel-type.sonnen.batteryChargingState.label = Battery Charging State
+channel-type.sonnen.batteryChargingState.description = Indicates if the Battery is charging at that moment.
+channel-type.sonnen.batteryDischarging.label = Battery Discharging
+channel-type.sonnen.batteryDischarging.description = Indicates the actual current discharging the Battery. Otherwise 0.
+channel-type.sonnen.batteryDischargingState.label = Battery Discharging State
+channel-type.sonnen.batteryDischargingState.description = Indicates if the Battery is discharging at that moment.
+channel-type.sonnen.consumption.label = Consumption
+channel-type.sonnen.consumption.description = Indicates the actual consumption of the House.
+channel-type.sonnen.flowConsumptionBatteryState.label = Flow Battery Towards Consumption State
+channel-type.sonnen.flowConsumptionBatteryState.description = Indicates if there is a current flow from battery towards consumption.
+channel-type.sonnen.flowConsumptionGridState.label = Flow Grid Towards Consumption State
+channel-type.sonnen.flowConsumptionGridState.description = Indicates if there is a current flow from grid towards consumption.
+channel-type.sonnen.flowConsumptionProductionState.label = Flow Production Towards Consumption State
+channel-type.sonnen.flowConsumptionProductionState.description = Indicates if there is a current flow from solar production towards consumption.
+channel-type.sonnen.flowGridBatteryState.label = Flow Grid Towards Battery State
+channel-type.sonnen.flowGridBatteryState.description = Indicates if there is a current flow from grid towards battery.
+channel-type.sonnen.flowProductionBatteryState.label = Flow Production Towards Battery State
+channel-type.sonnen.flowProductionBatteryState.description = Indicates if there is a current flow from production towards battery.
+channel-type.sonnen.flowProductionGridState.label = Flow Production Towards Grid State
+channel-type.sonnen.flowProductionGridState.description = Indicates if there is a current flow from production towards grid.
+channel-type.sonnen.gridConsumption.label = Grid Consumption
+channel-type.sonnen.gridConsumption.description = Indicates the actual current consumption from the the Grid. Otherwise 0.
+channel-type.sonnen.gridFeedIn.label = Grid Feed In
+channel-type.sonnen.gridFeedIn.description = Indicates the actual current feeding to the Grid. Otherwise 0.
+channel-type.sonnen.solarProduction.label = Solar Production
+channel-type.sonnen.solarProduction.description = Indicates the actual production of the Solar system.
diff --git a/bundles/org.openhab.binding.sonnen/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.sonnen/src/main/resources/OH-INF/thing/thing-types.xml
new file mode 100644
index 00000000000..5821dcf8952
--- /dev/null
+++ b/bundles/org.openhab.binding.sonnen/src/main/resources/OH-INF/thing/thing-types.xml
@@ -0,0 +1,131 @@
+
+
+
+
+
+
+ Monitoring of a sonnen battery.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ network-address
+
+ Please add the IP Address of your sonnen battery.
+
+
+
+ How often in seconds the sonnen battery should schedule a refresh after a channel is linked to an item.
+ Valid input is 0 - 1000.
+ true
+ 30
+
+
+
+
+
+
+ Switch
+
+ Indicates if the Battery is charging at that moment.
+
+
+
+ Switch
+
+ Indicates if the Battery is discharging at that moment.
+
+
+
+ Number:Energy
+
+ Indicates the actual current charging the Battery. Otherwise 0.
+
+
+
+ Number:Energy
+
+ Indicates the actual current discharging the Battery. Otherwise 0.
+
+
+
+ Number:Energy
+
+ Indicates the actual consumption of the House.
+
+
+
+ Number:Energy
+
+ Indicates the actual current feeding to the Grid. Otherwise 0.
+
+
+
+ Number:Energy
+
+ Indicates the actual current consumption from the the Grid. Otherwise 0.
+
+
+
+ Number:Energy
+
+ Indicates the actual production of the Solar system.
+
+
+
+ Switch
+
+ Indicates if there is a current flow from battery towards consumption.
+
+
+
+ Switch
+
+ Indicates if there is a current flow from grid towards consumption.
+
+
+
+ Switch
+
+ Indicates if there is a current flow from solar production towards consumption.
+
+
+
+ Switch
+
+ Indicates if there is a current flow from grid towards battery.
+
+
+
+ Switch
+
+ Indicates if there is a current flow from production towards battery.
+
+
+
+ Switch
+
+ Indicates if there is a current flow from production towards grid.
+
+
+
diff --git a/bundles/pom.xml b/bundles/pom.xml
index 536eef33390..c45ac553505 100644
--- a/bundles/pom.xml
+++ b/bundles/pom.xml
@@ -322,6 +322,7 @@
org.openhab.binding.solarwattorg.openhab.binding.somfymylinkorg.openhab.binding.somfytahoma
+ org.openhab.binding.sonnenorg.openhab.binding.sonosorg.openhab.binding.sonyaudioorg.openhab.binding.sonyprojector