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