]> git.basschouten.com Git - openhab-addons.git/commitdiff
[boschshc] Support for Universal Switch I + II (#16274)
authorDavid Pace <dev@davidpace.de>
Thu, 18 Jan 2024 21:43:44 +0000 (22:43 +0100)
committerGitHub <noreply@github.com>
Thu, 18 Jan 2024 21:43:44 +0000 (22:43 +0100)
* [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>
15 files changed:
bundles/org.openhab.binding.boschshc/README.md
bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/BoschSHCBindingConstants.java
bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/BoschSHCHandlerFactory.java
bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/universalswitch/UniversalSwitch2Handler.java [new file with mode: 0644]
bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/universalswitch/UniversalSwitchHandler.java [new file with mode: 0644]
bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/discovery/ThingDiscoveryService.java
bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/keypad/KeypadService.java [new file with mode: 0644]
bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/keypad/dto/KeyEventType.java [new file with mode: 0644]
bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/keypad/dto/KeyName.java [new file with mode: 0644]
bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/keypad/dto/KeypadServiceState.java [new file with mode: 0644]
bundles/org.openhab.binding.boschshc/src/main/resources/OH-INF/i18n/boschshc.properties
bundles/org.openhab.binding.boschshc/src/main/resources/OH-INF/thing/thing-types.xml
bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/devices/BoschSHCHandlerFactoryTest.java
bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/devices/universalswitch/UniversalSwitchHandler2Test.java [new file with mode: 0644]
bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/devices/universalswitch/UniversalSwitchHandlerTest.java [new file with mode: 0644]

index 7758c2d52ae4a1f9c06114a8301ec51c5427b57d..56be053b448e74d99eba373491b03f796353eb94 100644 (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
 
index 158c37acad7f29ec22f3f5445243fb3282eceda0..b2aee2d82485c4544e3fee73283dec25aa6817e0 100644 (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";
 
index 486f471d3bcc40ad491db3415bd028a43ad518e7..b5664588eec2c8846b459d8b2c703a8194c3d51e 100644 (file)
  */
 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);
     }
 }
diff --git a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/universalswitch/UniversalSwitch2Handler.java b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/universalswitch/UniversalSwitch2Handler.java
new file mode 100644 (file)
index 0000000..86628d3
--- /dev/null
@@ -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);
+    }
+}
diff --git a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/universalswitch/UniversalSwitchHandler.java b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/universalswitch/UniversalSwitchHandler.java
new file mode 100644 (file)
index 0000000..fc15f72
--- /dev/null
@@ -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())));
+    }
+}
index 3766ece6ebea3aac3d9d4421dd9cf97c330a25a8..1a7a6bbe5712037bfe1ef5394d153e172a3fafb2 100644 (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.),
diff --git a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/keypad/KeypadService.java b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/keypad/KeypadService.java
new file mode 100644 (file)
index 0000000..ac0c1d8
--- /dev/null
@@ -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);
+    }
+}
diff --git a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/keypad/dto/KeyEventType.java b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/keypad/dto/KeyEventType.java
new file mode 100644 (file)
index 0000000..36b2a85
--- /dev/null
@@ -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
+}
diff --git a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/keypad/dto/KeyName.java b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/keypad/dto/KeyName.java
new file mode 100644 (file)
index 0000000..284468a
--- /dev/null
@@ -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
+}
diff --git a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/keypad/dto/KeypadServiceState.java b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/keypad/dto/KeypadServiceState.java
new file mode 100644 (file)
index 0000000..e05e5b8
--- /dev/null
@@ -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;
+}
index 4734e7eaaa537cdaa81e45cf18a0abeb1fd21fb4..c5fc3174f5f3820eb8198ca6d0b082bb92b0e287 100644 (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
index f7460859dd5b6d5f68ea7513fd45705f6960ea83..ea8b6510232639fb8824d3655c5959e9e7fdb3d6 100644 (file)
                <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">
                </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>
index a1bdcd657cdaeff2f62afd9ac999c6533d0fac21..6a526a22ceda67ef177140dd1f4750fb520cedba 100644 (file)
  */
 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
diff --git a/bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/devices/universalswitch/UniversalSwitchHandler2Test.java b/bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/devices/universalswitch/UniversalSwitchHandler2Test.java
new file mode 100644 (file)
index 0000000..df1bf9d
--- /dev/null
@@ -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;
+    }
+}
diff --git a/bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/devices/universalswitch/UniversalSwitchHandlerTest.java b/bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/devices/universalswitch/UniversalSwitchHandlerTest.java
new file mode 100644 (file)
index 0000000..8e37ed9
--- /dev/null
@@ -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));
+    }
+}