diff --git a/bundles/org.openhab.binding.homewizard/README.md b/bundles/org.openhab.binding.homewizard/README.md index d835c2aed32d7..eaa1da8cfd862 100644 --- a/bundles/org.openhab.binding.homewizard/README.md +++ b/bundles/org.openhab.binding.homewizard/README.md @@ -6,18 +6,11 @@ The HomeWizard binding provides access to several HomeWizard devices by using th There are two important points of attention: -1. For API v1, the local API of each device must be enabled and a fixed address must be configured for the devices. -1. For API v2, a bearer token needs to be obtained from the device. See for instructions how to obtain a token. +1. For API v1, the local API of each device must be enabled. +1. For API v2, a bearer token needs to be obtained from the device. -### Local API v1 +See for a more detailed description of the API and for instructions how to enable/use the API versions. -The local API of a device can be enabled from the HomeWizard app. -Go to Settings in the app, then Meters and select the device you want to enable. -On this page enable the local API. - -### Local API v2 - -This version is still in beta. Currently hwe-p1 and hwe-bat are supported. ### Fixed Address @@ -52,7 +45,7 @@ All devices can be configured through the web interface. |--------------|----------|---------|---------------------------------------------------------------------------------------------------| | ipAddress | * | | This specifies the IP address (or host name) where the meter can be found. | | refreshDelay | | 5 | This specifies the interval in seconds used by the binding to read updated values from the meter. | -| apiVersion | * | v1 | The API version to be used. v2 is still in beta but is already supported in this binding. | +| apiVersion | * | v1 | The API version to be used. | | bearerToken | | | The bearer token to be used when using API v2. | Note that update rate of the P1 Meter itself depends on the frequency of the telegrams it receives from the Smart Meter. @@ -60,41 +53,46 @@ For DSMR5 meters this is generally once per second, for older versions the frequ ## Channels -| Channel ID | Item Type | Description | Available | -|------------------------|---------------------------|--------------------------------------------------------------------------------------------|-----------------------------------| -| power | Number:Power | This channel provides the active usage in Watt. | hwe-p1, hwe-skt, hwe-kwh, hwe-bat | -| power_l1 | Number:Power | This channel provides the active usage for phase 1 in Watt. | hwe-p1, hwe-kwh | -| power_l2 | Number:Power | This channel provides the active usage for phase 2 in Watt. | hwe-p1, hwe-kwh | -| power_l3 | Number:Power | This channel provides the active usage for phase 3 in Watt. | hwe-p1, hwe-kwh | -| voltage | Number:ElectricPotential | This channel provides the active voltage in Volt. | hwe-skt | -| voltage_l1 | Number:ElectricPotential | This channel provides the active usage for phase 1 in Watt. | hwe-p1, hwe-kwh, hwe-bat | -| voltage_l2 | Number:ElectricPotential | This channel provides the active usage for phase 2 in Watt. | hwe-p1, hwe-kwh | -| voltage_l3 | Number:ElectricPotential | This channel provides the active usage for phase 3 in Watt. | hwe-p1, hwe-kwh | -| current | Number:ElectricCurrent | This channel provides the active current in Ampere. | hwe-skt, hwe-kwh, hwe-bat | -| current_l1 | Number:ElectricCurrent | This channel provides the active current for phase 1 in Ampere. | hwe-p1, hwe-kwh | -| current_l2 | Number:ElectricCurrent | This channel provides the active current for phase 2 in Ampere. | hwe-p1, hwe-kwh | -| current_l3 | Number:ElectricCurrent | This channel provides the active current for phase 3 in Ampere. | hwe-p1, hwe-kwh | -| energy_import | Number:Energy | This channel provides the total energy usage meter reading in kWh. | hwe-p1, hwe-skt, hwe-kwh, hwe-bat | -| energy_import_t1 | Number:Energy | This channel provides the energy usage meter reading for tariff 1 in kWh. | hwe-p1 | -| energy_import_t2 | Number:Energy | This channel provides the energy usage meter reading for tariff 2 in kWh. | hwe-p1 | -| energy_export | Number:Energy | This channel provides the total energy feed-in meter reading in kWh. | hwe-p1, hwe-skt, hwe-kwh, hwe-bat | -| energy_export_t1 | Number:Energy | This channel provides the energy feed-in meter reading for tarff 1 in kWh. | hwe-p1 | -| energy_export_t2 | Number:Energy | This channel provides the energy feed-in meter reading for tarff 2 in kWh. | hwe-p1 | -| reactive_power | Number | This channel provides the active reactive power in Volt-Ampere reactive. | hwe-p1, hwe-skt, hwe-kwh | -| apparent_power | Number | This channel provides the active apparent power in Volt-Ampere. | hwe-p1, hwe-skt, hwe-kwh | -| power_factor | Number:Dimensionless | This channel provides the active power factor. | hwe-p1, hwe-skt, hwe-kwh | -| frequency | Number:Frequency | This channel provides the active frequency in Hertz. | hwe-p1, hwe-skt, hwe-kwh, hwe-bat | -| total_gas | Number:Volume | This channel provides the most recently reported total imported gas in m^3. | hwe-p1 | -| gas_timestamp | DateTime | This channel provides the time stamp of the total_gas measurement. | hwe-p1 | -| power_failures | Number | This channel provides the number of power failures detected by meter. | hwe-p1 | -| long_power_failures | Number | This channel provides the number of 'long' power failures detected by meter. | hwe-p1 | -| power_switch | Switch | This channel provides access to the power switch of the Energy Socket. | hwe-skt | -| power_lock | Switch | This channel provides access to the power lock of the Energy Socket. | hwe-skt | -| ring_brightness | Number:Dimensionless | This channel provides access to the brightness of the ring of the Energy Socket. | hwe-skt | -| total_liter | Number:Volume | This channel provides total water usage in cubic meters. | hwe-wtr | -| active_liter | Number:VolumetricFlowRate | This channel provides the active water usage in liters per minute. | hwe-wtr | -| state_of_charge | Number:Dimensionless | This channel provides access to the current state of charge in percent. | hwe-bat | -| cycles | Number:Dimensionless | This channel provides access to the number of battery cycles. | hwe-bat | +| Channel ID | Item Type | Description | Available | +|---------------------------|---------------------------|--------------------------------------------------------------------------------------------------------------|-----------------------------------| +| power | Number:Power | This channel provides the active usage in Watt. | hwe-p1, hwe-skt, hwe-kwh, hwe-bat | +| power_l1 | Number:Power | This channel provides the active usage for phase 1 in Watt. | hwe-p1, hwe-kwh | +| power_l2 | Number:Power | This channel provides the active usage for phase 2 in Watt. | hwe-p1, hwe-kwh | +| power_l3 | Number:Power | This channel provides the active usage for phase 3 in Watt. | hwe-p1, hwe-kwh | +| voltage | Number:ElectricPotential | This channel provides the active voltage in Volt. | hwe-skt | +| voltage_l1 | Number:ElectricPotential | This channel provides the active usage for phase 1 in Watt. | hwe-p1, hwe-kwh, hwe-bat | +| voltage_l2 | Number:ElectricPotential | This channel provides the active usage for phase 2 in Watt. | hwe-p1, hwe-kwh | +| voltage_l3 | Number:ElectricPotential | This channel provides the active usage for phase 3 in Watt. | hwe-p1, hwe-kwh | +| current | Number:ElectricCurrent | This channel provides the active current in Ampere. | hwe-skt, hwe-kwh, hwe-bat | +| current_l1 | Number:ElectricCurrent | This channel provides the active current for phase 1 in Ampere. | hwe-p1, hwe-kwh | +| current_l2 | Number:ElectricCurrent | This channel provides the active current for phase 2 in Ampere. | hwe-p1, hwe-kwh | +| current_l3 | Number:ElectricCurrent | This channel provides the active current for phase 3 in Ampere. | hwe-p1, hwe-kwh | +| energy_import | Number:Energy | This channel provides the total energy usage meter reading in kWh. | hwe-p1, hwe-skt, hwe-kwh, hwe-bat | +| energy_import_t1 | Number:Energy | This channel provides the energy usage meter reading for tariff 1 in kWh. | hwe-p1 | +| energy_import_t2 | Number:Energy | This channel provides the energy usage meter reading for tariff 2 in kWh. | hwe-p1 | +| energy_export | Number:Energy | This channel provides the total energy feed-in meter reading in kWh. | hwe-p1, hwe-skt, hwe-kwh, hwe-bat | +| energy_export_t1 | Number:Energy | This channel provides the energy feed-in meter reading for tarff 1 in kWh. | hwe-p1 | +| energy_export_t2 | Number:Energy | This channel provides the energy feed-in meter reading for tarff 2 in kWh. | hwe-p1 | +| reactive_power | Number | This channel provides the active reactive power in Volt-Ampere reactive. | hwe-p1, hwe-skt, hwe-kwh | +| apparent_power | Number | This channel provides the active apparent power in Volt-Ampere. | hwe-p1, hwe-skt, hwe-kwh | +| power_factor | Number:Dimensionless | This channel provides the active power factor. | hwe-p1, hwe-skt, hwe-kwh | +| frequency | Number:Frequency | This channel provides the active frequency in Hertz. | hwe-p1, hwe-skt, hwe-kwh, hwe-bat | +| total_gas | Number:Volume | This channel provides the most recently reported total imported gas in m^3. | hwe-p1 | +| gas_timestamp | DateTime | This channel provides the time stamp of the total_gas measurement. | hwe-p1 | +| power_failures | Number | This channel provides the number of power failures detected by meter. | hwe-p1 | +| long_power_failures | Number | This channel provides the number of 'long' power failures detected by meter. | hwe-p1 | +| power_switch | Switch | This channel provides access to the power switch of the Energy Socket. | hwe-skt | +| power_lock | Switch | This channel provides access to the power lock of the Energy Socket. | hwe-skt | +| ring_brightness | Number:Dimensionless | This channel provides access to the brightness of the ring of the Energy Socket. | hwe-skt | +| total_liter | Number:Volume | This channel provides total water usage in cubic meters. | hwe-wtr | +| active_liter | Number:VolumetricFlowRate | This channel provides the active water usage in liters per minute. | hwe-wtr | +| state_of_charge | Number:Dimensionless | This channel provides access to the current state of charge in percent. | hwe-bat | +| cycles | Number:Dimensionless | This channel provides access to the number of battery cycles. | hwe-bat | +| batteries_mode | String | This channel provides the control mode of the Plug-In Battery. | hwe-p1 | +| batteries_power | Number:Power | This channel provides the current combined power consumption/production of the controlled Plug-In Batteries. | hwe-p1 | +| batteries_target_power | Number:Power | This channel provides the target power consumption/production of the controlled Plug-In Batteries. | hwe-p1 | +| batteries_max_consumption | Number:Power | This channel provides the maximum allowed consumption power of the controlled Plug-In Batteries. | hwe-p1 | +| batteries_max_production | Number:Power | This channel provides the maximum allowed production power of the controlled Plug-In Batteries. | hwe-p1 | ## Full Example diff --git a/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/HomeWizardBindingConstants.java b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/HomeWizardBindingConstants.java index ce48d58098e9b..8938e4f9a7ed2 100644 --- a/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/HomeWizardBindingConstants.java +++ b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/HomeWizardBindingConstants.java @@ -52,6 +52,7 @@ public class HomeWizardBindingConstants { // Channel Groups public static final String CHANNEL_GROUP_ENERGY = "energy"; + public static final String CHANNEL_GROUP_P1_BATTERIES = "batteries"; public static final String CHANNEL_GROUP_WATER = "water"; public static final String CHANNEL_GROUP_SKT_CONTROL = "control"; @@ -104,6 +105,12 @@ public class HomeWizardBindingConstants { public static final String CHANNEL_GAS_TIMESTAMP = "gas_timestamp"; public static final String CHANNEL_GAS_TOTAL = "total_gas"; + public static final String CHANNEL_BATTERIES_MODE = "batteries_mode"; + public static final String CHANNEL_BATTERIES_POWER = "batteries_power"; + public static final String CHANNEL_BATTERIES_TARGET_POWER = "batteries_target_power"; + public static final String CHANNEL_BATTERIES_MAX_CONSUMPTION = "batteries_max_consumption"; + public static final String CHANNEL_BATTERIES_MAX_PRODUCTION = "batteries_max_production"; + // Energy Socket And kWh Meter Channels public static final String CHANNEL_REACTIVE_POWER = "reactive_power"; public static final String CHANNEL_APPARENT_POWER = "apparent_power"; diff --git a/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/HomeWizardDeviceHandler.java b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/HomeWizardDeviceHandler.java index f854612a02f96..d05ce2f8bb0cf 100644 --- a/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/HomeWizardDeviceHandler.java +++ b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/HomeWizardDeviceHandler.java @@ -27,13 +27,19 @@ import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.client.util.StringContentProvider; import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.openhab.binding.homewizard.internal.HomeWizardConfiguration; +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.State; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -116,7 +122,7 @@ public void initialize() { if (configure() && processDeviceInformation()) { updateStatus(ThingStatus.UNKNOWN); - pollingJob = executorService.scheduleWithFixedDelay(this::pollingCode, 0, config.refreshDelay, + pollingJob = executorService.scheduleWithFixedDelay(this::retrieveData, 0, config.refreshDelay, TimeUnit.SECONDS); } } @@ -155,6 +161,20 @@ private boolean configure() { return true; } + /** + * Not listening to any commands. + */ + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + } + + /** + * The actual polling loop + */ + protected void retrieveData() { + retrieveMeasurementData(); + } + private boolean processDeviceInformation() { String deviceInformation = ""; @@ -226,19 +246,29 @@ protected void updateState(String groupID, String channelID, State state) { } /** - * Device specific handling of the returned data. + * Device specific handling of the returned measurement data. * * @param payload The data obtained form the API call */ - protected abstract void handleDataPayload(String data); + protected abstract void handleMeasurementData(String data); + + protected ContentResponse putDataTo(String url, String data) + throws InterruptedException, TimeoutException, ExecutionException { + var request = httpClient.newRequest(url).method(HttpMethod.PUT).content(new StringContentProvider(data)); + + return sendRequest(request); + } protected ContentResponse getResponseFrom(String url) throws InterruptedException, TimeoutException, ExecutionException { - var request = httpClient.newRequest(url); + return sendRequest(httpClient.newRequest(url)); + } + private ContentResponse sendRequest(Request request) + throws InterruptedException, TimeoutException, ExecutionException { if (config.apiVersion > 1) { - request = request.header(HttpHeader.AUTHORIZATION, BEARER + " " + config.bearerToken); - request = request.header(API_VERSION_HEADER, "" + config.apiVersion); + request.header(HttpHeader.AUTHORIZATION, BEARER + " " + config.bearerToken); + request.header(API_VERSION_HEADER, "" + config.apiVersion); } return request.timeout(20, TimeUnit.SECONDS).send(); } @@ -250,7 +280,7 @@ protected ContentResponse getResponseFrom(String url) public String getDeviceInformationData() throws InterruptedException, TimeoutException, ExecutionException, SecurityException { var response = getResponseFrom(apiURL); - if (response.getStatus() == 401) { + if (response.getStatus() == HttpStatus.UNAUTHORIZED_401) { throw new SecurityException("Bearer token is invalid."); } return response.getContentAsString(); @@ -267,13 +297,11 @@ public String getMeasurementData() throws InterruptedException, TimeoutException } else { url += "measurement"; } - return getResponseFrom(url).getContentAsString(); } - protected void pollData() { + protected void retrieveMeasurementData() { final String measurementData; - try { measurementData = getMeasurementData(); } catch (Exception e) { @@ -281,15 +309,7 @@ protected void pollData() { String.format("Device is offline or doesn't support the API version")); return; } - updateStatus(ThingStatus.ONLINE); - handleDataPayload(measurementData); - } - - /** - * The actual polling loop - */ - protected void pollingCode() { - pollData(); + handleMeasurementData(measurementData); } } diff --git a/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/HomeWizardEnergyMeterHandler.java b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/HomeWizardEnergyMeterHandler.java index a81db947c5c3b..050a24ce94c91 100644 --- a/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/HomeWizardEnergyMeterHandler.java +++ b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/HomeWizardEnergyMeterHandler.java @@ -16,9 +16,7 @@ import org.openhab.binding.homewizard.internal.HomeWizardBindingConstants; import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.unit.Units; -import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; -import org.openhab.core.types.Command; /** * The {@link HomeWizardEnergyMeterHandler} implements functionality generic to several energy meters. @@ -38,20 +36,13 @@ public HomeWizardEnergyMeterHandler(Thing thing) { super(thing); } - /** - * Not listening to any commands. - */ - @Override - public void handleCommand(ChannelUID channelUID, Command command) { - } - /** * Device specific handling of the returned data. * * @param data The data obtained form the API call */ @Override - protected void handleDataPayload(String data) { + protected void handleMeasurementData(String data) { var payload = gson.fromJson(data, HomeWizardEnergyMeterMeasurementPayload.class); if (payload != null) { if (!thing.getThingTypeUID().equals(HomeWizardBindingConstants.THING_TYPE_P1_METER) diff --git a/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/energy_socket/HomeWizardEnergySocketHandler.java b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/energy_socket/HomeWizardEnergySocketHandler.java index dbdbedddb81e3..99fd637737ce1 100644 --- a/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/energy_socket/HomeWizardEnergySocketHandler.java +++ b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/energy_socket/HomeWizardEnergySocketHandler.java @@ -130,8 +130,8 @@ public void handleCommand(ChannelUID channelUID, Command command) { * @param data The data obtained from the API call */ @Override - protected void handleDataPayload(String data) { - super.handleDataPayload(data); + protected void handleMeasurementData(String data) { + super.handleMeasurementData(data); var payload = gson.fromJson(data, HomeWizardEnergySocketMeasurementPayload.class); if (payload != null) { diff --git a/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/energy_socket/HomeWizardEnergySocketStateHandler.java b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/energy_socket/HomeWizardEnergySocketStateHandler.java index 80bc35cb0523d..dc337ccfdf03b 100644 --- a/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/energy_socket/HomeWizardEnergySocketStateHandler.java +++ b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/energy_socket/HomeWizardEnergySocketStateHandler.java @@ -12,20 +12,13 @@ */ package org.openhab.binding.homewizard.internal.devices.energy_socket; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; - import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.homewizard.internal.devices.HomeWizardEnergyMeterHandler; -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 com.google.gson.JsonSyntaxException; - /** * The {@link HomeWizardEnergySocketStateHandler} extends the base class * to provide support for devices that also have a 'state' interface. @@ -38,6 +31,8 @@ @NonNullByDefault public abstract class HomeWizardEnergySocketStateHandler extends HomeWizardEnergyMeterHandler { + private final String STATE_URL = "v1/state"; + /** * Constructor * @@ -57,10 +52,10 @@ public HomeWizardEnergySocketStateHandler(Thing thing) { /** * @return json response from the state api - * @throws IOException + * @throws Exception */ public String getStateData() throws Exception { - return getResponseFrom(apiURL + "v1/state").getContentAsString(); + return getResponseFrom(apiURL + STATE_URL).getContentAsString(); } protected void pollState() { @@ -96,21 +91,22 @@ protected void pollState() { * @param command The command to send. */ protected @Nullable HomeWizardEnergySocketStatePayload sendStateCommand(String command) { - try (InputStream is = new ByteArrayInputStream(command.getBytes())) { - String updatedState = HttpUtil.executeUrl("PUT", apiURL + "v1/state", is, "application/json", 30000); - return gson.fromJson(updatedState, HomeWizardEnergySocketStatePayload.class); - } catch (IOException | JsonSyntaxException e) { - logger.warn("Failed to send command {} to {}", command, apiURL + "state"); - return null; + String updatedState = ""; + try { + updatedState = putDataTo(apiURL + STATE_URL, command).getContentAsString(); + } catch (Exception ex) { + logger.warn("Failed to send command {} to {}", command, apiURL + STATE_URL); } + + return gson.fromJson(updatedState, HomeWizardEnergySocketStatePayload.class); } /* * This overrides the original polling loop by including a request for the current state.. */ @Override - protected void pollingCode() { - pollData(); + protected void retrieveData() { + retrieveMeasurementData(); pollState(); } } diff --git a/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/kwh_meter/HomeWizardKwhMeterHandler.java b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/kwh_meter/HomeWizardKwhMeterHandler.java index 2e643b22e4c97..a28a9c7f116e7 100644 --- a/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/kwh_meter/HomeWizardKwhMeterHandler.java +++ b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/kwh_meter/HomeWizardKwhMeterHandler.java @@ -50,8 +50,8 @@ public HomeWizardKwhMeterHandler(Thing thing) { * @param payload The data obtained form the API call */ @Override - protected void handleDataPayload(String data) { - super.handleDataPayload(data); + protected void handleMeasurementData(String data) { + super.handleMeasurementData(data); var payload = gson.fromJson(data, HomeWizardEnergySocketMeasurementPayload.class); if (payload != null) { diff --git a/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/p1_meter/HomeWizardP1MeterBatteriesPayload.java b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/p1_meter/HomeWizardP1MeterBatteriesPayload.java new file mode 100644 index 0000000000000..dd73474521042 --- /dev/null +++ b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/p1_meter/HomeWizardP1MeterBatteriesPayload.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2010-2025 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.homewizard.internal.devices.p1_meter; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +import com.google.gson.annotations.SerializedName; + +/** + * Class that provides storage for the json objects obtained from HomeWizard devices. + * + * @author Gearrel Welvaart - Initial contribution + * + * + */ +@NonNullByDefault +public class HomeWizardP1MeterBatteriesPayload { + + private String mode = ""; + + @SerializedName("power_w") + private Double power = 0.0; + + @SerializedName("target_power_w") + private Double targetPower = 0.0; + + @SerializedName("max_consumption_w") + private Double maxConsumption = 0.0; + + @SerializedName("max_production_w") + private Double maxProduction = 0.0; + + /** + * Getter for the mode + * + * @return mode + */ + public String getMode() { + return mode; + } + + /** + * Getter for the power in watt + * + * @return power + */ + public int getPower() { + return power.intValue(); + } + + /** + * Getter for the target power in watt + * + * @return target power + */ + public int getTargetPower() { + return targetPower.intValue(); + } + + /** + * Getter for the max consumption in watt + * + * @return max consumption + */ + public int getMaxConsumption() { + return maxConsumption.intValue(); + } + + /** + * Getter for the max production in watt + * + * @return max production + */ + public int getMaxProduction() { + return maxProduction.intValue(); + } + + @Override + public String toString() { + return String.format(""" + Data [mode: %s power: %f targetPower: %f + maxConsumption: %f maxProduction: %f + + """, mode, power, targetPower, maxConsumption, maxProduction); + } +} diff --git a/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/p1_meter/HomeWizardP1MeterHandler.java b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/p1_meter/HomeWizardP1MeterHandler.java index 3534a78d51327..c8db0a450476f 100644 --- a/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/p1_meter/HomeWizardP1MeterHandler.java +++ b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/p1_meter/HomeWizardP1MeterHandler.java @@ -14,18 +14,28 @@ import java.time.DateTimeException; import java.time.ZonedDateTime; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jetty.http.HttpStatus; import org.openhab.binding.homewizard.internal.HomeWizardBindingConstants; import org.openhab.binding.homewizard.internal.devices.HomeWizardEnergyMeterHandler; import org.openhab.core.i18n.TimeZoneProvider; import org.openhab.core.library.types.DateTimeType; 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.library.unit.SIUnits; +import org.openhab.core.library.unit.Units; 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.types.Command; +import org.openhab.core.types.RefreshType; + +import com.google.gson.JsonSyntaxException; /** * The {@link HomeWizardP1MeterHandler} implements functionality to handle a HomeWizard P1 Meter. @@ -36,6 +46,8 @@ @NonNullByDefault public class HomeWizardP1MeterHandler extends HomeWizardEnergyMeterHandler { + private final String BATTERIES_URL = "batteries"; + private String meterModel = ""; private int meterVersion = 0; private TimeZoneProvider timeZoneProvider; @@ -52,21 +64,47 @@ public HomeWizardP1MeterHandler(Thing thing, TimeZoneProvider timeZoneProvider) supportedTypes.add(HomeWizardBindingConstants.HWE_P1); } - /** - * Not listening to any commands. - */ + @Override + protected void retrieveData() { + super.retrieveData(); + if (config.apiVersion == 2) { + retrieveBatteriesData(); + } + } + @Override public void handleCommand(ChannelUID channelUID, Command command) { + if (command instanceof RefreshType) { + retrieveBatteriesData(); + return; + } + + if (channelUID.getIdWithoutGroup().equals(HomeWizardBindingConstants.CHANNEL_BATTERIES_MODE)) { + var cmd = String.format("{\"mode\": \"%s\"}", command.toFullString()); + + try { + var response = putDataTo(apiURL + BATTERIES_URL, cmd); + if (response.getStatus() == HttpStatus.OK_200) { + handleBatteriesData(response.getContentAsString()); + } else { + logger.warn("Failed to send command {} to {}", command, apiURL + BATTERIES_URL); + } + } catch (Exception ex) { + logger.warn("Failed to send command {} to {}", command, apiURL + BATTERIES_URL); + } + } else { + logger.warn("Should handle {} {}", channelUID.getIdWithoutGroup(), command); + } } /** - * Device specific handling of the returned data. + * Device specific handling of the returned measurement data. * - * @param payload The data obtained form the API call + * @param data The data obtained form the API call */ @Override - protected void handleDataPayload(String data) { - super.handleDataPayload(data); + protected void handleMeasurementData(String data) { + super.handleMeasurementData(data); var payload = gson.fromJson(data, HomeWizardP1MeterMeasurementPayload.class); if (payload != null) { @@ -135,4 +173,62 @@ protected void handleDataPayload(String data) { } } } + + /** + * Device specific handling of the returned batteries data. + * + * @param data The data obtained form the API call + */ + protected void handleBatteriesData(String data) { + HomeWizardP1MeterBatteriesPayload payload = null; + try { + payload = gson.fromJson(data, HomeWizardP1MeterBatteriesPayload.class); + } catch (JsonSyntaxException ex) { + logger.warn("No Batteries data available"); + } + if (payload != null) { + updateState(HomeWizardBindingConstants.CHANNEL_GROUP_P1_BATTERIES, + HomeWizardBindingConstants.CHANNEL_BATTERIES_MODE, new StringType(payload.getMode())); + updateState(HomeWizardBindingConstants.CHANNEL_GROUP_P1_BATTERIES, + HomeWizardBindingConstants.CHANNEL_BATTERIES_POWER, + new QuantityType<>(payload.getPower(), Units.WATT)); + updateState(HomeWizardBindingConstants.CHANNEL_GROUP_P1_BATTERIES, + HomeWizardBindingConstants.CHANNEL_BATTERIES_TARGET_POWER, + new QuantityType<>(payload.getTargetPower(), Units.WATT)); + updateState(HomeWizardBindingConstants.CHANNEL_GROUP_P1_BATTERIES, + HomeWizardBindingConstants.CHANNEL_BATTERIES_MAX_CONSUMPTION, + new QuantityType<>(payload.getMaxConsumption(), Units.WATT)); + updateState(HomeWizardBindingConstants.CHANNEL_GROUP_P1_BATTERIES, + HomeWizardBindingConstants.CHANNEL_BATTERIES_MAX_PRODUCTION, + new QuantityType<>(payload.getMaxProduction(), Units.WATT)); + } + } + + protected void retrieveBatteriesData() { + final String batteriesData; + + try { + batteriesData = getBatteriesData(); + } catch (Exception e) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, + String.format("Device is offline or doesn't support the API version")); + return; + } + + handleBatteriesData(batteriesData); + } + + /** + * @return json response from the batteries api + * @throws InterruptedException, TimeoutException, ExecutionException + */ + public String getBatteriesData() throws InterruptedException, TimeoutException, ExecutionException { + var response = getResponseFrom(apiURL + BATTERIES_URL); + if (response.getStatus() == HttpStatus.OK_200) { + return response.getContentAsString(); + } else { + logger.warn("No Batteries data available"); + return ""; + } + } } diff --git a/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/plug_in_battery/HomeWizardPlugInBatteryHandler.java b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/plug_in_battery/HomeWizardPlugInBatteryHandler.java index 671bd433dbd6f..376b74b154d11 100644 --- a/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/plug_in_battery/HomeWizardPlugInBatteryHandler.java +++ b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/plug_in_battery/HomeWizardPlugInBatteryHandler.java @@ -16,9 +16,7 @@ import org.openhab.binding.homewizard.internal.HomeWizardBindingConstants; import org.openhab.binding.homewizard.internal.devices.HomeWizardEnergyMeterHandler; import org.openhab.core.library.types.DecimalType; -import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; -import org.openhab.core.types.Command; /** * The {@link HomeWizardPlugInBatteryHandler} implements functionality to handle a HomeWizard P1 Meter. @@ -40,21 +38,14 @@ public HomeWizardPlugInBatteryHandler(Thing thing) { supportedTypes.add(HomeWizardBindingConstants.HWE_BAT); } - /** - * Not listening to any commands. - */ - @Override - public void handleCommand(ChannelUID channelUID, Command command) { - } - /** * Device specific handling of the returned data. * * @param payload The data obtained form the API call */ @Override - protected void handleDataPayload(String data) { - super.handleDataPayload(data); + protected void handleMeasurementData(String data) { + super.handleMeasurementData(data); var payload = gson.fromJson(data, HomeWizardPlugInBatteryMeasurementPayload.class); if (payload != null) { diff --git a/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/water_meter/HomeWizardWaterMeterHandler.java b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/water_meter/HomeWizardWaterMeterHandler.java index 73e695ea30cc0..ef9e58304d720 100644 --- a/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/water_meter/HomeWizardWaterMeterHandler.java +++ b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/devices/water_meter/HomeWizardWaterMeterHandler.java @@ -18,9 +18,7 @@ import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.unit.SIUnits; import org.openhab.core.library.unit.Units; -import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; -import org.openhab.core.types.Command; /** * The {@link HomeWizardWaterMeterHandler} implements functionality to handle a HomeWizard Watermeter. @@ -43,20 +41,13 @@ public HomeWizardWaterMeterHandler(Thing thing) { supportedTypes.add(HomeWizardBindingConstants.HWE_WTR); } - /** - * Not listening to any commands. - */ - @Override - public void handleCommand(ChannelUID channelUID, Command command) { - } - /** * Device specific handling of the returned data. * * @param payload The data obtained form the API call */ @Override - protected void handleDataPayload(String data) { + protected void handleMeasurementData(String data) { var payload = gson.fromJson(data, HomeWizardWaterMeterMeasurementPayload.class); if (payload != null) { if (!thing.getThingTypeUID().equals(HomeWizardBindingConstants.THING_TYPE_WATERMETER)) { diff --git a/bundles/org.openhab.binding.homewizard/src/main/resources/OH-INF/i18n/homewizard.properties b/bundles/org.openhab.binding.homewizard/src/main/resources/OH-INF/i18n/homewizard.properties index be80878a5e5e4..add88ee1dbec3 100644 --- a/bundles/org.openhab.binding.homewizard/src/main/resources/OH-INF/i18n/homewizard.properties +++ b/bundles/org.openhab.binding.homewizard/src/main/resources/OH-INF/i18n/homewizard.properties @@ -5,12 +5,12 @@ addon.homewizard.description = This binding provides access to the data provided # thing types -thing-type.homewizard.hwe-kwh.label = HomeWizard kWh Meter -thing-type.homewizard.hwe-kwh.description = This thing provides the measurement data that is available through the API of a HomeWizard kWh Meter. thing-type.homewizard.energy_socket.label = HomeWizard Energysocket thing-type.homewizard.energy_socket.description = This thing provides the measurement data that is available through the http interface of a HomeWizard Energysocket. thing-type.homewizard.hwe-bat.label = HomeWizard Plug-In Battery thing-type.homewizard.hwe-bat.description = This thing provides the measurement data that is available through the API of a HomeWizard Plug-In Battery. +thing-type.homewizard.hwe-kwh.label = HomeWizard kWh Meter +thing-type.homewizard.hwe-kwh.description = This thing provides the measurement data that is available through the API of a HomeWizard kWh Meter. thing-type.homewizard.hwe-p1.label = HomeWizard P1 Meter thing-type.homewizard.hwe-p1.description = This thing provides the measurement data that is available through the API of a HomeWizard P1 Meter. thing-type.homewizard.hwe-skt.label = HomeWizard Energy Socket @@ -81,6 +81,15 @@ channel-group-type.homewizard.kwh-energy-group.channel.voltage_l2.label = Active channel-group-type.homewizard.kwh-energy-group.channel.voltage_l2.description = This channel provides the active voltage for phase 2 in Volt. channel-group-type.homewizard.kwh-energy-group.channel.voltage_l3.label = Active Voltage L3 channel-group-type.homewizard.kwh-energy-group.channel.voltage_l3.description = This channel provides the active voltage for phase 3 in Volt. +channel-group-type.homewizard.p1-batteries-group.label = Batteries +channel-group-type.homewizard.p1-batteries-group.channel.batteries_max_consumption.label = Maximum Consumption +channel-group-type.homewizard.p1-batteries-group.channel.batteries_max_consumption.description = This channel provides the maximum allowed consumption power of the controlled Plug-In Batteries. +channel-group-type.homewizard.p1-batteries-group.channel.batteries_max_production.label = Maximum Production +channel-group-type.homewizard.p1-batteries-group.channel.batteries_max_production.description = This channel provides the maximum allowed production power of the controlled Plug-In Batteries. +channel-group-type.homewizard.p1-batteries-group.channel.batteries_power.label = Power +channel-group-type.homewizard.p1-batteries-group.channel.batteries_power.description = This channel provides the current combined power consumption/production of the controlled Plug-In Batteries. +channel-group-type.homewizard.p1-batteries-group.channel.batteries_target_power.label = Target Power +channel-group-type.homewizard.p1-batteries-group.channel.batteries_target_power.description = This channel provides the target power consumption/production of the controlled Plug-In Batteries. channel-group-type.homewizard.p1-energy-group.label = Recent Measurements channel-group-type.homewizard.p1-energy-group.channel.current_l1.label = Active Current L1 channel-group-type.homewizard.p1-energy-group.channel.current_l1.description = This channel provides the active current for phase 1 in Ampere. @@ -165,6 +174,11 @@ channel-type.homewizard.hw-voltage-advanced.label = Active Voltage channel-type.homewizard.hw-voltage-advanced.description = This channel provides the active voltage in Volt. channel-type.homewizard.hw-voltage.label = Active Voltage channel-type.homewizard.hw-voltage.description = This channel provides the active voltage in Volt. +channel-type.homewizard.p1-batteries-mode.label = Battery Control Mode +channel-type.homewizard.p1-batteries-mode.description = This channel provides the control mode of the Plug-In Battery. +channel-type.homewizard.p1-batteries-mode.command.option.zero = Maintain net-zero balance +channel-type.homewizard.p1-batteries-mode.command.option.to_full = Charge to 100% +channel-type.homewizard.p1-batteries-mode.command.option.standby = Stand-by mode channel-type.homewizard.p1-gas-timestamp.label = Gas Update Time Stamp channel-type.homewizard.p1-gas-timestamp.description = This channel provides the time stamp of the total_gas measurement. channel-type.homewizard.p1-power-failures.label = Power Failures diff --git a/bundles/org.openhab.binding.homewizard/src/main/resources/OH-INF/thing/channels.xml b/bundles/org.openhab.binding.homewizard/src/main/resources/OH-INF/thing/channels.xml index 30a028a5d7edf..ab4aa3cc75bfb 100644 --- a/bundles/org.openhab.binding.homewizard/src/main/resources/OH-INF/thing/channels.xml +++ b/bundles/org.openhab.binding.homewizard/src/main/resources/OH-INF/thing/channels.xml @@ -24,6 +24,10 @@ This channel provides the active usage in Watt. Energy + + Measurement + Power + @@ -46,6 +50,10 @@ This channel provides the active voltage in Volt. Energy + + Measurement + Voltage + @@ -69,6 +77,10 @@ This channel provides the active current in Ampere. Energy + + Measurement + Current + @@ -92,6 +104,10 @@ This channel provides the total energy usage meter reading in kWh. Energy + + Measurement + Energy + @@ -114,6 +130,10 @@ This channel provides the total energy feed-in meter reading in kWh. Energy + + Measurement + Energy + diff --git a/bundles/org.openhab.binding.homewizard/src/main/resources/OH-INF/thing/hwe-p1.xml b/bundles/org.openhab.binding.homewizard/src/main/resources/OH-INF/thing/hwe-p1.xml index 1ab8fe59d45aa..c1966934b8863 100644 --- a/bundles/org.openhab.binding.homewizard/src/main/resources/OH-INF/thing/hwe-p1.xml +++ b/bundles/org.openhab.binding.homewizard/src/main/resources/OH-INF/thing/hwe-p1.xml @@ -11,9 +11,10 @@ ElectricMeter + - 1 + 2 @@ -122,6 +123,40 @@ + + + + + + + + + This channel provides the current combined power consumption/production of the controlled Plug-In + Batteries. + + + + + + This channel provides the target power consumption/production of the controlled Plug-In Batteries. + + + + + + This channel provides the maximum allowed consumption power of the controlled Plug-In Batteries. + + + + + + This channel provides the maximum allowed production power of the controlled Plug-In Batteries. + + + + + + Number @@ -150,5 +185,24 @@ + + String + + + This channel provides the control mode of the Plug-In Battery. + + + Setpoint + Mode + + + + + + + + + + diff --git a/bundles/org.openhab.binding.homewizard/src/main/resources/OH-INF/update/update-hwe-p1.xml b/bundles/org.openhab.binding.homewizard/src/main/resources/OH-INF/update/update-hwe-p1.xml new file mode 100644 index 0000000000000..ba08c0d95f457 --- /dev/null +++ b/bundles/org.openhab.binding.homewizard/src/main/resources/OH-INF/update/update-hwe-p1.xml @@ -0,0 +1,46 @@ + + + + + + + + homewizard:p1-batteries-mode + + + homewizard:hw-power-advanced + + + This channel provides the current combined power consumption/production of the controlled Plug-In + Batteries. + + + + homewizard:hw-power-advanced + + + This channel provides the target power consumption/production of the controlled Plug-In Batteries. + + + + homewizard:hw-power-advanced + + + This channel provides the maximum allowed consumption power of the controlled Plug-In Batteries. + + + + homewizard:hw-power-advanced + + + This channel provides the maximum allowed production power of the controlled Plug-In Batteries. + + + + + + + + diff --git a/bundles/org.openhab.binding.homewizard/src/test/java/org/openhab/binding/homewizard/internal/devices/HomeWizardHandlerTest.java b/bundles/org.openhab.binding.homewizard/src/test/java/org/openhab/binding/homewizard/internal/devices/HomeWizardHandlerTest.java index f2f6826a8690d..6db184d8b7b89 100644 --- a/bundles/org.openhab.binding.homewizard/src/test/java/org/openhab/binding/homewizard/internal/devices/HomeWizardHandlerTest.java +++ b/bundles/org.openhab.binding.homewizard/src/test/java/org/openhab/binding/homewizard/internal/devices/HomeWizardHandlerTest.java @@ -23,6 +23,7 @@ import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.types.StringType; import org.openhab.core.thing.Channel; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; @@ -38,11 +39,14 @@ @NonNullByDefault public class HomeWizardHandlerTest { - protected static final Configuration CONFIG = createConfig(); + protected static final Configuration CONFIG_V1 = createConfig(1); + protected static final Configuration CONFIG_V2 = createConfig(2); - protected static Configuration createConfig() { + protected static Configuration createConfig(int apiVersion) { final Configuration config = new Configuration(); config.put("ipAddress", "192.168.1.1"); + config.put("apiVersion", apiVersion); + config.put("bearerToken", "token"); return config; } @@ -66,6 +70,10 @@ protected static State getState(final int input, Unit unit) { return new QuantityType<>(input, unit); } + protected static State getState(final String input) { + return new StringType(input); + } + protected static State getState(final double input) { return new DecimalType(input); } @@ -81,4 +89,8 @@ protected static State getState(final double input, Unit unit) { protected static ChannelUID getEnergyChannelUid(Thing thing, String channelId) { return new ChannelUID(thing.getUID(), HomeWizardBindingConstants.CHANNEL_GROUP_ENERGY + "#" + channelId); } + + protected static ChannelUID getBatteriesChannelUid(Thing thing, String channelId) { + return new ChannelUID(thing.getUID(), HomeWizardBindingConstants.CHANNEL_GROUP_P1_BATTERIES + "#" + channelId); + } } diff --git a/bundles/org.openhab.binding.homewizard/src/test/java/org/openhab/binding/homewizard/internal/devices/energy_socket/HomeWizardEnergySocketHandlerTest.java b/bundles/org.openhab.binding.homewizard/src/test/java/org/openhab/binding/homewizard/internal/devices/energy_socket/HomeWizardEnergySocketHandlerTest.java index ebd0ae757ded7..e4758d51de54e 100644 --- a/bundles/org.openhab.binding.homewizard/src/test/java/org/openhab/binding/homewizard/internal/devices/energy_socket/HomeWizardEnergySocketHandlerTest.java +++ b/bundles/org.openhab.binding.homewizard/src/test/java/org/openhab/binding/homewizard/internal/devices/energy_socket/HomeWizardEnergySocketHandlerTest.java @@ -53,7 +53,7 @@ private static Thing mockThing(boolean legacy) { new ThingUID(HomeWizardBindingConstants.THING_TYPE_HWE_SKT, "homewizard-test-thing-skt")); when(thing.getThingTypeUID()).thenReturn(HomeWizardBindingConstants.THING_TYPE_HWE_SKT); } - when(thing.getConfiguration()).thenReturn(CONFIG); + when(thing.getConfiguration()).thenReturn(CONFIG_V1); final List channelList = Arrays.asList( mockChannel(thing.getUID(), HomeWizardBindingConstants.CHANNEL_GROUP_ENERGY, diff --git a/bundles/org.openhab.binding.homewizard/src/test/java/org/openhab/binding/homewizard/internal/devices/kwh_meter/HomeWizardKwhMeterHandlerTest.java b/bundles/org.openhab.binding.homewizard/src/test/java/org/openhab/binding/homewizard/internal/devices/kwh_meter/HomeWizardKwhMeterHandlerTest.java index ff7f87cb9292c..0e63cb4968369 100644 --- a/bundles/org.openhab.binding.homewizard/src/test/java/org/openhab/binding/homewizard/internal/devices/kwh_meter/HomeWizardKwhMeterHandlerTest.java +++ b/bundles/org.openhab.binding.homewizard/src/test/java/org/openhab/binding/homewizard/internal/devices/kwh_meter/HomeWizardKwhMeterHandlerTest.java @@ -45,7 +45,7 @@ private static Thing mockThing(boolean legacy) { when(thing.getUID()) .thenReturn(new ThingUID(HomeWizardBindingConstants.THING_TYPE_HWE_SKT, "homewizard-test-thing-skt")); when(thing.getThingTypeUID()).thenReturn(HomeWizardBindingConstants.THING_TYPE_HWE_KWH); - when(thing.getConfiguration()).thenReturn(CONFIG); + when(thing.getConfiguration()).thenReturn(CONFIG_V1); final List channelList = Arrays.asList( mockChannel(thing.getUID(), HomeWizardBindingConstants.CHANNEL_GROUP_ENERGY, diff --git a/bundles/org.openhab.binding.homewizard/src/test/java/org/openhab/binding/homewizard/internal/devices/p1_meter/HomeWizardP1MeterBatteriesPayloadTest.java b/bundles/org.openhab.binding.homewizard/src/test/java/org/openhab/binding/homewizard/internal/devices/p1_meter/HomeWizardP1MeterBatteriesPayloadTest.java new file mode 100644 index 0000000000000..96242fb33fc6a --- /dev/null +++ b/bundles/org.openhab.binding.homewizard/src/test/java/org/openhab/binding/homewizard/internal/devices/p1_meter/HomeWizardP1MeterBatteriesPayloadTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2010-2025 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.homewizard.internal.devices.p1_meter; + +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; + +import java.io.IOException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.Test; +import org.openhab.binding.homewizard.internal.dto.DataUtil; + +/** + * Tests deserialization of HomeWizard API responses from JSON. + * + * @author Gearrel Welvaart - Initial contribution + * + * + */ +@NonNullByDefault +public class HomeWizardP1MeterBatteriesPayloadTest { + + private static final DataUtil DATA_UTIL = new DataUtil(); + + @Test + public void deserializeResponse() throws IOException { + HomeWizardP1MeterBatteriesPayload key = DATA_UTIL.fromJson("response-batteries-p1-meter.json", + HomeWizardP1MeterBatteriesPayload.class); + assertThat(key, is(notNullValue())); + + assertThat(key.getMode(), is("to_full")); + assertThat(key.getPower(), is(1599)); + assertThat(key.getTargetPower(), is(1600)); + assertThat(key.getMaxConsumption(), is(1600)); + assertThat(key.getMaxProduction(), is(800)); + } + + @Test + public void deserializeResponseEmpty() throws IOException { + HomeWizardP1MeterBatteriesPayload key = DATA_UTIL.fromJson("response-empty.json", + HomeWizardP1MeterBatteriesPayload.class); + assertThat(key, is(notNullValue())); + + assertThat(key.getMode(), is("")); + assertThat(key.getPower(), is(0)); + assertThat(key.getTargetPower(), is(0)); + assertThat(key.getMaxConsumption(), is(0)); + assertThat(key.getMaxProduction(), is(0)); + } +} diff --git a/bundles/org.openhab.binding.homewizard/src/test/java/org/openhab/binding/homewizard/internal/devices/p1_meter/HomeWizardP1MeterHandlerTest.java b/bundles/org.openhab.binding.homewizard/src/test/java/org/openhab/binding/homewizard/internal/devices/p1_meter/HomeWizardP1MeterHandlerTest.java index 114403cce572f..05f7017c27074 100644 --- a/bundles/org.openhab.binding.homewizard/src/test/java/org/openhab/binding/homewizard/internal/devices/p1_meter/HomeWizardP1MeterHandlerTest.java +++ b/bundles/org.openhab.binding.homewizard/src/test/java/org/openhab/binding/homewizard/internal/devices/p1_meter/HomeWizardP1MeterHandlerTest.java @@ -46,7 +46,7 @@ @NonNullByDefault public class HomeWizardP1MeterHandlerTest extends HomeWizardHandlerTest { - private static Thing mockThing(boolean legacy) { + private static Thing mockThing(int apiVersion, boolean legacy) { final Thing thing = mock(Thing.class); if (legacy) { when(thing.getUID()).thenReturn( @@ -57,7 +57,11 @@ private static Thing mockThing(boolean legacy) { .thenReturn(new ThingUID(HomeWizardBindingConstants.THING_TYPE_HWE_P1, "homewizard-test-thing-p1")); when(thing.getThingTypeUID()).thenReturn(HomeWizardBindingConstants.THING_TYPE_HWE_P1); } - when(thing.getConfiguration()).thenReturn(CONFIG); + if (apiVersion == 1) { + when(thing.getConfiguration()).thenReturn(CONFIG_V1); + } else { + when(thing.getConfiguration()).thenReturn(CONFIG_V2); + } final List channelList = Arrays.asList( mockChannel(thing.getUID(), HomeWizardBindingConstants.CHANNEL_GROUP_ENERGY, @@ -97,7 +101,17 @@ private static Thing mockThing(boolean legacy) { mockChannel(thing.getUID(), HomeWizardBindingConstants.CHANNEL_GROUP_ENERGY, HomeWizardBindingConstants.CHANNEL_GAS_TIMESTAMP), // mockChannel(thing.getUID(), HomeWizardBindingConstants.CHANNEL_GROUP_ENERGY, - HomeWizardBindingConstants.CHANNEL_GAS_TOTAL)); + HomeWizardBindingConstants.CHANNEL_GAS_TOTAL), + mockChannel(thing.getUID(), HomeWizardBindingConstants.CHANNEL_GROUP_P1_BATTERIES, + HomeWizardBindingConstants.CHANNEL_BATTERIES_MODE), // + mockChannel(thing.getUID(), HomeWizardBindingConstants.CHANNEL_GROUP_P1_BATTERIES, + HomeWizardBindingConstants.CHANNEL_BATTERIES_POWER), // + mockChannel(thing.getUID(), HomeWizardBindingConstants.CHANNEL_GROUP_P1_BATTERIES, + HomeWizardBindingConstants.CHANNEL_BATTERIES_TARGET_POWER), // + mockChannel(thing.getUID(), HomeWizardBindingConstants.CHANNEL_GROUP_P1_BATTERIES, + HomeWizardBindingConstants.CHANNEL_BATTERIES_MAX_CONSUMPTION), // + mockChannel(thing.getUID(), HomeWizardBindingConstants.CHANNEL_GROUP_P1_BATTERIES, + HomeWizardBindingConstants.CHANNEL_BATTERIES_MAX_PRODUCTION)); when(thing.getChannels()).thenReturn(channelList); return thing; @@ -113,6 +127,7 @@ private static HomeWizardP1MeterHandlerMock createAndInitHandler(final ThingHand doReturn(DataUtil.fromFile("response-device-information-p1-meter.json")).when(handler) .getDeviceInformationData(); doReturn(DataUtil.fromFile("response-measurement-p1-meter.json")).when(handler).getMeasurementData(); + doReturn(DataUtil.fromFile("response-batteries-p1-meter.json")).when(handler).getBatteriesData(); } catch (Exception e) { assertFalse(true); } @@ -124,7 +139,7 @@ private static HomeWizardP1MeterHandlerMock createAndInitHandler(final ThingHand @Test public void testUpdateChannels() { - final Thing thing = mockThing(false); + final Thing thing = mockThing(1, false); final ThingHandlerCallback callback = mock(ThingHandlerCallback.class); final HomeWizardP1MeterHandlerMock handler = createAndInitHandler(callback, thing); @@ -181,9 +196,40 @@ public void testUpdateChannels() { } } + @Test + public void testUpdateBatteriesChannels() { + final Thing thing = mockThing(2, false); + final ThingHandlerCallback callback = mock(ThingHandlerCallback.class); + final HomeWizardP1MeterHandlerMock handler = createAndInitHandler(callback, thing); + + try { + verify(callback).statusUpdated(eq(thing), argThat(arg -> arg.getStatus().equals(ThingStatus.UNKNOWN))); + verify(callback).statusUpdated(eq(thing), argThat(arg -> arg.getStatus().equals(ThingStatus.ONLINE))); + + verify(callback).stateUpdated( + getBatteriesChannelUid(thing, HomeWizardBindingConstants.CHANNEL_BATTERIES_MODE), + getState("to_full")); + verify(callback).stateUpdated( + getBatteriesChannelUid(thing, HomeWizardBindingConstants.CHANNEL_BATTERIES_POWER), + getState(1599, Units.WATT)); + verify(callback).stateUpdated( + getBatteriesChannelUid(thing, HomeWizardBindingConstants.CHANNEL_BATTERIES_TARGET_POWER), + getState(1600, Units.WATT)); + verify(callback).stateUpdated( + getBatteriesChannelUid(thing, HomeWizardBindingConstants.CHANNEL_BATTERIES_MAX_CONSUMPTION), + getState(1600, Units.WATT)); + verify(callback).stateUpdated( + getBatteriesChannelUid(thing, HomeWizardBindingConstants.CHANNEL_BATTERIES_MAX_PRODUCTION), + getState(800, Units.WATT)); + + } finally { + handler.dispose(); + } + } + @Test public void testUpdateLegacyChannels() { - final Thing thing = mockThing(true); + final Thing thing = mockThing(1, true); final ThingHandlerCallback callback = mock(ThingHandlerCallback.class); final HomeWizardP1MeterHandlerMock handler = createAndInitHandler(callback, thing); diff --git a/bundles/org.openhab.binding.homewizard/src/test/java/org/openhab/binding/homewizard/internal/devices/plug_in_battery/HomeWizardPlugInBatteryMeterHandlerTest.java b/bundles/org.openhab.binding.homewizard/src/test/java/org/openhab/binding/homewizard/internal/devices/plug_in_battery/HomeWizardPlugInBatteryMeterHandlerTest.java index 1d9fc3fd83caa..07360f6d30e1f 100644 --- a/bundles/org.openhab.binding.homewizard/src/test/java/org/openhab/binding/homewizard/internal/devices/plug_in_battery/HomeWizardPlugInBatteryMeterHandlerTest.java +++ b/bundles/org.openhab.binding.homewizard/src/test/java/org/openhab/binding/homewizard/internal/devices/plug_in_battery/HomeWizardPlugInBatteryMeterHandlerTest.java @@ -46,7 +46,7 @@ private static Thing mockThing() { .thenReturn(new ThingUID(HomeWizardBindingConstants.THING_TYPE_HWE_P1, "homewizard-test-thing-bat")); when(thing.getThingTypeUID()).thenReturn(HomeWizardBindingConstants.THING_TYPE_HWE_BAT); - when(thing.getConfiguration()).thenReturn(CONFIG); + when(thing.getConfiguration()).thenReturn(CONFIG_V2); final List channelList = Arrays.asList( mockChannel(thing.getUID(), HomeWizardBindingConstants.CHANNEL_GROUP_ENERGY, diff --git a/bundles/org.openhab.binding.homewizard/src/test/resources/org/openhab/binding/homewizard/internal/dto/response-batteries-p1-meter.json b/bundles/org.openhab.binding.homewizard/src/test/resources/org/openhab/binding/homewizard/internal/dto/response-batteries-p1-meter.json new file mode 100644 index 0000000000000..65e1d0f6a3001 --- /dev/null +++ b/bundles/org.openhab.binding.homewizard/src/test/resources/org/openhab/binding/homewizard/internal/dto/response-batteries-p1-meter.json @@ -0,0 +1,8 @@ +{ + "mode": "to_full", + "power_w": 1599, + "target_power_w": 1600, + "max_consumption_w": 1600, + "max_production_w": 800 +} +