# HomeWizard Binding
-The HomeWizard binding retrieves measurements from the HomeWizard Wi-Fi P1 meter.
-The meter itself is attached to a DSMR Smart Meter and reads out the telegrams, which it will forward to cloud storage.
-However, recently HomeWizard also added an interface that can be queried locally.
+The HomeWizard binding provides access to several HomeWizard devices by using the local API of those devices.
-This binding uses that local interface to make the measurements available.
+## Installation
+
+There are two important points of attention: the local API of each device must be enabled and a fixed address must be configured for the devices.
+
+### Local API
+
+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.
+
+### Fixed Address
+
+The devices support mDNS discovery but the binding does not support that yet.
+As a result the devices should be reachable through a hostname or a fixed IP address.
+Since the devices themselves have no option to set a fixed IP address you will need a different solution, for instance having your router hand out an IP address based upon the MAC address of the devices.
## Supported Things
-The binding provides the P1 Meter thing.
+The binding offers three Things, providing support for the P1 meter, the Watermeter and the Energy Socket.
+
+| Thing | Device | Description |
+|---------------|---------------------|---------------------------------------------------------------------------------------------------|
+| p1_wifi_meter | Wi-Fi P1 Meter | Reads total and current energy usage and total gas usage. |
+| energy_socket | Wi-Fi Energy Socket | Reads total and current energy usage. Controls power switch, lock and ring brightness. |
+| watermeter | Wi-Fi Watermeter | Reads total and current water usage. |
+
+The HomeWizard kWh meters are not yet officially supported, but they can probably be added as as 'p1_wifi_meter'. However, this has not been tested.
## Discovery
-Auto discovery is not available for this binding.
+Auto discovery is not yet available for this binding.
## Thing Configuration
-The P1 Meter thing can be configured through the web interface.
+All devices can be configured through the web interface.
| Parameter | Required | Default | Description |
|--------------|----------|---------|---------------------------------------------------------------------------------------------------|
Note that update rate of the P1 Meter itself depends on the frequency of the telegrams it receives from the Smart Meter.
For DSMR5 meters this is generally once per second, for older versions the frequency is much lower.
-Example of configuration through a .thing file:
+## Channels
+
+| Channel ID | Item Type | Description |Available|
+|------------------------|---------------------------|--------------------------------------------------------------------------------------------|---------|
+| total_energy_import_t1 | Number:Energy | The most recently reported total imported energy in kWh by counter 1. | P,E |
+| total_energy_import_t2 | Number:Energy | The most recently reported total imported energy in kWh by counter 2. | P |
+| total_energy_export_t1 | Number:Energy | The most recently reported total exported energy in kWh by counter 1. | P,E |
+| total_energy_export_t2 | Number:Energy | The most recently reported total exported energy in kWh by counter 2. | P |
+| active_power | Number:Power | The current net total power in W. It will be below 0 if power is currently being exported. | P,E |
+| active_power_l1 | Number:Power | The current net total power in W for phase 1. | P |
+| active_power_l2 | Number:Power | The current net total power in W for phase 2. | P |
+| active_power_l3 | Number:Power | The current net total power in W for phase 3. | P |
+| total_gas | Number:Volume | The most recently reported total imported gas in m^3. | P |
+| gas_timestamp | DateTime | The time stamp of the total_gas measurement. | P |
+| total_water | Number:Volume | Total water used. | W |
+| current_water | Number:VolumetricFlowRate | Current water usage. | W |
+| power_switch | Switch | Controls the power switch of the socket. | E |
+| power_lock | Switch | Controls the lock of the power switch (un/locking both the API and the physical button) | E |
+| ring_brightness | Number:Dimensionless | Controls the brightness of the ring on the socket | E |
+
+## Full Example
+
+### `homewizard.things` Example
```java
-Thing homewizard:p1_wifi_meter:my_meter [ ipAddress="192.178.1.67", refreshDelay=5 ]
+Thing homewizard:p1_wifi_meter:my_p1 [ ipAddress="192.178.1.67", refreshDelay=5 ]
+Thing homewizard:energy_socket:my_socket [ ipAddress="192.178.1.61", refreshDelay=5 ]
+Thing homewizard:watermeter:my_water [ ipAddress="192.178.1.27", refreshDelay=15 ]
```
-## Channels
-
-| Channel ID | Item Type | Description |
-|------------------------|---------------|--------------------------------------------------------------------------------------------|
-| total_energy_import_t1 | Number:Energy | The most recently reported total imported energy in kWh by counter 1. |
-| total_energy_import_t2 | Number:Energy | The most recently reported total imported energy in kWh by counter 2. |
-| total_energy_export_t1 | Number:Energy | The most recently reported total exported energy in kWh by counter 1. |
-| total_energy_export_t2 | Number:Energy | The most recently reported total exported energy in kWh by counter 2. |
-| active_power | Number:Power | The current net total power in W. It will be below 0 if power is currently being exported. |
-| active_power_l1 | Number:Power | The current net total power in W for phase 1. |
-| active_power_l2 | Number:Power | The current net total power in W for phase 2. |
-| active_power_l3 | Number:Power | The current net total power in W for phase 3. |
-| total_gas | Number:Volume | The most recently reported total imported gas in m^3. |
-| gas_timestamp | DateTime | The time stamp of the total_gas measurement. |
-
-Example of configuration through a .items file:
+### `homewizard.items` Example
```java
Number:Energy Energy_Import_T1 "Imported Energy T1 [%.0f kWh]" {channel="homewizard:p1_wifi_meter:my_meter:total_energy_import_t1" }
--- /dev/null
+/**
+ * Copyright (c) 2010-2024 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;
+
+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 Daniël van Os - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class DataPayload {
+ private int smrVersion = 0;
+ private String meterModel = "";
+ private String wifiSsid = "";
+ private int wifiStrength = 0;
+
+ @SerializedName("total_power_import_t1_kwh")
+ private double totalEnergyImportT1Kwh;
+ @SerializedName("total_power_import_t2_kwh")
+ private double totalEnergyImportT2Kwh;
+ @SerializedName("total_power_export_t1_kwh")
+ private double totalEnergyExportT1Kwh;
+ @SerializedName("total_power_export_t2_kwh")
+ private double totalEnergyExportT2Kwh;
+
+ private double activePowerW;
+ private double activePowerL1W;
+ private double activePowerL2W;
+ private double activePowerL3W;
+ private double totalGasM3;
+ private long gasTimestamp = 0;
+
+ @SerializedName("total_liter_m3")
+ private double totalWaterM3;
+ @SerializedName("active_liter_lpm")
+ private double currentWaterLPM;
+
+ /**
+ * Getter for the smart meter version
+ *
+ * @return The most recent smart meter version obtained from the API
+ */
+ public int getSmrVersion() {
+ return smrVersion;
+ }
+
+ /**
+ * Setter for the smart meter version
+ *
+ * @param smrVersion The smart meter version to set
+ */
+ public void setSmrVersion(int smrVersion) {
+ this.smrVersion = smrVersion;
+ }
+
+ /**
+ * Getter for the meter model
+ *
+ * @return meter model
+ */
+ public String getMeterModel() {
+ return meterModel;
+ }
+
+ /**
+ * Setter for the meter model
+ *
+ * @param meterModel meter model
+ */
+ public void setMeterModel(String meterModel) {
+ this.meterModel = meterModel;
+ }
+
+ /**
+ * Getter for the meter's wifi ssid
+ *
+ * @return the meter's wifi sid
+ */
+ public String getWifiSsid() {
+ return wifiSsid;
+ }
+
+ /**
+ * Setter for the wifi ssid
+ *
+ * @param wifiSsid wifi ssid
+ */
+ public void setWifiSsid(String wifiSsid) {
+ this.wifiSsid = wifiSsid;
+ }
+
+ /**
+ * Getter for the wifi rssi
+ *
+ * @return wifi rssi
+ */
+ public int getWifiStrength() {
+ return wifiStrength;
+ }
+
+ /**
+ * Setter for the wifi rssi
+ *
+ * @param wifiStrength wifi rssi
+ */
+ public void setWifiStrength(int wifiStrength) {
+ this.wifiStrength = wifiStrength;
+ }
+
+ /**
+ * Getter for the total imported energy on counter 1
+ *
+ * @return total imported energy on counter 1
+ */
+ public double getTotalEnergyImportT1Kwh() {
+ return totalEnergyImportT1Kwh;
+ }
+
+ /**
+ * Setter for the total imported energy on counter 1
+ *
+ * @param totalEnergyImportT1Kwh total imported energy on counter 1
+ */
+ public void setTotalEnergyImportT1Kwh(double totalEnergyImportT1Kwh) {
+ this.totalEnergyImportT1Kwh = totalEnergyImportT1Kwh;
+ }
+
+ /**
+ * Getter for the total imported energy on counter 2
+ *
+ * @return total imported energy on counter 2
+ */
+ public double getTotalEnergyImportT2Kwh() {
+ return totalEnergyImportT2Kwh;
+ }
+
+ /**
+ * Setter for the total imported energy on counter 2
+ *
+ * @param totalEnergyImportT2Kwh
+ */
+ public void setTotalEnergyImportT2Kwh(double totalEnergyImportT2Kwh) {
+ this.totalEnergyImportT2Kwh = totalEnergyImportT2Kwh;
+ }
+
+ /**
+ * Getter for the total exported energy on counter 1
+ *
+ * @return total exported energy on counter 1
+ */
+ public double getTotalEnergyExportT1Kwh() {
+ return totalEnergyExportT1Kwh;
+ }
+
+ /**
+ * Setter for the total exported energy on counter 1
+ *
+ * @param totalEnergyExportT1Kwh
+ */
+ public void setTotalEnergyExportT1Kwh(double totalEnergyExportT1Kwh) {
+ this.totalEnergyExportT1Kwh = totalEnergyExportT1Kwh;
+ }
+
+ /**
+ * Getter for the total exported energy on counter 2
+ *
+ * @return total exported energy on counter 2
+ */
+ public double getTotalEnergyExportT2Kwh() {
+ return totalEnergyExportT2Kwh;
+ }
+
+ /**
+ * Setter for the total exported energy on counter 2
+ *
+ * @param totalEnergyExportT2Kwh
+ */
+ public void setTotalEnergyExportT2Kwh(double totalEnergyExportT2Kwh) {
+ this.totalEnergyExportT2Kwh = totalEnergyExportT2Kwh;
+ }
+
+ /**
+ * Getter for the current active total power
+ *
+ * @return current active total power
+ */
+ public double getActivePowerW() {
+ return activePowerW;
+ }
+
+ /**
+ * Setter for the current active total power
+ *
+ * @param activePowerW
+ */
+ public void setActivePowerW(double activePowerW) {
+ this.activePowerW = activePowerW;
+ }
+
+ /**
+ * Getter for the current active total power on phase 1
+ *
+ * @return current active total power on phase 1
+ */
+ public double getActivePowerL1W() {
+ return activePowerL1W;
+ }
+
+ /**
+ * Setter for the current active power on phase 1
+ *
+ * @param activePowerL1W current active total power on phase 1
+ */
+ public void setActivePowerL1W(double activePowerL1W) {
+ this.activePowerL1W = activePowerL1W;
+ }
+
+ /**
+ * Getter for the current active total power on phase 2
+ *
+ * @return current active total power on phase 2
+ */
+ public double getActivePowerL2W() {
+ return activePowerL2W;
+ }
+
+ /**
+ * Setter for the current active power on phase 2
+ *
+ * @param activePowerL2W current active total power on phase 2
+ */
+ public void setActivePowerL2W(double activePowerL2W) {
+ this.activePowerL2W = activePowerL2W;
+ }
+
+ /**
+ * Getter for the current active total power on phase 3
+ *
+ * @return current active total power on phase 3
+ */
+ public double getActivePowerL3W() {
+ return activePowerL3W;
+ }
+
+ /**
+ * Setter for the current active power on phase 3
+ *
+ * @param activePowerL3W current active total power on phase 3
+ */
+ public void setActivePowerL3W(double activePowerL3W) {
+ this.activePowerL3W = activePowerL3W;
+ }
+
+ /**
+ * Getter for the total imported gas volume
+ *
+ * @return total imported gas volume
+ */
+ public double getTotalGasM3() {
+ return totalGasM3;
+ }
+
+ /**
+ * Setter for the total imported gas volume
+ *
+ * @param totalGasM3 total imported gas volume
+ */
+ public void setTotalGasM3(double totalGasM3) {
+ this.totalGasM3 = totalGasM3;
+ }
+
+ /**
+ * Getter for the time stamp of the last gas update
+ *
+ * @return time stamp of the last gas update
+ */
+ public long getGasTimestamp() {
+ return gasTimestamp;
+ }
+
+ /**
+ * Setter for the time stamp of the last gas update
+ *
+ * @param gasTimestamp time stamp of the last gas update
+ */
+ public void setGasTimestamp(long gasTimestamp) {
+ this.gasTimestamp = gasTimestamp;
+ }
+
+ /**
+ * Getter for the total imported water volume
+ *
+ * @return total imported water volume
+ */
+ public double getTotalWaterM3() {
+ return totalWaterM3;
+ }
+
+ /**
+ * Setter for the total imported water volume
+ *
+ * @param totalWaterM3 total imported water volume
+ */
+ public void setTotalWaterM3(double totalWaterM3) {
+ this.totalWaterM3 = totalWaterM3;
+ }
+
+ /**
+ * Getter for the current water flow
+ *
+ * @return current water flow
+ */
+ public double getCurrentWaterLPM() {
+ return currentWaterLPM;
+ }
+
+ /**
+ * Setter for the current water flow
+ *
+ * @param currentWaterLPM current water flow
+ */
+ public void setCurrentWaterLPM(double currentWaterLPM) {
+ this.currentWaterLPM = currentWaterLPM;
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ """
+ Data [smrVersion: %d meterModel: %s wifiSsid: %s wifiStrength: %d"
+ totalEnergyImportT1Kwh: %f totalEnergyImportT2Kwh: %f totalEnergyExportT1Kwh: %f totalEnergyExportT2Kwh: %f"
+ activePowerW: %f activePowerL1W: %f activePowerL2W: %f activePowerL3W: %f totalGasM3: %f gasTimestamp: %.0f"
+ totalWaterM3: %f currentWaterLPM: %f]
+ """,
+ smrVersion, meterModel, wifiSsid, wifiStrength, totalEnergyImportT1Kwh, totalEnergyImportT2Kwh,
+ totalEnergyExportT1Kwh, totalEnergyExportT2Kwh, activePowerW, activePowerL1W, activePowerL2W,
+ activePowerL3W, totalGasM3, gasTimestamp, totalWaterM3, currentWaterLPM);
+ }
+}
private static final String BINDING_ID = "homewizard";
// List of all Thing Type UIDs
- public static final ThingTypeUID THING_TYPE_P1_WIFI_METER = new ThingTypeUID(BINDING_ID, "p1_wifi_meter");
+ public static final ThingTypeUID THING_TYPE_P1_METER = new ThingTypeUID(BINDING_ID, "p1_wifi_meter");
+ public static final ThingTypeUID THING_TYPE_ENERGY_SOCKET = new ThingTypeUID(BINDING_ID, "energy_socket");
+ public static final ThingTypeUID THING_TYPE_WATERMETER = new ThingTypeUID(BINDING_ID, "watermeter");
// List of all Channel ids
public static final String CHANNEL_ENERGY_IMPORT_T1 = "total_energy_import_t1";
public static final String CHANNEL_ACTIVE_POWER_L3 = "active_power_l3";
public static final String CHANNEL_TOTAL_GAS = "total_gas";
public static final String CHANNEL_GAS_TIMESTAMP = "gas_timestamp";
+ public static final String CHANNEL_TOTAL_WATER = "total_water";
+ public static final String CHANNEL_CURRENT_WATER = "current_water";
+
+ public static final String CHANNEL_POWER_SWITCH = "power_switch";
+ public static final String CHANNEL_POWER_LOCK = "power_lock";
+ public static final String CHANNEL_RING_BRIGHTNESS = "ring_brightness";
public static final String PROPERTY_METER_MODEL = "meterModel";
public static final String PROPERTY_METER_VERSION = "meterVersion";
public class HomeWizardConfiguration {
/**
- * IP Address or host for the P1 Meter
+ * IP Address or host for a HomeWizard device.
*/
public String ipAddress = "";
--- /dev/null
+/**
+ * Copyright (c) 2010-2024 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;
+
+import java.io.IOException;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.core.io.net.http.HttpUtil;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingStatus;
+import org.openhab.core.thing.ThingStatusDetail;
+import org.openhab.core.thing.binding.BaseThingHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.FieldNamingPolicy;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+/**
+ * The {@link HomeWizardDeviceHandler} is a base class for all
+ * HomeWizard devices. It provides configuration and polling of
+ * data from a device. It also processes common data.
+ *
+ * @author Daniël van Os - Initial contribution
+ */
+@NonNullByDefault
+public abstract class HomeWizardDeviceHandler extends BaseThingHandler {
+
+ protected final Logger logger = LoggerFactory.getLogger(HomeWizardDeviceHandler.class);
+ protected final Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
+ .create();
+
+ private HomeWizardConfiguration config = new HomeWizardConfiguration();
+ private @Nullable ScheduledFuture<?> pollingJob;
+
+ protected String apiURL = "";
+
+ /**
+ * Constructor
+ *
+ * @param thing The thing to handle
+ */
+ public HomeWizardDeviceHandler(Thing thing) {
+ super(thing);
+ }
+
+ /**
+ * If a host has been specified start polling it
+ */
+ @Override
+ public void initialize() {
+ config = getConfigAs(HomeWizardConfiguration.class);
+ if (configure()) {
+ pollingJob = scheduler.scheduleWithFixedDelay(this::pollingCode, 0, config.refreshDelay, TimeUnit.SECONDS);
+ }
+ }
+
+ /**
+ * Check the current configuration
+ *
+ * @return true if the configuration is ok to start polling, false otherwise
+ */
+ private boolean configure() {
+ if (config.ipAddress.trim().isEmpty()) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
+ "Missing ipAddress/host configuration");
+ return false;
+ } else {
+ updateStatus(ThingStatus.UNKNOWN);
+ apiURL = String.format("http://%s/api/v1/", config.ipAddress.trim());
+ return true;
+ }
+ }
+
+ /**
+ * dispose: stop the poller
+ */
+ @Override
+ public void dispose() {
+ var job = pollingJob;
+ if (job != null) {
+ job.cancel(true);
+ }
+ pollingJob = null;
+ }
+
+ /**
+ * Device specific handling of the returned data payload.
+ *
+ * @param payload The data parsed from the data Json file
+ */
+ abstract protected void handleDataPayload(DataPayload payload);
+
+ /**
+ *
+ */
+ protected void pollData() {
+ final String dataResult;
+
+ try {
+ dataResult = HttpUtil.executeUrl("GET", apiURL + "data", 30000);
+ } catch (IOException e) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
+ String.format("Unable to query device data: %s", e.getMessage()));
+ return;
+ }
+
+ if (dataResult.trim().isEmpty()) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Device returned empty data");
+ return;
+ }
+
+ DataPayload dataPayload = gson.fromJson(dataResult, DataPayload.class);
+ if (dataPayload == null) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
+ "Unable to parse data response from device");
+ return;
+ }
+
+ if ("".equals(dataPayload.getWifiSsid())) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Results from API are empty");
+ return;
+ }
+
+ updateStatus(ThingStatus.ONLINE);
+ handleDataPayload(dataPayload);
+ }
+
+ /**
+ * The actual polling loop
+ */
+ protected void pollingCode() {
+ pollData();
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2010-2024 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;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.library.types.PercentType;
+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;
+import org.openhab.core.types.RefreshType;
+
+/**
+ * The {@link HomeWizardEnergySocketHandler} implements functionality to handle a HomeWizard EnergySocket.
+ *
+ * @author Daniël van Os - Initial contribution
+ */
+@NonNullByDefault
+public class HomeWizardEnergySocketHandler extends HomeWizardStatefulDeviceHandler {
+
+ /**
+ * Constructor
+ *
+ * @param thing The thing to handle
+ */
+ public HomeWizardEnergySocketHandler(Thing thing) {
+ super(thing);
+ }
+
+ /**
+ * Converts a brightness value (0..255) to a percentage.
+ *
+ * @param brightness The brightness to convert.
+ * @return brightness percentage
+ */
+ private int brightnessToPercentage(int brightness) {
+ return (int) (100.0 * brightness / 255.0 + 0.5);
+ }
+
+ /**
+ * Converts a percentage to a brightness value (0..255)
+ *
+ * @param percentage The percentage to convert.
+ * @return brightness value
+ */
+ private int percentageToBrightness(String percentage) {
+ return (int) (Double.valueOf(percentage) * 255.0 / 100.0 + 0.5);
+ }
+
+ /**
+ * Handle incoming commands.
+ *
+ * Power on/off, Power lock/unlock and Ring brightness are supported.
+ */
+ @Override
+ public void handleCommand(ChannelUID channelUID, Command command) {
+ if (command instanceof RefreshType) {
+ // For now I prefer not updating immediately above firing a full update request for each channel
+ return;
+ }
+
+ StatePayload result = null;
+
+ /*
+ * The returned payloads below only contain the modified value, so each has it's own
+ * call to updateState instead of just calling handleStatePayload() with the returned
+ * payload.
+ */
+
+ switch (channelUID.getId()) {
+ case HomeWizardBindingConstants.CHANNEL_RING_BRIGHTNESS: {
+ result = sendStateCommand(
+ String.format("{\"brightness\": %d}", percentageToBrightness(command.toFullString())));
+ if (result != null) {
+ updateState(HomeWizardBindingConstants.CHANNEL_RING_BRIGHTNESS,
+ new PercentType(brightnessToPercentage(result.getBrightness())));
+ }
+ break;
+ }
+ case HomeWizardBindingConstants.CHANNEL_POWER_SWITCH: {
+ boolean onOff = command.equals(OnOffType.ON);
+ result = sendStateCommand(String.format("{\"power_on\": %b}", onOff));
+ if (result != null) {
+ updateState(HomeWizardBindingConstants.CHANNEL_POWER_SWITCH, OnOffType.from(result.getPowerOn()));
+ }
+ break;
+ }
+ case HomeWizardBindingConstants.CHANNEL_POWER_LOCK: {
+ boolean onOff = command.equals(OnOffType.ON);
+ result = sendStateCommand(String.format("{\"switch_lock\": %b}", onOff));
+ if (result != null) {
+ updateState(HomeWizardBindingConstants.CHANNEL_POWER_LOCK, OnOffType.from(result.getSwitchLock()));
+ }
+ break;
+ }
+ default:
+ logger.warn("Should handle {} {}", channelUID.getIdWithoutGroup(), command);
+ break;
+ }
+ }
+
+ /**
+ * Device specific handling of the returned payload.
+ *
+ * @param payload The data parsed from the Json file
+ */
+ @Override
+ protected void handleDataPayload(DataPayload payload) {
+ updateState(HomeWizardBindingConstants.CHANNEL_ENERGY_IMPORT_T1,
+ new QuantityType<>(payload.getTotalEnergyImportT1Kwh(), Units.KILOWATT_HOUR));
+ updateState(HomeWizardBindingConstants.CHANNEL_ENERGY_EXPORT_T1,
+ new QuantityType<>(payload.getTotalEnergyExportT1Kwh(), Units.KILOWATT_HOUR));
+ updateState(HomeWizardBindingConstants.CHANNEL_ACTIVE_POWER,
+ new QuantityType<>(payload.getActivePowerW(), Units.WATT));
+ }
+
+ @Override
+ protected void handleStatePayload(StatePayload payload) {
+ updateState(HomeWizardBindingConstants.CHANNEL_POWER_SWITCH, OnOffType.from(payload.getPowerOn()));
+ updateState(HomeWizardBindingConstants.CHANNEL_POWER_LOCK, OnOffType.from(payload.getSwitchLock()));
+ updateState(HomeWizardBindingConstants.CHANNEL_RING_BRIGHTNESS,
+ new PercentType(brightnessToPercentage(payload.getBrightness())));
+ }
+}
+++ /dev/null
-/**
- * Copyright (c) 2010-2024 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;
-
-import java.io.IOException;
-import java.time.DateTimeException;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
-import org.openhab.core.io.net.http.HttpUtil;
-import org.openhab.core.library.types.DateTimeType;
-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.thing.ThingStatus;
-import org.openhab.core.thing.ThingStatusDetail;
-import org.openhab.core.thing.binding.BaseThingHandler;
-import org.openhab.core.types.Command;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.gson.FieldNamingPolicy;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-
-/**
- * The {@link HomeWizardHandler} is responsible for handling commands, which are
- * sent to one of the channels.
- *
- * @author Daniël van Os - Initial contribution
- */
-@NonNullByDefault
-public class HomeWizardHandler extends BaseThingHandler {
-
- private final Logger logger = LoggerFactory.getLogger(HomeWizardHandler.class);
- private final Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
- .create();
-
- private HomeWizardConfiguration config = new HomeWizardConfiguration();
- private @Nullable ScheduledFuture<?> pollingJob;
-
- private String apiURL = "";
- private String meterModel = "";
- private int meterVersion = 0;
-
- /**
- * Constructor
- *
- * @param thing The thing to handle
- */
- public HomeWizardHandler(Thing thing) {
- super(thing);
- }
-
- /**
- * Not listening to any commands.
- */
- @Override
- public void handleCommand(ChannelUID channelUID, Command command) {
- }
-
- /**
- * If a host has been specified start polling it
- */
- @Override
- public void initialize() {
- config = getConfigAs(HomeWizardConfiguration.class);
- if (configure()) {
- pollingJob = scheduler.scheduleWithFixedDelay(this::pollingCode, 0, config.refreshDelay, TimeUnit.SECONDS);
- }
- }
-
- /**
- * Check the current configuration
- *
- * @return true if the configuration is ok to start polling, false otherwise
- */
- private boolean configure() {
- if (config.ipAddress.trim().isEmpty()) {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
- "Missing ipAddress/host configuration");
- return false;
- } else {
- updateStatus(ThingStatus.UNKNOWN);
- apiURL = String.format("http://%s/api/v1/data", config.ipAddress.trim());
- return true;
- }
- }
-
- /**
- * dispose: stop the poller
- */
- @Override
- public void dispose() {
- var job = pollingJob;
- if (job != null) {
- job.cancel(true);
- }
- pollingJob = null;
- }
-
- /**
- * The actual polling loop
- */
- private void pollingCode() {
- final String result;
-
- try {
- result = HttpUtil.executeUrl("GET", apiURL, 30000);
- } catch (IOException e) {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
- String.format("Unable to query P1 Meter: %s", e.getMessage()));
- return;
- }
-
- if (result.trim().isEmpty()) {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
- "P1 Meter API returned empty status");
- return;
- }
-
- P1Payload payload = gson.fromJson(result, P1Payload.class);
- if (payload == null) {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
- "Unable to parse response from P1 meter");
- return;
- }
-
- if ("".equals(payload.getMeterModel())) {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Results from API are empty");
- return;
- }
-
- updateStatus(ThingStatus.ONLINE);
-
- if (!meterModel.equals(payload.getMeterModel())) {
- meterModel = payload.getMeterModel();
- updateProperty(HomeWizardBindingConstants.PROPERTY_METER_MODEL, meterModel);
- }
-
- if (meterVersion != payload.getSmrVersion()) {
- meterVersion = payload.getSmrVersion();
- updateProperty(HomeWizardBindingConstants.PROPERTY_METER_VERSION, String.format("%d", meterVersion));
- }
-
- updateState(HomeWizardBindingConstants.CHANNEL_ENERGY_IMPORT_T1,
- new QuantityType<>(payload.getTotalEnergyImportT1Kwh(), Units.KILOWATT_HOUR));
- updateState(HomeWizardBindingConstants.CHANNEL_ENERGY_IMPORT_T2,
- new QuantityType<>(payload.getTotalEnergyImportT2Kwh(), Units.KILOWATT_HOUR));
- updateState(HomeWizardBindingConstants.CHANNEL_ENERGY_EXPORT_T1,
- new QuantityType<>(payload.getTotalEnergyExportT1Kwh(), Units.KILOWATT_HOUR));
- updateState(HomeWizardBindingConstants.CHANNEL_ENERGY_EXPORT_T2,
- new QuantityType<>(payload.getTotalEnergyExportT2Kwh(), Units.KILOWATT_HOUR));
-
- updateState(HomeWizardBindingConstants.CHANNEL_ACTIVE_POWER,
- new QuantityType<>(payload.getActivePowerW(), Units.WATT));
- updateState(HomeWizardBindingConstants.CHANNEL_ACTIVE_POWER_L1,
- new QuantityType<>(payload.getActivePowerL1W(), Units.WATT));
- updateState(HomeWizardBindingConstants.CHANNEL_ACTIVE_POWER_L2,
- new QuantityType<>(payload.getActivePowerL2W(), Units.WATT));
- updateState(HomeWizardBindingConstants.CHANNEL_ACTIVE_POWER_L3,
- new QuantityType<>(payload.getActivePowerL3W(), Units.WATT));
-
- // If no data from the gas meter is present, the json value will be null, which means gson ignores it,
- // leaving the value in the payload object at 0.
- long dtv = payload.getGasTimestamp();
- if (dtv > 0) {
- updateState(HomeWizardBindingConstants.CHANNEL_TOTAL_GAS,
- new QuantityType<>(payload.getTotalGasM3(), SIUnits.CUBIC_METRE));
-
- // 210119164000
- int seconds = (int) (dtv % 100);
-
- dtv /= 100;
- int minutes = (int) (dtv % 100);
-
- dtv /= 100;
- int hours = (int) (dtv % 100);
-
- dtv /= 100;
- int day = (int) (dtv % 100);
-
- dtv /= 100;
- int month = (int) (dtv % 100);
-
- dtv /= 100;
- int year = (int) (dtv + 2000);
-
- try {
- DateTimeType dtt = new DateTimeType(
- ZonedDateTime.of(year, month, day, hours, minutes, seconds, 0, ZoneId.systemDefault()));
- updateState(HomeWizardBindingConstants.CHANNEL_GAS_TIMESTAMP, dtt);
- updateState(HomeWizardBindingConstants.CHANNEL_TOTAL_GAS,
- new QuantityType<>(payload.getTotalGasM3(), SIUnits.CUBIC_METRE));
- } catch (DateTimeException e) {
- logger.warn("Unable to parse Gas timestamp: {}", payload.getGasTimestamp());
- }
- }
- }
-}
*/
package org.openhab.binding.homewizard.internal;
-import static org.openhab.binding.homewizard.internal.HomeWizardBindingConstants.THING_TYPE_P1_WIFI_METER;
+import static org.openhab.binding.homewizard.internal.HomeWizardBindingConstants.*;
import java.util.Set;
@Component(configurationPid = "binding.homewizard", service = ThingHandlerFactory.class)
public class HomeWizardHandlerFactory extends BaseThingHandlerFactory {
- private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_P1_WIFI_METER);
+ private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_P1_METER,
+ THING_TYPE_ENERGY_SOCKET, THING_TYPE_WATERMETER);
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
- if (THING_TYPE_P1_WIFI_METER.equals(thingTypeUID)) {
- return new HomeWizardHandler(thing);
+ if (THING_TYPE_P1_METER.equals(thingTypeUID)) {
+ return new HomeWizardP1MeterHandler(thing);
+ }
+
+ if (THING_TYPE_ENERGY_SOCKET.equals(thingTypeUID)) {
+ return new HomeWizardEnergySocketHandler(thing);
+ }
+
+ if (THING_TYPE_WATERMETER.equals(thingTypeUID)) {
+ return new HomeWizardWaterMeterHandler(thing);
}
return null;
--- /dev/null
+/**
+ * Copyright (c) 2010-2024 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;
+
+import java.time.DateTimeException;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.library.types.DateTimeType;
+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 HomeWizardP1MeterHandler} implements functionality to handle a HomeWizard P1 Meter.
+ *
+ * @author Daniël van Os - Initial contribution
+ */
+@NonNullByDefault
+public class HomeWizardP1MeterHandler extends HomeWizardDeviceHandler {
+
+ private String meterModel = "";
+ private int meterVersion = 0;
+
+ /**
+ * Constructor
+ *
+ * @param thing The thing to handle
+ */
+ public HomeWizardP1MeterHandler(Thing thing) {
+ super(thing);
+ }
+
+ /**
+ * Not listening to any commands.
+ */
+ @Override
+ public void handleCommand(ChannelUID channelUID, Command command) {
+ }
+
+ /**
+ * Device specific handling of the returned payload.
+ *
+ * @param payload The data parsed from the Json file
+ */
+ @Override
+ protected void handleDataPayload(DataPayload payload) {
+ if (!meterModel.equals(payload.getMeterModel())) {
+ meterModel = payload.getMeterModel();
+ updateProperty(HomeWizardBindingConstants.PROPERTY_METER_MODEL, meterModel);
+ }
+
+ if (meterVersion != payload.getSmrVersion()) {
+ meterVersion = payload.getSmrVersion();
+ updateProperty(HomeWizardBindingConstants.PROPERTY_METER_VERSION, String.format("%d", meterVersion));
+ }
+
+ updateState(HomeWizardBindingConstants.CHANNEL_ENERGY_IMPORT_T1,
+ new QuantityType<>(payload.getTotalEnergyImportT1Kwh(), Units.KILOWATT_HOUR));
+ updateState(HomeWizardBindingConstants.CHANNEL_ENERGY_IMPORT_T2,
+ new QuantityType<>(payload.getTotalEnergyImportT2Kwh(), Units.KILOWATT_HOUR));
+ updateState(HomeWizardBindingConstants.CHANNEL_ENERGY_EXPORT_T1,
+ new QuantityType<>(payload.getTotalEnergyExportT1Kwh(), Units.KILOWATT_HOUR));
+ updateState(HomeWizardBindingConstants.CHANNEL_ENERGY_EXPORT_T2,
+ new QuantityType<>(payload.getTotalEnergyExportT2Kwh(), Units.KILOWATT_HOUR));
+
+ updateState(HomeWizardBindingConstants.CHANNEL_ACTIVE_POWER,
+ new QuantityType<>(payload.getActivePowerW(), Units.WATT));
+ updateState(HomeWizardBindingConstants.CHANNEL_ACTIVE_POWER_L1,
+ new QuantityType<>(payload.getActivePowerL1W(), Units.WATT));
+ updateState(HomeWizardBindingConstants.CHANNEL_ACTIVE_POWER_L2,
+ new QuantityType<>(payload.getActivePowerL2W(), Units.WATT));
+ updateState(HomeWizardBindingConstants.CHANNEL_ACTIVE_POWER_L3,
+ new QuantityType<>(payload.getActivePowerL3W(), Units.WATT));
+
+ // If no data from the gas meter is present, the json value will be null, which means gson ignores it,
+ // leaving the value in the payload object at 0.
+ long dtv = payload.getGasTimestamp();
+ if (dtv > 0) {
+ updateState(HomeWizardBindingConstants.CHANNEL_TOTAL_GAS,
+ new QuantityType<>(payload.getTotalGasM3(), SIUnits.CUBIC_METRE));
+
+ // 210119164000
+ int seconds = (int) (dtv % 100);
+
+ dtv /= 100;
+ int minutes = (int) (dtv % 100);
+
+ dtv /= 100;
+ int hours = (int) (dtv % 100);
+
+ dtv /= 100;
+ int day = (int) (dtv % 100);
+
+ dtv /= 100;
+ int month = (int) (dtv % 100);
+
+ dtv /= 100;
+ int year = (int) (dtv + 2000);
+
+ try {
+ DateTimeType dtt = new DateTimeType(
+ ZonedDateTime.of(year, month, day, hours, minutes, seconds, 0, ZoneId.systemDefault()));
+ updateState(HomeWizardBindingConstants.CHANNEL_GAS_TIMESTAMP, dtt);
+ updateState(HomeWizardBindingConstants.CHANNEL_TOTAL_GAS,
+ new QuantityType<>(payload.getTotalGasM3(), SIUnits.CUBIC_METRE));
+ } catch (DateTimeException e) {
+ logger.warn("Unable to parse Gas timestamp: {}", payload.getGasTimestamp());
+ }
+ }
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2010-2024 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;
+
+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.core.io.net.http.HttpUtil;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingStatus;
+import org.openhab.core.thing.ThingStatusDetail;
+
+/**
+ * The {@link HomeWizardStatefulDeviceHandler} extends the base class
+ * to provide support for devices that also have a 'state' interface.
+ * This interface can be used to query and control the state of a device.
+ *
+ * @author Daniël van Os - Initial contribution
+ */
+@NonNullByDefault
+public abstract class HomeWizardStatefulDeviceHandler extends HomeWizardDeviceHandler {
+
+ /**
+ * Constructor
+ *
+ * @param thing The thing to handle
+ */
+ public HomeWizardStatefulDeviceHandler(Thing thing) {
+ super(thing);
+ }
+
+ /**
+ * Device specific handling of the returned state payload.
+ *
+ * @param payload The data parsed from the state Json file
+ */
+ abstract protected void handleStatePayload(StatePayload payload);
+
+ protected void pollState() {
+ final String stateResult;
+
+ try {
+ stateResult = HttpUtil.executeUrl("GET", apiURL + "state", 30000);
+ } catch (IOException e) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
+ String.format("Unable to query device state: %s", e.getMessage()));
+ return;
+ }
+
+ if (stateResult.trim().isEmpty()) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Device returned empty state");
+ return;
+ }
+
+ StatePayload statePayload = gson.fromJson(stateResult, StatePayload.class);
+ if (statePayload == null) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
+ "Unable to parse state response from device");
+ return;
+ }
+
+ handleStatePayload(statePayload);
+ }
+
+ /**
+ * Sends a command to the state interface of the device.
+ *
+ * @param command The command to send.
+ */
+ protected @Nullable StatePayload sendStateCommand(String command) {
+ try (InputStream is = new ByteArrayInputStream(command.getBytes())) {
+ String updatedState = HttpUtil.executeUrl("PUT", apiURL + "state", is, "application/json", 30000);
+ return gson.fromJson(updatedState, StatePayload.class);
+ } catch (IOException e) {
+ logger.warn("Failed to send command {} to {}", command, apiURL + "state");
+ return null;
+ }
+ }
+
+ /*
+ * This overrides the original polling loop by including a request for the current state..
+ */
+ @Override
+ protected void pollingCode() {
+ pollData();
+ pollState();
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2010-2024 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;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+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.
+ *
+ * @author Daniël van Os - Initial contribution
+ */
+@NonNullByDefault
+public class HomeWizardWaterMeterHandler extends HomeWizardDeviceHandler {
+
+ /**
+ * Constructor
+ *
+ * @param thing The thing to handle
+ */
+ public HomeWizardWaterMeterHandler(Thing thing) {
+ super(thing);
+ }
+
+ /**
+ * Not listening to any commands.
+ */
+ @Override
+ public void handleCommand(ChannelUID channelUID, Command command) {
+ }
+
+ /**
+ * Device specific handling of the returned payload.
+ *
+ * @param payload The data parsed from the Json file
+ */
+ @Override
+ protected void handleDataPayload(DataPayload payload) {
+ updateState(HomeWizardBindingConstants.CHANNEL_CURRENT_WATER,
+ new QuantityType<>(payload.getCurrentWaterLPM(), Units.LITRE_PER_MINUTE));
+ updateState(HomeWizardBindingConstants.CHANNEL_TOTAL_WATER,
+ new QuantityType<>(payload.getTotalWaterM3(), SIUnits.CUBIC_METRE));
+ }
+}
+++ /dev/null
-/**
- * Copyright (c) 2010-2024 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;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-
-import com.google.gson.annotations.SerializedName;
-
-/**
- * Class that provides storage for the json object obtained from the P1 meter API
- *
- * @author Daniël van Os - Initial contribution
- *
- */
-@NonNullByDefault
-public class P1Payload {
- private int smrVersion = 0;
- private String meterModel = "";
- private String wifiSsid = "";
- private int wifiStrength = 0;
-
- @SerializedName("total_power_import_t1_kwh")
- private double totalEnergyImportT1Kwh;
- @SerializedName("total_power_import_t2_kwh")
- private double totalEnergyImportT2Kwh;
- @SerializedName("total_power_export_t1_kwh")
- private double totalEnergyExportT1Kwh;
- @SerializedName("total_power_export_t2_kwh")
- private double totalEnergyExportT2Kwh;
-
- private double activePowerW;
- private double activePowerL1W;
- private double activePowerL2W;
- private double activePowerL3W;
- private double totalGasM3;
- private long gasTimestamp = 0;
-
- /**
- * Getter for the smart meter version
- *
- * @return The most recent smart meter version obtained from the API
- */
- public int getSmrVersion() {
- return smrVersion;
- }
-
- /**
- * Setter for the smart meter version
- *
- * @param smrVersion The smart meter version to set
- */
- public void setSmrVersion(int smrVersion) {
- this.smrVersion = smrVersion;
- }
-
- /**
- * Getter for the meter model
- *
- * @return meter model
- */
- public String getMeterModel() {
- return meterModel;
- }
-
- /**
- * Setter for the meter model
- *
- * @param meterModel meter model
- */
- public void setMeterModel(String meterModel) {
- this.meterModel = meterModel;
- }
-
- /**
- * Getter for the meter's wifi ssid
- *
- * @return the meter's wifi sid
- */
- public String getWifiSsid() {
- return wifiSsid;
- }
-
- /**
- * Setter for the wifi ssid
- *
- * @param wifiSsid wifi ssid
- */
- public void setWifiSsid(String wifiSsid) {
- this.wifiSsid = wifiSsid;
- }
-
- /**
- * Getter for the wifi rssi
- *
- * @return wifi rssi
- */
- public int getWifiStrength() {
- return wifiStrength;
- }
-
- /**
- * Setter for the wifi rssi
- *
- * @param wifiStrength wifi rssi
- */
- public void setWifiStrength(int wifiStrength) {
- this.wifiStrength = wifiStrength;
- }
-
- /**
- * Getter for the total imported energy on counter 1
- *
- * @return total imported energy on counter 1
- */
- public double getTotalEnergyImportT1Kwh() {
- return totalEnergyImportT1Kwh;
- }
-
- /**
- * Setter for the total imported energy on counter 1
- *
- * @param totalEnergyImportT1Kwh total imported energy on counter 1
- */
- public void setTotalEnergyImportT1Kwh(double totalEnergyImportT1Kwh) {
- this.totalEnergyImportT1Kwh = totalEnergyImportT1Kwh;
- }
-
- /**
- * Getter for the total imported energy on counter 2
- *
- * @return total imported energy on counter 2
- */
- public double getTotalEnergyImportT2Kwh() {
- return totalEnergyImportT2Kwh;
- }
-
- /**
- * Setter for the total imported energy on counter 2
- *
- * @param totalEnergyImportT2Kwh
- */
- public void setTotalEnergyImportT2Kwh(double totalEnergyImportT2Kwh) {
- this.totalEnergyImportT2Kwh = totalEnergyImportT2Kwh;
- }
-
- /**
- * Getter for the total exported energy on counter 1
- *
- * @return total exported energy on counter 1
- */
- public double getTotalEnergyExportT1Kwh() {
- return totalEnergyExportT1Kwh;
- }
-
- /**
- * Setter for the total exported energy on counter 1
- *
- * @param totalEnergyExportT1Kwh
- */
- public void setTotalEnergyExportT1Kwh(double totalEnergyExportT1Kwh) {
- this.totalEnergyExportT1Kwh = totalEnergyExportT1Kwh;
- }
-
- /**
- * Getter for the total exported energy on counter 2
- *
- * @return total exported energy on counter 2
- */
- public double getTotalEnergyExportT2Kwh() {
- return totalEnergyExportT2Kwh;
- }
-
- /**
- * Setter for the total exported energy on counter 2
- *
- * @param totalEnergyExportT2Kwh
- */
- public void setTotalEnergyExportT2Kwh(double totalEnergyExportT2Kwh) {
- this.totalEnergyExportT2Kwh = totalEnergyExportT2Kwh;
- }
-
- /**
- * Getter for the current active total power
- *
- * @return current active total power
- */
- public double getActivePowerW() {
- return activePowerW;
- }
-
- /**
- * Setter for the current active total power
- *
- * @param activePowerW
- */
- public void setActivePowerW(double activePowerW) {
- this.activePowerW = activePowerW;
- }
-
- /**
- * Getter for the current active total power on phase 1
- *
- * @return current active total power on phase 1
- */
- public double getActivePowerL1W() {
- return activePowerL1W;
- }
-
- /**
- * Setter for the current active power on phase 1
- *
- * @param activePowerL1W current active total power on phase 1
- */
- public void setActivePowerL1W(double activePowerL1W) {
- this.activePowerL1W = activePowerL1W;
- }
-
- /**
- * Getter for the current active total power on phase 2
- *
- * @return current active total power on phase 2
- */
- public double getActivePowerL2W() {
- return activePowerL2W;
- }
-
- /**
- * Setter for the current active power on phase 2
- *
- * @param activePowerL2W current active total power on phase 2
- */
- public void setActivePowerL2W(double activePowerL2W) {
- this.activePowerL2W = activePowerL2W;
- }
-
- /**
- * Getter for the current active total power on phase 3
- *
- * @return current active total power on phase 3
- */
- public double getActivePowerL3W() {
- return activePowerL3W;
- }
-
- /**
- * Setter for the current active power on phase 3
- *
- * @param activePowerL3W current active total power on phase 3
- */
- public void setActivePowerL3W(double activePowerL3W) {
- this.activePowerL3W = activePowerL3W;
- }
-
- /**
- * Getter for the total imported gas volume
- *
- * @return total imported gas volume
- */
- public double getTotalGasM3() {
- return totalGasM3;
- }
-
- /**
- * Setter for the total imported gas volume
- *
- * @param totalGasM3 total imported gas volume
- */
- public void setTotalGasM3(double totalGasM3) {
- this.totalGasM3 = totalGasM3;
- }
-
- /**
- * Getter for the time stamp of the last gas update
- *
- * @return time stamp of the last gas update
- */
- public long getGasTimestamp() {
- return gasTimestamp;
- }
-
- /**
- * Setter for the time stamp of the last gas update
- *
- * @param gasTimestamp time stamp of the last gas update
- */
- public void setGasTimestamp(long gasTimestamp) {
- this.gasTimestamp = gasTimestamp;
- }
-
- @Override
- public String toString() {
- return String.format(
- """
- P1 [version: %d model: %s ssid: %s signal: %d\
- imp1: %f imp2: %f exp1: %f exp2: %f active: %f active1: %f active2: %f active3: %f gas: %f timestamp: %.0f]\
- """,
- smrVersion, meterModel, wifiSsid, wifiStrength, totalEnergyImportT1Kwh, totalEnergyImportT2Kwh,
- totalEnergyExportT1Kwh, totalEnergyExportT2Kwh, activePowerW, activePowerL1W, activePowerL2W,
- activePowerL3W, totalGasM3, gasTimestamp);
- }
-}
--- /dev/null
+/**
+ * Copyright (c) 2010-2024 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;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Class that provides storage for the json object obtained from the HomeWizard device State API
+ *
+ * @author Daniël van Os - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class StatePayload {
+ @SerializedName("power_on")
+ private boolean powerOn;
+ @SerializedName("switch_lock")
+ private boolean switchLock;
+ private int brightness = 0;
+
+ /**
+ * Getter for the power_on field
+ *
+ * @return true if the device is currently on, false if it is off
+ */
+ public boolean getPowerOn() {
+ return powerOn;
+ }
+
+ /**
+ * Setter for the power_on field
+ *
+ * @param powerOn true to turn the device on, false to turn it off
+ */
+ public void setPowerOn(boolean powerOn) {
+ this.powerOn = powerOn;
+ }
+
+ /**
+ * Getter for the switch_lock field
+ *
+ * @return true if the device currently locked, false if it is not
+ */
+ public boolean getSwitchLock() {
+ return switchLock;
+ }
+
+ /**
+ * Setter for the power_on field
+ *
+ * @param switchLock true to lock the device, false to unlock it
+ */
+ public void setSwitchLock(boolean switchLock) {
+ this.switchLock = switchLock;
+ }
+
+ /**
+ * Getter for the ring brightness
+ *
+ * @return ring brightness percentage
+ */
+ public int getBrightness() {
+ return brightness;
+ }
+
+ /**
+ * Setter for the ring brightness
+ *
+ * @param brightness ring brightness
+ */
+ public void setBrightness(int brightness) {
+ this.brightness = brightness;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("State [power_on: %b switch_lock: %b brightness: %d]", powerOn, switchLock, brightness);
+ }
+}
# thing types
+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.p1_wifi_meter.label = HomeWizard Wi-Fi P1 Meter
thing-type.homewizard.p1_wifi_meter.description = This thing provides the measurement data that is available through the http interface of the HomeWizard Wi-Fi P1 Meter.
+thing-type.homewizard.watermeter.label = HomeWizard Wi-Fi Watermeter
+thing-type.homewizard.watermeter.description = This thing provides the measurement data that is available through the http interface of a HomeWizard Watermeter.
# thing types config
+thing-type.config.homewizard.energy_socket.ipAddress.label = Network Address
+thing-type.config.homewizard.energy_socket.ipAddress.description = The IP or host name of the Energysocket.
+thing-type.config.homewizard.energy_socket.refreshDelay.label = Refresh Interval
+thing-type.config.homewizard.energy_socket.refreshDelay.description = The refresh interval in seconds for polling the Energysocket.
thing-type.config.homewizard.p1_wifi_meter.ipAddress.label = Network Address
thing-type.config.homewizard.p1_wifi_meter.ipAddress.description = The IP or host name of the P1 Meter.
thing-type.config.homewizard.p1_wifi_meter.refreshDelay.label = Refresh Interval
thing-type.config.homewizard.p1_wifi_meter.refreshDelay.description = The refresh interval in seconds for polling the P1 Meter.
+thing-type.config.homewizard.watermeter.ipAddress.label = Network Address
+thing-type.config.homewizard.watermeter.ipAddress.description = The IP or host name of the Watermeter.
+thing-type.config.homewizard.watermeter.refreshDelay.label = Refresh Interval
+thing-type.config.homewizard.watermeter.refreshDelay.description = The refresh interval in seconds for polling the Watermeter.
# channel types
channel-type.homewizard.active_power_l2.description = This channel provides the current net phase 2 power in W. It will be below 0 if power is currently being exported. It will be 0 for single phase systems.
channel-type.homewizard.active_power_l3.label = Current Phase 3 Net Power
channel-type.homewizard.active_power_l3.description = This channel provides the current net phase 3 power in W. It will be below 0 if power is currently being exported. It will be 0 for single phase systems.
+channel-type.homewizard.current_water.label = Current Water Rate
+channel-type.homewizard.current_water.description = This channel provides the most recently reported current water usage in liters per minute.
channel-type.homewizard.gas_timestamp.label = Gas Update Time Stamp
channel-type.homewizard.gas_timestamp.description = This channel provides the time stamp of the total_gas measurement.
+channel-type.homewizard.power_lock.label = Power Lock
+channel-type.homewizard.power_lock.description = This channel provides access to the power lock of the Energysocket
+channel-type.homewizard.power_switch.label = Power Switch
+channel-type.homewizard.power_switch.description = This channel provides access to the power switch of the Energysocket
+channel-type.homewizard.ring_brightness.label = Ring Brightness
+channel-type.homewizard.ring_brightness.description = This channel provides access to the brightness of the ring of the Energysocket
channel-type.homewizard.total_energy_export_t1.label = Total Exported Energy Counter 1
channel-type.homewizard.total_energy_export_t1.description = This channel provides the most recently reported total exported energy in kWh by counter 1, most commonly used for export during the night or weekend.
channel-type.homewizard.total_energy_export_t2.label = Total Exported Energy Counter 2
channel-type.homewizard.total_energy_import_t2.description = This channel provides the most recently reported total imported energy in kWh by counter 2, most commonly used for import during the day.
channel-type.homewizard.total_gas.label = Total Imported Gas
channel-type.homewizard.total_gas.description = This channel provides the most recently reported total imported gas in m^3. It does not get updated as frequently as the data in the other channels, the gas_timestamp channel provides the time stamp of the most recent update.
+channel-type.homewizard.total_water.label = Total Imported Water
+channel-type.homewizard.total_water.description = This channel provides the most recently reported total imported water in m^3.
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
+
<thing-type id="p1_wifi_meter">
<label>HomeWizard Wi-Fi P1 Meter</label>
<description>This thing provides the measurement data that is available through the http interface of the HomeWizard
</thing-type>
+ <thing-type id="energy_socket">
+ <label>HomeWizard Energysocket</label>
+ <description>This thing provides the measurement data that is available through the http interface of a HomeWizard
+ Energysocket.</description>
+
+ <channels>
+ <channel id="total_energy_import_t1" typeId="total_energy_import_t1"/>
+ <channel id="total_energy_export_t1" typeId="total_energy_export_t1"/>
+ <channel id="active_power" typeId="active_power"/>
+
+ <channel id="power_switch" typeId="power_switch"/>
+ <channel id="power_lock" typeId="power_lock"/>
+ <channel id="ring_brightness" typeId="ring_brightness"/>
+
+ </channels>
+
+ <config-description>
+ <parameter name="ipAddress" type="text" required="true">
+ <label>Network Address</label>
+ <description>The IP or host name of the Energysocket.</description>
+ <context>network-address</context>
+ </parameter>
+ <parameter name="refreshDelay" type="integer" min="1" unit="s">
+ <label>Refresh Interval</label>
+ <description>The refresh interval in seconds for polling the Energysocket.</description>
+ <default>5</default>
+ </parameter>
+ </config-description>
+
+ </thing-type>
+
+ <thing-type id="watermeter">
+ <label>HomeWizard Wi-Fi Watermeter</label>
+ <description>This thing provides the measurement data that is available through the http interface of a HomeWizard
+ Watermeter.</description>
+
+ <channels>
+ <channel id="total_water" typeId="total_water"/>
+ <channel id="current_water" typeId="current_water"/>
+ </channels>
+
+ <config-description>
+ <parameter name="ipAddress" type="text" required="true">
+ <label>Network Address</label>
+ <description>The IP or host name of the Watermeter.</description>
+ <context>network-address</context>
+ </parameter>
+ <parameter name="refreshDelay" type="integer" min="1" unit="s">
+ <label>Refresh Interval</label>
+ <description>The refresh interval in seconds for polling the Watermeter.</description>
+ <default>5</default>
+ </parameter>
+ </config-description>
+
+ </thing-type>
+
<channel-type id="total_energy_import_t1">
<item-type>Number:Energy</item-type>
<label>Total Imported Energy Counter 1</label>
</description>
</channel-type>
+ <channel-type id="total_water">
+ <item-type>Number:Volume</item-type>
+ <label>Total Imported Water</label>
+ <description>
+ This channel provides the most recently reported total imported water in m^3.
+ </description>
+ <state readOnly="true" pattern="%.3f %unit%"/>
+ </channel-type>
+
+ <channel-type id="current_water">
+ <item-type>Number:VolumetricFlowRate</item-type>
+ <label>Current Water Rate</label>
+ <description>
+ This channel provides the most recently reported current water usage in liters per minute.
+ </description>
+ <state readOnly="true" pattern="%.0f %unit%"/>
+ </channel-type>
+
+ <channel-type id="power_switch">
+ <item-type>Switch</item-type>
+ <label>Power Switch</label>
+ <description>
+ This channel provides access to the power switch of the Energysocket
+ </description>
+ </channel-type>
+
+ <channel-type id="power_lock">
+ <item-type>Switch</item-type>
+ <label>Power Lock</label>
+ <description>
+ This channel provides access to the power lock of the Energysocket
+ </description>
+ </channel-type>
+
+ <channel-type id="ring_brightness">
+ <item-type unitHint="%">Number:Dimensionless</item-type>
+ <label>Ring Brightness</label>
+ <description>
+ This channel provides access to the brightness of the ring of the Energysocket
+ </description>
+ <state readOnly="true" pattern="%.0f %unit%"/>
+ </channel-type>
+
</thing:thing-descriptions>