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