Skip to content

Commit

Permalink
Merge branch 'openhab:main' into sungrow_additions
Browse files Browse the repository at this point in the history
  • Loading branch information
tscholand authored Mar 7, 2025
2 parents 9e7cca5 + 2e82fe6 commit 5192e2e
Show file tree
Hide file tree
Showing 64 changed files with 1,117 additions and 1,152 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@ void testConfigErrors() {
assertEquals(ThingStatus.OFFLINE, tsi.getStatus());
assertEquals(ThingStatusDetail.CONFIGURATION_ERROR, tsi.getStatusDetail());
assertEquals("@text/casokitchen.winecooler-2z.status.device-id-missing", tsi.getDescription());

config.put("deviceId", "xyz");
thing.setConfiguration(config);
winecoolerHandler.initialize();
callback.waitForOnline();
tsi = thing.getStatusInfo();
assertEquals(ThingStatus.ONLINE, tsi.getStatus());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,8 @@ public String toString() {
voltage: %f voltageL1: %f voltageL2: %f voltageL3: %f
current: %f currentL1: %f currentL2: %f currentL3: %f frequency: %f
]
""", energyImport, energyImportT1, energyExportT2, energyExport, energyExportT1, energyExportT2,
voltage, voltageL1, voltageL2, voltageL3, current, currentL1, currentL2, currentL3, frequency);
""", energyImport, energyImportT1, energyImportT2, energyExport, energyExportT1, energyExportT2, power,
powerL1, powerL2, powerL3, voltage, voltageL1, voltageL2, voltageL3, current, currentL1, currentL2,
currentL3, frequency);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@ public double getTotalGasM3() {
@Override
public String toString() {
return super.toString() + " " + String.format("""
Data [protocolVersion: %d meterModel: %s anyPowerFailCount: %f longPowerFailCount: %f"
totalGasM3: %f gasTimestamp: %.0f"
Data [protocolVersion: %d meterModel: %s anyPowerFailCount: %d longPowerFailCount: %d"
totalGasM3: %f gasTimestamp: %d"
""", protocolVersion, meterModel, anyPowerFailCount, longPowerFailCount, totalGasM3, gasTimestamp);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public int getCycles() {
@Override
public String toString() {
return String.format("""
Battery Data [stateOfCharge: %d cycles: %d"]
Battery Data [stateOfCharge: %f cycles: %f"]
""", stateOfCharge, cycles);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public void handleCommand(ChannelUID channelUID, Command command) {
*/
@Override
protected void handleDataPayload(String data) {
var payload = gson.fromJson(data, HomeWizardWaterMeterDataPayload.class);
var payload = gson.fromJson(data, HomeWizardWaterMeterMeasurementPayload.class);
if (payload != null) {
if (!thing.getThingTypeUID().equals(HomeWizardBindingConstants.THING_TYPE_WATERMETER)) {
updateState(HomeWizardBindingConstants.CHANNEL_GROUP_WATER,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
*
*/
@NonNullByDefault
public class HomeWizardWaterMeterDataPayload {
public class HomeWizardWaterMeterMeasurementPayload {

@SerializedName("active_liter_lpm")
private double activeLiter;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ 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.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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
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="HWE-kwh">
<thing-type id="hwe-kwh">
<label>HomeWizard kWh Meter</label>
<description>This thing provides the measurement data that is available through the API of a HomeWizard
kWh Meter.</description>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ public class HomeWizardWaterMeterMeasurementPayloadTest {

@Test
public void deserializeResponse() throws IOException {
HomeWizardWaterMeterDataPayload key = DATA_UTIL.fromJson("response-measurement-water-meter.json",
HomeWizardWaterMeterDataPayload.class);
HomeWizardWaterMeterMeasurementPayload key = DATA_UTIL.fromJson("response-measurement-water-meter.json",
HomeWizardWaterMeterMeasurementPayload.class);
assertThat(key, is(notNullValue()));

assertThat(key.getActiveLiter(), is(7.2));
Expand All @@ -44,8 +44,8 @@ public void deserializeResponse() throws IOException {

@Test
public void deserializeResponseEmpty() throws IOException {
HomeWizardWaterMeterDataPayload key = DATA_UTIL.fromJson("response-empty.json",
HomeWizardWaterMeterDataPayload.class);
HomeWizardWaterMeterMeasurementPayload key = DATA_UTIL.fromJson("response-empty.json",
HomeWizardWaterMeterMeasurementPayload.class);
assertThat(key, is(notNullValue()));

assertThat(key.getActiveLiter(), is(0.0));
Expand Down
10 changes: 10 additions & 0 deletions bundles/org.openhab.binding.ipcamera/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,16 @@ then
end
```

## How To Reboot Camera
```
rule "Reboot Camera At 12:00 AM"
when
Time cron "0 0 0 ? *"
then
getActions("ipcamera", "ipcamera:reolink:1a40bbe041").reboot()
end
```

## HABpanel

This section is about how to get things working in HABpanel.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,17 @@ public void recordGIF(
public static void recordGIF(ThingActions actions, @Nullable String filename, int secondsToRecord) {
((IpCameraActions) actions).recordGIF(filename, secondsToRecord);
}

@RuleAction(label = "reboot", description = "Reboot camera")
public void reboot() {
logger.debug("Rebooting camera.");
IpCameraHandler localHandler = handler;
if (localHandler != null) {
localHandler.reboot();
}
}

public static void reboot(@Nullable ThingActions actions) {
((IpCameraActions) actions).reboot();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,12 @@ public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object ms
ipCameraHandler.setChannelState(CHANNEL_ENABLE_RECORDINGS, OnOffType.ON);
}
break;
case "/api.cgi?cmd=Reboot":
// This handles reboot action response.
if (!content.contains("\"rspCode\" : 200")) {
ipCameraHandler.logger.warn("Reboot failed:\n{}", content);
}
break;
default:
// ignore responses from all Setxx commands
if (!cutDownURL.startsWith("/cgi-bin/api.cgi?cmd=Set")
Expand Down Expand Up @@ -589,4 +595,8 @@ public void handleCommand(ChannelUID channelUID, Command command) {
public List<String> getLowPriorityRequests() {
return List.of();
}

public void reboot() {
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=Reboot" + ipCameraHandler.reolinkAuth, "[{\"cmd\":\"Reboot\"}]");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1059,6 +1059,17 @@ public void recordGif(String filename, int seconds) {
setChannelState(CHANNEL_RECORDING_GIF, DecimalType.valueOf(new String("" + seconds)));
}

public void reboot() {
switch (thing.getThingTypeUID().getId()) {
case REOLINK_THING:
ReolinkHandler reolinkHandler = new ReolinkHandler(getHandle());
reolinkHandler.reboot();
break;
default:
logger.warn("Reboot is not yet supported for ipcamera type {}", thing.getThingTypeUID().getId());
}
}

private void getReolinkToken() {
sendHttpPOST("/api.cgi?cmd=Login",
"[{\"cmd\":\"Login\", \"param\":{ \"User\":{ \"Version\": \"0\", \"userName\":\""
Expand Down
24 changes: 24 additions & 0 deletions bundles/org.openhab.binding.keba/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,30 @@ All devices support the following channels:
| maxpilotcurrent | Number:ElectricCurrent | yes | current offered to the vehicle via control pilot signalization |
| maxpilotcurrentdutycyle | Number:Dimensionless | yes | duty cycle of the control pilot signal |

## Rule Actions

Certain Keba models support setting the text on the built-in display.
The text can be set via a rule action `setDisplay`. It comes in two variants:

```java
rule "Set Display Text"
when
System reached start level 100
then
val keContactActions = getActions("keba", "keba:kecontact:1")
// Default duration
keContactActions.setDisplay("TEXT$1")
// Explicit duration set
keContactActions.setDisplay("TEXT$2", 5, 10)
end
```

| Parameter | Description |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| text | Text shown on the display. Maximum 23 ASCII characters can be used. `~` == Σ, `$` == blank, `,` == comma |
| durationMin _(optional)_ | Defines the duration in seconds how long the text will displayed before another display command will be processed (internal MID metering relevant information may overrule this) |
| durationMax _(optional)_ | Defines the duration in seconds how long the text will displayed if no additional display command follows. |

## Example

demo.Things:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* 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.keba.internal.handler;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.keba.internal.KebaBindingConstants;
import org.openhab.core.automation.annotation.ActionInput;
import org.openhab.core.automation.annotation.RuleAction;
import org.openhab.core.thing.binding.ThingActions;
import org.openhab.core.thing.binding.ThingActionsScope;
import org.openhab.core.thing.binding.ThingHandler;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ServiceScope;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* The {@link KeContactActions} is responsible for handling actions, which
* are sent to the binding.
*
* @author Simon Spielmann - Initial contribution
*/
@Component(scope = ServiceScope.PROTOTYPE, service = KeContactActions.class)
@ThingActionsScope(name = KebaBindingConstants.BINDING_ID)
@NonNullByDefault
public class KeContactActions implements ThingActions {
private final Logger logger = LoggerFactory.getLogger(KeContactActions.class);
private @Nullable KeContactHandler handler;

@Override
public void setThingHandler(ThingHandler handler) {
this.handler = (KeContactHandler) handler;
}

@Override
public @Nullable ThingHandler getThingHandler() {
return handler;
}

@RuleAction(label = "@text/actionLabel", description = "@text/actionDesc")
public void setDisplay(
@ActionInput(name = "text", label = "@text/actionInputTextLabel", description = "@text/actionInputTextDesc") @Nullable String text,
@ActionInput(name = "durationMin", label = "@text/actionInputDurationMinLabel", description = "@text/actionInputDurationMinDesc") int durationMin,
@ActionInput(name = "durationMax", label = "@text/actionInputDurationMaxLabel", description = "@text/actionInputDurationMaxDesc") int durationMax) {
if (handler == null) {
logger.warn("KeContact Action service ThingHandler is null!");
return;
}
handler.setDisplay(text, durationMin, durationMax);
}

public static void setDisplay(ThingActions actions, @Nullable String text, int durationMin, int durationMax) {
((KeContactActions) actions).setDisplay(text, durationMin, durationMax);
}

@RuleAction(label = "@text/actionLabel", description = "@text/actionDesc")
public void setDisplay(
@ActionInput(name = "text", label = "@text/actionInputTextLabel", description = "@text/actionInputTextDesc") @Nullable String text) {
if (handler == null) {
logger.warn("KeContact Action service ThingHandler is null!");
return;
}
handler.setDisplay(text, -1, -1);
}

public static void setDisplay(ThingActions actions, @Nullable String text) {
((KeContactActions) actions).setDisplay(text);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import java.net.Socket;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
Expand All @@ -41,6 +43,7 @@
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State;
Expand Down Expand Up @@ -121,6 +124,11 @@ public void initialize() {
}
}

@Override
public Collection<Class<? extends ThingHandlerService>> getServices() {
return List.of(KeContactActions.class);
}

private boolean isKebaReachable() throws IOException {
boolean isReachable = false;
SocketAddress sockAddr = new InetSocketAddress(getIPAddress(), SOCKET_CHECK_PORT_NUMBER);
Expand Down Expand Up @@ -571,13 +579,7 @@ public void handleCommand(ChannelUID channelUID, Command command) {
}
case CHANNEL_DISPLAY: {
if (command instanceof StringType) {
if (type == KebaType.P30 && (series == KebaSeries.C || series == KebaSeries.X)) {
String cmd = command.toString();
int maxLength = (cmd.length() < 23) ? cmd.length() : 23;
transceiver.send("display 0 0 0 0 " + cmd.substring(0, maxLength), this);
} else {
logger.warn("'Display' is not supported on a KEBA KeContact {}:{}", type, series);
}
setDisplay(command.toString(), -1, -1);
}
break;
}
Expand All @@ -602,4 +604,21 @@ public void handleCommand(ChannelUID channelUID, Command command) {
}
}
}

public void setDisplay(String text, int durationMin, int durationMax) {
if (type == KebaType.P30 && (series == KebaSeries.C || series == KebaSeries.X)) {
int maxLength = (text.length() < 23) ? text.length() : 23;
int a = 1;
if (durationMax < 0 || durationMax < 0) {
a = 0;
durationMin = 0;
durationMax = 0;
}
transceiver.send(
"display " + a + " " + durationMin + " " + durationMax + " 0 " + text.substring(0, maxLength),
this);
} else {
logger.warn("'Display' is not supported on a KEBA KeContact {}:{}", type, series);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,13 @@ channel-type.keba.x1.label = X1
channel-type.keba.x1.description = State of the X1 input
channel-type.keba.x2.label = X2
channel-type.keba.x2.description = State of the X2 output

# thing actions
actionLabel = set text in display
actionDesc = Sets a text to show in the display of the wallbox
actionInputTextLabel = Text
actionInputTextDesc = Text shown on the display. Maximum 23 ASCII characters can be used. ~ == \u03A3, $ == blank, == comma
actionInputDurationMinLabel = Duration (min)
actionInputDurationMinDesc = Defines the duration in seconds how long the text will displayed before another display command will be processed (internal MID metering relevant information may overrule this).
actionInputDurationMaxLabel = Duration (max)
actionInputDurationMaxDesc = Defines the duration in seconds how long the text will displayed if no additional display command follows.
Loading

0 comments on commit 5192e2e

Please sign in to comment.