]> git.basschouten.com Git - openhab-addons.git/blob
bb5a25cfc1f9e48339a142242637f9ed9b7f1809
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.io.neeo.internal;
14
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.HashSet;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Objects;
21 import java.util.Set;
22
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;
43
44 /**
45  * The class will handle the conversion between a {@link Thing} and a {@link NeeoDevice}
46  *
47  * @author Tim Roberts - Initial Contribution
48  */
49 @NonNullByDefault
50 class OpenHabToDeviceConverter {
51
52     /** The logger */
53     private final Logger logger = LoggerFactory.getLogger(OpenHabToDeviceConverter.class);
54
55     /** The service context */
56     private final ServiceContext context;
57
58     /** Whether to expose all items by default or not */
59     private final boolean exposeAll;
60
61     /** Whether to expose things by the NEEO binding by default or not */
62     private final boolean exposeNeeoBinding;
63
64     /**
65      * Constructs the object from the give {@link ServiceContext}
66      *
67      * @param context the non-null service context
68      */
69     OpenHabToDeviceConverter(ServiceContext context) {
70         Objects.requireNonNull(context, "context cannot be null");
71
72         this.context = context;
73
74         exposeAll = context.isExposeAllThings();
75         exposeNeeoBinding = context.isExposeNeeoBinding();
76     }
77
78     /**
79      * Convert the {@link Thing} to a {@link NeeoDevice}
80      *
81      * @param thing the non-null thing
82      * @return a potentially null neeo device
83      */
84     @Nullable
85     NeeoDevice convert(Thing thing) {
86         Objects.requireNonNull(thing, "thing cannot be null");
87
88         final List<NeeoDeviceChannel> channels = new ArrayList<>();
89
90         final ThingUID thingUID = thing.getUID();
91         final Set<String> existingLabels = new HashSet<>();
92
93         for (Channel channel : thing.getChannels()) {
94             final ChannelUID uid = channel.getUID();
95
96             if (channel.getKind() == ChannelKind.TRIGGER) {
97                 channels.addAll(
98                         NeeoDeviceChannel.from(channel, NeeoCapabilityType.BUTTON, ItemSubType.NONE, existingLabels));
99             } else {
100                 final ChannelType channelType = context.getChannelTypeRegistry()
101                         .getChannelType(channel.getChannelTypeUID());
102
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;
109                     } else {
110                         type = NeeoCapabilityType.guessType(channelType);
111                     }
112                 } else if (exposeAll) {
113                     type = NeeoCapabilityType.guessType(channelType);
114                 }
115
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));
120                     }
121                 }
122             }
123
124         }
125
126         if (channels.isEmpty()) {
127             logger.debug("No linked channels found for thing {} - ignoring", thing.getLabel());
128             return null;
129         }
130
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();
137             }
138             String manufacturer = properties.get("Manufacturer");
139             if (manufacturer == null || manufacturer.isEmpty()) {
140                 manufacturer = "openHAB";
141             }
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"));
145
146             final NeeoDeviceTiming timing = new NeeoDeviceTiming(standbyDelay, switchDelay, shutDownDelay);
147
148             final String dc = properties.get("Device Capabilities");
149             final String[] deviceCapabilities = dc == null || dc.isEmpty() ? new String[0] : StringUtils.split(dc, ',');
150
151             try {
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(),
157                         e.getMessage(), e);
158                 return null;
159             }
160         } else {
161             try {
162                 return new NeeoDevice(thing, channels, exposeAll ? NeeoUtil.guessType(thing) : NeeoDeviceType.EXCLUDE,
163                         null);
164             } catch (IllegalArgumentException e) {
165                 logger.debug("NeeoDevice constructor threw an IAE - ignoring device: {} - {}", thing.getUID(),
166                         e.getMessage(), e);
167                 return null;
168             }
169         }
170     }
171
172     /**
173      * Helper method to parse a value to an Integer (or null if not a number)
174      *
175      * @param value a possibly null, possibly empty value to parse
176      * @return an Integer or null if not a number
177      */
178
179     private static @Nullable Integer parseInteger(String value) {
180         if (value.isEmpty()) {
181             return null;
182         }
183         try {
184             return Integer.parseInt(value);
185         } catch (NumberFormatException e) {
186             return null;
187         }
188     }
189
190     /**
191      * Returns a {@link NeeoDeviceChannel} that represents the given itemname (or null if itemname is not found)
192      *
193      * @param itemName a possibly empty, possibly null item name
194      * @return a {@link NeeoDeviceChannel} representing the item name or null if not found
195      */
196     @Nullable
197     List<NeeoDeviceChannel> getNeeoDeviceChannel(String itemName) {
198         if (itemName.isEmpty()) {
199             return null;
200         }
201
202         try {
203             final Item item = context.getItemRegistry().getItem(itemName);
204             return NeeoDeviceChannel.from(item, null, null, NeeoCapabilityType.EXCLUDE, new HashSet<>());
205         } catch (ItemNotFoundException e) {
206             return null;
207         }
208     }
209 }