[boschshc] Support for Compact Smart Plugs (#13528) (#13533)

* add thing definition with ID "smart-plug-compact"
* add constant for thing type UID
* extract abstract implementation for devices with power switch and
energy monitoring
* let in-wall switch handler and smart plug handler extend the abstract
implementation
* register new handler
* add method with boolean parameter to fetch initial state actively
* make BoschSHCDeviceHandler abstract
* add documentation
* add unit tests

closes #13528

Signed-off-by: David Pace <dev@davidpace.de>
This commit is contained in:
David Pace 2022-10-31 17:21:25 +01:00 committed by GitHub
parent e528564bb6
commit 71da06dac7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 559 additions and 99 deletions

View File

@ -4,9 +4,10 @@ Binding for the Bosch Smart Home.
- [Bosch Smart Home Binding](#bosch-smart-home-binding) - [Bosch Smart Home Binding](#bosch-smart-home-binding)
- [Supported Things](#supported-things) - [Supported Things](#supported-things)
- [In-Wall switches & Smart Plugs](#in-wall-switches-smart-plugs) - [In-Wall Switch](#in-wall-switch)
- [TwinGuard smoke detector](#twinguard-smoke-detector) - [Compact Smart Plug](#compact-smart-plug)
- [Door/Window contact](#door-window-contact) - [Twinguard Smoke Detector](#twinguard-smoke-detector)
- [Door/Window Contact](#door-window-contact)
- [Motion Detector](#motion-detector) - [Motion Detector](#motion-detector)
- [Shutter Control](#shutter-control) - [Shutter Control](#shutter-control)
- [Thermostat](#thermostat) - [Thermostat](#thermostat)
@ -24,19 +25,31 @@ Binding for the Bosch Smart Home.
## Supported Things ## Supported Things
### In-Wall switches & Smart Plugs ### In-Wall Switch
A simple light control. A simple light control.
**Thing Type ID**: `in-wall-switch` **Thing Type ID**: `in-wall-switch`
| Channel Type ID | Item Type | Writable | Description | | Channel Type ID | Item Type | Writable | Description |
| ------------------ | ------------- | :------: | -------------------------------------------- | | ------------------ | ------------- | :------: | ------------------------------------------------ |
| power-switch | Switch | &#9745; | Current state of the switch. | | power-switch | Switch | &#9745; | Current state of the switch. |
| power-consumption | Number:Power | &#9744; | Current power consumption (W) of the device. | | power-consumption | Number:Power | &#9744; | Current power consumption (W) of the device. |
| energy-consumption | Number:Energy | &#9744; | Energy consumption of the device. | | energy-consumption | Number:Energy | &#9744; | Cumulated energy consumption (Wh) of the device. |
### TwinGuard smoke detector ### Compact Smart Plug
A compact smart plug with energy monitoring capabilities.
**Thing Type ID**: `smart-plug-compact`
| Channel Type ID | Item Type | Writable | Description |
| ------------------ | ------------- | :------: | ------------------------------------------------ |
| power-switch | Switch | &#9745; | Current state of the switch. |
| power-consumption | Number:Power | &#9744; | Current power consumption (W) of the device. |
| energy-consumption | Number:Energy | &#9744; | Cumulated energy consumption (Wh) of the device. |
### Twinguard smoke detector
The Twinguard smoke detector warns you in case of fire and constantly monitors the air. The Twinguard smoke detector warns you in case of fire and constantly monitors the air.
@ -53,7 +66,7 @@ The Twinguard smoke detector warns you in case of fire and constantly monitors t
| air-description | String | &#9744; | Overall description of the air quality. | | air-description | String | &#9744; | Overall description of the air quality. |
| combined-rating | String | &#9744; | Combined rating of the air quality. | | combined-rating | String | &#9744; | Combined rating of the air quality. |
### Door/Window contact ### Door/Window Contact
Detects open windows and doors. Detects open windows and doors.

View File

@ -0,0 +1,110 @@
/**
* Copyright (c) 2010-2022 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.boschshc.internal.devices;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.*;
import java.util.List;
import javax.measure.quantity.Energy;
import javax.measure.quantity.Power;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
import org.openhab.binding.boschshc.internal.services.powermeter.PowerMeterService;
import org.openhab.binding.boschshc.internal.services.powermeter.dto.PowerMeterServiceState;
import org.openhab.binding.boschshc.internal.services.powerswitch.PowerSwitchService;
import org.openhab.binding.boschshc.internal.services.powerswitch.PowerSwitchState;
import org.openhab.binding.boschshc.internal.services.powerswitch.dto.PowerSwitchServiceState;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
/**
* Abstract handler implementation for devices with power switches and energy monitoring.
* <p>
* This implementation provides the functionality to
* <ul>
* <li>Switch the device on and off using the <code>PowerSwitch</code> service</li>
* <li>Measuring the current power consumption and the overall energy consumption using the <code>PowerMeter</code>
* service</li>
* </ul>
*
* @author David Pace - Initial contribution (extracted from LightControlHandler)
*/
@NonNullByDefault
public abstract class AbstractPowerSwitchHandler extends BoschSHCDeviceHandler {
/**
* Service for switching the device on and off
*/
private final PowerSwitchService powerSwitchService;
protected AbstractPowerSwitchHandler(Thing thing) {
super(thing);
this.powerSwitchService = new PowerSwitchService();
}
@Override
protected void initializeServices() throws BoschSHCException {
super.initializeServices();
this.registerService(this.powerSwitchService, this::updateChannels, List.of(CHANNEL_POWER_SWITCH), true);
this.createService(PowerMeterService::new, this::updateChannels,
List.of(CHANNEL_POWER_CONSUMPTION, CHANNEL_ENERGY_CONSUMPTION), true);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
super.handleCommand(channelUID, command);
switch (channelUID.getId()) {
case CHANNEL_POWER_SWITCH:
if (command instanceof OnOffType) {
updatePowerSwitchState((OnOffType) command);
}
break;
}
}
/**
* Updates the channels which are linked to the {@link PowerMeterService} of the device.
*
* @param state Current state of {@link PowerMeterService}.
*/
private void updateChannels(PowerMeterServiceState state) {
super.updateState(CHANNEL_POWER_CONSUMPTION, new QuantityType<Power>(state.powerConsumption, Units.WATT));
super.updateState(CHANNEL_ENERGY_CONSUMPTION,
new QuantityType<Energy>(state.energyConsumption, Units.WATT_HOUR));
}
/**
* Updates the channels which are linked to the {@link PowerSwitchService} of the device.
*
* @param state Current state of {@link PowerSwitchService}.
*/
private void updateChannels(PowerSwitchServiceState state) {
State powerState = OnOffType.from(state.switchState.toString());
super.updateState(CHANNEL_POWER_SWITCH, powerState);
}
private void updatePowerSwitchState(OnOffType command) {
PowerSwitchServiceState state = new PowerSwitchServiceState();
state.switchState = PowerSwitchState.valueOf(command.toFullString());
this.updateServiceState(this.powerSwitchService, state);
}
}

View File

@ -44,6 +44,7 @@ public class BoschSHCBindingConstants {
public static final ThingTypeUID THING_TYPE_CAMERA_EYES = new ThingTypeUID(BINDING_ID, "security-camera-eyes"); public static final ThingTypeUID THING_TYPE_CAMERA_EYES = new ThingTypeUID(BINDING_ID, "security-camera-eyes");
public static final ThingTypeUID THING_TYPE_INTRUSION_DETECTION_SYSTEM = new ThingTypeUID(BINDING_ID, public static final ThingTypeUID THING_TYPE_INTRUSION_DETECTION_SYSTEM = new ThingTypeUID(BINDING_ID,
"intrusion-detection-system"); "intrusion-detection-system");
public static final ThingTypeUID THING_TYPE_SMART_PLUG_COMPACT = new ThingTypeUID(BINDING_ID, "smart-plug-compact");
// List of all Channel IDs // List of all Channel IDs
// Auto-generated from thing-types.xml via script, don't modify // Auto-generated from thing-types.xml via script, don't modify

View File

@ -40,7 +40,7 @@ import org.openhab.core.thing.ThingStatusDetail;
* *
*/ */
@NonNullByDefault @NonNullByDefault
public class BoschSHCDeviceHandler extends BoschSHCHandler { public abstract class BoschSHCDeviceHandler extends BoschSHCHandler {
/** /**
* Bosch SHC configuration loaded from openHAB configuration. * Bosch SHC configuration loaded from openHAB configuration.
@ -85,6 +85,7 @@ public class BoschSHCDeviceHandler extends BoschSHCHandler {
* *
* @return Unique id of the Bosch device. * @return Unique id of the Bosch device.
*/ */
@Override
public @Nullable String getBoschID() { public @Nullable String getBoschID() {
if (config != null) { if (config != null) {
return config.id; return config.id;

View File

@ -241,8 +241,29 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
protected <TService extends BoschSHCService<TState>, TState extends BoschSHCServiceState> TService createService( protected <TService extends BoschSHCService<TState>, TState extends BoschSHCServiceState> TService createService(
Supplier<TService> newService, Consumer<TState> stateUpdateListener, Collection<String> affectedChannels) Supplier<TService> newService, Consumer<TState> stateUpdateListener, Collection<String> affectedChannels)
throws BoschSHCException { throws BoschSHCException {
return createService(newService, stateUpdateListener, affectedChannels, false);
}
/**
* Creates and registers a new service for this device.
*
* @param <TService> Type of service.
* @param <TState> Type of service state.
* @param newService Supplier function to create a new instance of the service.
* @param stateUpdateListener Function to call when a state update was received
* from the device.
* @param affectedChannels Channels which are affected by the state of this
* service.
* @param shouldFetchInitialState indicates whether the initial state should be actively requested from the device
* or service. Useful if state updates are not included in long poll results.
* @return Instance of registered service.
* @throws BoschSHCException
*/
protected <TService extends BoschSHCService<TState>, TState extends BoschSHCServiceState> TService createService(
Supplier<TService> newService, Consumer<TState> stateUpdateListener, Collection<String> affectedChannels,
boolean shouldFetchInitialState) throws BoschSHCException {
TService service = newService.get(); TService service = newService.get();
this.registerService(service, stateUpdateListener, affectedChannels); this.registerService(service, stateUpdateListener, affectedChannels, shouldFetchInitialState);
return service; return service;
} }

View File

@ -26,6 +26,7 @@ import org.openhab.binding.boschshc.internal.devices.climatecontrol.ClimateContr
import org.openhab.binding.boschshc.internal.devices.intrusion.IntrusionDetectionHandler; import org.openhab.binding.boschshc.internal.devices.intrusion.IntrusionDetectionHandler;
import org.openhab.binding.boschshc.internal.devices.lightcontrol.LightControlHandler; import org.openhab.binding.boschshc.internal.devices.lightcontrol.LightControlHandler;
import org.openhab.binding.boschshc.internal.devices.motiondetector.MotionDetectorHandler; import org.openhab.binding.boschshc.internal.devices.motiondetector.MotionDetectorHandler;
import org.openhab.binding.boschshc.internal.devices.plug.PlugHandler;
import org.openhab.binding.boschshc.internal.devices.shuttercontrol.ShutterControlHandler; import org.openhab.binding.boschshc.internal.devices.shuttercontrol.ShutterControlHandler;
import org.openhab.binding.boschshc.internal.devices.thermostat.ThermostatHandler; import org.openhab.binding.boschshc.internal.devices.thermostat.ThermostatHandler;
import org.openhab.binding.boschshc.internal.devices.twinguard.TwinguardHandler; import org.openhab.binding.boschshc.internal.devices.twinguard.TwinguardHandler;
@ -47,7 +48,7 @@ import org.osgi.service.component.annotations.Component;
* @author Stefan Kästle - Initial contribution * @author Stefan Kästle - Initial contribution
* @author Christian Oeing - Added Shutter Control and ThermostatHandler; refactored handler mapping * @author Christian Oeing - Added Shutter Control and ThermostatHandler; refactored handler mapping
* @author Christian Oeing - Added WallThermostatHandler * @author Christian Oeing - Added WallThermostatHandler
* @author David Pace - Added cameras and intrusion detection system * @author David Pace - Added cameras, intrusion detection system and smart plugs
*/ */
@NonNullByDefault @NonNullByDefault
@Component(configurationPid = "binding.boschshc", service = ThingHandlerFactory.class) @Component(configurationPid = "binding.boschshc", service = ThingHandlerFactory.class)
@ -75,7 +76,8 @@ public class BoschSHCHandlerFactory extends BaseThingHandlerFactory {
new ThingTypeHandlerMapping(THING_TYPE_WALL_THERMOSTAT, WallThermostatHandler::new), new ThingTypeHandlerMapping(THING_TYPE_WALL_THERMOSTAT, WallThermostatHandler::new),
new ThingTypeHandlerMapping(THING_TYPE_CAMERA_360, CameraHandler::new), new ThingTypeHandlerMapping(THING_TYPE_CAMERA_360, CameraHandler::new),
new ThingTypeHandlerMapping(THING_TYPE_CAMERA_EYES, CameraHandler::new), new ThingTypeHandlerMapping(THING_TYPE_CAMERA_EYES, CameraHandler::new),
new ThingTypeHandlerMapping(THING_TYPE_INTRUSION_DETECTION_SYSTEM, IntrusionDetectionHandler::new)); new ThingTypeHandlerMapping(THING_TYPE_INTRUSION_DETECTION_SYSTEM, IntrusionDetectionHandler::new),
new ThingTypeHandlerMapping(THING_TYPE_SMART_PLUG_COMPACT, PlugHandler::new));
@Override @Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) { public boolean supportsThingType(ThingTypeUID thingTypeUID) {

View File

@ -12,28 +12,9 @@
*/ */
package org.openhab.binding.boschshc.internal.devices.lightcontrol; package org.openhab.binding.boschshc.internal.devices.lightcontrol;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.*;
import java.util.List;
import javax.measure.quantity.Energy;
import javax.measure.quantity.Power;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.boschshc.internal.devices.BoschSHCDeviceHandler; import org.openhab.binding.boschshc.internal.devices.AbstractPowerSwitchHandler;
import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
import org.openhab.binding.boschshc.internal.services.powermeter.PowerMeterService;
import org.openhab.binding.boschshc.internal.services.powermeter.dto.PowerMeterServiceState;
import org.openhab.binding.boschshc.internal.services.powerswitch.PowerSwitchService;
import org.openhab.binding.boschshc.internal.services.powerswitch.PowerSwitchState;
import org.openhab.binding.boschshc.internal.services.powerswitch.dto.PowerSwitchServiceState;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing; import org.openhab.core.thing.Thing;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
/** /**
* A simple light control. * A simple light control.
@ -41,61 +22,9 @@ import org.openhab.core.types.State;
* @author Stefan Kästle - Initial contribution * @author Stefan Kästle - Initial contribution
*/ */
@NonNullByDefault @NonNullByDefault
public class LightControlHandler extends BoschSHCDeviceHandler { public class LightControlHandler extends AbstractPowerSwitchHandler {
private final PowerSwitchService powerSwitchService;
public LightControlHandler(Thing thing) { public LightControlHandler(Thing thing) {
super(thing); super(thing);
this.powerSwitchService = new PowerSwitchService();
}
@Override
protected void initializeServices() throws BoschSHCException {
super.initializeServices();
this.registerService(this.powerSwitchService, this::updateChannels, List.of(CHANNEL_POWER_SWITCH));
this.createService(PowerMeterService::new, this::updateChannels,
List.of(CHANNEL_POWER_CONSUMPTION, CHANNEL_ENERGY_CONSUMPTION));
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
super.handleCommand(channelUID, command);
switch (channelUID.getId()) {
case CHANNEL_POWER_SWITCH:
if (command instanceof OnOffType) {
updatePowerSwitchState((OnOffType) command);
}
break;
}
}
/**
* Updates the channels which are linked to the {@link PowerMeterService} of the device.
*
* @param state Current state of {@link PowerMeterService}.
*/
private void updateChannels(PowerMeterServiceState state) {
super.updateState(CHANNEL_POWER_CONSUMPTION, new QuantityType<Power>(state.powerConsumption, Units.WATT));
super.updateState(CHANNEL_ENERGY_CONSUMPTION,
new QuantityType<Energy>(state.energyConsumption, Units.WATT_HOUR));
}
/**
* Updates the channels which are linked to the {@link PowerSwitchService} of the device.
*
* @param state Current state of {@link PowerSwitchService}.
*/
private void updateChannels(PowerSwitchServiceState state) {
State powerState = OnOffType.from(state.switchState.toString());
super.updateState(CHANNEL_POWER_SWITCH, powerState);
}
private void updatePowerSwitchState(OnOffType command) {
PowerSwitchServiceState state = new PowerSwitchServiceState();
state.switchState = PowerSwitchState.valueOf(command.toFullString());
this.updateServiceState(this.powerSwitchService, state);
} }
} }

View File

@ -0,0 +1,30 @@
/**
* Copyright (c) 2010-2022 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.boschshc.internal.devices.plug;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.boschshc.internal.devices.AbstractPowerSwitchHandler;
import org.openhab.core.thing.Thing;
/**
* A handler for compact smart plugs.
*
* @author David Pace - Initial contribution
*/
@NonNullByDefault
public class PlugHandler extends AbstractPowerSwitchHandler {
public PlugHandler(Thing thing) {
super(thing);
}
}

View File

@ -30,6 +30,24 @@
</thing-type> </thing-type>
<thing-type id="smart-plug-compact">
<supported-bridge-type-refs>
<bridge-type-ref id="shc"/>
</supported-bridge-type-refs>
<label>Compact Smart Plug</label>
<description>A compact smart plug with energy monitoring capabilities.</description>
<channels>
<channel id="power-switch" typeId="system.power"/>
<channel id="power-consumption" typeId="power-consumption"/>
<channel id="energy-consumption" typeId="energy-consumption"/>
</channels>
<config-description-ref uri="thing-type:boschshc:device"/>
</thing-type>
<thing-type id="twinguard"> <thing-type id="twinguard">
<supported-bridge-type-refs> <supported-bridge-type-refs>
<bridge-type-ref id="shc"/> <bridge-type-ref id="shc"/>

View File

@ -0,0 +1,35 @@
/**
* Copyright (c) 2010-2022 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.boschshc.internal.devices;
import org.openhab.core.config.core.Configuration;
/**
* Abstract unit test implementation for device handlers.
*
* @author David Pace - Initial contribution
*
* @param <T> type of the device handler to be tested
*/
public abstract class AbstractBoschSHCDeviceHandlerTest<T extends BoschSHCDeviceHandler>
extends AbstractSHCHandlerTest<T> {
@Override
protected Configuration getConfiguration() {
Configuration configuration = super.getConfiguration();
configuration.put("id", getDeviceID());
return configuration;
}
protected abstract String getDeviceID();
}

View File

@ -0,0 +1,118 @@
/**
* Copyright (c) 2010-2022 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.boschshc.internal.devices;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import javax.measure.quantity.Energy;
import javax.measure.quantity.Power;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
import org.openhab.binding.boschshc.internal.services.powerswitch.PowerSwitchState;
import org.openhab.binding.boschshc.internal.services.powerswitch.dto.PowerSwitchServiceState;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
/**
* Abstract unit test implementation for devices with power switches and energy monitoring.
*
* @author David Pace - Initial contribution
*
* @param <T> type of the handler to be tested
*/
public abstract class AbstractPowerSwitchHandlerTest<T extends AbstractPowerSwitchHandler>
extends AbstractBoschSHCDeviceHandlerTest<T> {
@Captor
private ArgumentCaptor<PowerSwitchServiceState> serviceStateCaptor;
@Captor
private ArgumentCaptor<QuantityType<Power>> powerCaptor;
@Captor
private ArgumentCaptor<QuantityType<Energy>> energyCaptor;
@Test
public void testHandleCommand()
throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
when(getThing().getUID()).thenReturn(new ThingUID("boschshc", "abcdef"));
getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_POWER_SWITCH),
OnOffType.ON);
verify(getBridgeHandler()).putState(eq(getDeviceID()), eq("PowerSwitch"), serviceStateCaptor.capture());
PowerSwitchServiceState state = serviceStateCaptor.getValue();
assertSame(PowerSwitchState.ON, state.switchState);
getFixture().handleCommand(new ChannelUID(new ThingUID(getThingTypeUID(), "abcdef"),
BoschSHCBindingConstants.CHANNEL_POWER_SWITCH), OnOffType.OFF);
verify(getBridgeHandler(), times(2)).putState(eq(getDeviceID()), eq("PowerSwitch"),
serviceStateCaptor.capture());
state = serviceStateCaptor.getValue();
assertSame(PowerSwitchState.OFF, state.switchState);
}
protected abstract ThingTypeUID getThingTypeUID();
@Test
public void testUpdateChannel_PowerSwitchState() {
when(getThing().getUID()).thenReturn(new ThingUID("boschshc", "abcdef"));
JsonElement jsonObject = JsonParser
.parseString("{\n" + " \"@type\": \"powerSwitchState\",\n" + " \"switchState\": \"ON\"\n" + "}");
getFixture().processUpdate("PowerSwitch", jsonObject);
verify(getCallback()).stateUpdated(
new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_POWER_SWITCH), OnOffType.ON);
jsonObject = JsonParser
.parseString("{\n" + " \"@type\": \"powerSwitchState\",\n" + " \"switchState\": \"OFF\"\n" + "}");
getFixture().processUpdate("PowerSwitch", jsonObject);
verify(getCallback()).stateUpdated(
new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_POWER_SWITCH), OnOffType.OFF);
}
@Test
public void testUpdateChannel_PowerMeterServiceState() {
when(getThing().getUID()).thenReturn(new ThingUID("boschshc", "abcdef"));
JsonElement jsonObject = JsonParser.parseString("{\n" + " \"@type\": \"powerMeterState\",\n"
+ " \"powerConsumption\": \"23\",\n" + " \"energyConsumption\": 42\n" + "}");
getFixture().processUpdate("PowerMeter", jsonObject);
verify(getCallback()).stateUpdated(
eq(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_POWER_CONSUMPTION)),
powerCaptor.capture());
QuantityType<Power> powerValue = powerCaptor.getValue();
assertEquals(23, powerValue.intValue());
verify(getCallback()).stateUpdated(
eq(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_ENERGY_CONSUMPTION)),
energyCaptor.capture());
QuantityType<Energy> energyValue = energyCaptor.getValue();
assertEquals(42, energyValue.intValue());
}
}

View File

@ -0,0 +1,96 @@
/**
* Copyright (c) 2010-2022 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.boschshc.internal.devices;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.openhab.binding.boschshc.internal.devices.bridge.BridgeHandler;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingStatusInfo;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.ThingHandlerCallback;
/**
* Abstract unit test implementation for all types of handlers.
*
* @author David Pace - Initial contribution
*
* @param <T> type of the handler to be tested
*/
@ExtendWith(MockitoExtension.class)
public abstract class AbstractSHCHandlerTest<T extends BoschSHCHandler> {
private T fixture;
@Mock
private Thing thing;
@Mock
private Bridge bridge;
@Mock
private BridgeHandler bridgeHandler;
@Mock
private ThingHandlerCallback callback;
@BeforeEach
public void beforeEach() {
fixture = createFixture();
when(thing.getBridgeUID()).thenReturn(new ThingUID("boschshc", "shc", "myBridgeUID"));
when(callback.getBridge(any())).thenReturn(bridge);
fixture.setCallback(callback);
when(bridge.getHandler()).thenReturn(bridgeHandler);
when(thing.getConfiguration()).thenReturn(getConfiguration());
fixture.initialize();
}
protected abstract T createFixture();
protected T getFixture() {
return fixture;
}
protected Configuration getConfiguration() {
return new Configuration();
}
protected Thing getThing() {
return thing;
}
public BridgeHandler getBridgeHandler() {
return bridgeHandler;
}
public ThingHandlerCallback getCallback() {
return callback;
}
@Test
public void testInitialize() {
ThingStatusInfo expectedStatusInfo = new ThingStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, null);
verify(callback).statusUpdated(same(thing), eq(expectedStatusInfo));
}
}

View File

@ -0,0 +1,43 @@
/**
* Copyright (c) 2010-2022 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.boschshc.internal.devices.lightcontrol;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.boschshc.internal.devices.AbstractPowerSwitchHandlerTest;
import org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants;
import org.openhab.core.thing.ThingTypeUID;
/**
* Unit tests for {@link LightControlHandler}.
*
* @author David Pace - Initial contribution
*
*/
@NonNullByDefault
public class LightControlHandlerTest extends AbstractPowerSwitchHandlerTest<LightControlHandler> {
@Override
protected ThingTypeUID getThingTypeUID() {
return BoschSHCBindingConstants.THING_TYPE_INWALL_SWITCH;
}
@Override
protected String getDeviceID() {
return "hdm:ZigBee:50325ffffe61d7b9c6e";
}
@Override
protected LightControlHandler createFixture() {
return new LightControlHandler(getThing());
}
}

View File

@ -0,0 +1,43 @@
/**
* Copyright (c) 2010-2022 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.boschshc.internal.devices.plug;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.boschshc.internal.devices.AbstractPowerSwitchHandlerTest;
import org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants;
import org.openhab.core.thing.ThingTypeUID;
/**
* Unit tests for {@link PlugHandler}.
*
* @author David Pace - Initial contribution
*
*/
@NonNullByDefault
public class PlugHandlerTest extends AbstractPowerSwitchHandlerTest<PlugHandler> {
@Override
protected PlugHandler createFixture() {
return new PlugHandler(getThing());
}
@Override
protected String getDeviceID() {
return "hdm:ZigBee:50325ffffe61d7b9c6e";
}
@Override
protected ThingTypeUID getThingTypeUID() {
return BoschSHCBindingConstants.THING_TYPE_SMART_PLUG_COMPACT;
}
}