import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.common.ThreadPoolManager;
+import org.openhab.core.items.GroupItem;
import org.openhab.core.items.Item;
import org.openhab.core.library.items.ColorItem;
import org.openhab.core.library.items.DimmerItem;
private final Logger logger = LoggerFactory.getLogger(HomekitOHItemProxy.class);
private static final int DEFAULT_DELAY = 50; // in ms
private final Item item;
+ private final Item baseItem;
private final Map<HomekitCommandType, State> commandCache = new ConcurrentHashMap<>();
private final ScheduledExecutorService scheduler = ThreadPoolManager
.getScheduledPool(ThreadPoolManager.THREAD_POOL_NAME_COMMON);
// delay, how long wait for further commands. in ms.
private int delay = DEFAULT_DELAY;
+ public static Item getBaseItem(Item item) {
+ if (item instanceof GroupItem) {
+ final GroupItem groupItem = (GroupItem) item;
+ final Item baseItem = groupItem.getBaseItem();
+ if (baseItem != null) {
+ return baseItem;
+ }
+ }
+ return item;
+ }
+
public HomekitOHItemProxy(Item item) {
this.item = item;
+ this.baseItem = getBaseItem(item);
}
public Item getItem() {
@SuppressWarnings("null")
private void sendCommand() {
- if (!(item instanceof DimmerItem)) {
+ if (!(baseItem instanceof DimmerItem)) {
// currently supports only DimmerItem and ColorItem (which extends DimmerItem)
- logger.debug("unexpected item type {}. Only DimmerItem and ColorItem are supported.", item);
+ logger.debug("unexpected item type {}. Only DimmerItem and ColorItem are supported.", baseItem);
return;
}
final OnOffType on = (OnOffType) commandCache.remove(ON_COMMAND);
|| ((dimmerMode == DIMMER_MODE_FILTER_ON_EXCEPT_BRIGHTNESS_100) && (currentOnState != OnOffType.ON)
&& ((brightness == null) || (brightness.intValue() == 100)))) {
logger.trace("send OnOff command for item {} with value {}", item, on);
- ((DimmerItem) item).send(on);
+ if (item instanceof GroupItem) {
+ ((GroupItem) item).send(on);
+ } else {
+ ((DimmerItem) item).send(on);
+ }
}
}
// if hue or saturation present, send an HSBType state update. no filter applied for HUE & Saturation
if ((hue != null) || (saturation != null)) {
- if (item instanceof ColorItem) {
+ if (baseItem instanceof ColorItem) {
sendHSBCommand((ColorItem) item, hue, saturation, brightness);
}
- } else if ((brightness != null) && (item instanceof DimmerItem)) {
+ } else if ((brightness != null) && (baseItem instanceof DimmerItem)) {
// sends brightness:
// - DIMMER_MODE_NORMAL
// - DIMMER_MODE_FILTER_ON
logger.trace("send Brightness command for item {} with value {}", item, brightness);
if (item instanceof ColorItem) {
sendHSBCommand((ColorItem) item, hue, saturation, brightness);
+ } else if (item instanceof GroupItem) {
+ ((GroupItem) item).send(brightness);
} else {
((DimmerItem) item).send(brightness);
}
commandCache.clear();
}
- private void sendHSBCommand(ColorItem item, @Nullable DecimalType hue, @Nullable PercentType saturation,
+ private void sendHSBCommand(Item item, @Nullable DecimalType hue, @Nullable PercentType saturation,
@Nullable PercentType brightness) {
final HSBType currentState = item.getState() instanceof UnDefType ? HSBType.BLACK : (HSBType) item.getState();
// logic for ColorItem = combine hue, saturation and brightness update to one command
final DecimalType targetHue = hue != null ? hue : currentState.getHue();
final PercentType targetSaturation = saturation != null ? saturation : currentState.getSaturation();
final PercentType targetBrightness = brightness != null ? brightness : currentState.getBrightness();
- item.send(new HSBType(targetHue, targetSaturation, targetBrightness));
+ final HSBType command = new HSBType(targetHue, targetSaturation, targetBrightness);
+ if (item instanceof GroupItem) {
+ ((GroupItem) item).send(command);
+ } else {
+ ((ColorItem) item).send(command);
+ }
logger.trace("send HSB command for item {} with following values hue={} saturation={} brightness={}", item,
targetHue, targetSaturation, targetBrightness);
}
logger.trace("add command to command cache: item {}, command type {}, command state {}. cache state after: {}",
this, commandType, state, commandCache);
// if cache has already HUE+SATURATION or BRIGHTNESS+ON then we don't expect any further relevant command
- if (((item instanceof ColorItem) && commandCache.containsKey(HUE_COMMAND)
+ if (((baseItem instanceof ColorItem) && commandCache.containsKey(HUE_COMMAND)
&& commandCache.containsKey(SATURATION_COMMAND))
|| (commandCache.containsKey(BRIGHTNESS_COMMAND) && commandCache.containsKey(ON_COMMAND))) {
if (future != null) {
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.items.GroupItem;
import org.openhab.core.items.Item;
+import org.openhab.core.library.items.DimmerItem;
+import org.openhab.core.library.items.NumberItem;
+import org.openhab.core.library.items.RollershutterItem;
+import org.openhab.core.library.items.StringItem;
+import org.openhab.core.library.items.SwitchItem;
+import org.openhab.core.library.types.DecimalType;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.library.types.PercentType;
+import org.openhab.core.library.types.StringType;
import org.openhab.core.types.State;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
return proxyItem.getItem();
}
+ /**
+ * return the base item for a group, or the item itself, in order to do type checks
+ */
+ public Item getBaseItem() {
+ return HomekitOHItemProxy.getBaseItem(proxyItem.getItem());
+ }
+
/**
* return proxy item which is used to group commands.
*
return proxyItem;
}
+ /**
+ * Send DecimalType command to a NumberItem (or a Group:Number)
+ *
+ * @param command
+ */
+ public void send(DecimalType command) {
+ if (getItem() instanceof GroupItem && getBaseItem() instanceof NumberItem) {
+ ((GroupItem) getItem()).send(command);
+ return;
+ } else if (getItem() instanceof NumberItem) {
+ ((NumberItem) getItem()).send(command);
+ return;
+ }
+ logger.warn("Received DecimalType command for item {} that doesn't support it. This is probably a bug.",
+ getName());
+ }
+
+ /**
+ * Send OnOffType command to a SwitchItem (or a Group:Switch)
+ *
+ * @param command
+ */
+ public void send(OnOffType command) {
+ if (getItem() instanceof GroupItem && getBaseItem() instanceof SwitchItem) {
+ ((GroupItem) getItem()).send(command);
+ return;
+ } else if (getItem() instanceof SwitchItem) {
+ ((SwitchItem) getItem()).send(command);
+ return;
+ }
+ logger.warn("Received OnOffType command for item {} that doesn't support it. This is probably a bug.",
+ getName());
+ }
+
+ /**
+ * Send PercentType command to a DimmerItem or RollershutterItem (or a Group:Dimmer/Group:Rollershutter)
+ *
+ * @param command
+ */
+ public void send(PercentType command) {
+ if (getItem() instanceof GroupItem
+ && (getBaseItem() instanceof DimmerItem || getBaseItem() instanceof RollershutterItem)) {
+ ((GroupItem) getItem()).send(command);
+ return;
+ } else if (getItem() instanceof DimmerItem) {
+ ((DimmerItem) getItem()).send(command);
+ return;
+ } else if (getItem() instanceof RollershutterItem) {
+ ((RollershutterItem) getItem()).send(command);
+ return;
+ }
+ logger.warn("Received PercentType command for item {} that doesn't support it. This is probably a bug.",
+ getName());
+ }
+
+ /**
+ * Send StringType command to a StringItem (or a Group:String)
+ *
+ * @param command
+ */
+ public void send(StringType command) {
+ if (getItem() instanceof GroupItem && getBaseItem() instanceof StringItem) {
+ ((GroupItem) getItem()).send(command);
+ return;
+ } else if (getItem() instanceof StringItem) {
+ ((StringItem) getItem()).send(command);
+ return;
+ }
+ logger.warn("Received StringType command for item {} that doesn't support it. This is probably a bug.",
+ getName());
+ }
+
/**
* send openHAB item command via proxy item, which allows to group commands.
* e.g. sendCommandProxy(hue), sendCommandProxy(brightness) would lead to one openHAB command that updates hue and
final Optional<HomekitTaggedItem> taggedItem = getCharacteristic(type);
if (taggedItem.isPresent()) {
final Item item = taggedItem.get().getItem();
- Item baseItem = item;
- // Check the type of the base item for a group item
- if (item instanceof GroupItem) {
- baseItem = ((GroupItem) item).getBaseItem();
- if (baseItem == null) {
- baseItem = item;
- }
- }
+ final Item baseItem = taggedItem.get().getBaseItem();
if (baseItem instanceof RollershutterItem || baseItem instanceof DimmerItem) {
value = item.getStateAs(PercentType.class);
} else {
import org.openhab.core.library.types.OpenClosedType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.types.State;
+import org.openhab.io.homekit.internal.HomekitOHItemProxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
this.item = item;
this.trueOnOffValue = trueOnOffValue;
this.trueOpenClosedValue = trueOpenClosedValue;
- if (!(item instanceof SwitchItem) && !(item instanceof ContactItem) && !(item instanceof StringItem)) {
+ final Item baseItem = HomekitOHItemProxy.getBaseItem(item);
+ if (!(baseItem instanceof SwitchItem) && !(baseItem instanceof ContactItem)
+ && !(baseItem instanceof StringItem)) {
logger.warn("Item {} is a {} instead of the expected SwitchItem, ContactItem or StringItem", item.getName(),
item.getClass().getName());
}
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.items.GenericItem;
-import org.openhab.core.items.Item;
import org.openhab.core.library.items.ColorItem;
import org.openhab.core.library.items.DimmerItem;
import org.openhab.core.library.items.NumberItem;
if (optional.containsKey(type)) {
return optional.get(type).apply(item, updater);
}
- logger.warn("Unsupported optional characteristic. Accessory type {}, characteristic type {}",
- item.getAccessoryType(), type.getTag());
+ logger.warn("Unsupported optional characteristic from item {}. Accessory type {}, characteristic type {}",
+ item.getName(), item.getAccessoryType(), type.getTag());
throw new HomekitException(
"Unsupported optional characteristic. Characteristic type \"" + type.getTag() + "\"");
}
private static void setValueFromEnum(HomekitTaggedItem taggedItem, CharacteristicEnum value,
CharacteristicEnum offEnum, CharacteristicEnum onEnum) {
- if (taggedItem.getItem() instanceof SwitchItem) {
+ if (taggedItem.getBaseItem() instanceof SwitchItem) {
if (value.equals(offEnum)) {
- ((SwitchItem) taggedItem.getItem()).send(taggedItem.isInverted() ? OnOffType.ON : OnOffType.OFF);
+ taggedItem.send(taggedItem.isInverted() ? OnOffType.ON : OnOffType.OFF);
} else if (value.equals(onEnum)) {
- ((SwitchItem) taggedItem.getItem()).send(taggedItem.isInverted() ? OnOffType.OFF : OnOffType.ON);
+ taggedItem.send(taggedItem.isInverted() ? OnOffType.OFF : OnOffType.ON);
} else {
- logger.warn("Enum value {} is not supported. Only following values are supported: {},{}", value,
- offEnum, onEnum);
+ logger.warn("Enum value {} is not supported for {}. Only following values are supported: {},{}", value,
+ taggedItem.getName(), offEnum, onEnum);
}
- } else if (taggedItem.getItem() instanceof NumberItem) {
- ((NumberItem) taggedItem.getItem()).send(new DecimalType(value.getCode()));
+ } else if (taggedItem.getBaseItem() instanceof NumberItem) {
+ taggedItem.send(new DecimalType(value.getCode()));
} else {
- logger.warn("Item type {} is not supported. Only Switch and Number item types are supported.",
- taggedItem.getItem().getType());
+ logger.warn("Item {} of type {} is not supported. Only Switch and Number item types are supported.",
+ taggedItem.getName(), taggedItem.getBaseItem().getType());
}
}
private static ExceptionalConsumer<Integer> setIntConsumer(HomekitTaggedItem taggedItem) {
return (value) -> {
- if (taggedItem.getItem() instanceof NumberItem) {
- ((NumberItem) taggedItem.getItem()).send(new DecimalType(value));
+ if (taggedItem.getBaseItem() instanceof NumberItem) {
+ taggedItem.send(new DecimalType(value));
} else {
logger.warn("Item type {} is not supported for {}. Only NumberItem is supported.",
- taggedItem.getItem().getType(), taggedItem.getName());
+ taggedItem.getBaseItem().getType(), taggedItem.getName());
}
};
}
private static ExceptionalConsumer<Integer> setPercentConsumer(HomekitTaggedItem taggedItem) {
return (value) -> {
- if (taggedItem.getItem() instanceof NumberItem) {
- ((NumberItem) taggedItem.getItem()).send(new DecimalType(value));
- } else if (taggedItem.getItem() instanceof DimmerItem) {
- ((DimmerItem) taggedItem.getItem()).send(new PercentType(value));
+ if (taggedItem.getBaseItem() instanceof NumberItem) {
+ taggedItem.send(new DecimalType(value));
+ } else if (taggedItem.getBaseItem() instanceof DimmerItem) {
+ taggedItem.send(new PercentType(value));
} else {
logger.warn("Item type {} is not supported for {}. Only DimmerItem and NumberItem are supported.",
- taggedItem.getItem().getType(), taggedItem.getName());
+ taggedItem.getBaseItem().getType(), taggedItem.getName());
}
};
}
private static ExceptionalConsumer<Integer> setAngleConsumer(HomekitTaggedItem taggedItem) {
return (value) -> {
- if (taggedItem.getItem() instanceof NumberItem) {
- ((NumberItem) taggedItem.getItem()).send(new DecimalType(value));
- } else if (taggedItem.getItem() instanceof DimmerItem) {
+ if (taggedItem.getBaseItem() instanceof NumberItem) {
+ taggedItem.send(new DecimalType(value));
+ } else if (taggedItem.getBaseItem() instanceof DimmerItem) {
value = (int) (value * 50.0 / 90.0 + 50.0);
- ((DimmerItem) taggedItem.getItem()).send(new PercentType(value));
+ taggedItem.send(new PercentType(value));
} else {
logger.warn("Item type {} is not supported for {}. Only DimmerItem and NumberItem are supported.",
- taggedItem.getItem().getType(), taggedItem.getName());
+ taggedItem.getBaseItem().getType(), taggedItem.getName());
}
};
}
private static ExceptionalConsumer<Double> setDoubleConsumer(HomekitTaggedItem taggedItem) {
return (value) -> {
- if (taggedItem.getItem() instanceof NumberItem) {
- ((NumberItem) taggedItem.getItem()).send(new DecimalType(value.doubleValue()));
- } else if (taggedItem.getItem() instanceof DimmerItem) {
- ((DimmerItem) taggedItem.getItem()).send(new PercentType(value.intValue()));
+ if (taggedItem.getBaseItem() instanceof NumberItem) {
+ taggedItem.send(new DecimalType(value.doubleValue()));
+ } else if (taggedItem.getBaseItem() instanceof DimmerItem) {
+ taggedItem.send(new PercentType(value.intValue()));
} else {
logger.warn("Item type {} is not supported for {}. Only Number and Dimmer type are supported.",
- taggedItem.getItem().getType(), taggedItem.getName());
+ taggedItem.getBaseItem().getType(), taggedItem.getName());
}
};
}
private static ExceptionalConsumer<Double> setTemperatureConsumer(HomekitTaggedItem taggedItem) {
return (value) -> {
- if (taggedItem.getItem() instanceof NumberItem) {
- ((NumberItem) taggedItem.getItem()).send(new DecimalType(convertFromCelsius(value)));
+ if (taggedItem.getBaseItem() instanceof NumberItem) {
+ taggedItem.send(new DecimalType(convertFromCelsius(value)));
} else {
logger.warn("Item type {} is not supported for {}. Only Number type is supported.",
- taggedItem.getItem().getType(), taggedItem.getName());
+ taggedItem.getBaseItem().getType(), taggedItem.getName());
}
};
}
}
return CompletableFuture.completedFuture(value);
}, (hue) -> {
- if (taggedItem.getItem() instanceof ColorItem) {
+ if (taggedItem.getBaseItem() instanceof ColorItem) {
taggedItem.sendCommandProxy(HomekitCommandType.HUE_COMMAND, new DecimalType(hue));
} else {
logger.warn("Item type {} is not supported for {}. Only Color type is supported.",
- taggedItem.getItem().getType(), taggedItem.getName());
+ taggedItem.getBaseItem().getType(), taggedItem.getName());
}
}, getSubscriber(taggedItem, HUE, updater), getUnsubscriber(taggedItem, HUE, updater));
}
}
return CompletableFuture.completedFuture(value);
}, (brightness) -> {
- final Item item = taggedItem.getItem();
- if (item instanceof DimmerItem) {
+ if (taggedItem.getBaseItem() instanceof DimmerItem) {
taggedItem.sendCommandProxy(HomekitCommandType.BRIGHTNESS_COMMAND, new PercentType(brightness));
} else {
logger.warn("Item type {} is not supported for {}. Only ColorItem and DimmerItem are supported.",
- item.getType(), taggedItem.getName());
+ taggedItem.getBaseItem().getType(), taggedItem.getName());
}
}, getSubscriber(taggedItem, BRIGHTNESS, updater), getUnsubscriber(taggedItem, BRIGHTNESS, updater));
}
}
return CompletableFuture.completedFuture(value);
}, (saturation) -> {
- if (taggedItem.getItem() instanceof ColorItem) {
+ if (taggedItem.getBaseItem() instanceof ColorItem) {
taggedItem.sendCommandProxy(HomekitCommandType.SATURATION_COMMAND,
new PercentType(saturation.intValue()));
} else {
logger.warn("Item type {} is not supported for {}. Only Color type is supported.",
- taggedItem.getItem().getType(), taggedItem.getName());
+ taggedItem.getBaseItem().getType(), taggedItem.getName());
}
}, getSubscriber(taggedItem, SATURATION, updater), getUnsubscriber(taggedItem, SATURATION, updater));
}
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.StringType;
import org.openhab.io.homekit.internal.HomekitAccessoryUpdater;
+import org.openhab.io.homekit.internal.HomekitOHItemProxy;
import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import org.slf4j.Logger;
}
TargetDoorStateEnum mode;
- if (item instanceof SwitchItem) {
+ final Item baseItem = HomekitOHItemProxy.getBaseItem(item);
+ if (baseItem instanceof SwitchItem) {
mode = item.getState() == OnOffType.ON ? TargetDoorStateEnum.OPEN : TargetDoorStateEnum.CLOSED;
- } else if (item instanceof StringItem) {
+ } else if (baseItem instanceof StringItem) {
final HomekitSettings settings = getSettings();
final String stringValue = item.getState().toString();
if (stringValue.equalsIgnoreCase(settings.doorTargetStateClosed)) {
mode = TargetDoorStateEnum.CLOSED;
}
} else {
- logger.warn("Unsupported item type {} for {}. Only Switch and String are supported", item.getType(),
+ logger.warn("Unsupported item type {} for {}. Only Switch and String are supported", baseItem.getType(),
item.getName());
mode = TargetDoorStateEnum.CLOSED;
}
@Override
public CompletableFuture<Void> setTargetDoorState(TargetDoorStateEnum targetDoorStateEnum) {
final Optional<HomekitTaggedItem> characteristic = getCharacteristic(TARGET_DOOR_STATE);
- Item item;
+ final HomekitTaggedItem taggedItem;
if (characteristic.isPresent()) {
- item = characteristic.get().getItem();
+ taggedItem = characteristic.get();
} else {
logger.warn("Missing mandatory characteristic {}", TARGET_DOOR_STATE);
return CompletableFuture.completedFuture(null);
}
- if (item instanceof SwitchItem) {
- ((SwitchItem) item).send(OnOffType.from(targetDoorStateEnum == TargetDoorStateEnum.OPEN));
- } else if (item instanceof StringItem) {
+ if (taggedItem.getBaseItem() instanceof SwitchItem) {
+ taggedItem.send(OnOffType.from(targetDoorStateEnum == TargetDoorStateEnum.OPEN));
+ } else if (taggedItem.getBaseItem() instanceof StringItem) {
final HomekitSettings settings = getSettings();
- ((StringItem) item)
+ taggedItem
.send(new StringType(targetDoorStateEnum == TargetDoorStateEnum.OPEN ? settings.doorTargetStateOpen
: settings.doorTargetStateClosed));
} else {
- logger.warn("Unsupported item type {} for {}. Only Switch and String are supported", item.getType(),
- item.getName());
+ logger.warn("Unsupported item type {} for {}. Only Switch and String are supported",
+ taggedItem.getBaseItem().getType(), taggedItem.getName());
}
return CompletableFuture.completedFuture(null);
}
import java.util.List;
import java.util.concurrent.CompletableFuture;
-import org.openhab.core.items.GenericItem;
-import org.openhab.core.items.GroupItem;
import org.openhab.core.library.items.DimmerItem;
import org.openhab.core.library.items.SwitchItem;
import org.openhab.core.library.types.OnOffType;
public CompletableFuture<Void> setLightbulbPowerState(boolean value) {
getCharacteristic(HomekitCharacteristicType.ON_STATE).ifPresent(tItem -> {
final OnOffType onOffState = OnOffType.from(value);
- final GenericItem item = (GenericItem) tItem.getItem();
- if (item instanceof DimmerItem) {
+ if (tItem.getBaseItem() instanceof DimmerItem) {
tItem.sendCommandProxy(HomekitCommandType.ON_COMMAND, onOffState);
- } else if (item instanceof SwitchItem) {
- ((SwitchItem) item).send(onOffState);
- } else if (item instanceof GroupItem) {
- ((GroupItem) item).send(onOffState);
+ } else if (tItem.getBaseItem() instanceof SwitchItem) {
+ tItem.send(onOffState);
}
});
return CompletableFuture.completedFuture(null);