2 * Copyright (c) 2010-2022 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.binding.livisismarthome.internal.manager;
15 import java.io.IOException;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.HashMap;
19 import java.util.List;
21 import java.util.Optional;
22 import java.util.concurrent.ConcurrentHashMap;
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.openhab.binding.livisismarthome.internal.LivisiBindingConstants;
26 import org.openhab.binding.livisismarthome.internal.client.api.entity.capability.CapabilityDTO;
27 import org.openhab.binding.livisismarthome.internal.client.api.entity.device.DeviceDTO;
28 import org.openhab.binding.livisismarthome.internal.client.api.entity.link.LinkDTO;
29 import org.openhab.binding.livisismarthome.internal.client.api.entity.message.MessageDTO;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
34 * Manages the structure of the {@link DeviceDTO}s and the calls to the
35 * {@link org.openhab.binding.livisismarthome.internal.client.LivisiClient} to load the {@link DeviceDTO}
36 * data from the LIVISI SmartHome web service.
38 * @author Oliver Kuhl - Initial contribution
42 public class DeviceStructureManager {
44 private final Logger logger = LoggerFactory.getLogger(DeviceStructureManager.class);
46 private final FullDeviceManager deviceManager;
47 private final Map<String, DeviceDTO> deviceMap;
48 private final Map<String, DeviceDTO> capabilityIdToDeviceMap;
49 private String bridgeDeviceId = "";
52 * Constructs the {@link DeviceStructureManager}.
54 * @param deviceManager the {@link FullDeviceManager}
56 public DeviceStructureManager(FullDeviceManager deviceManager) {
57 this.deviceManager = deviceManager;
58 deviceMap = Collections.synchronizedMap(new HashMap<>());
59 capabilityIdToDeviceMap = new ConcurrentHashMap<>();
63 * Returns the {@link #deviceMap}, a map with the device id and the device.
65 * @return map of device id and device
67 public Map<String, DeviceDTO> getDeviceMap() {
72 * Loads all device data from the bridge and stores the {@link DeviceDTO}s and their states in the
73 * {@link DeviceStructureManager}.
75 public void refreshDevices() throws IOException {
77 capabilityIdToDeviceMap.clear();
78 List<DeviceDTO> devices = deviceManager.getFullDevices();
79 for (DeviceDTO d : devices) {
80 handleRefreshedDevice(d);
85 * Refreshs the {@link DeviceDTO} with the given id and stores it in the {@link DeviceStructureManager}.
87 * @param deviceId device id
89 public Optional<DeviceDTO> refreshDevice(final String deviceId, final boolean isSHCClassic) throws IOException {
90 logger.trace("Refreshing Device with id '{}'", deviceId);
91 Optional<DeviceDTO> device = deviceManager.getFullDeviceById(deviceId, isSHCClassic);
92 device.ifPresent(this::handleRefreshedDevice);
97 * Stores the newly refreshed {@link DeviceDTO} in the {@link DeviceStructureManager} structure and logs the
98 * {@link DeviceDTO}s details and state, if the debug logging is enabled.
100 * @param d the {@link DeviceDTO}
102 private void handleRefreshedDevice(DeviceDTO d) {
103 if (LivisiBindingConstants.SUPPORTED_DEVICES.contains(d.getType())) {
104 addDeviceToStructure(d);
106 if (d.isController()) {
107 bridgeDeviceId = d.getId();
110 logger.debug("Device {}:'{}' by {} ({}) ignored - UNSUPPORTED.", d.getType(), d.getConfig().getName(),
111 d.getManufacturer(), d.getId());
112 logger.debug("====================================");
117 * Adds the {@link DeviceDTO} to the structure.
119 * @param device device
121 private void addDeviceToStructure(DeviceDTO device) {
122 if (device.getId() != null) {
123 getDeviceMap().put(device.getId(), device);
126 for (String capability : device.getCapabilities()) {
127 capabilityIdToDeviceMap.put(LinkDTO.getId(capability), device);
130 logDeviceLoaded(device);
134 * Returns the {@link DeviceDTO} with the given id.
136 * @param id device id
137 * @return the {@link DeviceDTO} or null, if it does not exist
139 public Optional<DeviceDTO> getDeviceById(String id) {
140 logger.debug("getDeviceById {}:{}", id, getDeviceMap().containsKey(id));
141 return Optional.ofNullable(getDeviceMap().get(id));
145 * Returns the {@link DeviceDTO}, that provides the given capability.
147 * @param capabilityId capability id
148 * @return {@link DeviceDTO} or null
150 public Optional<DeviceDTO> getDeviceByCapabilityId(String capabilityId) {
151 return Optional.ofNullable(capabilityIdToDeviceMap.get(capabilityId));
155 * Returns the bridge {@link DeviceDTO}.
157 * @return bridge device
159 public Optional<DeviceDTO> getBridgeDevice() {
160 return Optional.ofNullable(getDeviceMap().get(bridgeDeviceId));
164 * Returns a {@link Collection} of all {@link DeviceDTO}s handled by the {@link DeviceStructureManager}.
168 public Collection<DeviceDTO> getDeviceList() {
169 return Collections.unmodifiableCollection(getDeviceMap().values());
173 * Returns the {@link DeviceDTO}, that has the {@link MessageDTO} with the given messageId.
175 * @param messageId the id of the {@link MessageDTO}
176 * @return the {@link DeviceDTO} or null if none found
178 public Optional<DeviceDTO> getDeviceWithMessageId(String messageId) {
179 logger.trace("Getting Device with MessageId '{}'", messageId);
180 for (DeviceDTO d : getDeviceMap().values()) {
181 if (d.hasMessages()) {
182 for (MessageDTO m : d.getMessageList()) {
183 if (messageId.equals(m.getId())) {
184 return Optional.of(d);
189 return Optional.empty();
193 * Returns the id of the {@link CapabilityDTO} for {@link DeviceDTO} with the given id and the given capabilityType.
195 * @param deviceId device id
196 * @param capabilityType capability type
197 * @return the id of the found {@link CapabilityDTO} or null
199 public Optional<String> getCapabilityId(String deviceId, String capabilityType) {
200 DeviceDTO device = getDeviceMap().get(deviceId);
201 if (device != null) {
202 for (CapabilityDTO c : device.getCapabilityMap().values()) {
203 if (c.getType().equals(capabilityType)) {
204 return Optional.of(c.getId());
208 return Optional.empty();
211 private void logDeviceLoaded(DeviceDTO device) {
212 if (logger.isDebugEnabled()) {
213 String location = device.getLocationName();
214 logger.debug("Device {}:'{}@{}' by {} ({}) loaded.", device.getType(), device.getConfig().getName(),
215 location, device.getManufacturer(), device.getId());
216 for (CapabilityDTO c : device.getCapabilityMap().values()) {
217 logger.debug("> CAP: {}/{} ({})", c.getType(), c.getName(), c.getId());
218 if (device.isRadioDevice() && device.isReachable() != null && !device.isReachable()) {
219 logger.debug(">> CAP-State: unknown (device NOT REACHABLE).");
222 logger.debug(">> CAP-State: unknown (NULL)");
226 logger.debug("====================================");