[homekit] Allow configuring thermostat modes via metadata (#17056)

* [homekit] allow configuring thermostat modes via metadata

Signed-off-by: Cody Cutrer <cody@cutrer.us>
Signed-off-by: Ciprian Pascu <contact@ciprianpascu.ro>
This commit is contained in:
Cody Cutrer 2024-07-14 16:18:10 -06:00 committed by Ciprian Pascu
parent 468b29549b
commit bf661d2464
44 changed files with 352 additions and 326 deletions

View File

@ -899,6 +899,8 @@ All accessories also support the following optional characteristic that can be l
| | | CoolingThresholdTemperature | Number | Maximum temperature that must be reached before cooling is turned on | minValue (10), maxValue (35), step (0.1) | |
| | | HeatingThresholdTemperature | Number | Minimum temperature that must be reached before heating is turned on | minValue (0), maxValue (25), step (0.1) | |
| | | RelativeHumidity | Number | Relative humidity in % between 0 and 100. | | |
| | | TargetRelativeHumidity | Number | Target relative humidity in % between 0 and 100. | | |
| | | TemperatureUnit | Number, String, Switch | The units the accessory itself uses to display the temperature. Can also be configured via metadata, e.g. [TemperatureUnit="CELSIUS"] | | CELSIUS (0, OFF), FAHRENHEIT (1, ON) |
| Valve | | | | Valve | ValveType = ["Generic", "Irrigation", "Shower", "Faucet"] ("Generic") | |
| | ActiveStatus | | Dimmer, Switch | Accessory current working status. A value of "ON"/"OPEN" indicates that the accessory is active and is functioning without any errors. | | |
| | InUseStatus | | Contact, Dimmer, Switch | Indicates whether fluid flowing through the valve. A value of "ON"/"OPEN" indicates that fluid is flowing. | inverted (false) | |

View File

@ -90,6 +90,7 @@ public enum HomekitCharacteristicType {
CURRENT_HEATING_COOLING_STATE("CurrentHeatingCoolingMode"),
TARGET_TEMPERATURE("TargetTemperature"),
TEMPERATURE_UNIT("TemperatureUnit"),
TARGET_RELATIVE_HUMIDITY("TargetRelativeHumidity"),
LOCK_CURRENT_STATE("LockCurrentState"),
LOCK_TARGET_STATE("LockTargetState"),

View File

@ -72,9 +72,10 @@ public abstract class AbstractHomekitAccessoryImpl implements HomekitAccessory {
private final Map<Class<? extends Characteristic>, Characteristic> rawCharacteristics;
private boolean isLinkedService = false;
public AbstractHomekitAccessoryImpl(HomekitTaggedItem accessory, List<HomekitTaggedItem> characteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) {
this.characteristics = characteristics;
public AbstractHomekitAccessoryImpl(HomekitTaggedItem accessory, List<HomekitTaggedItem> mandatoryCharacteristics,
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater,
HomekitSettings settings) {
this.characteristics = mandatoryCharacteristics;
this.accessory = accessory;
this.updater = updater;
this.services = new ArrayList<>();
@ -88,6 +89,15 @@ public abstract class AbstractHomekitAccessoryImpl implements HomekitAccessory {
rawCharacteristics.put(rawCharacteristic.getClass(), rawCharacteristic);
}
});
mandatoryRawCharacteristics.forEach(c -> {
if (rawCharacteristics.get(c.getClass()) != null) {
logger.warn(
"Accessory {} already has a characteristic of type {}; ignoring additional definition from metadata.",
accessory.getName(), c.getClass().getSimpleName());
} else {
rawCharacteristics.put(c.getClass(), c);
}
});
}
/**

View File

@ -39,6 +39,7 @@ import org.openhab.io.homekit.internal.HomekitTaggedItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.windowcovering.PositionStateEnum;
@ -58,9 +59,9 @@ abstract class AbstractHomekitPositionAccessoryImpl extends AbstractHomekitAcces
protected PositionStateEnum emulatedState = PositionStateEnum.STOPPED;
public AbstractHomekitPositionAccessoryImpl(HomekitTaggedItem taggedItem,
List<HomekitTaggedItem> mandatoryCharacteristics, HomekitAccessoryUpdater updater,
HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<HomekitTaggedItem> mandatoryCharacteristics, List<Characteristic> mandatoryRawCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
final boolean inverted = getAccessoryConfigurationAsBoolean(HomekitTaggedItem.INVERTED, true);
emulateState = getAccessoryConfigurationAsBoolean(HomekitTaggedItem.EMULATE_STOP_STATE, false);
emulateStopSameDirection = getAccessoryConfigurationAsBoolean(HomekitTaggedItem.EMULATE_STOP_SAME_DIRECTION,

View File

@ -192,12 +192,14 @@ public class HomekitAccessoryFactory {
throws HomekitException {
final HomekitAccessoryType accessoryType = taggedItem.getAccessoryType();
LOGGER.trace("Constructing {} of accessory type {}", taggedItem.getName(), accessoryType.getTag());
final List<HomekitTaggedItem> foundCharacteristics = getMandatoryCharacteristicsFromItem(taggedItem,
metadataRegistry);
final List<HomekitTaggedItem> characteristics = new ArrayList<>();
final List<Characteristic> rawCharacteristics = new ArrayList<>();
getMandatoryCharacteristicsFromItem(taggedItem, metadataRegistry, characteristics, rawCharacteristics);
final List<HomekitCharacteristicType> mandatoryCharacteristics = getRequiredCharacteristics(taggedItem);
if (foundCharacteristics.size() < mandatoryCharacteristics.size()) {
LOGGER.warn("Accessory of type {} must have following characteristics {}. Found only {}",
accessoryType.getTag(), mandatoryCharacteristics, foundCharacteristics);
if (characteristics.size() + rawCharacteristics.size() < mandatoryCharacteristics.size()) {
LOGGER.warn("Accessory of type {} must have following characteristics {}. Found only {}, {}",
accessoryType.getTag(), mandatoryCharacteristics, characteristics, rawCharacteristics);
throw new HomekitException("Missing mandatory characteristics");
}
AbstractHomekitAccessoryImpl accessoryImpl;
@ -210,9 +212,10 @@ public class HomekitAccessoryFactory {
taggedItem.getName());
throw new HomekitException("Circular accessory references");
}
accessoryImpl = accessoryImplClass.getConstructor(HomekitTaggedItem.class, List.class,
HomekitAccessoryUpdater.class, HomekitSettings.class)
.newInstance(taggedItem, foundCharacteristics, updater, settings);
accessoryImpl = accessoryImplClass
.getConstructor(HomekitTaggedItem.class, List.class, List.class, HomekitAccessoryUpdater.class,
HomekitSettings.class)
.newInstance(taggedItem, characteristics, rawCharacteristics, updater, settings);
addOptionalCharacteristics(taggedItem, accessoryImpl, metadataRegistry);
addOptionalMetadataCharacteristics(taggedItem, accessoryImpl);
accessoryImpl.setIsLinkedService(!ancestorServices.isEmpty());
@ -298,18 +301,18 @@ public class HomekitAccessoryFactory {
* @param metadataRegistry meta data registry
* @return list of mandatory
*/
private static List<HomekitTaggedItem> getMandatoryCharacteristicsFromItem(HomekitTaggedItem taggedItem,
MetadataRegistry metadataRegistry) {
List<HomekitTaggedItem> collectedCharacteristics = new ArrayList<>();
private static void getMandatoryCharacteristicsFromItem(HomekitTaggedItem taggedItem,
MetadataRegistry metadataRegistry, List<HomekitTaggedItem> characteristics,
List<Characteristic> rawCharacteristics) {
if (taggedItem.isGroup()) {
for (Item item : ((GroupItem) taggedItem.getItem()).getMembers()) {
addMandatoryCharacteristics(taggedItem, collectedCharacteristics, item, metadataRegistry);
addMandatoryCharacteristics(taggedItem, characteristics, rawCharacteristics, item, metadataRegistry);
}
} else {
addMandatoryCharacteristics(taggedItem, collectedCharacteristics, taggedItem.getItem(), metadataRegistry);
addMandatoryCharacteristics(taggedItem, characteristics, rawCharacteristics, taggedItem.getItem(),
metadataRegistry);
}
LOGGER.trace("Mandatory characteristics: {}", collectedCharacteristics);
return collectedCharacteristics;
LOGGER.trace("Mandatory characteristics: {}, {}", characteristics, rawCharacteristics);
}
/**
@ -325,7 +328,7 @@ public class HomekitAccessoryFactory {
* @param metadataRegistry meta date registry
*/
private static void addMandatoryCharacteristics(HomekitTaggedItem mainItem, List<HomekitTaggedItem> characteristics,
Item item, MetadataRegistry metadataRegistry) {
List<Characteristic> rawCharacteristics, Item item, MetadataRegistry metadataRegistry) {
// get list of mandatory characteristics
List<HomekitCharacteristicType> mandatoryCharacteristics = getRequiredCharacteristics(mainItem);
if (mandatoryCharacteristics.isEmpty()) {
@ -362,6 +365,23 @@ public class HomekitAccessoryFactory {
}
}
}
mandatoryCharacteristics.forEach(c -> {
// Check every metadata key looking for a characteristics we can create
var config = mainItem.getConfiguration();
if (config == null) {
return;
}
for (var entry : config.entrySet().stream().sorted((lhs, rhs) -> lhs.getKey().compareTo(rhs.getKey()))
.collect(Collectors.toList())) {
var type = HomekitCharacteristicType.valueOfTag(entry.getKey());
if (type.isPresent() && isMandatoryCharacteristic(mainItem, type.get())) {
var characteristic = HomekitMetadataCharacteristicFactory.createCharacteristic(type.get(),
entry.getValue());
characteristic.ifPresent(rc -> rawCharacteristics.add(rc));
}
}
});
}
/**

View File

@ -19,6 +19,8 @@ import org.openhab.io.homekit.internal.HomekitAccessoryUpdater;
import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.characteristics.Characteristic;
/**
* Bare accessory (for being the root of a multi-service accessory).
*
@ -27,7 +29,8 @@ import org.openhab.io.homekit.internal.HomekitTaggedItem;
@NonNullByDefault
public class HomekitAccessoryGroupImpl extends AbstractHomekitAccessoryImpl {
public HomekitAccessoryGroupImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
}
}

View File

@ -24,6 +24,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.AirQualityAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.airquality.AirQualityEnum;
import io.github.hapjava.services.impl.AirQualityService;
@ -37,8 +38,9 @@ public class HomekitAirQualitySensorImpl extends AbstractHomekitAccessoryImpl im
private final Map<AirQualityEnum, String> qualityStateMapping;
public HomekitAirQualitySensorImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
qualityStateMapping = createMapping(AIR_QUALITY, AirQualityEnum.class);
}

View File

@ -24,6 +24,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.BasicFanAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.services.impl.BasicFanService;
@ -37,8 +38,9 @@ class HomekitBasicFanImpl extends AbstractHomekitAccessoryImpl implements BasicF
private final BooleanItemReader onReader;
public HomekitBasicFanImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
onReader = createBooleanReader(ON_STATE);
}

View File

@ -29,6 +29,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.BatteryAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.battery.ChargingStateEnum;
import io.github.hapjava.characteristics.impl.battery.StatusLowBatteryEnum;
@ -48,8 +49,9 @@ public class HomekitBatteryImpl extends AbstractHomekitAccessoryImpl implements
private final BigDecimal lowThreshold;
public HomekitBatteryImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
lowThreshold = getAccessoryConfiguration(HomekitCharacteristicType.BATTERY_LOW_STATUS,
HomekitTaggedItem.BATTERY_LOW_THRESHOLD, BigDecimal.valueOf(20));
lowBatteryReader = createBooleanReader(BATTERY_LOW_STATUS, lowThreshold, true);

View File

@ -24,6 +24,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.CarbonDioxideSensorAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.carbondioxidesensor.CarbonDioxideDetectedEnum;
import io.github.hapjava.services.impl.CarbonDioxideSensorService;
@ -37,9 +38,9 @@ public class HomekitCarbonDioxideSensorImpl extends AbstractHomekitAccessoryImpl
private final Map<CarbonDioxideDetectedEnum, String> mapping;
public HomekitCarbonDioxideSensorImpl(HomekitTaggedItem taggedItem,
List<HomekitTaggedItem> mandatoryCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<HomekitTaggedItem> mandatoryCharacteristics, List<Characteristic> mandatoryRawCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
mapping = createMapping(CARBON_DIOXIDE_DETECTED_STATE, CarbonDioxideDetectedEnum.class);
}

View File

@ -24,6 +24,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.CarbonMonoxideSensorAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.carbonmonoxidesensor.CarbonMonoxideDetectedEnum;
import io.github.hapjava.services.impl.CarbonMonoxideSensorService;
@ -37,9 +38,9 @@ public class HomekitCarbonMonoxideSensorImpl extends AbstractHomekitAccessoryImp
private final Map<CarbonMonoxideDetectedEnum, String> mapping;
public HomekitCarbonMonoxideSensorImpl(HomekitTaggedItem taggedItem,
List<HomekitTaggedItem> mandatoryCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<HomekitTaggedItem> mandatoryCharacteristics, List<Characteristic> mandatoryRawCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
mapping = createMapping(CARBON_MONOXIDE_DETECTED_STATE, CarbonMonoxideDetectedEnum.class);
}

View File

@ -16,6 +16,7 @@ import static org.openhab.io.homekit.internal.HomekitCharacteristicType.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
@ -116,6 +117,7 @@ import io.github.hapjava.characteristics.impl.fan.TargetFanStateEnum;
import io.github.hapjava.characteristics.impl.filtermaintenance.FilterLifeLevelCharacteristic;
import io.github.hapjava.characteristics.impl.filtermaintenance.ResetFilterIndicationCharacteristic;
import io.github.hapjava.characteristics.impl.humiditysensor.CurrentRelativeHumidityCharacteristic;
import io.github.hapjava.characteristics.impl.humiditysensor.TargetRelativeHumidityCharacteristic;
import io.github.hapjava.characteristics.impl.inputsource.CurrentVisibilityStateCharacteristic;
import io.github.hapjava.characteristics.impl.inputsource.CurrentVisibilityStateEnum;
import io.github.hapjava.characteristics.impl.inputsource.InputDeviceTypeCharacteristic;
@ -149,7 +151,15 @@ import io.github.hapjava.characteristics.impl.televisionspeaker.VolumeControlTyp
import io.github.hapjava.characteristics.impl.televisionspeaker.VolumeSelectorCharacteristic;
import io.github.hapjava.characteristics.impl.televisionspeaker.VolumeSelectorEnum;
import io.github.hapjava.characteristics.impl.thermostat.CoolingThresholdTemperatureCharacteristic;
import io.github.hapjava.characteristics.impl.thermostat.CurrentHeatingCoolingStateCharacteristic;
import io.github.hapjava.characteristics.impl.thermostat.CurrentHeatingCoolingStateEnum;
import io.github.hapjava.characteristics.impl.thermostat.CurrentTemperatureCharacteristic;
import io.github.hapjava.characteristics.impl.thermostat.HeatingThresholdTemperatureCharacteristic;
import io.github.hapjava.characteristics.impl.thermostat.TargetHeatingCoolingStateCharacteristic;
import io.github.hapjava.characteristics.impl.thermostat.TargetHeatingCoolingStateEnum;
import io.github.hapjava.characteristics.impl.thermostat.TargetTemperatureCharacteristic;
import io.github.hapjava.characteristics.impl.thermostat.TemperatureDisplayUnitCharacteristic;
import io.github.hapjava.characteristics.impl.thermostat.TemperatureDisplayUnitEnum;
import io.github.hapjava.characteristics.impl.valve.RemainingDurationCharacteristic;
import io.github.hapjava.characteristics.impl.valve.SetDurationCharacteristic;
import io.github.hapjava.characteristics.impl.windowcovering.CurrentHorizontalTiltAngleCharacteristic;
@ -184,6 +194,8 @@ public class HomekitCharacteristicFactory {
put(CONFIGURED, HomekitCharacteristicFactory::createIsConfiguredCharacteristic);
put(CONFIGURED_NAME, HomekitCharacteristicFactory::createConfiguredNameCharacteristic);
put(COOLING_THRESHOLD_TEMPERATURE, HomekitCharacteristicFactory::createCoolingThresholdCharacteristic);
put(CURRENT_HEATING_COOLING_STATE,
HomekitCharacteristicFactory::createCurrentHeatingCoolingStateCharacteristic);
put(CURRENT_FAN_STATE, HomekitCharacteristicFactory::createCurrentFanStateCharacteristic);
put(CURRENT_HORIZONTAL_TILT_ANGLE,
HomekitCharacteristicFactory::createCurrentHorizontalTiltAngleCharacteristic);
@ -192,6 +204,7 @@ public class HomekitCharacteristicFactory {
put(CURRENT_VERTICAL_TILT_ANGLE,
HomekitCharacteristicFactory::createCurrentVerticalTiltAngleCharacteristic);
put(CURRENT_VISIBILITY, HomekitCharacteristicFactory::createCurrentVisibilityStateCharacteristic);
put(CURRENT_TEMPERATURE, HomekitCharacteristicFactory::createCurrentTemperatureCharacteristic);
put(DURATION, HomekitCharacteristicFactory::createDurationCharacteristic);
put(FAULT_STATUS, HomekitCharacteristicFactory::createStatusFaultCharacteristic);
put(FIRMWARE_REVISION, HomekitCharacteristicFactory::createFirmwareRevisionCharacteristic);
@ -229,12 +242,17 @@ public class HomekitCharacteristicFactory {
put(SWING_MODE, HomekitCharacteristicFactory::createSwingModeCharacteristic);
put(TAMPERED_STATUS, HomekitCharacteristicFactory::createStatusTamperedCharacteristic);
put(TARGET_FAN_STATE, HomekitCharacteristicFactory::createTargetFanStateCharacteristic);
put(TARGET_HEATING_COOLING_STATE,
HomekitCharacteristicFactory::createTargetHeatingCoolingStateCharacteristic);
put(TARGET_HORIZONTAL_TILT_ANGLE,
HomekitCharacteristicFactory::createTargetHorizontalTiltAngleCharacteristic);
put(TARGET_MEDIA_STATE, HomekitCharacteristicFactory::createTargetMediaStateCharacteristic);
put(TARGET_RELATIVE_HUMIDITY, HomekitCharacteristicFactory::createTargetRelativeHumidityCharacteristic);
put(TARGET_TEMPERATURE, HomekitCharacteristicFactory::createTargetTemperatureCharacteristic);
put(TARGET_TILT_ANGLE, HomekitCharacteristicFactory::createTargetTiltAngleCharacteristic);
put(TARGET_VERTICAL_TILT_ANGLE, HomekitCharacteristicFactory::createTargetVerticalTiltAngleCharacteristic);
put(TARGET_VISIBILITY_STATE, HomekitCharacteristicFactory::createTargetVisibilityStateCharacteristic);
put(TEMPERATURE_UNIT, HomekitCharacteristicFactory::createTemperatureDisplayUnitCharacteristic);
put(VOC_DENSITY, HomekitCharacteristicFactory::createVOCDensityCharacteristic);
put(VOLUME, HomekitCharacteristicFactory::createVolumeCharacteristic);
put(VOLUME_CONTROL_TYPE, HomekitCharacteristicFactory::createVolumeControlTypeCharacteristic);
@ -339,6 +357,9 @@ public class HomekitCharacteristicFactory {
}
});
}
if (customEnumList != null && customEnumList.isEmpty()) {
customEnumList.addAll(map.keySet());
}
LOGGER.debug("Created {} mapping for item {} ({}): {}", klazz.getSimpleName(), item.getName(),
item.getBaseItem().getClass().getSimpleName(), map);
return map;
@ -349,6 +370,11 @@ public class HomekitCharacteristicFactory {
return createMapping(item, klazz, null, false);
}
public static <T extends Enum<T> & CharacteristicEnum> Map<T, String> createMapping(HomekitTaggedItem item,
Class<T> klazz, @Nullable List<T> customEnumList) {
return createMapping(item, klazz, customEnumList, false);
}
public static <T extends Enum<T> & CharacteristicEnum> Map<T, String> createMapping(HomekitTaggedItem item,
Class<T> klazz, boolean inverted) {
return createMapping(item, klazz, null, inverted);
@ -405,6 +431,16 @@ public class HomekitCharacteristicFactory {
.getServiceReference(Homekit.class.getName()).getProperty("useFahrenheitTemperature"));
}
public static TemperatureDisplayUnitCharacteristic createSystemTemperatureDisplayUnitCharacteristic() {
return new TemperatureDisplayUnitCharacteristic(() -> CompletableFuture
.completedFuture(HomekitCharacteristicFactory.useFahrenheit() ? TemperatureDisplayUnitEnum.FAHRENHEIT
: TemperatureDisplayUnitEnum.CELSIUS),
(value) -> {
}, (cb) -> {
}, () -> {
});
}
private static <T extends CharacteristicEnum> CompletableFuture<T> getEnumFromItem(HomekitTaggedItem item,
Map<T, String> mapping, T defaultValue) {
return CompletableFuture.completedFuture(getKeyFromMapping(item, mapping, defaultValue));
@ -761,6 +797,16 @@ public class HomekitCharacteristicFactory {
getUnsubscriber(taggedItem, COOLING_THRESHOLD_TEMPERATURE, updater));
}
private static CurrentHeatingCoolingStateCharacteristic createCurrentHeatingCoolingStateCharacteristic(
HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
List<CurrentHeatingCoolingStateEnum> validValues = new ArrayList<>();
var map = createMapping(taggedItem, CurrentHeatingCoolingStateEnum.class, validValues);
return new CurrentHeatingCoolingStateCharacteristic(validValues.toArray(new CurrentHeatingCoolingStateEnum[0]),
() -> getEnumFromItem(taggedItem, map, CurrentHeatingCoolingStateEnum.OFF),
getSubscriber(taggedItem, CURRENT_HEATING_COOLING_STATE, updater),
getUnsubscriber(taggedItem, CURRENT_HEATING_COOLING_STATE, updater));
}
private static CurrentFanStateCharacteristic createCurrentFanStateCharacteristic(HomekitTaggedItem taggedItem,
HomekitAccessoryUpdater updater) {
var map = createMapping(taggedItem, CurrentFanStateEnum.class);
@ -785,6 +831,18 @@ public class HomekitCharacteristicFactory {
getUnsubscriber(taggedItem, CURRENT_MEDIA_STATE, updater));
}
private static CurrentTemperatureCharacteristic createCurrentTemperatureCharacteristic(HomekitTaggedItem taggedItem,
HomekitAccessoryUpdater updater) {
double minValue = HomekitCharacteristicFactory.convertToCelsius(taggedItem.getConfigurationAsDouble(
HomekitTaggedItem.MIN_VALUE, CurrentTemperatureCharacteristic.DEFAULT_MIN_VALUE));
double maxValue = HomekitCharacteristicFactory.convertToCelsius(taggedItem.getConfigurationAsDouble(
HomekitTaggedItem.MAX_VALUE, CurrentTemperatureCharacteristic.DEFAULT_MAX_VALUE));
double step = getTemperatureStep(taggedItem, CurrentTemperatureCharacteristic.DEFAULT_STEP);
return new CurrentTemperatureCharacteristic(minValue, maxValue, step,
getTemperatureSupplier(taggedItem, minValue), getSubscriber(taggedItem, TARGET_TEMPERATURE, updater),
getUnsubscriber(taggedItem, TARGET_TEMPERATURE, updater));
}
private static CurrentTiltAngleCharacteristic createCurrentTiltAngleCharacteristic(HomekitTaggedItem taggedItem,
HomekitAccessoryUpdater updater) {
return new CurrentTiltAngleCharacteristic(getAngleSupplier(taggedItem, 0),
@ -1192,6 +1250,17 @@ public class HomekitCharacteristicFactory {
getUnsubscriber(taggedItem, TARGET_FAN_STATE, updater));
}
private static TargetHeatingCoolingStateCharacteristic createTargetHeatingCoolingStateCharacteristic(
HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
List<TargetHeatingCoolingStateEnum> validValues = new ArrayList<>();
var map = createMapping(taggedItem, TargetHeatingCoolingStateEnum.class, validValues);
return new TargetHeatingCoolingStateCharacteristic(validValues.toArray(new TargetHeatingCoolingStateEnum[0]),
() -> getEnumFromItem(taggedItem, map, TargetHeatingCoolingStateEnum.OFF),
(value) -> setValueFromEnum(taggedItem, value, map),
getSubscriber(taggedItem, TARGET_HEATING_COOLING_STATE, updater),
getUnsubscriber(taggedItem, TARGET_HEATING_COOLING_STATE, updater));
}
private static TargetHorizontalTiltAngleCharacteristic createTargetHorizontalTiltAngleCharacteristic(
HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
return new TargetHorizontalTiltAngleCharacteristic(getAngleSupplier(taggedItem, 0),
@ -1208,6 +1277,26 @@ public class HomekitCharacteristicFactory {
getUnsubscriber(taggedItem, TARGET_MEDIA_STATE, updater));
}
private static TargetRelativeHumidityCharacteristic createTargetRelativeHumidityCharacteristic(
HomekitTaggedItem item, HomekitAccessoryUpdater updater) {
return new TargetRelativeHumidityCharacteristic(getDoubleSupplier(item, 0), setDoubleConsumer(item),
getSubscriber(item, TARGET_RELATIVE_HUMIDITY, updater),
getUnsubscriber(item, TARGET_RELATIVE_HUMIDITY, updater));
}
private static TargetTemperatureCharacteristic createTargetTemperatureCharacteristic(HomekitTaggedItem taggedItem,
HomekitAccessoryUpdater updater) {
double minValue = HomekitCharacteristicFactory.convertToCelsius(taggedItem.getConfigurationAsDouble(
HomekitTaggedItem.MIN_VALUE, TargetTemperatureCharacteristic.DEFAULT_MIN_VALUE));
double maxValue = HomekitCharacteristicFactory.convertToCelsius(taggedItem.getConfigurationAsDouble(
HomekitTaggedItem.MAX_VALUE, TargetTemperatureCharacteristic.DEFAULT_MAX_VALUE));
double step = getTemperatureStep(taggedItem, TargetTemperatureCharacteristic.DEFAULT_STEP);
return new TargetTemperatureCharacteristic(minValue, maxValue, step,
getTemperatureSupplier(taggedItem, minValue), setTemperatureConsumer(taggedItem),
getSubscriber(taggedItem, TARGET_TEMPERATURE, updater),
getUnsubscriber(taggedItem, TARGET_TEMPERATURE, updater));
}
private static TargetTiltAngleCharacteristic createTargetTiltAngleCharacteristic(HomekitTaggedItem taggedItem,
HomekitAccessoryUpdater updater) {
return new TargetTiltAngleCharacteristic(getAngleSupplier(taggedItem, 0), setAngleConsumer(taggedItem),
@ -1232,6 +1321,17 @@ public class HomekitCharacteristicFactory {
getUnsubscriber(taggedItem, TARGET_VISIBILITY_STATE, updater));
}
private static TemperatureDisplayUnitCharacteristic createTemperatureDisplayUnitCharacteristic(
HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
var map = createMapping(taggedItem, TemperatureDisplayUnitEnum.class, true);
return new TemperatureDisplayUnitCharacteristic(
() -> getEnumFromItem(taggedItem, map,
useFahrenheit() ? TemperatureDisplayUnitEnum.FAHRENHEIT : TemperatureDisplayUnitEnum.CELSIUS),
(value) -> setValueFromEnum(taggedItem, value, map),
getSubscriber(taggedItem, TEMPERATURE_UNIT, updater),
getUnsubscriber(taggedItem, TEMPERATURE_UNIT, updater));
}
private static VOCDensityCharacteristic createVOCDensityCharacteristic(final HomekitTaggedItem taggedItem,
HomekitAccessoryUpdater updater) {
return new VOCDensityCharacteristic(

View File

@ -24,6 +24,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.ContactSensorAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.contactsensor.ContactStateEnum;
import io.github.hapjava.services.impl.ContactSensorService;
@ -36,8 +37,9 @@ public class HomekitContactSensorImpl extends AbstractHomekitAccessoryImpl imple
private final Map<ContactStateEnum, String> mapping;
public HomekitContactSensorImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
mapping = createMapping(CONTACT_SENSOR_STATE, ContactStateEnum.class);
}

View File

@ -22,6 +22,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.DoorAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.windowcovering.PositionStateEnum;
import io.github.hapjava.services.impl.DoorService;
@ -34,8 +35,9 @@ import io.github.hapjava.services.impl.DoorService;
public class HomekitDoorImpl extends AbstractHomekitPositionAccessoryImpl implements DoorAccessory {
public HomekitDoorImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater,
HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
}
@Override

View File

@ -23,6 +23,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.FanAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.services.impl.FanService;
@ -35,8 +36,9 @@ class HomekitFanImpl extends AbstractHomekitAccessoryImpl implements FanAccessor
private final BooleanItemReader activeReader;
public HomekitFanImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
activeReader = createBooleanReader(ACTIVE_STATUS);
}

View File

@ -23,6 +23,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.FaucetAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.services.impl.FaucetService;
@ -35,8 +36,9 @@ class HomekitFaucetImpl extends AbstractHomekitAccessoryImpl implements FaucetAc
private final BooleanItemReader activeReader;
public HomekitFaucetImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
activeReader = createBooleanReader(ACTIVE);
}

View File

@ -24,6 +24,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.FilterMaintenanceAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.filtermaintenance.FilterChangeIndicationEnum;
import io.github.hapjava.services.impl.FilterMaintenanceService;
@ -37,8 +38,9 @@ public class HomekitFilterMaintenanceImpl extends AbstractHomekitAccessoryImpl i
private final Map<FilterChangeIndicationEnum, String> mapping;
public HomekitFilterMaintenanceImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
mapping = createMapping(FILTER_CHANGE_INDICATION, FilterChangeIndicationEnum.class);
}

View File

@ -28,6 +28,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.github.hapjava.accessories.GarageDoorOpenerAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.garagedoor.CurrentDoorStateEnum;
import io.github.hapjava.characteristics.impl.garagedoor.TargetDoorStateEnum;
@ -45,8 +46,9 @@ public class HomekitGarageDoorOpenerImpl extends AbstractHomekitAccessoryImpl im
private final Map<TargetDoorStateEnum, String> targetDoorStateMapping;
public HomekitGarageDoorOpenerImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
obstructionReader = createBooleanReader(OBSTRUCTION_STATUS);
currentDoorStateMapping = createMapping(CURRENT_DOOR_STATE, CurrentDoorStateEnum.class, true);
targetDoorStateMapping = createMapping(TARGET_DOOR_STATE, TargetDoorStateEnum.class, true);

View File

@ -35,12 +35,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.github.hapjava.accessories.HeaterCoolerAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.heatercooler.CurrentHeaterCoolerStateEnum;
import io.github.hapjava.characteristics.impl.heatercooler.TargetHeaterCoolerStateEnum;
import io.github.hapjava.characteristics.impl.thermostat.CurrentTemperatureCharacteristic;
import io.github.hapjava.characteristics.impl.thermostat.TemperatureDisplayUnitCharacteristic;
import io.github.hapjava.characteristics.impl.thermostat.TemperatureDisplayUnitEnum;
import io.github.hapjava.services.impl.HeaterCoolerService;
/**
@ -59,8 +59,9 @@ public class HomekitHeaterCoolerImpl extends AbstractHomekitAccessoryImpl implem
private final List<TargetHeaterCoolerStateEnum> customTargetStateList = new ArrayList<>();
public HomekitHeaterCoolerImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
activeReader = new BooleanItemReader(getItem(ACTIVE_STATUS, GenericItem.class)
.orElseThrow(() -> new IncompleteAccessoryException(ACTIVE_STATUS)), OnOffType.ON, OpenClosedType.OPEN);
currentStateMapping = createMapping(CURRENT_HEATER_COOLER_STATE, CurrentHeaterCoolerStateEnum.class,
@ -73,10 +74,14 @@ public class HomekitHeaterCoolerImpl extends AbstractHomekitAccessoryImpl implem
public void init() throws HomekitException {
super.init();
final HeaterCoolerService service = new HeaterCoolerService(this);
var temperatureDisplayUnit = getCharacteristic(TemperatureDisplayUnitCharacteristic.class);
if (temperatureDisplayUnit.isEmpty()) {
service.addOptionalCharacteristic(
HomekitCharacteristicFactory.createSystemTemperatureDisplayUnitCharacteristic());
}
addService(service);
service.addOptionalCharacteristic(new TemperatureDisplayUnitCharacteristic(this::getTemperatureDisplayUnit,
this::setTemperatureDisplayUnit, this::subscribeTemperatureDisplayUnit,
this::unsubscribeTemperatureDisplayUnit));
}
@Override
@ -133,17 +138,6 @@ public class HomekitHeaterCoolerImpl extends AbstractHomekitAccessoryImpl implem
return CompletableFuture.completedFuture(null);
}
public CompletableFuture<TemperatureDisplayUnitEnum> getTemperatureDisplayUnit() {
return CompletableFuture
.completedFuture(HomekitCharacteristicFactory.useFahrenheit() ? TemperatureDisplayUnitEnum.FAHRENHEIT
: TemperatureDisplayUnitEnum.CELSIUS);
}
public void setTemperatureDisplayUnit(TemperatureDisplayUnitEnum value) {
// temperature unit set globally via binding setting and cannot be changed at item level.
// this method is intentionally empty.
}
@Override
public void subscribeCurrentHeaterCoolerState(HomekitCharacteristicChangeCallback callback) {
subscribe(HomekitCharacteristicType.CURRENT_HEATER_COOLER_STATE, callback);
@ -183,14 +177,4 @@ public class HomekitHeaterCoolerImpl extends AbstractHomekitAccessoryImpl implem
public void unsubscribeCurrentTemperature() {
unsubscribe(HomekitCharacteristicType.CURRENT_TEMPERATURE);
}
public void subscribeTemperatureDisplayUnit(HomekitCharacteristicChangeCallback callback) {
// temperature unit set globally via binding setting and cannot be changed at item level.
// this method is intentionally empty
}
public void unsubscribeTemperatureDisplayUnit() {
// temperature unit set globally via binding setting and cannot be changed at item level.
// this method is intentionally empty
}
}

View File

@ -25,6 +25,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.HumiditySensorAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.services.impl.HumiditySensorService;
@ -36,8 +37,9 @@ public class HomekitHumiditySensorImpl extends AbstractHomekitAccessoryImpl impl
private static final String CONFIG_MULTIPLICATOR = "homekitMultiplicator";
public HomekitHumiditySensorImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater,
HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
}
@Override

View File

@ -22,6 +22,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.HomekitAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.impl.common.ConfiguredNameCharacteristic;
import io.github.hapjava.characteristics.impl.common.IdentifierCharacteristic;
import io.github.hapjava.characteristics.impl.common.IsConfiguredCharacteristic;
@ -46,8 +47,9 @@ import io.github.hapjava.services.impl.InputSourceService;
public class HomekitInputSourceImpl extends AbstractHomekitAccessoryImpl {
public HomekitInputSourceImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
}
@Override

View File

@ -25,6 +25,7 @@ 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.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.common.ActiveEnum;
import io.github.hapjava.characteristics.impl.common.InUseEnum;
@ -50,8 +51,9 @@ public class HomekitIrrigationSystemImpl extends AbstractHomekitAccessoryImpl im
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);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
inUseMapping = createMapping(HomekitCharacteristicType.INUSE_STATUS, InUseEnum.class);
programModeMap = HomekitCharacteristicFactory
.createMapping(getCharacteristic(HomekitCharacteristicType.PROGRAM_MODE).get(), ProgramModeEnum.class);

View File

@ -24,6 +24,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.LeakSensorAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.leaksensor.LeakDetectedStateEnum;
import io.github.hapjava.services.impl.LeakSensorService;
@ -36,8 +37,9 @@ public class HomekitLeakSensorImpl extends AbstractHomekitAccessoryImpl implemen
private final Map<LeakDetectedStateEnum, String> mapping;
public HomekitLeakSensorImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
mapping = createMapping(LEAK_DETECTED_STATE, LeakDetectedStateEnum.class);
}

View File

@ -27,6 +27,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.LightSensorAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.lightsensor.CurrentAmbientLightLevelCharacteristic;
import io.github.hapjava.services.impl.LightSensorService;
@ -39,8 +40,9 @@ import io.github.hapjava.services.impl.LightSensorService;
public class HomekitLightSensorImpl extends AbstractHomekitAccessoryImpl implements LightSensorAccessory {
public HomekitLightSensorImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater,
HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
}
@Override

View File

@ -26,6 +26,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.LightbulbAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.services.impl.LightbulbService;
@ -37,8 +38,9 @@ import io.github.hapjava.services.impl.LightbulbService;
class HomekitLightbulbImpl extends AbstractHomekitAccessoryImpl implements LightbulbAccessory {
public HomekitLightbulbImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater,
HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
}
@Override

View File

@ -23,6 +23,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.LockMechanismAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.lock.LockCurrentStateEnum;
import io.github.hapjava.characteristics.impl.lock.LockTargetStateEnum;
@ -39,8 +40,9 @@ public class HomekitLockImpl extends AbstractHomekitAccessoryImpl implements Loc
final Map<LockTargetStateEnum, String> targetStateMapping;
public HomekitLockImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater,
HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
currentStateMapping = createMapping(HomekitCharacteristicType.LOCK_CURRENT_STATE, LockCurrentStateEnum.class);
targetStateMapping = createMapping(HomekitCharacteristicType.LOCK_TARGET_STATE, LockTargetStateEnum.class);

View File

@ -65,6 +65,8 @@ import io.github.hapjava.characteristics.impl.thermostat.CurrentHeatingCoolingSt
import io.github.hapjava.characteristics.impl.thermostat.CurrentHeatingCoolingStateEnum;
import io.github.hapjava.characteristics.impl.thermostat.TargetHeatingCoolingStateCharacteristic;
import io.github.hapjava.characteristics.impl.thermostat.TargetHeatingCoolingStateEnum;
import io.github.hapjava.characteristics.impl.thermostat.TemperatureDisplayUnitCharacteristic;
import io.github.hapjava.characteristics.impl.thermostat.TemperatureDisplayUnitEnum;
/**
* Creates an optional characteristics from metadata
@ -104,16 +106,24 @@ public class HomekitMetadataCharacteristicFactory {
HomekitMetadataCharacteristicFactory::createTargetHeaterCoolerStateCharacteristic);
put(TARGET_HEATING_COOLING_STATE,
HomekitMetadataCharacteristicFactory::createTargetHeatingCoolingStateCharacteristic);
put(TEMPERATURE_UNIT, HomekitMetadataCharacteristicFactory::createTemperatureDisplayUnitCharacteristic);
put(VOLUME_CONTROL_TYPE, HomekitMetadataCharacteristicFactory::createVolumeControlTypeCharacteristic);
}
};
public static Optional<Characteristic> createCharacteristic(String characteristic, Object value) {
var type = HomekitCharacteristicType.valueOfTag(characteristic);
if (type.isEmpty() || !OPTIONAL.containsKey(type.get())) {
if (type.isEmpty()) {
return Optional.empty();
}
return Optional.of(OPTIONAL.get(type.get()).apply(value));
return createCharacteristic(type.get(), value);
}
public static Optional<Characteristic> createCharacteristic(HomekitCharacteristicType type, Object value) {
if (!OPTIONAL.containsKey(type)) {
return Optional.empty();
}
return Optional.of(OPTIONAL.get(type).apply(value));
}
private static Supplier<CompletableFuture<Integer>> getInteger(Object value) {
@ -321,6 +331,22 @@ public class HomekitMetadataCharacteristicFactory {
});
}
private static Characteristic createTemperatureDisplayUnitCharacteristic(Object value) {
var enumSupplier = getEnum(value, TemperatureDisplayUnitEnum.class);
TemperatureDisplayUnitEnum enumValue;
try {
enumValue = enumSupplier.get().get();
} catch (InterruptedException | ExecutionException e) {
enumValue = HomekitCharacteristicFactory.useFahrenheit() ? TemperatureDisplayUnitEnum.FAHRENHEIT
: TemperatureDisplayUnitEnum.CELSIUS;
}
return new TemperatureDisplayUnitCharacteristic(enumSupplier, v -> {
}, v -> {
}, () -> {
});
}
private static Characteristic createVolumeControlTypeCharacteristic(Object value) {
return new VolumeControlTypeCharacteristic(getEnum(value, VolumeControlTypeEnum.class), v -> {
}, () -> {

View File

@ -22,6 +22,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.MicrophoneAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.services.impl.MicrophoneService;
@ -34,8 +35,9 @@ public class HomekitMicrophoneImpl extends AbstractHomekitAccessoryImpl implemen
private final BooleanItemReader muteReader;
public HomekitMicrophoneImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
muteReader = createBooleanReader(HomekitCharacteristicType.MUTE);
}

View File

@ -22,6 +22,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.MotionSensorAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.services.impl.MotionSensorService;
@ -33,8 +34,9 @@ public class HomekitMotionSensorImpl extends AbstractHomekitAccessoryImpl implem
private final BooleanItemReader motionSensedReader;
public HomekitMotionSensorImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
motionSensedReader = createBooleanReader(HomekitCharacteristicType.MOTION_DETECTED_STATE);
}

View File

@ -24,6 +24,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.OccupancySensorAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.occupancysensor.OccupancyDetectedEnum;
import io.github.hapjava.services.impl.OccupancySensorService;
@ -36,8 +37,9 @@ public class HomekitOccupancySensorImpl extends AbstractHomekitAccessoryImpl imp
private final Map<OccupancyDetectedEnum, String> mapping;
public HomekitOccupancySensorImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
mapping = createMapping(OCCUPANCY_DETECTED_STATE, OccupancyDetectedEnum.class);
}

View File

@ -22,6 +22,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.OutletAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.services.impl.OutletService;
@ -34,8 +35,9 @@ public class HomekitOutletImpl extends AbstractHomekitAccessoryImpl implements O
private final BooleanItemReader onReader;
public HomekitOutletImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
inUseReader = createBooleanReader(HomekitCharacteristicType.INUSE_STATUS);
onReader = createBooleanReader(HomekitCharacteristicType.ON_STATE);
}

View File

@ -27,6 +27,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.SecuritySystemAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.securitysystem.CurrentSecuritySystemStateEnum;
import io.github.hapjava.characteristics.impl.securitysystem.TargetSecuritySystemStateEnum;
@ -48,8 +49,9 @@ public class HomekitSecuritySystemImpl extends AbstractHomekitAccessoryImpl impl
private final List<TargetSecuritySystemStateEnum> customTargetStateList = new ArrayList<>();
public HomekitSecuritySystemImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater,
HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
currentStateMapping = createMapping(SECURITY_SYSTEM_CURRENT_STATE, CurrentSecuritySystemStateEnum.class,
customCurrentStateList);
targetStateMapping = createMapping(SECURITY_SYSTEM_TARGET_STATE, TargetSecuritySystemStateEnum.class,

View File

@ -24,6 +24,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.SlatAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.slat.CurrentSlatStateEnum;
import io.github.hapjava.characteristics.impl.slat.SlatTypeEnum;
@ -39,8 +40,9 @@ public class HomekitSlatImpl extends AbstractHomekitAccessoryImpl implements Sla
private final SlatTypeEnum slatType;
public HomekitSlatImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater,
HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
final String slatTypeConfig = getAccessoryConfiguration(CONFIG_TYPE, "horizontal");
slatType = "horizontal".equalsIgnoreCase(slatTypeConfig) ? SlatTypeEnum.HORIZONTAL : SlatTypeEnum.VERTICAL;
currentSlatStateMapping = createMapping(CURRENT_SLAT_STATE, CurrentSlatStateEnum.class);

View File

@ -25,6 +25,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.SmartSpeakerAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.television.CurrentMediaStateEnum;
import io.github.hapjava.characteristics.impl.television.TargetMediaStateEnum;
@ -39,8 +40,9 @@ public class HomekitSmartSpeakerImpl extends AbstractHomekitAccessoryImpl implem
private final Map<TargetMediaStateEnum, String> targetMediaState;
public HomekitSmartSpeakerImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater,
HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
currentMediaState = createMapping(CURRENT_MEDIA_STATE, CurrentMediaStateEnum.class);
targetMediaState = createMapping(TARGET_MEDIA_STATE, TargetMediaStateEnum.class);
}

View File

@ -24,6 +24,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.SmokeSensorAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.smokesensor.SmokeDetectedStateEnum;
import io.github.hapjava.services.impl.SmokeSensorService;
@ -36,8 +37,9 @@ public class HomekitSmokeSensorImpl extends AbstractHomekitAccessoryImpl impleme
private final Map<SmokeDetectedStateEnum, String> mapping;
public HomekitSmokeSensorImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
mapping = createMapping(SMOKE_DETECTED_STATE, SmokeDetectedStateEnum.class);
}

View File

@ -22,6 +22,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.SpeakerAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.services.impl.SpeakerService;
@ -34,8 +35,9 @@ public class HomekitSpeakerImpl extends AbstractHomekitAccessoryImpl implements
private final BooleanItemReader muteReader;
public HomekitSpeakerImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
muteReader = createBooleanReader(HomekitCharacteristicType.MUTE);
}

View File

@ -23,6 +23,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.SwitchAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.services.impl.SwitchService;
@ -35,8 +36,9 @@ public class HomekitSwitchImpl extends AbstractHomekitAccessoryImpl implements S
private final BooleanItemReader onReader;
public HomekitSwitchImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
onReader = createBooleanReader(ON_STATE);
}

View File

@ -21,6 +21,7 @@ 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.ActiveCharacteristic;
import io.github.hapjava.characteristics.impl.common.ActiveIdentifierCharacteristic;
import io.github.hapjava.characteristics.impl.common.ConfiguredNameCharacteristic;
@ -43,8 +44,9 @@ import io.github.hapjava.services.impl.TelevisionService;
public class HomekitTelevisionImpl extends AbstractHomekitAccessoryImpl {
public HomekitTelevisionImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
}
@Override

View File

@ -22,6 +22,7 @@ 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.audio.MuteCharacteristic;
import io.github.hapjava.characteristics.impl.audio.VolumeCharacteristic;
import io.github.hapjava.characteristics.impl.televisionspeaker.VolumeControlTypeCharacteristic;
@ -43,8 +44,9 @@ import io.github.hapjava.services.impl.TelevisionSpeakerService;
public class HomekitTelevisionSpeakerImpl extends AbstractHomekitAccessoryImpl {
public HomekitTelevisionSpeakerImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
}
@Override

View File

@ -24,6 +24,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.TemperatureSensorAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.thermostat.CurrentTemperatureCharacteristic;
import io.github.hapjava.characteristics.impl.thermostat.TargetTemperatureCharacteristic;
@ -37,8 +38,9 @@ import io.github.hapjava.services.impl.TemperatureSensorService;
class HomekitTemperatureSensorImpl extends AbstractHomekitAccessoryImpl implements TemperatureSensorAccessory {
public HomekitTemperatureSensorImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater,
HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
}
@Override

View File

@ -12,33 +12,23 @@
*/
package org.openhab.io.homekit.internal.accessories;
import static org.openhab.io.homekit.internal.HomekitCharacteristicType.CURRENT_HEATING_COOLING_STATE;
import static org.openhab.io.homekit.internal.HomekitCharacteristicType.TARGET_HEATING_COOLING_STATE;
import static org.openhab.io.homekit.internal.HomekitCharacteristicType.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import org.openhab.core.library.items.NumberItem;
import org.openhab.core.library.types.DecimalType;
import org.openhab.io.homekit.internal.HomekitAccessoryUpdater;
import org.openhab.io.homekit.internal.HomekitCharacteristicType;
import org.openhab.io.homekit.internal.HomekitException;
import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.github.hapjava.accessories.ThermostatAccessory;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.thermostat.CurrentHeatingCoolingStateEnum;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.impl.thermostat.CurrentHeatingCoolingStateCharacteristic;
import io.github.hapjava.characteristics.impl.thermostat.CurrentTemperatureCharacteristic;
import io.github.hapjava.characteristics.impl.thermostat.TargetHeatingCoolingStateEnum;
import io.github.hapjava.characteristics.impl.thermostat.TargetHeatingCoolingStateCharacteristic;
import io.github.hapjava.characteristics.impl.thermostat.TargetTemperatureCharacteristic;
import io.github.hapjava.characteristics.impl.thermostat.TemperatureDisplayUnitEnum;
import io.github.hapjava.characteristics.impl.thermostat.TemperatureDisplayUnitCharacteristic;
import io.github.hapjava.services.impl.ThermostatService;
/**
@ -52,203 +42,26 @@ import io.github.hapjava.services.impl.ThermostatService;
*
* @author Andy Lintner - Initial contribution
*/
class HomekitThermostatImpl extends AbstractHomekitAccessoryImpl implements ThermostatAccessory {
class HomekitThermostatImpl extends AbstractHomekitAccessoryImpl {
private final Logger logger = LoggerFactory.getLogger(HomekitThermostatImpl.class);
private final Map<CurrentHeatingCoolingStateEnum, String> currentHeatingCoolingStateMapping;
private final Map<TargetHeatingCoolingStateEnum, String> targetHeatingCoolingStateMapping;
private final List<CurrentHeatingCoolingStateEnum> customCurrentHeatingCoolingStateList;
private final List<TargetHeatingCoolingStateEnum> customTargetHeatingCoolingStateList;
public HomekitThermostatImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, updater, settings);
customCurrentHeatingCoolingStateList = new ArrayList<>();
customTargetHeatingCoolingStateList = new ArrayList<>();
currentHeatingCoolingStateMapping = createMapping(CURRENT_HEATING_COOLING_STATE,
CurrentHeatingCoolingStateEnum.class, customCurrentHeatingCoolingStateList);
targetHeatingCoolingStateMapping = createMapping(TARGET_HEATING_COOLING_STATE,
TargetHeatingCoolingStateEnum.class, customTargetHeatingCoolingStateList);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater,
HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
}
@Override
public void init() throws HomekitException {
super.init();
addService(new ThermostatService(this));
}
@Override
public CurrentHeatingCoolingStateEnum[] getCurrentHeatingCoolingStateValidValues() {
return customCurrentHeatingCoolingStateList.isEmpty()
? currentHeatingCoolingStateMapping.keySet().toArray(new CurrentHeatingCoolingStateEnum[0])
: customCurrentHeatingCoolingStateList.toArray(new CurrentHeatingCoolingStateEnum[0]);
}
// This characteristic is technically mandatory, but we provide a default if it's not provided
var displayUnitCharacteristic = getCharacteristic(TemperatureDisplayUnitCharacteristic.class)
.orElseGet(() -> HomekitCharacteristicFactory.createSystemTemperatureDisplayUnitCharacteristic());
@Override
public TargetHeatingCoolingStateEnum[] getTargetHeatingCoolingStateValidValues() {
return customTargetHeatingCoolingStateList.isEmpty()
? targetHeatingCoolingStateMapping.keySet().toArray(new TargetHeatingCoolingStateEnum[0])
: customTargetHeatingCoolingStateList.toArray(new TargetHeatingCoolingStateEnum[0]);
}
@Override
public CompletableFuture<CurrentHeatingCoolingStateEnum> getCurrentState() {
return CompletableFuture.completedFuture(getKeyFromMapping(CURRENT_HEATING_COOLING_STATE,
currentHeatingCoolingStateMapping, CurrentHeatingCoolingStateEnum.OFF));
}
@Override
public CompletableFuture<Double> getCurrentTemperature() {
Double state = getStateAsTemperature(HomekitCharacteristicType.CURRENT_TEMPERATURE);
return CompletableFuture.completedFuture(state != null ? state : getMinCurrentTemperature());
}
@Override
public double getMinCurrentTemperature() {
// Apple defines default values in Celsius. We need to convert them to Fahrenheit if openHAB is using Fahrenheit
// convertToCelsius and convertFromCelsius are only converting if useFahrenheit is set to true, so no additional
// check here needed
return HomekitCharacteristicFactory.convertToCelsius(
getAccessoryConfiguration(HomekitCharacteristicType.CURRENT_TEMPERATURE, HomekitTaggedItem.MIN_VALUE,
BigDecimal.valueOf(HomekitCharacteristicFactory
.convertFromCelsius(CurrentTemperatureCharacteristic.DEFAULT_MIN_VALUE)))
.doubleValue());
}
@Override
public double getMaxCurrentTemperature() {
return HomekitCharacteristicFactory.convertToCelsius(
getAccessoryConfiguration(HomekitCharacteristicType.CURRENT_TEMPERATURE, HomekitTaggedItem.MAX_VALUE,
BigDecimal.valueOf(HomekitCharacteristicFactory
.convertFromCelsius(CurrentTemperatureCharacteristic.DEFAULT_MAX_VALUE)))
.doubleValue());
}
@Override
public double getMinStepCurrentTemperature() {
return HomekitCharacteristicFactory.getTemperatureStep(
getCharacteristic(HomekitCharacteristicType.CURRENT_TEMPERATURE).get(),
TargetTemperatureCharacteristic.DEFAULT_STEP);
}
@Override
public CompletableFuture<TargetHeatingCoolingStateEnum> getTargetState() {
return CompletableFuture.completedFuture(getKeyFromMapping(TARGET_HEATING_COOLING_STATE,
targetHeatingCoolingStateMapping, TargetHeatingCoolingStateEnum.OFF));
}
@Override
public CompletableFuture<TemperatureDisplayUnitEnum> getTemperatureDisplayUnit() {
return CompletableFuture
.completedFuture(HomekitCharacteristicFactory.useFahrenheit() ? TemperatureDisplayUnitEnum.FAHRENHEIT
: TemperatureDisplayUnitEnum.CELSIUS);
}
@Override
public void setTemperatureDisplayUnit(TemperatureDisplayUnitEnum value) {
// TODO: add support for display unit change
}
@Override
public CompletableFuture<Double> getTargetTemperature() {
Double state = getStateAsTemperature(HomekitCharacteristicType.TARGET_TEMPERATURE);
return CompletableFuture.completedFuture(state != null ? state : 0.0);
}
@Override
public void setTargetState(TargetHeatingCoolingStateEnum mode) {
HomekitCharacteristicFactory.setValueFromEnum(getCharacteristic(TARGET_HEATING_COOLING_STATE).get(), mode,
targetHeatingCoolingStateMapping);
}
@Override
public void setTargetTemperature(Double value) {
final Optional<HomekitTaggedItem> characteristic = getCharacteristic(
HomekitCharacteristicType.TARGET_TEMPERATURE);
if (characteristic.isPresent()) {
((NumberItem) characteristic.get().getItem())
.send(new DecimalType(BigDecimal.valueOf(HomekitCharacteristicFactory.convertFromCelsius(value))));
} else {
logger.warn("Missing mandatory characteristic {}", HomekitCharacteristicType.TARGET_TEMPERATURE);
}
}
@Override
public double getMinTargetTemperature() {
return HomekitCharacteristicFactory
.convertToCelsius(
getAccessoryConfiguration(HomekitCharacteristicType.TARGET_TEMPERATURE,
HomekitTaggedItem.MIN_VALUE,
BigDecimal.valueOf(HomekitCharacteristicFactory
.convertFromCelsius(TargetTemperatureCharacteristic.DEFAULT_MIN_VALUE)))
.doubleValue());
}
@Override
public double getMaxTargetTemperature() {
return HomekitCharacteristicFactory
.convertToCelsius(
getAccessoryConfiguration(HomekitCharacteristicType.TARGET_TEMPERATURE,
HomekitTaggedItem.MAX_VALUE,
BigDecimal.valueOf(HomekitCharacteristicFactory
.convertFromCelsius(TargetTemperatureCharacteristic.DEFAULT_MAX_VALUE)))
.doubleValue());
}
@Override
public double getMinStepTargetTemperature() {
return HomekitCharacteristicFactory.getTemperatureStep(
getCharacteristic(HomekitCharacteristicType.TARGET_TEMPERATURE).get(),
TargetTemperatureCharacteristic.DEFAULT_STEP);
}
@Override
public void subscribeCurrentState(HomekitCharacteristicChangeCallback callback) {
subscribe(CURRENT_HEATING_COOLING_STATE, callback);
}
@Override
public void subscribeCurrentTemperature(HomekitCharacteristicChangeCallback callback) {
subscribe(HomekitCharacteristicType.CURRENT_TEMPERATURE, callback);
}
@Override
public void subscribeTargetState(HomekitCharacteristicChangeCallback callback) {
subscribe(HomekitCharacteristicType.TARGET_HEATING_COOLING_STATE, callback);
}
@Override
public void subscribeTargetTemperature(HomekitCharacteristicChangeCallback callback) {
subscribe(HomekitCharacteristicType.TARGET_TEMPERATURE, callback);
}
@Override
public void subscribeTemperatureDisplayUnit(HomekitCharacteristicChangeCallback callback) {
// TODO: add support for display unit change
}
@Override
public void unsubscribeCurrentState() {
unsubscribe(CURRENT_HEATING_COOLING_STATE);
}
@Override
public void unsubscribeCurrentTemperature() {
unsubscribe(HomekitCharacteristicType.CURRENT_TEMPERATURE);
}
@Override
public void unsubscribeTemperatureDisplayUnit() {
// TODO: add support for display unit change
}
@Override
public void unsubscribeTargetState() {
unsubscribe(HomekitCharacteristicType.TARGET_HEATING_COOLING_STATE);
}
@Override
public void unsubscribeTargetTemperature() {
unsubscribe(HomekitCharacteristicType.TARGET_TEMPERATURE);
addService(new ThermostatService(getCharacteristic(CurrentHeatingCoolingStateCharacteristic.class).get(),
getCharacteristic(TargetHeatingCoolingStateCharacteristic.class).get(),
getCharacteristic(CurrentTemperatureCharacteristic.class).get(),
getCharacteristic(TargetTemperatureCharacteristic.class).get(), displayUnitCharacteristic));
}
}

View File

@ -41,6 +41,7 @@ import org.slf4j.LoggerFactory;
import io.github.hapjava.accessories.HomekitAccessory;
import io.github.hapjava.accessories.ValveAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.common.ActiveEnum;
import io.github.hapjava.characteristics.impl.common.InUseEnum;
@ -76,8 +77,9 @@ public class HomekitValveImpl extends AbstractHomekitAccessoryImpl implements Va
private ValveTypeEnum valveType;
public HomekitValveImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
inUseReader = createBooleanReader(INUSE_STATUS);
activeReader = createBooleanReader(ACTIVE_STATUS);
homekitTimer = getAccessoryConfigurationAsBoolean(CONFIG_TIMER, false);

View File

@ -22,6 +22,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.WindowCoveringAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.windowcovering.PositionStateEnum;
import io.github.hapjava.services.impl.WindowCoveringService;
@ -34,8 +35,9 @@ import io.github.hapjava.services.impl.WindowCoveringService;
public class HomekitWindowCoveringImpl extends AbstractHomekitPositionAccessoryImpl implements WindowCoveringAccessory {
public HomekitWindowCoveringImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater,
HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
}
@Override

View File

@ -22,6 +22,7 @@ import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.accessories.WindowAccessory;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import io.github.hapjava.characteristics.impl.windowcovering.PositionStateEnum;
import io.github.hapjava.services.impl.WindowService;
@ -34,8 +35,9 @@ import io.github.hapjava.services.impl.WindowService;
public class HomekitWindowImpl extends AbstractHomekitPositionAccessoryImpl implements WindowAccessory {
public HomekitWindowImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, updater, settings);
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater,
HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
}
@Override