[homekit] Implement IrrigationSystem Accessory (#14209)
* [homekit] Implement IrrigationSystem Fairly trivial now, except that a ServiceLabelService has to be added to the accessory. Signed-off-by: Cody Cutrer <cody@cutrer.us>
This commit is contained in:
@@ -59,6 +59,7 @@ public enum HomekitAccessoryType {
|
||||
INPUT_SOURCE("InputSource"),
|
||||
TELEVISION_SPEAKER("TelevisionSpeaker"),
|
||||
ACCESSORY_GROUP("AccessoryGroup"),
|
||||
IRRIGATION_SYSTEM("IrrigationSystem"),
|
||||
DUMMY("Dummy");
|
||||
|
||||
private static final Map<String, HomekitAccessoryType> TAG_MAP = new HashMap<>();
|
||||
|
||||
@@ -141,7 +141,11 @@ public enum HomekitCharacteristicType {
|
||||
TARGET_VISIBILITY_STATE("TargetVisibilityState"),
|
||||
|
||||
VOLUME_SELECTOR("VolumeSelector"),
|
||||
VOLUME_CONTROL_TYPE("VolumeControlType");
|
||||
VOLUME_CONTROL_TYPE("VolumeControlType"),
|
||||
|
||||
PROGRAM_MODE("ProgramMode"),
|
||||
SERVICE_LABEL("ServiceLabel"),
|
||||
SERVICE_INDEX("ServiceIndex");
|
||||
|
||||
private static final Map<String, HomekitCharacteristicType> TAG_MAP = new HashMap<>();
|
||||
|
||||
|
||||
@@ -108,6 +108,7 @@ public class HomekitAccessoryFactory {
|
||||
put(TELEVISION, new HomekitCharacteristicType[] { ACTIVE });
|
||||
put(INPUT_SOURCE, new HomekitCharacteristicType[] {});
|
||||
put(TELEVISION_SPEAKER, new HomekitCharacteristicType[] { MUTE });
|
||||
put(IRRIGATION_SYSTEM, new HomekitCharacteristicType[] { ACTIVE, INUSE_STATUS, PROGRAM_MODE });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -150,6 +151,7 @@ public class HomekitAccessoryFactory {
|
||||
put(TELEVISION, HomekitTelevisionImpl.class);
|
||||
put(INPUT_SOURCE, HomekitInputSourceImpl.class);
|
||||
put(TELEVISION_SPEAKER, HomekitTelevisionSpeakerImpl.class);
|
||||
put(IRRIGATION_SYSTEM, HomekitIrrigationSystemImpl.class);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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 java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.io.homekit.internal.HomekitAccessoryUpdater;
|
||||
import org.openhab.io.homekit.internal.HomekitCharacteristicType;
|
||||
import org.openhab.io.homekit.internal.HomekitSettings;
|
||||
import org.openhab.io.homekit.internal.HomekitTaggedItem;
|
||||
|
||||
import io.github.hapjava.accessories.IrrigationSystemAccessory;
|
||||
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
|
||||
import io.github.hapjava.characteristics.impl.common.ActiveEnum;
|
||||
import io.github.hapjava.characteristics.impl.common.InUseEnum;
|
||||
import io.github.hapjava.characteristics.impl.common.ProgramModeEnum;
|
||||
import io.github.hapjava.characteristics.impl.common.ServiceLabelNamespaceCharacteristic;
|
||||
import io.github.hapjava.characteristics.impl.common.ServiceLabelNamespaceEnum;
|
||||
import io.github.hapjava.services.impl.IrrigationSystemService;
|
||||
import io.github.hapjava.services.impl.ServiceLabelService;
|
||||
|
||||
/**
|
||||
* Implements an Irrigation System accessory.
|
||||
*
|
||||
* To be a complete accessory, the user must configure individual valves linked
|
||||
* to this primary service. This class also adds the ServiceLabelService
|
||||
* automatically.
|
||||
*
|
||||
* @author Cody Cutrer - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault({})
|
||||
public class HomekitIrrigationSystemImpl extends AbstractHomekitAccessoryImpl implements IrrigationSystemAccessory {
|
||||
private BooleanItemReader inUseReader;
|
||||
private Map<ProgramModeEnum, String> programModeMap;
|
||||
private static final String SERVICE_LABEL = "ServiceLabel";
|
||||
|
||||
public HomekitIrrigationSystemImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
|
||||
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
|
||||
super(taggedItem, mandatoryCharacteristics, updater, settings);
|
||||
inUseReader = createBooleanReader(HomekitCharacteristicType.INUSE_STATUS);
|
||||
programModeMap = HomekitCharacteristicFactory
|
||||
.createMapping(getCharacteristic(HomekitCharacteristicType.PROGRAM_MODE).get(), ProgramModeEnum.class);
|
||||
getServices().add(new IrrigationSystemService(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void 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)));
|
||||
getServices().add(new ServiceLabelService(serviceLabelNamespace));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<ActiveEnum> getActive() {
|
||||
OnOffType state = getStateAs(HomekitCharacteristicType.ACTIVE, OnOffType.class);
|
||||
return CompletableFuture.completedFuture(state == OnOffType.ON ? ActiveEnum.ACTIVE : ActiveEnum.INACTIVE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> setActive(ActiveEnum value) {
|
||||
getCharacteristic(HomekitCharacteristicType.ACTIVE).ifPresent(tItem -> {
|
||||
tItem.send(value == ActiveEnum.ACTIVE ? OnOffType.ON : OnOffType.OFF);
|
||||
});
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<InUseEnum> getInUse() {
|
||||
return CompletableFuture.completedFuture(inUseReader.getValue() ? InUseEnum.IN_USE : InUseEnum.NOT_IN_USE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<ProgramModeEnum> getProgramMode() {
|
||||
return CompletableFuture.completedFuture(getKeyFromMapping(HomekitCharacteristicType.PROGRAM_MODE,
|
||||
programModeMap, ProgramModeEnum.NO_SCHEDULED));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribeActive(HomekitCharacteristicChangeCallback callback) {
|
||||
subscribe(HomekitCharacteristicType.ACTIVE, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsubscribeActive() {
|
||||
unsubscribe(HomekitCharacteristicType.ACTIVE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribeInUse(HomekitCharacteristicChangeCallback callback) {
|
||||
subscribe(HomekitCharacteristicType.INUSE_STATUS, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsubscribeInUse() {
|
||||
unsubscribe(HomekitCharacteristicType.INUSE_STATUS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribeProgramMode(HomekitCharacteristicChangeCallback callback) {
|
||||
subscribe(HomekitCharacteristicType.PROGRAM_MODE, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsubscribeProgramMode() {
|
||||
unsubscribe(HomekitCharacteristicType.PROGRAM_MODE);
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,7 @@ import io.github.hapjava.characteristics.impl.common.IdentifierCharacteristic;
|
||||
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.heatercooler.CurrentHeaterCoolerStateCharacteristic;
|
||||
import io.github.hapjava.characteristics.impl.heatercooler.CurrentHeaterCoolerStateEnum;
|
||||
import io.github.hapjava.characteristics.impl.heatercooler.TargetHeaterCoolerStateCharacteristic;
|
||||
@@ -90,6 +91,7 @@ public class HomekitMetadataCharacteristicFactory {
|
||||
put(INPUT_SOURCE_TYPE, HomekitMetadataCharacteristicFactory::createInputSourceTypeCharacteristic);
|
||||
put(NAME, HomekitMetadataCharacteristicFactory::createNameCharacteristic);
|
||||
put(PICTURE_MODE, HomekitMetadataCharacteristicFactory::createPictureModeCharacteristic);
|
||||
put(SERVICE_INDEX, HomekitMetadataCharacteristicFactory::createServiceIndexCharacteristic);
|
||||
put(SLEEP_DISCOVERY_MODE, HomekitMetadataCharacteristicFactory::createSleepDiscoveryModeCharacteristic);
|
||||
put(TARGET_HEATER_COOLER_STATE,
|
||||
HomekitMetadataCharacteristicFactory::createTargetHeaterCoolerStateCharacteristic);
|
||||
@@ -249,6 +251,10 @@ public class HomekitMetadataCharacteristicFactory {
|
||||
});
|
||||
}
|
||||
|
||||
private static Characteristic createServiceIndexCharacteristic(Object value) {
|
||||
return new ServiceLabelIndexCharacteristic(getInteger(value));
|
||||
}
|
||||
|
||||
private static Characteristic createSleepDiscoveryModeCharacteristic(Object value) {
|
||||
return new SleepDiscoveryModeCharacteristic(getEnum(value, SleepDiscoveryModeEnum.class,
|
||||
SleepDiscoveryModeEnum.ALWAYS_DISCOVERABLE, SleepDiscoveryModeEnum.NOT_DISCOVERABLE), v -> {
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.openhab.io.homekit.internal.HomekitTaggedItem;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.github.hapjava.accessories.HomekitAccessory;
|
||||
import io.github.hapjava.accessories.ValveAccessory;
|
||||
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
|
||||
import io.github.hapjava.characteristics.impl.common.ActiveEnum;
|
||||
@@ -53,7 +54,8 @@ import io.github.hapjava.services.impl.ValveService;
|
||||
*/
|
||||
public class HomekitValveImpl extends AbstractHomekitAccessoryImpl implements ValveAccessory {
|
||||
private final Logger logger = LoggerFactory.getLogger(HomekitValveImpl.class);
|
||||
private static final String CONFIG_VALVE_TYPE = "homekitValveType";
|
||||
private static final String CONFIG_VALVE_TYPE = "ValveType";
|
||||
private static final String CONFIG_VALVE_TYPE_DEPRECATED = "homekitValveType";
|
||||
public static final String CONFIG_DEFAULT_DURATION = "homekitDefaultDuration";
|
||||
private static final String CONFIG_TIMER = "homekitTimer";
|
||||
|
||||
@@ -70,6 +72,7 @@ public class HomekitValveImpl extends AbstractHomekitAccessoryImpl implements Va
|
||||
private final ScheduledExecutorService timerService = Executors.newSingleThreadScheduledExecutor();
|
||||
private ScheduledFuture<?> valveTimer;
|
||||
private final boolean homekitTimer;
|
||||
private ValveTypeEnum valveType;
|
||||
|
||||
public HomekitValveImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
|
||||
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
|
||||
@@ -82,6 +85,10 @@ public class HomekitValveImpl extends AbstractHomekitAccessoryImpl implements Va
|
||||
if (homekitTimer) {
|
||||
addRemainingDurationCharacteristic(taggedItem, updater, service);
|
||||
}
|
||||
String valveTypeConfig = getAccessoryConfiguration(CONFIG_VALVE_TYPE, "GENERIC");
|
||||
valveTypeConfig = getAccessoryConfiguration(CONFIG_VALVE_TYPE_DEPRECATED, valveTypeConfig);
|
||||
var valveType = CONFIG_VALVE_TYPE_MAPPING.get(valveTypeConfig.toUpperCase());
|
||||
this.valveType = valveType != null ? valveType : ValveTypeEnum.GENERIC;
|
||||
}
|
||||
|
||||
private void addRemainingDurationCharacteristic(HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater,
|
||||
@@ -191,9 +198,7 @@ public class HomekitValveImpl extends AbstractHomekitAccessoryImpl implements Va
|
||||
|
||||
@Override
|
||||
public CompletableFuture<ValveTypeEnum> getValveType() {
|
||||
final String valveType = getAccessoryConfiguration(CONFIG_VALVE_TYPE, "GENERIC");
|
||||
ValveTypeEnum type = CONFIG_VALVE_TYPE_MAPPING.get(valveType.toUpperCase());
|
||||
return CompletableFuture.completedFuture(type != null ? type : ValveTypeEnum.GENERIC);
|
||||
return CompletableFuture.completedFuture(valveType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -205,4 +210,14 @@ public class HomekitValveImpl extends AbstractHomekitAccessoryImpl implements Va
|
||||
public void unsubscribeValveType() {
|
||||
// nothing changes here
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLinkable(HomekitAccessory parentAccessory) {
|
||||
// When part of an irrigation system, the valve type _must_ be irrigation.
|
||||
if (parentAccessory instanceof HomekitIrrigationSystemImpl) {
|
||||
valveType = ValveTypeEnum.IRRIGATION;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user