*/
package org.openhab.io.homekit.internal.accessories;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
-import javax.measure.Quantity;
-import javax.measure.Unit;
-
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.items.GenericItem;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.OpenClosedType;
import org.openhab.core.library.types.StringType;
-import org.openhab.core.library.unit.ImperialUnits;
-import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.types.State;
import org.openhab.io.homekit.internal.HomekitAccessoryUpdater;
import org.openhab.io.homekit.internal.HomekitCharacteristicType;
characteristics.add(characteristic);
}
- @NonNullByDefault
- private <T extends Quantity<T>> double convertAndRound(double value, Unit<T> from, Unit<T> to) {
- double rawValue = from.equals(to) ? value : from.getConverterTo(to).convert(value);
- return new BigDecimal(rawValue).setScale(1, RoundingMode.HALF_UP).doubleValue();
- }
-
- @NonNullByDefault
- protected double convertToCelsius(double degrees) {
- return convertAndRound(degrees,
- getSettings().useFahrenheitTemperature ? ImperialUnits.FAHRENHEIT : SIUnits.CELSIUS, SIUnits.CELSIUS);
- }
-
- @NonNullByDefault
- protected double convertFromCelsius(double degrees) {
- return convertAndRound(degrees,
- getSettings().useFahrenheitTemperature ? SIUnits.CELSIUS : ImperialUnits.FAHRENHEIT,
- ImperialUnits.FAHRENHEIT);
- }
-
/**
* create boolean reader with ON state mapped to trueOnOffValue or trueOpenClosedValue depending of item type
*
* @param characteristicType characteristic id
* @param trueOnOffValue ON value for switch
* @param trueOpenClosedValue ON value for contact
- * @return boolean readed
+ * @return boolean read
* @throws IncompleteAccessoryException
*/
@NonNullByDefault
import static org.openhab.io.homekit.internal.HomekitCharacteristicType.*;
import java.math.BigDecimal;
+import java.math.RoundingMode;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Supplier;
+import javax.measure.Quantity;
+import javax.measure.Unit;
+
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.items.GenericItem;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.OpenClosedType;
import org.openhab.core.library.types.PercentType;
+import org.openhab.core.library.unit.ImperialUnits;
+import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
+import org.openhab.io.homekit.Homekit;
import org.openhab.io.homekit.internal.HomekitAccessoryUpdater;
import org.openhab.io.homekit.internal.HomekitCharacteristicType;
import org.openhab.io.homekit.internal.HomekitCommandType;
import org.openhab.io.homekit.internal.HomekitException;
+import org.openhab.io.homekit.internal.HomekitImpl;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
+import org.osgi.framework.FrameworkUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// METHODS TO CREATE SINGLE CHARACTERISTIC FROM OH ITEM
// supporting methods
+
+ public static boolean useFahrenheit() {
+ return FrameworkUtil.getBundle(HomekitImpl.class).getBundleContext()
+ .getServiceReference(Homekit.class.getName()).getProperty("useFahrenheitTemperature") == Boolean.TRUE;
+ }
+
private static <T extends CharacteristicEnum> CompletableFuture<T> getEnumFromItem(HomekitTaggedItem item,
T offEnum, T onEnum, T defaultEnum) {
final State state = item.getItem().getState();
return value;
}
+ private static <T extends Quantity<T>> double convertAndRound(double value, Unit<T> from, Unit<T> to) {
+ double rawValue = from.equals(to) ? value : from.getConverterTo(to).convert(value);
+ return new BigDecimal(rawValue).setScale(1, RoundingMode.HALF_UP).doubleValue();
+ }
+
+ public static double convertToCelsius(double degrees) {
+ return convertAndRound(degrees, useFahrenheit() ? ImperialUnits.FAHRENHEIT : SIUnits.CELSIUS, SIUnits.CELSIUS);
+ }
+
+ public static double convertFromCelsius(double degrees) {
+ return convertAndRound(degrees, SIUnits.CELSIUS, useFahrenheit() ? ImperialUnits.FAHRENHEIT : SIUnits.CELSIUS);
+ }
+
private static Supplier<CompletableFuture<Integer>> getAngleSupplier(HomekitTaggedItem taggedItem,
int defaultValue) {
return () -> CompletableFuture.completedFuture(getAngleFromItem(taggedItem, defaultValue));
};
}
+ private static Supplier<CompletableFuture<Double>> getTemperatureSupplier(HomekitTaggedItem taggedItem,
+ double defaultValue) {
+ return () -> {
+ final @Nullable DecimalType value = taggedItem.getItem().getStateAs(DecimalType.class);
+ return CompletableFuture
+ .completedFuture(value != null ? convertToCelsius(value.doubleValue()) : defaultValue);
+ };
+ }
+
+ private static ExceptionalConsumer<Double> setTemperatureConsumer(HomekitTaggedItem taggedItem) {
+ return (value) -> {
+ if (taggedItem.getItem() instanceof NumberItem) {
+ ((NumberItem) taggedItem.getItem()).send(new DecimalType(convertFromCelsius(value)));
+ } else {
+ logger.warn("Item type {} is not supported for {}. Only Number type is supported.",
+ taggedItem.getItem().getType(), taggedItem.getName());
+ }
+ };
+ }
+
protected static Consumer<HomekitCharacteristicChangeCallback> getSubscriber(HomekitTaggedItem taggedItem,
HomekitCharacteristicType key, HomekitAccessoryUpdater updater) {
return (callback) -> updater.subscribe((GenericItem) taggedItem.getItem(), key.getTag(), callback);
CoolingThresholdTemperatureCharacteristic.DEFAULT_MAX_VALUE),
taggedItem.getConfigurationAsDouble(HomekitTaggedItem.STEP,
CoolingThresholdTemperatureCharacteristic.DEFAULT_STEP),
- getDoubleSupplier(taggedItem,
+ getTemperatureSupplier(taggedItem,
taggedItem.getConfigurationAsDouble(HomekitTaggedItem.MIN_VALUE,
CoolingThresholdTemperatureCharacteristic.DEFAULT_MIN_VALUE)),
- setDoubleConsumer(taggedItem), getSubscriber(taggedItem, COOLING_THRESHOLD_TEMPERATURE, updater),
+ setTemperatureConsumer(taggedItem), getSubscriber(taggedItem, COOLING_THRESHOLD_TEMPERATURE, updater),
getUnsubscriber(taggedItem, COOLING_THRESHOLD_TEMPERATURE, updater));
}
HeatingThresholdTemperatureCharacteristic.DEFAULT_MAX_VALUE),
taggedItem.getConfigurationAsDouble(HomekitTaggedItem.STEP,
HeatingThresholdTemperatureCharacteristic.DEFAULT_STEP),
- getDoubleSupplier(taggedItem,
+ getTemperatureSupplier(taggedItem,
taggedItem.getConfigurationAsDouble(HomekitTaggedItem.MIN_VALUE,
HeatingThresholdTemperatureCharacteristic.DEFAULT_MIN_VALUE)),
- setDoubleConsumer(taggedItem), getSubscriber(taggedItem, HEATING_THRESHOLD_TEMPERATURE, updater),
+ setTemperatureConsumer(taggedItem), getSubscriber(taggedItem, HEATING_THRESHOLD_TEMPERATURE, updater),
getUnsubscriber(taggedItem, HEATING_THRESHOLD_TEMPERATURE, updater));
}
public CompletableFuture<Double> getCurrentTemperature() {
final @Nullable DecimalType state = getStateAs(HomekitCharacteristicType.CURRENT_TEMPERATURE,
DecimalType.class);
- return CompletableFuture.completedFuture(state != null ? convertToCelsius(state.doubleValue())
+ return CompletableFuture.completedFuture(state != null
+ ? HomekitCharacteristicFactory.convertToCelsius(state.doubleValue())
: getAccessoryConfiguration(HomekitCharacteristicType.CURRENT_TEMPERATURE, HomekitTaggedItem.MIN_VALUE,
- BigDecimal.valueOf(CurrentTemperatureCharacteristic.DEFAULT_MIN_VALUE)).doubleValue());
+ BigDecimal.valueOf(HomekitCharacteristicFactory
+ .convertFromCelsius(CurrentTemperatureCharacteristic.DEFAULT_MIN_VALUE)))
+ .doubleValue());
}
@Override
public CompletableFuture<TemperatureDisplayUnitEnum> getTemperatureDisplayUnit() {
return CompletableFuture
- .completedFuture(getSettings().useFahrenheitTemperature ? TemperatureDisplayUnitEnum.FAHRENHEIT
+ .completedFuture(HomekitCharacteristicFactory.useFahrenheit() ? TemperatureDisplayUnitEnum.FAHRENHEIT
: TemperatureDisplayUnitEnum.CELSIUS);
}
import io.github.hapjava.accessories.TemperatureSensorAccessory;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.thermostat.CurrentTemperatureCharacteristic;
import io.github.hapjava.characteristics.impl.thermostat.TargetTemperatureCharacteristic;
import io.github.hapjava.services.impl.TemperatureSensorService;
final @Nullable DecimalType state = getStateAs(HomekitCharacteristicType.CURRENT_TEMPERATURE,
DecimalType.class);
return CompletableFuture
- .completedFuture(state != null ? convertToCelsius(state.doubleValue()) : getMinCurrentTemperature());
+ .completedFuture(state != null ? HomekitCharacteristicFactory.convertToCelsius(state.doubleValue())
+ : getMinCurrentTemperature());
}
@Override
@Override
public double getMinCurrentTemperature() {
- return convertToCelsius(
+ // 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(TargetTemperatureCharacteristic.DEFAULT_MIN_VALUE)).doubleValue());
+ BigDecimal.valueOf(HomekitCharacteristicFactory
+ .convertFromCelsius(CurrentTemperatureCharacteristic.DEFAULT_MIN_VALUE)))
+ .doubleValue());
}
@Override
public double getMaxCurrentTemperature() {
- return convertToCelsius(
+ return HomekitCharacteristicFactory.convertToCelsius(
getAccessoryConfiguration(HomekitCharacteristicType.CURRENT_TEMPERATURE, HomekitTaggedItem.MAX_VALUE,
- BigDecimal.valueOf(TargetTemperatureCharacteristic.DEFAULT_MAX_VALUE)).doubleValue());
+ BigDecimal.valueOf(HomekitCharacteristicFactory
+ .convertFromCelsius(CurrentTemperatureCharacteristic.DEFAULT_MAX_VALUE)))
+ .doubleValue());
}
@Override
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.impl.thermostat.CurrentTemperatureCharacteristic;
import io.github.hapjava.characteristics.impl.thermostat.TargetHeatingCoolingStateEnum;
import io.github.hapjava.characteristics.impl.thermostat.TargetTemperatureCharacteristic;
import io.github.hapjava.characteristics.impl.thermostat.TemperatureDisplayUnitEnum;
@Override
public CompletableFuture<Double> getCurrentTemperature() {
DecimalType state = getStateAs(HomekitCharacteristicType.CURRENT_TEMPERATURE, DecimalType.class);
- return CompletableFuture.completedFuture(state != null ? convertToCelsius(state.doubleValue()) : 0.0);
+ return CompletableFuture
+ .completedFuture(state != null ? HomekitCharacteristicFactory.convertToCelsius(state.doubleValue())
+ : getMinCurrentTemperature());
}
@Override
public double getMinCurrentTemperature() {
- return convertToCelsius(
+ // 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(TargetTemperatureCharacteristic.DEFAULT_MIN_VALUE)).doubleValue());
+ BigDecimal.valueOf(HomekitCharacteristicFactory
+ .convertFromCelsius(CurrentTemperatureCharacteristic.DEFAULT_MIN_VALUE)))
+ .doubleValue());
}
@Override
public double getMaxCurrentTemperature() {
- return convertToCelsius(
+ return HomekitCharacteristicFactory.convertToCelsius(
getAccessoryConfiguration(HomekitCharacteristicType.CURRENT_TEMPERATURE, HomekitTaggedItem.MAX_VALUE,
- BigDecimal.valueOf(TargetTemperatureCharacteristic.DEFAULT_MAX_VALUE)).doubleValue());
+ BigDecimal.valueOf(HomekitCharacteristicFactory
+ .convertFromCelsius(CurrentTemperatureCharacteristic.DEFAULT_MAX_VALUE)))
+ .doubleValue());
}
@Override
@Override
public CompletableFuture<TemperatureDisplayUnitEnum> getTemperatureDisplayUnit() {
return CompletableFuture
- .completedFuture(getSettings().useFahrenheitTemperature ? TemperatureDisplayUnitEnum.FAHRENHEIT
+ .completedFuture(HomekitCharacteristicFactory.useFahrenheit() ? TemperatureDisplayUnitEnum.FAHRENHEIT
: TemperatureDisplayUnitEnum.CELSIUS);
}
@Override
public CompletableFuture<Double> getTargetTemperature() {
DecimalType state = getStateAs(HomekitCharacteristicType.TARGET_TEMPERATURE, DecimalType.class);
- return CompletableFuture.completedFuture(state != null ? convertToCelsius(state.doubleValue()) : 0.0);
+ return CompletableFuture.completedFuture(
+ state != null ? HomekitCharacteristicFactory.convertToCelsius(state.doubleValue()) : 0.0);
}
@Override
HomekitCharacteristicType.TARGET_TEMPERATURE);
if (characteristic.isPresent()) {
((NumberItem) characteristic.get().getItem())
- .send(new DecimalType(BigDecimal.valueOf(convertFromCelsius(value))));
+ .send(new DecimalType(BigDecimal.valueOf(HomekitCharacteristicFactory.convertFromCelsius(value))));
} else {
logger.warn("Missing mandatory characteristic {}", HomekitCharacteristicType.TARGET_TEMPERATURE);
}
@Override
public double getMinTargetTemperature() {
- return convertToCelsius(
- getAccessoryConfiguration(HomekitCharacteristicType.TARGET_TEMPERATURE, HomekitTaggedItem.MIN_VALUE,
- BigDecimal.valueOf(TargetTemperatureCharacteristic.DEFAULT_MIN_VALUE)).doubleValue());
+ return HomekitCharacteristicFactory
+ .convertToCelsius(
+ getAccessoryConfiguration(HomekitCharacteristicType.TARGET_TEMPERATURE,
+ HomekitTaggedItem.MIN_VALUE,
+ BigDecimal.valueOf(HomekitCharacteristicFactory
+ .convertFromCelsius(TargetTemperatureCharacteristic.DEFAULT_MIN_VALUE)))
+ .doubleValue());
}
@Override
public double getMaxTargetTemperature() {
- return convertToCelsius(
- getAccessoryConfiguration(HomekitCharacteristicType.TARGET_TEMPERATURE, HomekitTaggedItem.MAX_VALUE,
- BigDecimal.valueOf(TargetTemperatureCharacteristic.DEFAULT_MAX_VALUE)).doubleValue());
+ return HomekitCharacteristicFactory
+ .convertToCelsius(
+ getAccessoryConfiguration(HomekitCharacteristicType.TARGET_TEMPERATURE,
+ HomekitTaggedItem.MAX_VALUE,
+ BigDecimal.valueOf(HomekitCharacteristicFactory
+ .convertFromCelsius(TargetTemperatureCharacteristic.DEFAULT_MAX_VALUE)))
+ .doubleValue());
}
@Override