]> git.basschouten.com Git - openhab-addons.git/blob
f753873dd8aa359e21dea50469bc2ecc24dce6cf
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 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.binding.amazonechocontrol.internal;
14
15 import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.*;
16
17 import java.util.*;
18
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.openhab.binding.amazonechocontrol.internal.handler.AccountHandler;
22 import org.openhab.binding.amazonechocontrol.internal.handler.EchoHandler;
23 import org.openhab.binding.amazonechocontrol.internal.handler.FlashBriefingProfileHandler;
24 import org.openhab.binding.amazonechocontrol.internal.jsons.JsonBluetoothStates.BluetoothState;
25 import org.openhab.binding.amazonechocontrol.internal.jsons.JsonBluetoothStates.PairedDevice;
26 import org.openhab.binding.amazonechocontrol.internal.jsons.JsonDevices.Device;
27 import org.openhab.binding.amazonechocontrol.internal.jsons.JsonMusicProvider;
28 import org.openhab.binding.amazonechocontrol.internal.jsons.JsonNotificationSound;
29 import org.openhab.binding.amazonechocontrol.internal.jsons.JsonPlaylists;
30 import org.openhab.binding.amazonechocontrol.internal.jsons.JsonPlaylists.PlayList;
31 import org.openhab.core.thing.Channel;
32 import org.openhab.core.thing.Thing;
33 import org.openhab.core.thing.ThingRegistry;
34 import org.openhab.core.thing.ThingUID;
35 import org.openhab.core.thing.binding.ThingHandler;
36 import org.openhab.core.thing.type.ChannelTypeUID;
37 import org.openhab.core.thing.type.DynamicStateDescriptionProvider;
38 import org.openhab.core.types.StateDescription;
39 import org.openhab.core.types.StateDescriptionFragmentBuilder;
40 import org.openhab.core.types.StateOption;
41 import org.osgi.service.component.annotations.Activate;
42 import org.osgi.service.component.annotations.Component;
43 import org.osgi.service.component.annotations.Reference;
44
45 /**
46  * Dynamic channel state description provider.
47  * Overrides the state description for the controls, which receive its configuration in the runtime.
48  *
49  * @author Michael Geramb - Initial contribution
50  */
51 @Component(service = { DynamicStateDescriptionProvider.class, AmazonEchoDynamicStateDescriptionProvider.class })
52 @NonNullByDefault
53 public class AmazonEchoDynamicStateDescriptionProvider implements DynamicStateDescriptionProvider {
54     private final ThingRegistry thingRegistry;
55
56     @Activate
57     public AmazonEchoDynamicStateDescriptionProvider(@Reference ThingRegistry thingRegistry) {
58         this.thingRegistry = thingRegistry;
59     }
60
61     public @Nullable ThingHandler findHandler(Channel channel) {
62         Thing thing = thingRegistry.get(channel.getUID().getThingUID());
63         if (thing == null) {
64             return null;
65         }
66         ThingUID accountThingId = thing.getBridgeUID();
67         if (accountThingId == null) {
68             return null;
69         }
70         Thing accountThing = thingRegistry.get(accountThingId);
71         if (accountThing == null) {
72             return null;
73         }
74         AccountHandler accountHandler = (AccountHandler) accountThing.getHandler();
75         if (accountHandler == null) {
76             return null;
77         }
78         Connection connection = accountHandler.findConnection();
79         if (connection == null || !connection.getIsLoggedIn()) {
80             return null;
81         }
82         return thing.getHandler();
83     }
84
85     @Override
86     public @Nullable StateDescription getStateDescription(Channel channel,
87             @Nullable StateDescription originalStateDescription, @Nullable Locale locale) {
88         ChannelTypeUID channelTypeUID = channel.getChannelTypeUID();
89         if (channelTypeUID == null || !BINDING_ID.equals(channelTypeUID.getBindingId())) {
90             return null;
91         }
92         if (originalStateDescription == null) {
93             return null;
94         }
95
96         if (CHANNEL_TYPE_BLUETHOOTH_MAC.equals(channel.getChannelTypeUID())) {
97             EchoHandler handler = (EchoHandler) findHandler(channel);
98             if (handler == null) {
99                 return null;
100             }
101             BluetoothState bluetoothState = handler.findBluetoothState();
102             if (bluetoothState == null) {
103                 return null;
104             }
105             List<PairedDevice> pairedDeviceList = bluetoothState.getPairedDeviceList();
106             if (pairedDeviceList.isEmpty()) {
107                 return null;
108             }
109             List<StateOption> options = new ArrayList<>();
110             options.add(new StateOption("", ""));
111             for (PairedDevice device : pairedDeviceList) {
112                 final String value = device.address;
113                 if (value != null && device.friendlyName != null) {
114                     options.add(new StateOption(value, device.friendlyName));
115                 }
116             }
117             StateDescription result = StateDescriptionFragmentBuilder.create(originalStateDescription)
118                     .withOptions(options).build().toStateDescription();
119             return result;
120         } else if (CHANNEL_TYPE_AMAZON_MUSIC_PLAY_LIST_ID.equals(channel.getChannelTypeUID())) {
121             EchoHandler handler = (EchoHandler) findHandler(channel);
122             if (handler == null) {
123                 return null;
124             }
125
126             JsonPlaylists playLists = handler.findPlaylists();
127             if (playLists == null) {
128                 return null;
129             }
130
131             List<StateOption> options = new ArrayList<>();
132             options.add(new StateOption("", ""));
133             Map<String, PlayList @Nullable []> playlistMap = playLists.playlists;
134             if (playlistMap != null) {
135                 for (PlayList[] innerLists : playlistMap.values()) {
136                     if (innerLists != null && innerLists.length > 0) {
137                         PlayList playList = innerLists[0];
138                         final String value = playList.playlistId;
139                         if (value != null && playList.title != null) {
140                             options.add(new StateOption(value,
141                                     String.format("%s (%d)", playList.title, playList.trackCount)));
142                         }
143                     }
144                 }
145             }
146             StateDescription result = StateDescriptionFragmentBuilder.create(originalStateDescription)
147                     .withOptions(options).build().toStateDescription();
148             return result;
149         } else if (CHANNEL_TYPE_PLAY_ALARM_SOUND.equals(channel.getChannelTypeUID())) {
150             EchoHandler handler = (EchoHandler) findHandler(channel);
151             if (handler == null) {
152                 return null;
153             }
154
155             List<JsonNotificationSound> notificationSounds = handler.findAlarmSounds();
156             if (notificationSounds.isEmpty()) {
157                 return null;
158             }
159
160             List<StateOption> options = new ArrayList<>();
161             options.add(new StateOption("", ""));
162
163             for (JsonNotificationSound notificationSound : notificationSounds) {
164                 if (notificationSound.folder == null && notificationSound.providerId != null
165                         && notificationSound.id != null && notificationSound.displayName != null) {
166                     String providerSoundId = notificationSound.providerId + ":" + notificationSound.id;
167                     options.add(new StateOption(providerSoundId, notificationSound.displayName));
168                 }
169             }
170             StateDescription result = StateDescriptionFragmentBuilder.create(originalStateDescription)
171                     .withOptions(options).build().toStateDescription();
172             return result;
173         } else if (CHANNEL_TYPE_CHANNEL_PLAY_ON_DEVICE.equals(channel.getChannelTypeUID())) {
174             FlashBriefingProfileHandler handler = (FlashBriefingProfileHandler) findHandler(channel);
175             if (handler == null) {
176                 return null;
177             }
178             AccountHandler accountHandler = handler.findAccountHandler();
179             if (accountHandler == null) {
180                 return null;
181             }
182             List<Device> devices = accountHandler.getLastKnownDevices();
183             if (devices.isEmpty()) {
184                 return null;
185             }
186
187             List<StateOption> options = new ArrayList<>();
188             options.add(new StateOption("", ""));
189             for (Device device : devices) {
190                 final String value = device.serialNumber;
191                 if (value != null && device.getCapabilities().contains("FLASH_BRIEFING")) {
192                     options.add(new StateOption(value, device.accountName));
193                 }
194             }
195             return StateDescriptionFragmentBuilder.create(originalStateDescription).withOptions(options).build()
196                     .toStateDescription();
197         } else if (CHANNEL_TYPE_MUSIC_PROVIDER_ID.equals(channel.getChannelTypeUID())) {
198             EchoHandler handler = (EchoHandler) findHandler(channel);
199             if (handler == null) {
200                 return null;
201             }
202             List<JsonMusicProvider> musicProviders = handler.findMusicProviders();
203             if (musicProviders.isEmpty()) {
204                 return null;
205             }
206
207             List<StateOption> options = new ArrayList<>();
208             for (JsonMusicProvider musicProvider : musicProviders) {
209                 List<String> properties = musicProvider.supportedProperties;
210                 String providerId = musicProvider.id;
211                 String displayName = musicProvider.displayName;
212                 if (properties != null && properties.contains("Alexa.Music.PlaySearchPhrase") && providerId != null
213                         && !providerId.isEmpty() && "AVAILABLE".equals(musicProvider.availability)
214                         && displayName != null && !displayName.isEmpty()) {
215                     options.add(new StateOption(providerId, displayName));
216                 }
217             }
218             return StateDescriptionFragmentBuilder.create(originalStateDescription).withOptions(options).build()
219                     .toStateDescription();
220         } else if (CHANNEL_TYPE_START_COMMAND.equals(channel.getChannelTypeUID())) {
221             EchoHandler handler = (EchoHandler) findHandler(channel);
222             if (handler == null) {
223                 return null;
224             }
225             AccountHandler account = handler.findAccount();
226             if (account == null) {
227                 return null;
228             }
229             List<FlashBriefingProfileHandler> flashbriefings = account.getFlashBriefingProfileHandlers();
230             if (flashbriefings.isEmpty()) {
231                 return null;
232             }
233
234             List<StateOption> options = new ArrayList<>();
235             options.addAll(originalStateDescription.getOptions());
236
237             for (FlashBriefingProfileHandler flashBriefing : flashbriefings) {
238                 String value = FLASH_BRIEFING_COMMAND_PREFIX + flashBriefing.getThing().getUID().getId();
239                 String displayName = flashBriefing.getThing().getLabel();
240                 options.add(new StateOption(value, displayName));
241             }
242             return StateDescriptionFragmentBuilder.create(originalStateDescription).withOptions(options).build()
243                     .toStateDescription();
244         }
245         return null;
246     }
247 }