2 * Copyright (c) 2010-2021 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.amazonechocontrol.internal;
15 import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.*;
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;
46 * Dynamic channel state description provider.
47 * Overrides the state description for the controls, which receive its configuration in the runtime.
49 * @author Michael Geramb - Initial contribution
51 @Component(service = { DynamicStateDescriptionProvider.class, AmazonEchoDynamicStateDescriptionProvider.class })
53 public class AmazonEchoDynamicStateDescriptionProvider implements DynamicStateDescriptionProvider {
54 private final ThingRegistry thingRegistry;
57 public AmazonEchoDynamicStateDescriptionProvider(@Reference ThingRegistry thingRegistry) {
58 this.thingRegistry = thingRegistry;
61 public @Nullable ThingHandler findHandler(Channel channel) {
62 Thing thing = thingRegistry.get(channel.getUID().getThingUID());
66 ThingUID accountThingId = thing.getBridgeUID();
67 if (accountThingId == null) {
70 Thing accountThing = thingRegistry.get(accountThingId);
71 if (accountThing == null) {
74 AccountHandler accountHandler = (AccountHandler) accountThing.getHandler();
75 if (accountHandler == null) {
78 Connection connection = accountHandler.findConnection();
79 if (connection == null || !connection.getIsLoggedIn()) {
82 return thing.getHandler();
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())) {
92 if (originalStateDescription == null) {
96 if (CHANNEL_TYPE_BLUETHOOTH_MAC.equals(channel.getChannelTypeUID())) {
97 EchoHandler handler = (EchoHandler) findHandler(channel);
98 if (handler == null) {
101 BluetoothState bluetoothState = handler.findBluetoothState();
102 if (bluetoothState == null) {
105 List<PairedDevice> pairedDeviceList = bluetoothState.getPairedDeviceList();
106 if (pairedDeviceList.isEmpty()) {
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));
117 StateDescription result = StateDescriptionFragmentBuilder.create(originalStateDescription)
118 .withOptions(options).build().toStateDescription();
120 } else if (CHANNEL_TYPE_AMAZON_MUSIC_PLAY_LIST_ID.equals(channel.getChannelTypeUID())) {
121 EchoHandler handler = (EchoHandler) findHandler(channel);
122 if (handler == null) {
126 JsonPlaylists playLists = handler.findPlaylists();
127 if (playLists == null) {
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)));
146 StateDescription result = StateDescriptionFragmentBuilder.create(originalStateDescription)
147 .withOptions(options).build().toStateDescription();
149 } else if (CHANNEL_TYPE_PLAY_ALARM_SOUND.equals(channel.getChannelTypeUID())) {
150 EchoHandler handler = (EchoHandler) findHandler(channel);
151 if (handler == null) {
155 List<JsonNotificationSound> notificationSounds = handler.findAlarmSounds();
156 if (notificationSounds.isEmpty()) {
160 List<StateOption> options = new ArrayList<>();
161 options.add(new StateOption("", ""));
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));
170 StateDescription result = StateDescriptionFragmentBuilder.create(originalStateDescription)
171 .withOptions(options).build().toStateDescription();
173 } else if (CHANNEL_TYPE_CHANNEL_PLAY_ON_DEVICE.equals(channel.getChannelTypeUID())) {
174 FlashBriefingProfileHandler handler = (FlashBriefingProfileHandler) findHandler(channel);
175 if (handler == null) {
178 AccountHandler accountHandler = handler.findAccountHandler();
179 if (accountHandler == null) {
182 List<Device> devices = accountHandler.getLastKnownDevices();
183 if (devices.isEmpty()) {
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));
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) {
202 List<JsonMusicProvider> musicProviders = handler.findMusicProviders();
203 if (musicProviders.isEmpty()) {
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));
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) {
225 AccountHandler account = handler.findAccount();
226 if (account == null) {
229 List<FlashBriefingProfileHandler> flashbriefings = account.getFlashBriefingProfileHandlers();
230 if (flashbriefings.isEmpty()) {
234 List<StateOption> options = new ArrayList<>();
235 options.addAll(originalStateDescription.getOptions());
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));
242 return StateDescriptionFragmentBuilder.create(originalStateDescription).withOptions(options).build()
243 .toStateDescription();