2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.io.neeo.internal;
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.HashSet;
18 import java.util.List;
20 import java.util.Objects;
23 import org.apache.commons.lang3.StringUtils;
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.openhab.core.items.Item;
27 import org.openhab.core.items.ItemNotFoundException;
28 import org.openhab.core.thing.Channel;
29 import org.openhab.core.thing.ChannelUID;
30 import org.openhab.core.thing.Thing;
31 import org.openhab.core.thing.ThingUID;
32 import org.openhab.core.thing.type.ChannelKind;
33 import org.openhab.core.thing.type.ChannelType;
34 import org.openhab.io.neeo.internal.models.ItemSubType;
35 import org.openhab.io.neeo.internal.models.NeeoCapabilityType;
36 import org.openhab.io.neeo.internal.models.NeeoDevice;
37 import org.openhab.io.neeo.internal.models.NeeoDeviceChannel;
38 import org.openhab.io.neeo.internal.models.NeeoDeviceTiming;
39 import org.openhab.io.neeo.internal.models.NeeoDeviceType;
40 import org.openhab.io.neeo.internal.models.NeeoThingUID;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
45 * The class will handle the conversion between a {@link Thing} and a {@link NeeoDevice}
47 * @author Tim Roberts - Initial Contribution
50 class OpenHabToDeviceConverter {
53 private final Logger logger = LoggerFactory.getLogger(OpenHabToDeviceConverter.class);
55 /** The service context */
56 private final ServiceContext context;
58 /** Whether to expose all items by default or not */
59 private final boolean exposeAll;
61 /** Whether to expose things by the NEEO binding by default or not */
62 private final boolean exposeNeeoBinding;
65 * Constructs the object from the give {@link ServiceContext}
67 * @param context the non-null service context
69 OpenHabToDeviceConverter(ServiceContext context) {
70 Objects.requireNonNull(context, "context cannot be null");
72 this.context = context;
74 exposeAll = context.isExposeAllThings();
75 exposeNeeoBinding = context.isExposeNeeoBinding();
79 * Convert the {@link Thing} to a {@link NeeoDevice}
81 * @param thing the non-null thing
82 * @return a potentially null neeo device
85 NeeoDevice convert(Thing thing) {
86 Objects.requireNonNull(thing, "thing cannot be null");
88 final List<NeeoDeviceChannel> channels = new ArrayList<>();
90 final ThingUID thingUID = thing.getUID();
91 final Set<String> existingLabels = new HashSet<>();
93 for (Channel channel : thing.getChannels()) {
94 final ChannelUID uid = channel.getUID();
96 if (channel.getKind() == ChannelKind.TRIGGER) {
98 NeeoDeviceChannel.from(channel, NeeoCapabilityType.BUTTON, ItemSubType.NONE, existingLabels));
100 final ChannelType channelType = context.getChannelTypeRegistry()
101 .getChannelType(channel.getChannelTypeUID());
103 NeeoCapabilityType type = NeeoCapabilityType.EXCLUDE;
104 if (NeeoConstants.NEEOBINDING_BINDING_ID.equalsIgnoreCase(thingUID.getBindingId())) {
105 if (thingUID.getAsString().toLowerCase()
106 .startsWith(NeeoConstants.NEEOBINDING_DEVICE_ID.toLowerCase())) {
107 // all device channels are currently macros - so buttons are appropriate
108 type = NeeoCapabilityType.BUTTON;
110 type = NeeoCapabilityType.guessType(channelType);
112 } else if (exposeAll) {
113 type = NeeoCapabilityType.guessType(channelType);
116 final Set<Item> linkedItems = context.getItemChannelLinkRegistry().getLinkedItems(uid);
117 if (linkedItems != null) {
118 for (Item item : linkedItems) {
119 channels.addAll(NeeoDeviceChannel.from(item, channel, channelType, type, existingLabels));
126 if (channels.isEmpty()) {
127 logger.debug("No linked channels found for thing {} - ignoring", thing.getLabel());
131 if (NeeoConstants.NEEOBINDING_BINDING_ID.equalsIgnoreCase(thing.getUID().getBindingId())) {
132 final Map<String, String> properties = thing.getProperties();
133 /** The following properties have matches in org.openhab.binding.neeo.NeeoDeviceHandler.java */
134 String neeoType = properties.get("Type");
135 if (neeoType == null || neeoType.isEmpty()) {
136 neeoType = NeeoDeviceType.ACCESSOIRE.toString();
138 String manufacturer = properties.get("Manufacturer");
139 if (manufacturer == null || manufacturer.isEmpty()) {
140 manufacturer = "openHAB";
142 final Integer standbyDelay = parseInteger(properties.getOrDefault("Standby Command Delay", "0"));
143 final Integer switchDelay = parseInteger(properties.getOrDefault("Source Switch Delay", "0"));
144 final Integer shutDownDelay = parseInteger(properties.getOrDefault("Shutdown Delay", "0"));
146 final NeeoDeviceTiming timing = new NeeoDeviceTiming(standbyDelay, switchDelay, shutDownDelay);
148 final String dc = properties.get("Device Capabilities");
149 final String[] deviceCapabilities = dc == null || dc.isEmpty() ? new String[0] : StringUtils.split(dc, ',');
152 return new NeeoDevice(new NeeoThingUID(thing.getUID()), 0,
153 exposeNeeoBinding ? NeeoDeviceType.parse(neeoType) : NeeoDeviceType.EXCLUDE, manufacturer,
154 thing.getLabel(), channels, timing, Arrays.asList(deviceCapabilities), null, null);
155 } catch (IllegalArgumentException e) {
156 logger.debug("NeeoDevice constructor threw an IAE - ignoring device: {} - {}", thing.getUID(),
162 return new NeeoDevice(thing, channels, exposeAll ? NeeoUtil.guessType(thing) : NeeoDeviceType.EXCLUDE,
164 } catch (IllegalArgumentException e) {
165 logger.debug("NeeoDevice constructor threw an IAE - ignoring device: {} - {}", thing.getUID(),
173 * Helper method to parse a value to an Integer (or null if not a number)
175 * @param value a possibly null, possibly empty value to parse
176 * @return an Integer or null if not a number
179 private static @Nullable Integer parseInteger(String value) {
180 if (value.isEmpty()) {
184 return Integer.parseInt(value);
185 } catch (NumberFormatException e) {
191 * Returns a {@link NeeoDeviceChannel} that represents the given itemname (or null if itemname is not found)
193 * @param itemName a possibly empty, possibly null item name
194 * @return a {@link NeeoDeviceChannel} representing the item name or null if not found
197 List<NeeoDeviceChannel> getNeeoDeviceChannel(String itemName) {
198 if (itemName.isEmpty()) {
203 final Item item = context.getItemRegistry().getItem(itemName);
204 return NeeoDeviceChannel.from(item, null, null, NeeoCapabilityType.EXCLUDE, new HashSet<>());
205 } catch (ItemNotFoundException e) {