mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-25 14:55:55 +01:00
[homekit] implement StatelessProgrammableSwitch (#17129)
also supports adding multiple of them in a group, by supporting ServiceIndex as an optional characteristic refs #9969 Signed-off-by: Cody Cutrer <cody@cutrer.us>
This commit is contained in:
parent
64fc6bcd1f
commit
cbbc36697c
@ -694,6 +694,19 @@ or using UI
|
||||
|
||||
![sensor_ui_config.png](doc/sensor_ui_config.png)
|
||||
|
||||
### Stateless Programmable Switch Groups
|
||||
|
||||
To expose multiple Stateless Programmable Switches as a single accessory with multiple buttons (aka a scene controller), you need to configure ServiceLabel on the accessory group and ServiceIndex on each switch.
|
||||
Note that in the Home app, the individual switch names will be ignored, and will simply be displayed as "Button 1", "Button 2", etc. (for ARABIC_NUMERALS style).
|
||||
|
||||
```java
|
||||
Group gSceneController "Scene Controller" { homekit="AccessoryGroup"[ServiceLabel="ARABIC_NUMERALS"] }
|
||||
Switch Button1 "Switch A" (gSceneController) { homekit="StatelessProgrammableSwitch"[ServiceIndex=1] }
|
||||
Switch Button2 "Switch B" (gSceneController) { homekit="StatelessProgrammableSwitch"[ServiceIndex=2] }
|
||||
Switch Button3 "Switch C" (gSceneController) { homekit="StatelessProgrammableSwitch"[ServiceIndex=3] }
|
||||
Switch Button4 "Switch D" (gSceneController) { homekit="StatelessProgrammableSwitch"[ServiceIndex=4] }
|
||||
```
|
||||
|
||||
## Supported accessory types
|
||||
|
||||
For configuration options, the default values are in parentheses.
|
||||
@ -717,7 +730,7 @@ All accessories also support the following optional characteristic that can be l
|
||||
* Identify (receives `ON` command when the user wishes to identify the accessory)
|
||||
|
||||
| Accessory Tag | Mandatory Characteristics | Optional Characteristics | Supported openHAB item types | Description | Configuration Options | Valid Enum Values |
|
||||
|----------------------|-----------------------------|-----------------------------|-----------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------|
|
||||
|-----------------------------|-----------------------------|-----------------------------|-----------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------|
|
||||
| AirQualitySensor | | | | Air Quality Sensor which can measure different parameters | | |
|
||||
| | AirQuality | | Number, String, Switch | Air quality state | | UNKNOWN (0, OFF), EXCELLENT (1, ON), GOOD (2), FAIR (3), INFERIOR (4), POOR (5) |
|
||||
| | | ActiveStatus | Contact, Switch | Working status | | |
|
||||
@ -880,6 +893,9 @@ All accessories also support the following optional characteristic that can be l
|
||||
| | Mute | | Contact, Dimmer, Switch | Mute indication. ON/OPEN = speaker is muted | inverted (false) | |
|
||||
| | | Active | Contact, Dimmer, Number, String, Switch | Accessory current working status | inverted (false) | INACTIVE (0, OFF), ACTIVE (1, ON) |
|
||||
| | | Volume | Number | Speaker volume from 0% to 100% | | |
|
||||
| StatelessProgrammableSwitch | | | | A stateless programmable switch is a button or scene controller that simply sends an event to Home when it is pressed, allowing automations to occur. See [Stateless Programmable Switch Groups](#Stateless-Programmable-Switch-Groups) for configuring multiple in one accessory. | | |
|
||||
| | ProgrammableSwitchEvent | | Contact, Number, String, Switch | The button press event. Note that the event will be forwarded to Home for every _update_ of the item, not just on change. | inverted (false) | SINGLE_PRESS (0, ON, OPEN), DOUBLE_PRESS (1), LONG_PRESS (2) [*](#customizable-enum) |
|
||||
| | | Volume | Number | Speaker volume from 0% to 100% | | |
|
||||
| Switchable | | | | An accessory that can be turned off and on. While similar to a lightbulb, this will be presented differently in the Siri grammar and iOS apps | | |
|
||||
| | OnState | | Dimmer, Switch | State of the switch - ON/OFF | | |
|
||||
| Television | | | | Television accessory with inputs | | |
|
||||
|
@ -54,6 +54,7 @@ public enum HomekitAccessoryType {
|
||||
SMART_SPEAKER("SmartSpeaker"),
|
||||
SMOKE_SENSOR("SmokeSensor"),
|
||||
SPEAKER("Speaker"),
|
||||
STATELESS_PROGRAMMABLE_SWITCH("StatelessProgrammableSwitch"),
|
||||
SWITCH("Switchable"),
|
||||
TELEVISION("Television"),
|
||||
TELEVISION_SPEAKER("TelevisionSpeaker"),
|
||||
|
@ -14,6 +14,7 @@ package org.openhab.io.homekit.internal;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.items.GenericItem;
|
||||
@ -35,7 +36,7 @@ import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
|
||||
*/
|
||||
public class HomekitAccessoryUpdater {
|
||||
private final Logger logger = LoggerFactory.getLogger(HomekitAccessoryUpdater.class);
|
||||
private final ConcurrentMap<ItemKey, Subscription> subscriptionsByName = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<ItemKey, StateChangeListener> subscriptionsByName = new ConcurrentHashMap<>();
|
||||
|
||||
public void subscribe(GenericItem item, HomekitCharacteristicChangeCallback callback) {
|
||||
subscribe(item, null, callback);
|
||||
@ -63,6 +64,28 @@ public class HomekitAccessoryUpdater {
|
||||
});
|
||||
}
|
||||
|
||||
public void subscribeToUpdates(GenericItem item, String key, Consumer<State> callback) {
|
||||
logger.trace("Received subscription request for {} / {}", item, key);
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
if (callback == null) {
|
||||
logger.trace("The received subscription contains a null callback, skipping");
|
||||
return;
|
||||
}
|
||||
ItemKey itemKey = new ItemKey(item, key);
|
||||
subscriptionsByName.compute(itemKey, (k, v) -> {
|
||||
if (v != null) {
|
||||
logger.debug("Received duplicate subscription for {} / {}", item, key);
|
||||
unsubscribe(item, key);
|
||||
}
|
||||
logger.trace("Adding subscription for {} / {}", item, key);
|
||||
UpdateSubscription subscription = (changedItem, newState) -> callback.accept(newState);
|
||||
item.addStateChangeListener(subscription);
|
||||
return subscription;
|
||||
});
|
||||
}
|
||||
|
||||
public void unsubscribe(GenericItem item) {
|
||||
unsubscribe(item, null);
|
||||
}
|
||||
@ -91,6 +114,19 @@ public class HomekitAccessoryUpdater {
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
@NonNullByDefault
|
||||
private interface UpdateSubscription extends StateChangeListener {
|
||||
|
||||
@Override
|
||||
default void stateChanged(Item item, State oldState, State newState) {
|
||||
// Do nothing on change update
|
||||
}
|
||||
|
||||
@Override
|
||||
void stateUpdated(Item item, State state);
|
||||
}
|
||||
|
||||
private static class ItemKey {
|
||||
public final GenericItem item;
|
||||
public final String key;
|
||||
|
@ -97,6 +97,7 @@ public enum HomekitCharacteristicType {
|
||||
POSITION_STATE("PositionState"),
|
||||
POWER_MODE("PowerMode"),
|
||||
PROGRAM_MODE("ProgramMode"),
|
||||
PROGRAMMABLE_SWITCH_EVENT("ProgrammableSwitchEvent"),
|
||||
RELATIVE_HUMIDITY("RelativeHumidity"),
|
||||
REMAINING_DURATION("RemainingDuration"),
|
||||
REMOTE_KEY("RemoteKey"),
|
||||
|
@ -420,7 +420,8 @@ public abstract class AbstractHomekitAccessoryImpl implements HomekitAccessory {
|
||||
T defaultValue) {
|
||||
final Optional<HomekitTaggedItem> c = getCharacteristic(characteristicType);
|
||||
if (c.isPresent()) {
|
||||
return HomekitCharacteristicFactory.getKeyFromMapping(c.get(), mapping, defaultValue);
|
||||
return HomekitCharacteristicFactory.getKeyFromMapping(c.get(), c.get().getItem().getState(), mapping,
|
||||
defaultValue);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
@ -100,6 +100,7 @@ public class HomekitAccessoryFactory {
|
||||
put(SMOKE_SENSOR, new HomekitCharacteristicType[] { SMOKE_DETECTED_STATE });
|
||||
put(SLAT, new HomekitCharacteristicType[] { CURRENT_SLAT_STATE });
|
||||
put(SPEAKER, new HomekitCharacteristicType[] { MUTE });
|
||||
put(STATELESS_PROGRAMMABLE_SWITCH, new HomekitCharacteristicType[] { PROGRAMMABLE_SWITCH_EVENT });
|
||||
put(SWITCH, new HomekitCharacteristicType[] { ON_STATE });
|
||||
put(TELEVISION, new HomekitCharacteristicType[] { ACTIVE });
|
||||
put(TELEVISION_SPEAKER, new HomekitCharacteristicType[] { MUTE });
|
||||
@ -145,6 +146,7 @@ public class HomekitAccessoryFactory {
|
||||
put(SMART_SPEAKER, HomekitSmartSpeakerImpl.class);
|
||||
put(SMOKE_SENSOR, HomekitSmokeSensorImpl.class);
|
||||
put(SPEAKER, HomekitSpeakerImpl.class);
|
||||
put(STATELESS_PROGRAMMABLE_SWITCH, HomekitStatelessProgrammableSwitchImpl.class);
|
||||
put(SWITCH, HomekitSwitchImpl.class);
|
||||
put(TELEVISION, HomekitTelevisionImpl.class);
|
||||
put(TELEVISION_SPEAKER, HomekitTelevisionSpeakerImpl.class);
|
||||
|
@ -16,10 +16,13 @@ import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.io.homekit.internal.HomekitAccessoryUpdater;
|
||||
import org.openhab.io.homekit.internal.HomekitException;
|
||||
import org.openhab.io.homekit.internal.HomekitSettings;
|
||||
import org.openhab.io.homekit.internal.HomekitTaggedItem;
|
||||
|
||||
import io.github.hapjava.characteristics.Characteristic;
|
||||
import io.github.hapjava.characteristics.impl.common.ServiceLabelNamespaceCharacteristic;
|
||||
import io.github.hapjava.services.impl.ServiceLabelService;
|
||||
|
||||
/**
|
||||
* Bare accessory (for being the root of a multi-service accessory).
|
||||
@ -33,4 +36,12 @@ public class HomekitAccessoryGroupImpl extends AbstractHomekitAccessoryImpl {
|
||||
throws IncompleteAccessoryException {
|
||||
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() throws HomekitException {
|
||||
super.init();
|
||||
|
||||
getCharacteristic(ServiceLabelNamespaceCharacteristic.class)
|
||||
.ifPresent(c -> getServices().add(new ServiceLabelService(c)));
|
||||
}
|
||||
}
|
||||
|
@ -99,6 +99,8 @@ import io.github.hapjava.characteristics.impl.common.IsConfiguredCharacteristic;
|
||||
import io.github.hapjava.characteristics.impl.common.IsConfiguredEnum;
|
||||
import io.github.hapjava.characteristics.impl.common.NameCharacteristic;
|
||||
import io.github.hapjava.characteristics.impl.common.ObstructionDetectedCharacteristic;
|
||||
import io.github.hapjava.characteristics.impl.common.ProgrammableSwitchEnum;
|
||||
import io.github.hapjava.characteristics.impl.common.ProgrammableSwitchEventCharacteristic;
|
||||
import io.github.hapjava.characteristics.impl.common.StatusActiveCharacteristic;
|
||||
import io.github.hapjava.characteristics.impl.common.StatusFaultCharacteristic;
|
||||
import io.github.hapjava.characteristics.impl.common.StatusFaultEnum;
|
||||
@ -231,6 +233,7 @@ public class HomekitCharacteristicFactory {
|
||||
put(PM10_DENSITY, HomekitCharacteristicFactory::createPM10DensityCharacteristic);
|
||||
put(PM25_DENSITY, HomekitCharacteristicFactory::createPM25DensityCharacteristic);
|
||||
put(POWER_MODE, HomekitCharacteristicFactory::createPowerModeCharacteristic);
|
||||
put(PROGRAMMABLE_SWITCH_EVENT, HomekitCharacteristicFactory::createProgrammableSwitchEventCharacteristic);
|
||||
put(REMAINING_DURATION, HomekitCharacteristicFactory::createRemainingDurationCharacteristic);
|
||||
put(REMOTE_KEY, HomekitCharacteristicFactory::createRemoteKeyCharacteristic);
|
||||
put(RELATIVE_HUMIDITY, HomekitCharacteristicFactory::createRelativeHumidityCharacteristic);
|
||||
@ -391,8 +394,7 @@ public class HomekitCharacteristicFactory {
|
||||
* @param <T> type of the result derived from
|
||||
* @return key for the value
|
||||
*/
|
||||
public static <T> T getKeyFromMapping(HomekitTaggedItem item, Map<T, String> mapping, T defaultValue) {
|
||||
final State state = item.getItem().getState();
|
||||
public static <T> T getKeyFromMapping(HomekitTaggedItem item, State state, Map<T, String> mapping, T defaultValue) {
|
||||
LOGGER.trace("getKeyFromMapping: characteristic {}, state {}, mapping {}", item.getAccessoryType().getTag(),
|
||||
state, mapping);
|
||||
|
||||
@ -448,7 +450,8 @@ public class HomekitCharacteristicFactory {
|
||||
|
||||
private static <T extends CharacteristicEnum> CompletableFuture<T> getEnumFromItem(HomekitTaggedItem item,
|
||||
Map<T, String> mapping, T defaultValue) {
|
||||
return CompletableFuture.completedFuture(getKeyFromMapping(item, mapping, defaultValue));
|
||||
return CompletableFuture
|
||||
.completedFuture(getKeyFromMapping(item, item.getItem().getState(), mapping, defaultValue));
|
||||
}
|
||||
|
||||
public static <T extends Enum<T>> void setValueFromEnum(HomekitTaggedItem taggedItem, T value, Map<T, String> map) {
|
||||
@ -1160,6 +1163,80 @@ public class HomekitCharacteristicFactory {
|
||||
return new PowerModeCharacteristic((value) -> setValueFromEnum(taggedItem, value, map));
|
||||
}
|
||||
|
||||
// this characteristic is unique in a few ways, so we can't use the "normal" helpers:
|
||||
// * you don't return a "current" value, just the value of the most recent event
|
||||
// * NULL/invalid values are very much expected, and should silently _not_ trigger an event
|
||||
// * every update to the item should trigger an event, not just changes
|
||||
|
||||
private static ProgrammableSwitchEventCharacteristic createProgrammableSwitchEventCharacteristic(
|
||||
HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
|
||||
// have to build the map custom, since SINGLE_PRESS starts at 0
|
||||
Map<ProgrammableSwitchEnum, String> map = new EnumMap(ProgrammableSwitchEnum.class);
|
||||
List<ProgrammableSwitchEnum> validValues = new ArrayList<>();
|
||||
|
||||
if (taggedItem.getBaseItem().getAcceptedDataTypes().contains(OnOffType.class)) {
|
||||
map.put(ProgrammableSwitchEnum.SINGLE_PRESS, OnOffType.ON.toString());
|
||||
validValues.add(ProgrammableSwitchEnum.SINGLE_PRESS);
|
||||
} else if (taggedItem.getBaseItem().getAcceptedDataTypes().contains(OpenClosedType.class)) {
|
||||
map.put(ProgrammableSwitchEnum.SINGLE_PRESS, OpenClosedType.OPEN.toString());
|
||||
validValues.add(ProgrammableSwitchEnum.SINGLE_PRESS);
|
||||
} else {
|
||||
map = createMapping(taggedItem, ProgrammableSwitchEnum.class, validValues, false);
|
||||
}
|
||||
|
||||
var helper = new ProgrammableSwitchEventCharacteristicHelper(taggedItem, updater, map);
|
||||
|
||||
return new ProgrammableSwitchEventCharacteristic(validValues.toArray(new ProgrammableSwitchEnum[0]),
|
||||
helper::getValue, helper::subscribe, getUnsubscriber(taggedItem, PROGRAMMABLE_SWITCH_EVENT, updater));
|
||||
}
|
||||
|
||||
private static class ProgrammableSwitchEventCharacteristicHelper {
|
||||
private @Nullable ProgrammableSwitchEnum lastValue = null;
|
||||
private final HomekitTaggedItem taggedItem;
|
||||
private final Map<ProgrammableSwitchEnum, String> map;
|
||||
private final HomekitAccessoryUpdater updater;
|
||||
|
||||
ProgrammableSwitchEventCharacteristicHelper(HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater,
|
||||
Map<ProgrammableSwitchEnum, String> map) {
|
||||
this.taggedItem = taggedItem;
|
||||
this.map = map;
|
||||
this.updater = updater;
|
||||
}
|
||||
|
||||
public CompletableFuture<ProgrammableSwitchEnum> getValue() {
|
||||
return CompletableFuture.completedFuture(lastValue);
|
||||
}
|
||||
|
||||
public void subscribe(HomekitCharacteristicChangeCallback cb) {
|
||||
updater.subscribeToUpdates((GenericItem) taggedItem.getItem(), PROGRAMMABLE_SWITCH_EVENT.getTag(),
|
||||
state -> {
|
||||
// perform inversion here, so logic below only needs to deal with the
|
||||
// canonical style
|
||||
if (state instanceof OnOffType && taggedItem.isInverted()) {
|
||||
if (state.equals(OnOffType.ON)) {
|
||||
state = OnOffType.OFF;
|
||||
} else {
|
||||
state = OnOffType.ON;
|
||||
}
|
||||
} else if (state instanceof OpenClosedType && taggedItem.isInverted()) {
|
||||
if (state.equals(OpenClosedType.OPEN)) {
|
||||
state = OpenClosedType.CLOSED;
|
||||
} else {
|
||||
state = OpenClosedType.OPEN;
|
||||
}
|
||||
}
|
||||
// if "not pressed", don't send an event
|
||||
if (state instanceof UnDefType || (state instanceof OnOffType && state.equals(OnOffType.OFF))
|
||||
|| (state instanceof OpenClosedType && state.equals(OpenClosedType.CLOSED))) {
|
||||
lastValue = null;
|
||||
return;
|
||||
}
|
||||
lastValue = getKeyFromMapping(taggedItem, state, map, ProgrammableSwitchEnum.SINGLE_PRESS);
|
||||
cb.changed();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static RemainingDurationCharacteristic createRemainingDurationCharacteristic(HomekitTaggedItem taggedItem,
|
||||
HomekitAccessoryUpdater updater) {
|
||||
return new RemainingDurationCharacteristic(getIntSupplier(taggedItem, 0),
|
||||
|
@ -48,7 +48,6 @@ import io.github.hapjava.services.impl.ServiceLabelService;
|
||||
public class HomekitIrrigationSystemImpl extends AbstractHomekitAccessoryImpl implements IrrigationSystemAccessory {
|
||||
private Map<InUseEnum, String> inUseMapping;
|
||||
private Map<ProgramModeEnum, String> programModeMap;
|
||||
private static final String SERVICE_LABEL = "ServiceLabel";
|
||||
|
||||
public HomekitIrrigationSystemImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
|
||||
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
|
||||
@ -64,17 +63,9 @@ public class HomekitIrrigationSystemImpl extends AbstractHomekitAccessoryImpl im
|
||||
public void init() throws HomekitException {
|
||||
super.init();
|
||||
|
||||
String serviceLabelNamespaceConfig = getAccessoryConfiguration(SERVICE_LABEL, "ARABIC_NUMERALS");
|
||||
ServiceLabelNamespaceEnum serviceLabelEnum;
|
||||
|
||||
try {
|
||||
serviceLabelEnum = ServiceLabelNamespaceEnum.valueOf(serviceLabelNamespaceConfig.toUpperCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
serviceLabelEnum = ServiceLabelNamespaceEnum.ARABIC_NUMERALS;
|
||||
}
|
||||
final var finalEnum = serviceLabelEnum;
|
||||
var serviceLabelNamespace = getCharacteristic(ServiceLabelNamespaceCharacteristic.class).orElseGet(
|
||||
() -> new ServiceLabelNamespaceCharacteristic(() -> CompletableFuture.completedFuture(finalEnum)));
|
||||
var serviceLabelNamespace = getCharacteristic(ServiceLabelNamespaceCharacteristic.class)
|
||||
.orElseGet(() -> new ServiceLabelNamespaceCharacteristic(
|
||||
() -> CompletableFuture.completedFuture(ServiceLabelNamespaceEnum.ARABIC_NUMERALS)));
|
||||
addService(new ServiceLabelService(serviceLabelNamespace));
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,8 @@ import io.github.hapjava.characteristics.impl.common.IsConfiguredCharacteristic;
|
||||
import io.github.hapjava.characteristics.impl.common.IsConfiguredEnum;
|
||||
import io.github.hapjava.characteristics.impl.common.NameCharacteristic;
|
||||
import io.github.hapjava.characteristics.impl.common.ServiceLabelIndexCharacteristic;
|
||||
import io.github.hapjava.characteristics.impl.common.ServiceLabelNamespaceCharacteristic;
|
||||
import io.github.hapjava.characteristics.impl.common.ServiceLabelNamespaceEnum;
|
||||
import io.github.hapjava.characteristics.impl.heatercooler.CurrentHeaterCoolerStateCharacteristic;
|
||||
import io.github.hapjava.characteristics.impl.heatercooler.CurrentHeaterCoolerStateEnum;
|
||||
import io.github.hapjava.characteristics.impl.heatercooler.TargetHeaterCoolerStateCharacteristic;
|
||||
@ -101,6 +103,7 @@ public class HomekitMetadataCharacteristicFactory {
|
||||
put(PICTURE_MODE, HomekitMetadataCharacteristicFactory::createPictureModeCharacteristic);
|
||||
put(SERIAL_NUMBER, HomekitMetadataCharacteristicFactory::createSerialNumberCharacteristic);
|
||||
put(SERVICE_INDEX, HomekitMetadataCharacteristicFactory::createServiceIndexCharacteristic);
|
||||
put(SERVICE_LABEL, HomekitMetadataCharacteristicFactory::createServiceLabelNamespaceCharacteristic);
|
||||
put(SLEEP_DISCOVERY_MODE, HomekitMetadataCharacteristicFactory::createSleepDiscoveryModeCharacteristic);
|
||||
put(TARGET_HEATER_COOLER_STATE,
|
||||
HomekitMetadataCharacteristicFactory::createTargetHeaterCoolerStateCharacteristic);
|
||||
@ -292,6 +295,10 @@ public class HomekitMetadataCharacteristicFactory {
|
||||
return new ServiceLabelIndexCharacteristic(getInteger(value));
|
||||
}
|
||||
|
||||
private static Characteristic createServiceLabelNamespaceCharacteristic(Object value) {
|
||||
return new ServiceLabelNamespaceCharacteristic(getEnum(value, ServiceLabelNamespaceEnum.class));
|
||||
}
|
||||
|
||||
private static Characteristic createSleepDiscoveryModeCharacteristic(Object value) {
|
||||
return new SleepDiscoveryModeCharacteristic(getEnum(value, SleepDiscoveryModeEnum.class,
|
||||
SleepDiscoveryModeEnum.ALWAYS_DISCOVERABLE, SleepDiscoveryModeEnum.NOT_DISCOVERABLE), v -> {
|
||||
|
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* 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.io.homekit.internal.accessories;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.openhab.io.homekit.internal.HomekitAccessoryUpdater;
|
||||
import org.openhab.io.homekit.internal.HomekitException;
|
||||
import org.openhab.io.homekit.internal.HomekitSettings;
|
||||
import org.openhab.io.homekit.internal.HomekitTaggedItem;
|
||||
|
||||
import io.github.hapjava.characteristics.Characteristic;
|
||||
import io.github.hapjava.characteristics.impl.common.ProgrammableSwitchEventCharacteristic;
|
||||
import io.github.hapjava.services.impl.StatelessProgrammableSwitchService;
|
||||
|
||||
/**
|
||||
* Implements a HomeKit Stateless Programmable Switch
|
||||
*
|
||||
* @author Cody Cutrer - Initial contribution
|
||||
*/
|
||||
class HomekitStatelessProgrammableSwitchImpl extends AbstractHomekitAccessoryImpl {
|
||||
|
||||
public HomekitStatelessProgrammableSwitchImpl(HomekitTaggedItem taggedItem,
|
||||
List<HomekitTaggedItem> mandatoryCharacteristics, List<Characteristic> mandatoryRawCharacteristics,
|
||||
HomekitAccessoryUpdater updater, HomekitSettings settings) {
|
||||
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() throws HomekitException {
|
||||
super.init();
|
||||
|
||||
addService(new StatelessProgrammableSwitchService(
|
||||
getCharacteristic(ProgrammableSwitchEventCharacteristic.class).get()));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user