2 * Copyright (c) 2010-2023 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.openhab.binding.heos.internal.json.dto.HeosResponseObject;
27 import org.openhab.binding.heos.internal.json.payload.BrowseResult;
28 import org.openhab.binding.heos.internal.json.payload.Group;
29 import org.openhab.binding.heos.internal.json.payload.Media;
30 import org.openhab.binding.heos.internal.json.payload.Player;
31 import org.openhab.binding.heos.internal.resources.HeosCommands;
32 import org.openhab.binding.heos.internal.resources.HeosConstants;
33 import org.openhab.binding.heos.internal.resources.HeosEventListener;
34 import org.openhab.binding.heos.internal.resources.Telnet.ReadException;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
38 import com.google.gson.JsonElement;
41 * The {@link HeosFacade} is the interface for handling commands, which are
42 * sent to the HEOS system.
44 * @author Johannes Einig - Initial contribution
47 public class HeosFacade {
48 private static final int MAX_QUEUE_PAGES = 25;
49 private final Logger logger = LoggerFactory.getLogger(HeosFacade.class);
51 private final HeosSystem heosSystem;
52 private final HeosEventController eventController;
54 public HeosFacade(HeosSystem heosSystem, HeosEventController eventController) {
55 this.heosSystem = heosSystem;
56 this.eventController = eventController;
59 public synchronized List<BrowseResult> getFavorites() throws IOException, ReadException {
60 return getBrowseResults(FAVORITE_SID);
63 public List<BrowseResult> getInputs() throws IOException, ReadException {
64 return getBrowseResults(String.valueOf(INPUT_SID));
67 public List<BrowseResult> getPlaylists() throws IOException, ReadException {
68 return getBrowseResults(PLAYLISTS_SID);
71 private List<BrowseResult> getBrowseResults(String sourceIdentifier) throws IOException, ReadException {
72 HeosResponseObject<BrowseResult[]> response = browseSource(sourceIdentifier);
73 logger.debug("Response: {}", response);
75 if (response.payload == null) {
76 return Collections.emptyList();
78 logger.debug("Received results: {}", Arrays.asList(response.payload));
80 return Arrays.asList(response.payload);
83 public List<Media> getQueue(String pid) throws IOException, ReadException {
84 List<Media> media = new ArrayList<>();
85 for (int page = 0; page < MAX_QUEUE_PAGES; page++) {
86 HeosResponseObject<Media[]> response = fetchQueue(pid, page);
87 if (!response.result || response.payload == null) {
91 media.addAll(Arrays.asList(response.payload));
93 if (response.payload.length < 100) {
97 if (page == MAX_QUEUE_PAGES - 1) {
98 logger.info("Currently only a maximum of {} pages is fetched for every queue", MAX_QUEUE_PAGES);
105 HeosResponseObject<Media[]> fetchQueue(String pid, int page) throws IOException, ReadException {
106 return heosSystem.send(HeosCommands.getQueue(pid, page * 100, (page + 1) * 100), Media[].class);
109 public HeosResponseObject<Player> getPlayerInfo(String pid) throws IOException, ReadException {
110 return heosSystem.send(HeosCommands.getPlayerInfo(pid), Player.class);
113 public HeosResponseObject<Group> getGroupInfo(String gid) throws IOException, ReadException {
114 return heosSystem.send(HeosCommands.getGroupInfo(gid), Group.class);
118 * Pauses the HEOS player
120 * @param pid The PID of the dedicated player
122 public void pause(String pid) throws IOException, ReadException {
123 heosSystem.send(HeosCommands.setPlayStatePause(pid));
127 * Starts the HEOS player
129 * @param pid The PID of the dedicated player
131 public void play(String pid) throws IOException, ReadException {
132 heosSystem.send(HeosCommands.setPlayStatePlay(pid));
136 * Stops the HEOS player
138 * @param pid The PID of the dedicated player
140 public void stop(String pid) throws IOException, ReadException {
141 heosSystem.send(HeosCommands.setPlayStateStop(pid));
145 * Jumps to the next song on the HEOS player
147 * @param pid The PID of the dedicated player
149 public void next(String pid) throws IOException, ReadException {
150 heosSystem.send(HeosCommands.playNext(pid));
154 * Jumps to the previous song on the HEOS player
156 * @param pid The PID of the dedicated player
158 public void previous(String pid) throws IOException, ReadException {
159 heosSystem.send(HeosCommands.playPrevious(pid));
163 * Toggles the mute state the HEOS player
165 * @param pid The PID of the dedicated player
167 public void mute(String pid) throws IOException, ReadException {
168 heosSystem.send(HeosCommands.setMuteToggle(pid));
172 * Mutes the HEOS player
174 * @param pid The PID of the dedicated player
176 public void muteON(String pid) throws IOException, ReadException {
177 heosSystem.send(HeosCommands.setMuteOn(pid));
181 * Un-mutes the HEOS player
183 * @param pid The PID of the dedicated player
185 public void muteOFF(String pid) throws IOException, ReadException {
186 heosSystem.send(HeosCommands.setMuteOff(pid));
190 * Set the play mode of the player or group
192 * @param pid The PID of the dedicated player or group
193 * @param mode The shuffle mode: Allowed commands: on; off
195 public void setShuffleMode(String pid, String mode) throws IOException, ReadException {
196 heosSystem.send(HeosCommands.setShuffleMode(pid, mode));
200 * Sets the repeat mode of the player or group
202 * @param pid The ID of the dedicated player or group
203 * @param mode The repeat mode. Allowed commands: on_all; on_one; off
205 public void setRepeatMode(String pid, String mode) throws IOException, ReadException {
206 heosSystem.send(HeosCommands.setRepeatMode(pid, mode));
210 * Set the HEOS player to a dedicated volume
212 * @param vol The volume the player shall be set to (value between 0 -100)
213 * @param pid The ID of the dedicated player or group
215 public void setVolume(String vol, String pid) throws IOException, ReadException {
216 heosSystem.send(HeosCommands.setVolume(vol, pid));
220 * Increases the HEOS player volume 1 Step
222 * @param pid The ID of the dedicated player or group
224 public void increaseVolume(String pid) throws IOException, ReadException {
225 heosSystem.send(HeosCommands.volumeUp(pid));
229 * Decreases the HEOS player volume 1 Step
231 * @param pid The ID of the dedicated player or group
233 public void decreaseVolume(String pid) throws IOException, ReadException {
234 heosSystem.send(HeosCommands.volumeDown(pid));
238 * Toggles mute state of the HEOS group
240 * @param gid The GID of the group
242 public void muteGroup(String gid) throws IOException, ReadException {
243 heosSystem.send(HeosCommands.setMuteToggle(gid));
247 * Mutes the HEOS group
249 * @param gid The GID of the group
251 public void muteGroupON(String gid) throws IOException, ReadException {
252 heosSystem.send(HeosCommands.setGroupMuteOn(gid));
256 * Un-mutes the HEOS group
258 * @param gid The GID of the group
260 public void muteGroupOFF(String gid) throws IOException, ReadException {
261 heosSystem.send(HeosCommands.setGroupMuteOff(gid));
265 * Set the volume of the group to a specific level
267 * @param vol The volume the group shall be set to (value between 0-100)
268 * @param gid The GID of the group
270 public void volumeGroup(String vol, String gid) throws IOException, ReadException {
271 heosSystem.send(HeosCommands.setGroupVolume(vol, gid));
275 * Increases the HEOS group volume 1 Step
277 * @param gid The ID of the dedicated player or group
279 public void increaseGroupVolume(String gid) throws IOException, ReadException {
280 heosSystem.send(HeosCommands.setGroupVolumeUp(gid));
284 * Decreases the HEOS group volume 1 Step
286 * @param gid The ID of the dedicated player or group
288 public void decreaseGroupVolume(String gid) throws IOException, ReadException {
289 heosSystem.send(HeosCommands.setGroupVolumeDown(gid));
293 * Un-Group the HEOS group to single player
295 * @param gid The GID of the group
297 public void ungroupGroup(String gid) throws IOException, ReadException {
298 String[] pid = new String[] { gid };
299 heosSystem.send(HeosCommands.setGroup(pid));
303 * Builds a group from single players
305 * @param pids The single player IDs of the player which shall be grouped
308 public boolean groupPlayer(String[] pids) throws IOException, ReadException {
309 return heosSystem.send(HeosCommands.setGroup(pids)).result;
313 * Browses through a HEOS source. Currently no response
315 * @param sid The source sid which shall be browsed
318 public HeosResponseObject<BrowseResult[]> browseSource(String sid) throws IOException, ReadException {
319 return heosSystem.send(HeosCommands.browseSource(sid), BrowseResult[].class);
323 * Adds a media container to the queue and plays the media directly
324 * Information of the sid and cid has to be obtained via the browse function
326 * @param pid The player ID where the media object shall be played
327 * @param sid The source ID where the media is located
328 * @param cid The container ID of the media
330 public void addContainerToQueuePlayNow(String pid, String sid, String cid) throws IOException, ReadException {
331 heosSystem.send(HeosCommands.addContainerToQueuePlayNow(pid, sid, cid));
335 * Reboot the bridge to which the connection is established
337 public void reboot() throws IOException, ReadException {
338 heosSystem.send(HeosCommands.rebootSystem());
342 * Login in via the bridge to the HEOS account
344 * @param name The username
345 * @param password The password of the user
348 public HeosResponseObject<Void> logIn(String name, String password) throws IOException, ReadException {
349 return heosSystem.send(HeosCommands.signIn(name, password));
353 * Get all the players known by HEOS
357 public HeosResponseObject<Player[]> getPlayers() throws IOException, ReadException {
358 return heosSystem.send(HeosCommands.getPlayers(), Player[].class);
362 * Get all the groups known by HEOS
366 public HeosResponseObject<Group[]> getGroups() throws IOException, ReadException {
367 return heosSystem.send(HeosCommands.getGroups(), Group[].class);
371 * Plays a specific station on the HEOS player
373 * @param pid The player ID
374 * @param sid The source ID where the media is located
375 * @param cid The container ID of the media
376 * @param mid The media ID of the media
377 * @param name Station name returned by 'browse' command.
379 public void playStream(@Nullable String pid, @Nullable String sid, @Nullable String cid, @Nullable String mid,
380 @Nullable String name) throws IOException, ReadException {
381 heosSystem.send(HeosCommands.playStream(pid, sid, cid, mid, name));
385 * Plays a specific station on the HEOS player
387 * @param pid The player ID
388 * @param sid The source ID where the media is located
389 * @param mid The media ID of the media
391 public void playStream(String pid, String sid, String mid) throws IOException, ReadException {
392 heosSystem.send(HeosCommands.playStream(pid, sid, mid));
396 * Plays a specified local input source on the player.
397 * Input name as per specified in HEOS CLI Protocol
402 public void playInputSource(String pid, String input) throws IOException, ReadException {
403 heosSystem.send(HeosCommands.playInputSource(pid, pid, input));
407 * Plays a specified input source from another player on the selected player.
408 * Input name as per specified in HEOS CLI Protocol
410 * @param destinationPid the PID where the source shall be played
411 * @param sourcePid the PID where the source is located.
412 * @param input the input name
414 public void playInputSource(String destinationPid, String sourcePid, String input)
415 throws IOException, ReadException {
416 heosSystem.send(HeosCommands.playInputSource(destinationPid, sourcePid, input));
420 * Plays a file from a URL
422 * @param pid the PID where the file shall be played
423 * @param url the complete URL the file is located
425 public void playURL(String pid, URL url) throws IOException, ReadException {
426 heosSystem.send(HeosCommands.playURL(pid, url.toString()));
432 * @param pid The player ID the media is playing on
434 public void clearQueue(String pid) throws IOException, ReadException {
435 heosSystem.send(HeosCommands.clearQueue(pid));
439 * Deletes a media from the queue
441 * @param pid The player ID the media is playing on
442 * @param qid The queue ID of the media. (starts by 1)
444 public void deleteMediaFromQueue(String pid, String qid) throws IOException, ReadException {
445 heosSystem.send(HeosCommands.deleteQueueItem(pid, qid));
449 * Plays a specific media file from the queue
451 * @param pid The player ID the media shall be played on
452 * @param qid The queue ID of the media. (starts by 1)
454 public void playMediaFromQueue(String pid, String qid) throws IOException, ReadException {
455 heosSystem.send(HeosCommands.playQueueItem(pid, qid));
459 * Asks for the actual state of the player. The result has
460 * to be handled by the event controller. The system returns {@link HeosConstants.PLAY},
461 * {@link HeosConstants.PAUSE} or {@link HeosConstants.STOP}.
463 * @param id The player ID the state shall get for
466 public HeosResponseObject<Void> getPlayState(String id) throws IOException, ReadException {
467 return heosSystem.send(HeosCommands.getPlayState(id));
471 * Ask for the actual mute state of the player. The result has
472 * to be handled by the event controller. The HEOS system returns {@link HeosConstants.ON}
473 * or {@link HeosConstants.OFF}.
475 * @param id The player id the mute state shall get for
478 public HeosResponseObject<Void> getPlayerMuteState(String id) throws IOException, ReadException {
479 return heosSystem.send(HeosCommands.getMute(id));
483 * Ask for the actual volume the player. The result has
484 * to be handled by the event controller. The HEOS system returns
485 * a value between 0 and 100
487 * @param id The player id the volume shall get for
490 public HeosResponseObject<Void> getPlayerVolume(String id) throws IOException, ReadException {
491 return heosSystem.send(HeosCommands.getVolume(id));
495 * Ask for the actual shuffle mode of the player. The result has
496 * to be handled by the event controller. The HEOS system returns {@link HeosConstants.ON},
497 * {@link HeosConstants.HEOS_REPEAT_ALL} or {@link HeosConstants.HEOS_REPEAT_ONE}
499 * @param id The player id the shuffle mode shall get for
502 public HeosResponseObject<Void> getPlayMode(String id) throws IOException, ReadException {
503 return heosSystem.send(HeosCommands.getPlayMode(id));
506 public HeosResponseObject<Void> getGroupMuteState(String id) throws IOException, ReadException {
507 return heosSystem.send(HeosCommands.getGroupMute(id));
510 public HeosResponseObject<Void> getGroupVolume(String id) throws IOException, ReadException {
511 return heosSystem.send(HeosCommands.getGroupVolume(id));
514 public HeosResponseObject<Media> getNowPlayingMedia(String id) throws IOException, ReadException {
515 return heosSystem.send(HeosCommands.getNowPlayingMedia(id), Media.class);
519 * Sends a RAW command to the HEOS bridge. The command has to be
520 * in accordance with the HEOS CLI specification
522 * @param command to send
525 public HeosResponseObject<JsonElement> sendRawCommand(String command) throws IOException, ReadException {
526 return heosSystem.send(command, JsonElement.class);
530 * Register an {@link HeosEventListener} to get notification of system events
532 * @param listener The HeosEventListener
534 public void registerForChangeEvents(HeosEventListener listener) {
535 eventController.addListener(listener);
539 * Unregister an {@link HeosEventListener} to get notification of system events
541 * @param listener The HeosEventListener
543 public void unregisterForChangeEvents(HeosEventListener listener) {
544 eventController.removeListener(listener);
547 public boolean isConnected() {
548 return heosSystem.isConnected();
551 public void closeConnection() {
552 heosSystem.closeConnection();