[boschshc] Support for Universal Switch I + II (#16274)

* [boschshc] Support for Universal Switch I + II

- add thing type and channel type definitions
- re-generate i18n file
- add constants
- add model classes and enums
- implement service and handlers
- register handlers in factory
- register devices in discovery

closes #16244

Signed-off-by: David Pace <dev@davidpace.de>
This commit is contained in:
David Pace 2024-01-18 22:43:44 +01:00 committed by GitHub
parent bcdb664057
commit 15642af6b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 542 additions and 9 deletions

View File

@ -21,6 +21,8 @@ Binding for the Bosch Smart Home.
- [Smart Bulb](#smart-bulb)
- [Smoke Detector](#smoke-detector)
- [User-defined States](#user-defined-states)
- [Universal Switch](#universal-switch)
- [Universal Switch II](#universal-switch-ii)
- [Limitations](#limitations)
- [Discovery](#discovery)
- [Bridge Configuration](#bridge-configuration)
@ -246,6 +248,31 @@ Individual states can be activated/deactivated and can be used as triggers, cond
|-----------------|-----------| :------: |--------------------------------------------|
| user-state | Switch | &#9745; | Switches the User-defined state on or off. |
### Universal Switch
A universally configurable switch with two buttons.
**Thing Type ID**: `universal-switch`
| Channel Type ID | Item Type | Writable | Description |
| ------------------- | -------------------- | :------: | ----------------------------------------- |
| key-code | Number:Dimensionless | &#9744; | Integer code of the key that was pressed. |
| key-name | String | &#9744; | Name of a key pressed on a device. Possible values for Universal Switch: `LOWER_BUTTON`, `UPPER_BUTTON`. |
| key-event-type | String | &#9744; | Indicates how the key was pressed. Possible values are `PRESS_SHORT`, `PRESS_LONG` and `PRESS_LONG_RELEASED`. |
| key-event-timestamp | DateTime | &#9744; | Timestamp indicating when the key was pressed. |
### Universal Switch II
A universally configurable switch with four buttons.
**Thing Type ID**: `universal-switch-2`
| Channel Type ID | Item Type | Writable | Description |
| ------------------- | -------------------- | :------: | ----------------------------------------- |
| key-code | Number:Dimensionless | &#9744; | Integer code of the key that was pressed. |
| key-name | String | &#9744; | Name of the key that was pressed. Possible values for Universal Switch II: `LOWER_LEFT_BUTTON`, `LOWER_RIGHT_BUTTON`, `UPPER_LEFT_BUTTON`, `UPPER_RIGHT_BUTTON`. |
| key-event-type | String | &#9744; | Indicates how the key was pressed. Possible values are `PRESS_SHORT`, `PRESS_LONG` and `PRESS_LONG_RELEASED`. |
| key-event-timestamp | DateTime | &#9744; | Timestamp indicating when the key was pressed. |
## Limitations

View File

@ -49,6 +49,8 @@ public class BoschSHCBindingConstants {
public static final ThingTypeUID THING_TYPE_SMART_PLUG_COMPACT = new ThingTypeUID(BINDING_ID, "smart-plug-compact");
public static final ThingTypeUID THING_TYPE_SMART_BULB = new ThingTypeUID(BINDING_ID, "smart-bulb");
public static final ThingTypeUID THING_TYPE_SMOKE_DETECTOR = new ThingTypeUID(BINDING_ID, "smoke-detector");
public static final ThingTypeUID THING_TYPE_UNIVERSAL_SWITCH = new ThingTypeUID(BINDING_ID, "universal-switch");
public static final ThingTypeUID THING_TYPE_UNIVERSAL_SWITCH_2 = new ThingTypeUID(BINDING_ID, "universal-switch-2");
public static final ThingTypeUID THING_TYPE_USER_DEFINED_STATE = new ThingTypeUID(BINDING_ID, "user-defined-state");
@ -91,6 +93,10 @@ public class BoschSHCBindingConstants {
public static final String CHANNEL_ILLUMINANCE = "illuminance";
public static final String CHANNEL_BYPASS_STATE = "bypass-state";
public static final String CHANNEL_SIGNAL_STRENGTH = "signal-strength";
public static final String CHANNEL_KEY_CODE = "key-code";
public static final String CHANNEL_KEY_NAME = "key-name";
public static final String CHANNEL_KEY_EVENT_TYPE = "key-event-type";
public static final String CHANNEL_KEY_EVENT_TIMESTAMP = "key-event-timestamp";
public static final String CHANNEL_USER_DEFINED_STATE = "user-state";

View File

@ -12,7 +12,25 @@
*/
package org.openhab.binding.boschshc.internal.devices;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.*;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.THING_TYPE_CAMERA_360;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.THING_TYPE_CAMERA_EYES;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.THING_TYPE_CLIMATE_CONTROL;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.THING_TYPE_INTRUSION_DETECTION_SYSTEM;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.THING_TYPE_INWALL_SWITCH;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.THING_TYPE_MOTION_DETECTOR;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.THING_TYPE_SHC;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.THING_TYPE_SHUTTER_CONTROL;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.THING_TYPE_SMART_BULB;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.THING_TYPE_SMART_PLUG_COMPACT;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.THING_TYPE_SMOKE_DETECTOR;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.THING_TYPE_THERMOSTAT;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.THING_TYPE_TWINGUARD;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.THING_TYPE_UNIVERSAL_SWITCH;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.THING_TYPE_UNIVERSAL_SWITCH_2;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.THING_TYPE_USER_DEFINED_STATE;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.THING_TYPE_WALL_THERMOSTAT;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.THING_TYPE_WINDOW_CONTACT;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.THING_TYPE_WINDOW_CONTACT_2;
import java.util.Collection;
import java.util.List;
@ -32,10 +50,13 @@ import org.openhab.binding.boschshc.internal.devices.smartbulb.SmartBulbHandler;
import org.openhab.binding.boschshc.internal.devices.smokedetector.SmokeDetectorHandler;
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.universalswitch.UniversalSwitch2Handler;
import org.openhab.binding.boschshc.internal.devices.universalswitch.UniversalSwitchHandler;
import org.openhab.binding.boschshc.internal.devices.userdefinedstate.UserStateHandler;
import org.openhab.binding.boschshc.internal.devices.wallthermostat.WallThermostatHandler;
import org.openhab.binding.boschshc.internal.devices.windowcontact.WindowContact2Handler;
import org.openhab.binding.boschshc.internal.devices.windowcontact.WindowContactHandler;
import org.openhab.core.i18n.TimeZoneProvider;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
@ -43,7 +64,9 @@ import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
/**
* The {@link BoschSHCHandlerFactory} is responsible for creating things and
@ -59,6 +82,13 @@ import org.osgi.service.component.annotations.Component;
@Component(configurationPid = "binding.boschshc", service = ThingHandlerFactory.class)
public class BoschSHCHandlerFactory extends BaseThingHandlerFactory {
private TimeZoneProvider timeZoneProvider;
@Activate
public BoschSHCHandlerFactory(final @Reference TimeZoneProvider timeZoneProvider) {
this.timeZoneProvider = timeZoneProvider;
}
private static class ThingTypeHandlerMapping {
public ThingTypeUID thingTypeUID;
public Function<Thing, BaseThingHandler> handlerSupplier;
@ -69,7 +99,7 @@ public class BoschSHCHandlerFactory extends BaseThingHandlerFactory {
}
}
private static final Collection<ThingTypeHandlerMapping> SUPPORTED_THING_TYPES = List.of(
private final Collection<ThingTypeHandlerMapping> supportedThingTypes = List.of(
new ThingTypeHandlerMapping(THING_TYPE_SHC, thing -> new BridgeHandler((Bridge) thing)),
new ThingTypeHandlerMapping(THING_TYPE_INWALL_SWITCH, LightControlHandler::new),
new ThingTypeHandlerMapping(THING_TYPE_TWINGUARD, TwinguardHandler::new),
@ -86,11 +116,15 @@ public class BoschSHCHandlerFactory extends BaseThingHandlerFactory {
new ThingTypeHandlerMapping(THING_TYPE_SMART_PLUG_COMPACT, PlugHandler::new),
new ThingTypeHandlerMapping(THING_TYPE_SMART_BULB, SmartBulbHandler::new),
new ThingTypeHandlerMapping(THING_TYPE_SMOKE_DETECTOR, SmokeDetectorHandler::new),
new ThingTypeHandlerMapping(THING_TYPE_USER_DEFINED_STATE, UserStateHandler::new));
new ThingTypeHandlerMapping(THING_TYPE_USER_DEFINED_STATE, UserStateHandler::new),
new ThingTypeHandlerMapping(THING_TYPE_UNIVERSAL_SWITCH,
thing -> new UniversalSwitchHandler(thing, timeZoneProvider)),
new ThingTypeHandlerMapping(THING_TYPE_UNIVERSAL_SWITCH_2,
thing -> new UniversalSwitch2Handler(thing, timeZoneProvider)));
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES.stream().anyMatch(mapping -> mapping.thingTypeUID.equals(thingTypeUID));
return supportedThingTypes.stream().anyMatch(mapping -> mapping.thingTypeUID.equals(thingTypeUID));
}
@Override
@ -98,7 +132,7 @@ public class BoschSHCHandlerFactory extends BaseThingHandlerFactory {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
// Search for mapping for thing type and return handler for it if found. Otherwise return null.
return SUPPORTED_THING_TYPES.stream().filter(mapping -> mapping.thingTypeUID.equals(thingTypeUID)).findFirst()
return supportedThingTypes.stream().filter(mapping -> mapping.thingTypeUID.equals(thingTypeUID)).findFirst()
.<@Nullable BaseThingHandler> map(mapping -> mapping.handlerSupplier.apply(thing)).orElse(null);
}
}

View File

@ -0,0 +1,31 @@
/**
* 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.boschshc.internal.devices.universalswitch;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.i18n.TimeZoneProvider;
import org.openhab.core.thing.Thing;
/**
* Handler for a universally configurable switch with four buttons.
*
* @author David Pace - Initial contribution
*
*/
@NonNullByDefault
public class UniversalSwitch2Handler extends UniversalSwitchHandler {
public UniversalSwitch2Handler(Thing thing, TimeZoneProvider timeZoneProvider) {
super(thing, timeZoneProvider);
}
}

View File

@ -0,0 +1,68 @@
/**
* 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.boschshc.internal.devices.universalswitch;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.CHANNEL_KEY_CODE;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.CHANNEL_KEY_EVENT_TIMESTAMP;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.CHANNEL_KEY_EVENT_TYPE;
import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.CHANNEL_KEY_NAME;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.boschshc.internal.devices.AbstractBatteryPoweredDeviceHandler;
import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
import org.openhab.binding.boschshc.internal.services.keypad.KeypadService;
import org.openhab.binding.boschshc.internal.services.keypad.dto.KeypadServiceState;
import org.openhab.core.i18n.TimeZoneProvider;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.Thing;
/**
* Handler for a universally configurable switch with two buttons.
*
* @author David Pace - Initial contribution
*
*/
@NonNullByDefault
public class UniversalSwitchHandler extends AbstractBatteryPoweredDeviceHandler {
private TimeZoneProvider timeZoneProvider;
public UniversalSwitchHandler(Thing thing, TimeZoneProvider timeZoneProvider) {
super(thing);
this.timeZoneProvider = timeZoneProvider;
}
@Override
protected void initializeServices() throws BoschSHCException {
super.initializeServices();
createService(KeypadService::new, this::updateChannels,
List.of(CHANNEL_KEY_CODE, CHANNEL_KEY_NAME, CHANNEL_KEY_EVENT_TYPE, CHANNEL_KEY_EVENT_TIMESTAMP));
}
private void updateChannels(KeypadServiceState keypadServiceState) {
updateState(CHANNEL_KEY_CODE, new DecimalType(keypadServiceState.keyCode));
updateState(CHANNEL_KEY_NAME, new StringType(keypadServiceState.keyName.toString()));
updateState(CHANNEL_KEY_EVENT_TYPE, new StringType(keypadServiceState.eventType.toString()));
Instant instant = Instant.ofEpochMilli(keypadServiceState.eventTimestamp);
updateState(CHANNEL_KEY_EVENT_TIMESTAMP,
new DateTimeType(ZonedDateTime.ofInstant(instant, timeZoneProvider.getTimeZone())));
}
}

View File

@ -86,7 +86,9 @@ public class ThingDiscoveryService extends AbstractThingHandlerDiscoveryService<
new AbstractMap.SimpleEntry<>("LEDVANCE_LIGHT", BoschSHCBindingConstants.THING_TYPE_SMART_BULB),
new AbstractMap.SimpleEntry<>("SWD", BoschSHCBindingConstants.THING_TYPE_WINDOW_CONTACT),
new AbstractMap.SimpleEntry<>("SWD2", BoschSHCBindingConstants.THING_TYPE_WINDOW_CONTACT_2),
new AbstractMap.SimpleEntry<>("TRV", BoschSHCBindingConstants.THING_TYPE_THERMOSTAT)
new AbstractMap.SimpleEntry<>("TRV", BoschSHCBindingConstants.THING_TYPE_THERMOSTAT),
new AbstractMap.SimpleEntry<>("WRC2", BoschSHCBindingConstants.THING_TYPE_UNIVERSAL_SWITCH),
new AbstractMap.SimpleEntry<>("SWITCH2", BoschSHCBindingConstants.THING_TYPE_UNIVERSAL_SWITCH_2)
// Future Extension: map deviceModel names to BoschSHC Thing Types when they are supported
// new AbstractMap.SimpleEntry<>("SMOKE_DETECTION_SYSTEM", BoschSHCBindingConstants.),
// new AbstractMap.SimpleEntry<>("PRESENCE_SIMULATION_SERVICE", BoschSHCBindingConstants.),

View File

@ -0,0 +1,31 @@
/**
* 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.boschshc.internal.services.keypad;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.boschshc.internal.services.BoschSHCService;
import org.openhab.binding.boschshc.internal.services.keypad.dto.KeypadServiceState;
/**
* Service for the keypads for Universal Switches.
*
* @author David Pace - Initial contribution
*
*/
@NonNullByDefault
public class KeypadService extends BoschSHCService<KeypadServiceState> {
public KeypadService() {
super("Keypad", KeypadServiceState.class);
}
}

View File

@ -0,0 +1,25 @@
/**
* 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.boschshc.internal.services.keypad.dto;
/**
* Event types of keys/buttons pressed on Universal Switches.
*
* @author David Pace - Initial contribution
*
*/
public enum KeyEventType {
PRESS_SHORT,
PRESS_LONG,
PRESS_LONG_RELEASED
}

View File

@ -0,0 +1,28 @@
/**
* 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.boschshc.internal.services.keypad.dto;
/**
* Key names of keys/buttons pressed on Universal Switches.
*
* @author David Pace - Initial contribution
*
*/
public enum KeyName {
LOWER_BUTTON,
UPPER_BUTTON,
LOWER_LEFT_BUTTON,
LOWER_RIGHT_BUTTON,
UPPER_LEFT_BUTTON,
UPPER_RIGHT_BUTTON
}

View File

@ -0,0 +1,49 @@
/**
* 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.boschshc.internal.services.keypad.dto;
import org.openhab.binding.boschshc.internal.services.dto.BoschSHCServiceState;
import org.openhab.binding.boschshc.internal.services.keypad.KeypadService;
/**
* State object of the {@link KeypadService}.
* <p>
* Example JSON:
*
* <pre>
* {
* "@type":"keypadState",
* "keyCode":1,
* "keyName":"UPPER_LEFT_BUTTON",
* "eventType":"PRESS_SHORT",
* "eventTimestamp":1705130891435
* }
* </pre>
*
* @author David Pace - Initial contribution
*
*/
public class KeypadServiceState extends BoschSHCServiceState {
public KeypadServiceState() {
super("keypadState");
}
public int keyCode;
public KeyName keyName;
public KeyEventType eventType;
public long eventTimestamp;
}

View File

@ -31,6 +31,10 @@ thing-type.boschshc.thermostat.label = Thermostat
thing-type.boschshc.thermostat.description = Radiator thermostat
thing-type.boschshc.twinguard.label = Twinguard
thing-type.boschshc.twinguard.description = The Twinguard smoke detector warns you in case of fire and constantly monitors the air.
thing-type.boschshc.universal-switch-2.label = Universal Switch II
thing-type.boschshc.universal-switch-2.description = Universally configurable switch with four buttons.
thing-type.boschshc.universal-switch.label = Universal Switch
thing-type.boschshc.universal-switch.description = Universally configurable switch with two buttons.
thing-type.boschshc.user-defined-state.label = User-defined State
thing-type.boschshc.user-defined-state.description = A User-defined state.
thing-type.boschshc.wall-thermostat.label = Wall Thermostat
@ -101,6 +105,23 @@ channel-type.boschshc.humidity.label = Humidity
channel-type.boschshc.humidity.description = Current measured humidity.
channel-type.boschshc.illuminance.label = Illuminance
channel-type.boschshc.illuminance.description = The illuminance level measured by the sensor (0 to 1000).
channel-type.boschshc.key-code.label = Key Code
channel-type.boschshc.key-code.description = Integer code of the key that was pressed.
channel-type.boschshc.key-event-timestamp.label = Key Event Timestamp
channel-type.boschshc.key-event-timestamp.description = Timestamp indicating when the key was pressed.
channel-type.boschshc.key-event-type.label = Key Event Type
channel-type.boschshc.key-event-type.description = Indicates how the key was pressed.
channel-type.boschshc.key-event-type.state.option.PRESS_SHORT = Short
channel-type.boschshc.key-event-type.state.option.PRESS_LONG = Long (pressed)
channel-type.boschshc.key-event-type.state.option.PRESS_LONG_RELEASED = Long (released)
channel-type.boschshc.key-name.label = Key Name
channel-type.boschshc.key-name.description = Name of the key that was pressed.
channel-type.boschshc.key-name.state.option.LOWER_BUTTON = Lower button
channel-type.boschshc.key-name.state.option.UPPER_BUTTON = Upper button
channel-type.boschshc.key-name.state.option.LOWER_LEFT_BUTTON = Lower left button
channel-type.boschshc.key-name.state.option.LOWER_RIGHT_BUTTON = Lower right button
channel-type.boschshc.key-name.state.option.UPPER_LEFT_BUTTON = Upper left button
channel-type.boschshc.key-name.state.option.UPPER_RIGHT_BUTTON = Upper right button
channel-type.boschshc.latest-motion.label = Latest motion
channel-type.boschshc.latest-motion.description = Timestamp of the latest motion.
channel-type.boschshc.level.label = Level

View File

@ -325,6 +325,42 @@
<config-description-ref uri="thing-type:boschshc:user-defined-state"/>
</thing-type>
<thing-type id="universal-switch">
<supported-bridge-type-refs>
<bridge-type-ref id="shc"/>
</supported-bridge-type-refs>
<label>Universal Switch</label>
<description>Universally configurable switch with two buttons.</description>
<channels>
<channel id="key-code" typeId="key-code"/>
<channel id="key-name" typeId="key-name"/>
<channel id="key-event-type" typeId="key-event-type"/>
<channel id="key-event-timestamp" typeId="key-event-timestamp"/>
</channels>
<config-description-ref uri="thing-type:boschshc:user-defined-state"/>
</thing-type>
<thing-type id="universal-switch-2">
<supported-bridge-type-refs>
<bridge-type-ref id="shc"/>
</supported-bridge-type-refs>
<label>Universal Switch II</label>
<description>Universally configurable switch with four buttons.</description>
<channels>
<channel id="key-code" typeId="key-code"/>
<channel id="key-name" typeId="key-name"/>
<channel id="key-event-type" typeId="key-event-type"/>
<channel id="key-event-timestamp" typeId="key-event-timestamp"/>
</channels>
<config-description-ref uri="thing-type:boschshc:user-defined-state"/>
</thing-type>
<!-- Channels -->
<channel-type id="system-availability">
@ -606,4 +642,47 @@
</state>
</channel-type>
<channel-type id="key-code">
<item-type>Number:Dimensionless</item-type>
<label>Key Code</label>
<description>Integer code of the key that was pressed.</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="key-name">
<item-type>String</item-type>
<label>Key Name</label>
<description>Name of the key that was pressed.</description>
<state readOnly="true">
<options>
<option value="LOWER_BUTTON">Lower button</option>
<option value="UPPER_BUTTON">Upper button</option>
<option value="LOWER_LEFT_BUTTON">Lower left button</option>
<option value="LOWER_RIGHT_BUTTON">Lower right button</option>
<option value="UPPER_LEFT_BUTTON">Upper left button</option>
<option value="UPPER_RIGHT_BUTTON">Upper right button</option>
</options>
</state>
</channel-type>
<channel-type id="key-event-type">
<item-type>String</item-type>
<label>Key Event Type</label>
<description>Indicates how the key was pressed.</description>
<state readOnly="true">
<options>
<option value="PRESS_SHORT">Short</option>
<option value="PRESS_LONG">Long (pressed)</option>
<option value="PRESS_LONG_RELEASED">Long (released)</option>
</options>
</state>
</channel-type>
<channel-type id="key-event-timestamp">
<item-type>DateTime</item-type>
<label>Key Event Timestamp</label>
<description>Timestamp indicating when the key was pressed.</description>
<state readOnly="true"/>
</channel-type>
</thing:thing-descriptions>

View File

@ -12,8 +12,12 @@
*/
package org.openhab.binding.boschshc.internal.devices;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.time.ZoneId;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.BeforeEach;
@ -35,7 +39,7 @@ class BoschSHCHandlerFactoryTest {
@BeforeEach
public void setUp() throws Exception {
fixture = new BoschSHCHandlerFactory();
fixture = new BoschSHCHandlerFactory(() -> ZoneId.systemDefault());
}
@Test

View File

@ -0,0 +1,39 @@
/**
* 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.boschshc.internal.devices.universalswitch;
import java.time.ZoneId;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants;
import org.openhab.core.thing.ThingTypeUID;
/**
* Unit tests for {@link UniversalSwitch2Handler}.
*
* @author David Pace - Initial contribution
*
*/
@NonNullByDefault
class UniversalSwitchHandler2Test extends UniversalSwitchHandlerTest {
@Override
protected UniversalSwitchHandler createFixture() {
return new UniversalSwitch2Handler(getThing(), () -> ZoneId.systemDefault());
}
@Override
protected ThingTypeUID getThingTypeUID() {
return BoschSHCBindingConstants.THING_TYPE_UNIVERSAL_SWITCH_2;
}
}

View File

@ -0,0 +1,89 @@
/**
* 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.boschshc.internal.devices.universalswitch;
import static org.mockito.Mockito.verify;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.Test;
import org.openhab.binding.boschshc.internal.devices.AbstractBatteryPoweredDeviceHandlerTest;
import org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ThingTypeUID;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
/**
* Unit tests for {@link UniversalSwitchHandler}.
*
* @author David Pace - Initial contribution
*
*/
@NonNullByDefault
class UniversalSwitchHandlerTest extends AbstractBatteryPoweredDeviceHandlerTest<UniversalSwitchHandler> {
@Override
protected UniversalSwitchHandler createFixture() {
return new UniversalSwitchHandler(getThing(), () -> ZoneId.systemDefault());
}
@Override
protected String getDeviceID() {
return "hdm:ZigBee:001e43d085b91a96";
}
@Override
protected ThingTypeUID getThingTypeUID() {
return BoschSHCBindingConstants.THING_TYPE_UNIVERSAL_SWITCH;
}
@Test
void testUpdateChannelsKeypadService() {
JsonElement jsonObject = JsonParser.parseString("""
{
"@type":"keypadState",
"keyCode":1,
"keyName":"UPPER_LEFT_BUTTON",
"eventType":"PRESS_SHORT",
"eventTimestamp":1705130891435
}
""");
getFixture().processUpdate("Keypad", jsonObject);
verify(getCallback()).stateUpdated(
new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_KEY_CODE), new DecimalType(1));
verify(getCallback()).stateUpdated(
new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_KEY_NAME),
new StringType("UPPER_LEFT_BUTTON"));
verify(getCallback()).stateUpdated(
new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_KEY_EVENT_TYPE),
new StringType("PRESS_SHORT"));
ZonedDateTime expectedTime = ZonedDateTime.ofInstant(Instant.ofEpochMilli(1705130891435l),
ZoneId.systemDefault());
verify(getCallback()).stateUpdated(
new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_KEY_EVENT_TIMESTAMP),
new DateTimeType(expectedTime));
}
}