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.heos.internal.api;
15 import static org.openhab.binding.heos.internal.resources.HeosConstants.*;
17 import java.io.IOException;
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.Collections;
22 import java.util.List;
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.jetbrains.annotations.NotNull;
27 import org.openhab.binding.heos.internal.json.dto.HeosResponseObject;
28 import org.openhab.binding.heos.internal.json.payload.BrowseResult;
29 import org.openhab.binding.heos.internal.json.payload.Group;
30 import org.openhab.binding.heos.internal.json.payload.Media;
31 import org.openhab.binding.heos.internal.json.payload.Player;
32 import org.openhab.binding.heos.internal.resources.HeosCommands;
33 import org.openhab.binding.heos.internal.resources.HeosConstants;
34 import org.openhab.binding.heos.internal.resources.HeosEventListener;
35 import org.openhab.binding.heos.internal.resources.Telnet.ReadException;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
39 import com.google.gson.JsonElement;
42 * The {@link HeosFacade} is the interface for handling commands, which are
43 * sent to the HEOS system.
45 * @author Johannes Einig - Initial contribution
48 public class HeosFacade {
49 private static final int MAX_QUEUE_PAGES = 25;
50 private final Logger logger = LoggerFactory.getLogger(HeosFacade.class);
52 private final HeosSystem heosSystem;
53 private final HeosEventController eventController;
55 public HeosFacade(HeosSystem heosSystem, HeosEventController eventController) {
56 this.heosSystem = heosSystem;
57 this.eventController = eventController;
60 public synchronized List<BrowseResult> getFavorites() throws IOException, ReadException {
61 return getBrowseResults(FAVORITE_SID);
64 public List<BrowseResult> getInputs() throws IOException, ReadException {
65 return getBrowseResults(String.valueOf(INPUT_SID));
68 public List<BrowseResult> getPlaylists() throws IOException, ReadException {
69 return getBrowseResults(PLAYLISTS_SID);
73 private List<BrowseResult> getBrowseResults(String sourceIdentifier) throws IOException, ReadException {
74 HeosResponseObject<BrowseResult[]> response = browseSource(sourceIdentifier);
75 logger.debug("Response: {}", response);
77 if (response.payload == null) {
78 return Collections.emptyList();
80 logger.debug("Received results: {}", Arrays.asList(response.payload));
82 return Arrays.asList(response.payload);
85 public List<Media> getQueue(String pid) throws IOException, ReadException {
86 List<Media> media = new ArrayList<>();
87 for (int page = 0; page < MAX_QUEUE_PAGES; page++) {
88 HeosResponseObject<Media[]> response = fetchQueue(pid, page);
89 if (!response.result || response.payload == null) {
93 media.addAll(Arrays.asList(response.payload));
95 if (response.payload.length < 100) {
99 if (page == MAX_QUEUE_PAGES - 1) {
100 logger.info("Currently only a maximum of {} pages is fetched for every queue", MAX_QUEUE_PAGES);
107 HeosResponseObject<Media[]> fetchQueue(String pid, int page) throws IOException, ReadException {
108 return heosSystem.send(HeosCommands.getQueue(pid, page * 100, (page + 1) * 100), Media[].class);
111 public HeosResponseObject<Player> getPlayerInfo(String pid) throws IOException, ReadException {
112 return heosSystem.send(HeosCommands.getPlayerInfo(pid), Player.class);
115 public HeosResponseObject<Group> getGroupInfo(String gid) throws IOException, ReadException {
116 return heosSystem.send(HeosCommands.getGroupInfo(gid), Group.class);
120 * Pauses the HEOS player
122 * @param pid The PID of the dedicated player
124 public void pause(String pid) throws IOException, ReadException {
125 heosSystem.send(HeosCommands.setPlayStatePause(pid));
129 * Starts the HEOS player
131 * @param pid The PID of the dedicated player
133 public void play(String pid) throws IOException, ReadException {
134 heosSystem.send(HeosCommands.setPlayStatePlay(pid));
138 * Stops the HEOS player
140 * @param pid The PID of the dedicated player
142 public void stop(String pid) throws IOException, ReadException {
143 heosSystem.send(HeosCommands.setPlayStateStop(pid));
147 * Jumps to the next song on the HEOS player
149 * @param pid The PID of the dedicated player
151 public void next(String pid) throws IOException, ReadException {
152 heosSystem.send(HeosCommands.playNext(pid));
156 * Jumps to the previous song on the HEOS player
158 * @param pid The PID of the dedicated player
160 public void previous(String pid) throws IOException, ReadException {
161 heosSystem.send(HeosCommands.playPrevious(pid));
165 * Toggles the mute state the HEOS player
167 * @param pid The PID of the dedicated player
169 public void mute(String pid) throws IOException, ReadException {
170 heosSystem.send(HeosCommands.setMuteToggle(pid));
174 * Mutes the HEOS player
176 * @param pid The PID of the dedicated player
178 public void muteON(String pid) throws IOException, ReadException {
179 heosSystem.send(HeosCommands.setMuteOn(pid));
183 * Un-mutes the HEOS player
185 * @param pid The PID of the dedicated player
187 public void muteOFF(String pid) throws IOException, ReadException {
188 heosSystem.send(HeosCommands.setMuteOff(pid));
192 * Set the play mode of the player or group
194 * @param pid The PID of the dedicated player or group
195 * @param mode The shuffle mode: Allowed commands: on; off
197 public void setShuffleMode(String pid, String mode) throws IOException, ReadException {
198 heosSystem.send(HeosCommands.setShuffleMode(pid, mode));
202 * Sets the repeat mode of the player or group
204 * @param pid The ID of the dedicated player or group
205 * @param mode The repeat mode. Allowed commands: on_all; on_one; off
207 public void setRepeatMode(String pid, String mode) throws IOException, ReadException {
208 heosSystem.send(HeosCommands.setRepeatMode(pid, mode));
212 * Set the HEOS player to a dedicated volume
214 * @param vol The volume the player shall be set to (value between 0 -100)
215 * @param pid The ID of the dedicated player or group
217 public void setVolume(String vol, String pid) throws IOException, ReadException {
218 heosSystem.send(HeosCommands.setVolume(vol, pid));
222 * Increases the HEOS player volume 1 Step
224 * @param pid The ID of the dedicated player or group
226 public void increaseVolume(String pid) throws IOException, ReadException {
227 heosSystem.send(HeosCommands.volumeUp(pid));
231 * Decreases the HEOS player volume 1 Step
233 * @param pid The ID of the dedicated player or group
235 public void decreaseVolume(String pid) throws IOException, ReadException {
236 heosSystem.send(HeosCommands.volumeDown(pid));
240 * Toggles mute state of the HEOS group
242 * @param gid The GID of the group
244 public void muteGroup(String gid) throws IOException, ReadException {
245 heosSystem.send(HeosCommands.setMuteToggle(gid));
249 * Mutes the HEOS group
251 * @param gid The GID of the group
253 public void muteGroupON(String gid) throws IOException, ReadException {
254 heosSystem.send(HeosCommands.setGroupMuteOn(gid));
258 * Un-mutes the HEOS group
260 * @param gid The GID of the group
262 public void muteGroupOFF(String gid) throws IOException, ReadException {
263 heosSystem.send(HeosCommands.setGroupMuteOff(gid));
267 * Set the volume of the group to a specific level
269 * @param vol The volume the group shall be set to (value between 0-100)
270 * @param gid The GID of the group
272 public void volumeGroup(String vol, String gid) throws IOException, ReadException {
273 heosSystem.send(HeosCommands.setGroupVolume(vol, gid));
277 * Increases the HEOS group volume 1 Step
279 * @param gid The ID of the dedicated player or group
281 public void increaseGroupVolume(String gid) throws IOException, ReadException {
282 heosSystem.send(HeosCommands.setGroupVolumeUp(gid));
286 * Decreases the HEOS group volume 1 Step
288 * @param gid The ID of the dedicated player or group
290 public void decreaseGroupVolume(String gid) throws IOException, ReadException {
291 heosSystem.send(HeosCommands.setGroupVolumeDown(gid));
295 * Un-Group the HEOS group to single player
297 * @param gid The GID of the group
299 public void ungroupGroup(String gid) throws IOException, ReadException {
300 String[] pid = new String[] { gid };
301 heosSystem.send(HeosCommands.setGroup(pid));
305 * Builds a group from single players
307 * @param pids The single player IDs of the player which shall be grouped
310 public boolean groupPlayer(String[] pids) throws IOException, ReadException {
311 return heosSystem.send(HeosCommands.setGroup(pids)).result;
315 * Browses through a HEOS source. Currently no response
317 * @param sid The source sid which shall be browsed
320 public HeosResponseObject<BrowseResult[]> browseSource(String sid) throws IOException, ReadException {
321 return heosSystem.send(HeosCommands.browseSource(sid), BrowseResult[].class);
325 * Adds a media container to the queue and plays the media directly
326 * Information of the sid and cid has to be obtained via the browse function
328 * @param pid The player ID where the media object shall be played
329 * @param sid The source ID where the media is located
330 * @param cid The container ID of the media
332 public void addContainerToQueuePlayNow(String pid, String sid, String cid) throws IOException, ReadException {
333 heosSystem.send(HeosCommands.addContainerToQueuePlayNow(pid, sid, cid));
337 * Reboot the bridge to which the connection is established
339 public void reboot() throws IOException, ReadException {
340 heosSystem.send(HeosCommands.rebootSystem());
344 * Login in via the bridge to the HEOS account
346 * @param name The username
347 * @param password The password of the user
350 public HeosResponseObject<Void> logIn(String name, String password) throws IOException, ReadException {
351 return heosSystem.send(HeosCommands.signIn(name, password));
355 * Get all the players known by HEOS
359 public HeosResponseObject<Player[]> getPlayers() throws IOException, ReadException {
360 return heosSystem.send(HeosCommands.getPlayers(), Player[].class);
364 * Get all the groups known by HEOS
368 public HeosResponseObject<Group[]> getGroups() throws IOException, ReadException {
369 return heosSystem.send(HeosCommands.getGroups(), Group[].class);
373 * Plays a specific station on the HEOS player
375 * @param pid The player ID
376 * @param sid The source ID where the media is located
377 * @param cid The container ID of the media
378 * @param mid The media ID of the media
379 * @param name Station name returned by 'browse' command.
381 public void playStream(@Nullable String pid, @Nullable String sid, @Nullable String cid, @Nullable String mid,
382 @Nullable String name) throws IOException, ReadException {
383 heosSystem.send(HeosCommands.playStream(pid, sid, cid, mid, name));
387 * Plays a specific station on the HEOS player
389 * @param pid The player ID
390 * @param sid The source ID where the media is located
391 * @param mid The media ID of the media
393 public void playStream(String pid, String sid, String mid) throws IOException, ReadException {
394 heosSystem.send(HeosCommands.playStream(pid, sid, mid));
398 * Plays a specified local input source on the player.
399 * Input name as per specified in HEOS CLI Protocol
404 public void playInputSource(String pid, String input) throws IOException, ReadException {
405 heosSystem.send(HeosCommands.playInputSource(pid, pid, input));
409 * Plays a specified input source from another player on the selected player.
410 * Input name as per specified in HEOS CLI Protocol
412 * @param destinationPid the PID where the source shall be played
413 * @param sourcePid the PID where the source is located.
414 * @param input the input name
416 public void playInputSource(String destinationPid, String sourcePid, String input)
417 throws IOException, ReadException {
418 heosSystem.send(HeosCommands.playInputSource(destinationPid, sourcePid, input));
422 * Plays a file from a URL
424 * @param pid the PID where the file shall be played
425 * @param url the complete URL the file is located
427 public void playURL(String pid, URL url) throws IOException, ReadException {
428 heosSystem.send(HeosCommands.playURL(pid, url.toString()));
434 * @param pid The player ID the media is playing on
436 public void clearQueue(String pid) throws IOException, ReadException {
437 heosSystem.send(HeosCommands.clearQueue(pid));
441 * Deletes a media from the queue
443 * @param pid The player ID the media is playing on
444 * @param qid The queue ID of the media. (starts by 1)
446 public void deleteMediaFromQueue(String pid, String qid) throws IOException, ReadException {
447 heosSystem.send(HeosCommands.deleteQueueItem(pid, qid));
451 * Plays a specific media file from the queue
453 * @param pid The player ID the media shall be played on
454 * @param qid The queue ID of the media. (starts by 1)
456 public void playMediaFromQueue(String pid, String qid) throws IOException, ReadException {
457 heosSystem.send(HeosCommands.playQueueItem(pid, qid));
461 * Asks for the actual state of the player. The result has
462 * to be handled by the event controller. The system returns {@link HeosConstants.PLAY},
463 * {@link HeosConstants.PAUSE} or {@link HeosConstants.STOP}.
465 * @param id The player ID the state shall get for
468 public HeosResponseObject<Void> getPlayState(String id) throws IOException, ReadException {
469 return heosSystem.send(HeosCommands.getPlayState(id));
473 * Ask for the actual mute state of the player. The result has
474 * to be handled by the event controller. The HEOS system returns {@link HeosConstants.ON}
475 * or {@link HeosConstants.OFF}.
477 * @param id The player id the mute state shall get for
480 public HeosResponseObject<Void> getPlayerMuteState(String id) throws IOException, ReadException {
481 return heosSystem.send(HeosCommands.getMute(id));
485 * Ask for the actual volume the player. The result has
486 * to be handled by the event controller. The HEOS system returns
487 * a value between 0 and 100
489 * @param id The player id the volume shall get for
492 public HeosResponseObject<Void> getPlayerVolume(String id) throws IOException, ReadException {
493 return heosSystem.send(HeosCommands.getVolume(id));
497 * Ask for the actual shuffle mode of the player. The result has
498 * to be handled by the event controller. The HEOS system returns {@link HeosConstants.ON},
499 * {@link HeosConstants.HEOS_REPEAT_ALL} or {@link HeosConstants.HEOS_REPEAT_ONE}
501 * @param id The player id the shuffle mode shall get for
504 public HeosResponseObject<Void> getPlayMode(String id) throws IOException, ReadException {
505 return heosSystem.send(HeosCommands.getPlayMode(id));
508 public HeosResponseObject<Void> getGroupMuteState(String id) throws IOException, ReadException {
509 return heosSystem.send(HeosCommands.getGroupMute(id));
512 public HeosResponseObject<Void> getGroupVolume(String id) throws IOException, ReadException {
513 return heosSystem.send(HeosCommands.getGroupVolume(id));
516 public HeosResponseObject<Media> getNowPlayingMedia(String id) throws IOException, ReadException {
517 return heosSystem.send(HeosCommands.getNowPlayingMedia(id), Media.class);
521 * Sends a RAW command to the HEOS bridge. The command has to be
522 * in accordance with the HEOS CLI specification
524 * @param command to send
527 public HeosResponseObject<JsonElement> sendRawCommand(String command) throws IOException, ReadException {
528 return heosSystem.send(command, JsonElement.class);
532 * Register an {@link HeosEventListener} to get notification of system events
534 * @param listener The HeosEventListener
536 public void registerForChangeEvents(HeosEventListener listener) {
537 eventController.addListener(listener);
541 * Unregister an {@link HeosEventListener} to get notification of system events
543 * @param listener The HeosEventListener
545 public void unregisterForChangeEvents(HeosEventListener listener) {
546 eventController.removeListener(listener);
549 public boolean isConnected() {
550 return heosSystem.isConnected();
553 public void closeConnection() {
554 heosSystem.closeConnection();