[lgwebos] Subscribe to Play/Pause state changes from the TV (#18119)
Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>main
parent
f51e8f6186
commit
89187cc645
|
@ -60,7 +60,7 @@ Thing lgwebos:WebOSTV:tv1 [host="192.168.2.119", key="6ef1dff6c7c936c8dc5056fc85
|
|||
| volume | Dimmer | Current volume setting. Setting and reporting absolute percent values only works when using internal speakers. When connected to an external amp, the volume should be controlled using increase and decrease commands. | RW |
|
||||
| channel | String | Current channel. Use the channel number or channel id as command to update the channel. | RW |
|
||||
| toast | String | Displays a short message on the TV screen. See also rules section. | W |
|
||||
| mediaPlayer | Player | Media control player | W |
|
||||
| mediaPlayer | Player | Media control player | RW |
|
||||
| mediaStop | Switch | Media control stop | W |
|
||||
| appLauncher | String | Application ID of currently running application. This also allows to start applications on the TV by sending a specific Application ID to this channel. | RW |
|
||||
| rcButton | String | Simulates pressing of a button on the TV's remote control. See below for a list of button names. | W |
|
||||
|
@ -69,6 +69,9 @@ The available application IDs for your TV can be listed using a console command
|
|||
You have to use one of these IDs as command for the appLauncher channel.
|
||||
Here are examples of values that could be available for your TV: airplay, amazon, com.apple.appletv, com.webos.app.browser, com.webos.app.externalinput.av1, com.webos.app.externalinput.av2, com.webos.app.externalinput.component, com.webos.app.hdmi1, com.webos.app.hdmi2, com.webos.app.hdmi3, com.webos.app.hdmi4, com.webos.app.homeconnect, com.webos.app.igallery, com.webos.app.livetv, com.webos.app.music, com.webos.app.photovideo, com.webos.app.recordings, com.webos.app.screensaver, googleplaymovieswebos, netflix, youtube.leanback.v4.
|
||||
|
||||
Older WebOS versions don't publish its play state, so the `mediaPlayer` channel is write-only.
|
||||
Starting from WebOS version 7, the `mediaPlayer` channel receives the PLAY/PAUSE state from the TV.
|
||||
|
||||
### Remote Control Buttons
|
||||
|
||||
This is a list of button codes that are known to work with several LG WebOS TV models.
|
||||
|
@ -131,7 +134,6 @@ String LG_TV0_Toast { channel="lgwebos:WebOSTV:3aab9eea
|
|||
Switch LG_TV0_Stop "Stop" { autoupdate="false", channel="lgwebos:WebOSTV:3aab9eea-953b-4272-bdbd-f0cd0ecf4a46:mediaStop" }
|
||||
String LG_TV0_Application "Application [%s]" { channel="lgwebos:WebOSTV:3aab9eea-953b-4272-bdbd-f0cd0ecf4a46:appLauncher"}
|
||||
Player LG_TV0_Player { channel="lgwebos:WebOSTV:3aab9eea-953b-4272-bdbd-f0cd0ecf4a46:mediaPlayer"}
|
||||
|
||||
```
|
||||
|
||||
demo.sitemap:
|
||||
|
|
|
@ -12,13 +12,21 @@
|
|||
*/
|
||||
package org.openhab.binding.lgwebos.internal;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.lgwebos.internal.handler.LGWebOSHandler;
|
||||
import org.openhab.binding.lgwebos.internal.handler.command.ServiceSubscription;
|
||||
import org.openhab.binding.lgwebos.internal.handler.core.AppInfo;
|
||||
import org.openhab.binding.lgwebos.internal.handler.core.CommandConfirmation;
|
||||
import org.openhab.binding.lgwebos.internal.handler.core.MediaAppInfo;
|
||||
import org.openhab.binding.lgwebos.internal.handler.core.ResponseListener;
|
||||
import org.openhab.core.library.types.PlayPauseType;
|
||||
import org.openhab.core.library.types.RewindFastforwardType;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -27,28 +35,72 @@ import org.slf4j.LoggerFactory;
|
|||
*
|
||||
*
|
||||
* @author Sebastian Prehn - Initial contribution
|
||||
* @author Jimmy Tanagra - Add play/pause state subscription
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class MediaControlPlayer extends BaseChannelHandler<CommandConfirmation> {
|
||||
public class MediaControlPlayer extends BaseChannelHandler<MediaAppInfo> {
|
||||
private final Logger logger = LoggerFactory.getLogger(MediaControlPlayer.class);
|
||||
private final ResponseListener<CommandConfirmation> commandConfirmationResponseListener = createResponseListener();
|
||||
|
||||
@Override
|
||||
public void onReceiveCommand(String channelId, LGWebOSHandler handler, Command command) {
|
||||
if (RefreshType.REFRESH == command) {
|
||||
// nothing to do
|
||||
handler.getSocket().getMediaState(createResponseListener(channelId, handler));
|
||||
} else if (PlayPauseType.PLAY == command) {
|
||||
handler.getSocket().play(getDefaultResponseListener());
|
||||
handler.getSocket().play(commandConfirmationResponseListener);
|
||||
} else if (PlayPauseType.PAUSE == command) {
|
||||
handler.getSocket().pause(getDefaultResponseListener());
|
||||
handler.getSocket().pause(commandConfirmationResponseListener);
|
||||
} else if (RewindFastforwardType.FASTFORWARD == command) {
|
||||
handler.getSocket().fastForward(getDefaultResponseListener());
|
||||
handler.getSocket().fastForward(commandConfirmationResponseListener);
|
||||
} else if (RewindFastforwardType.REWIND == command) {
|
||||
handler.getSocket().rewind(getDefaultResponseListener());
|
||||
handler.getSocket().rewind(commandConfirmationResponseListener);
|
||||
} else {
|
||||
logger.info("Only accept PlayPauseType, RewindFastforwardType, RefreshType. Type was {}.",
|
||||
command.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: playstatesubscription
|
||||
@Override
|
||||
protected Optional<ServiceSubscription<MediaAppInfo>> getSubscription(String channelId, LGWebOSHandler handler) {
|
||||
return Optional.of(handler.getSocket().subscribeMediaState(createResponseListener(channelId, handler)));
|
||||
}
|
||||
|
||||
private ResponseListener<MediaAppInfo> createResponseListener(String channelId, LGWebOSHandler handler) {
|
||||
return new ResponseListener<>() {
|
||||
@Override
|
||||
public void onError(@Nullable String error) {
|
||||
logger.debug("Error in retrieving application: {}.", error);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(@Nullable MediaAppInfo mediaAppInfo) {
|
||||
logger.trace("Received media app info: {}.", mediaAppInfo);
|
||||
if (mediaAppInfo == null || mediaAppInfo.getForegroundAppInfo() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mediaAppInfo.getForegroundAppInfo().isEmpty()) {
|
||||
handler.postUpdate(channelId, UnDefType.UNDEF);
|
||||
return;
|
||||
}
|
||||
|
||||
AppInfo appInfo = mediaAppInfo.getForegroundAppInfo().get(0);
|
||||
|
||||
if (appInfo == null || appInfo.getPlayState() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (appInfo.getPlayState()) {
|
||||
case "playing":
|
||||
handler.postUpdate(channelId, PlayPauseType.PLAY);
|
||||
break;
|
||||
case "paused":
|
||||
handler.postUpdate(channelId, PlayPauseType.PAUSE);
|
||||
break;
|
||||
default:
|
||||
handler.postUpdate(channelId, UnDefType.UNDEF);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,6 +71,7 @@ import org.openhab.binding.lgwebos.internal.handler.core.ChannelInfo;
|
|||
import org.openhab.binding.lgwebos.internal.handler.core.CommandConfirmation;
|
||||
import org.openhab.binding.lgwebos.internal.handler.core.LaunchSession;
|
||||
import org.openhab.binding.lgwebos.internal.handler.core.LaunchSession.LaunchSessionType;
|
||||
import org.openhab.binding.lgwebos.internal.handler.core.MediaAppInfo;
|
||||
import org.openhab.binding.lgwebos.internal.handler.core.Response;
|
||||
import org.openhab.binding.lgwebos.internal.handler.core.ResponseListener;
|
||||
import org.openhab.binding.lgwebos.internal.handler.core.TextInputStatusInfo;
|
||||
|
@ -88,12 +89,14 @@ import com.google.gson.reflect.TypeToken;
|
|||
*
|
||||
* @author Hyun Kook Khang - Initial contribution
|
||||
* @author Sebastian Prehn - Web Socket implementation and adoption for openHAB
|
||||
* @author Jimmy Tanagra - Add media state subscription
|
||||
*/
|
||||
@WebSocket()
|
||||
@NonNullByDefault
|
||||
public class LGWebOSTVSocket {
|
||||
|
||||
private static final String FOREGROUND_APP = "ssap://com.webos.applicationManager/getForegroundAppInfo";
|
||||
private static final String MEDIA_FOREGROUND_APP = "ssap://com.webos.media/getForegroundAppInfo";
|
||||
// private static final String APP_STATUS = "ssap://com.webos.service.appstatus/getAppStatus";
|
||||
// private static final String APP_STATE = "ssap://system.launcher/getAppState";
|
||||
private static final String VOLUME = "ssap://audio/getVolume";
|
||||
|
@ -733,6 +736,20 @@ public class LGWebOSTVSocket {
|
|||
sendCommand(request);
|
||||
}
|
||||
|
||||
public ServiceSubscription<MediaAppInfo> subscribeMediaState(ResponseListener<MediaAppInfo> listener) {
|
||||
ServiceSubscription<MediaAppInfo> request = new ServiceSubscription<>(MEDIA_FOREGROUND_APP, null,
|
||||
jsonObj -> GSON.fromJson(jsonObj, MediaAppInfo.class), listener);
|
||||
sendCommand(request);
|
||||
return request;
|
||||
}
|
||||
|
||||
public ServiceCommand<MediaAppInfo> getMediaState(ResponseListener<MediaAppInfo> listener) {
|
||||
ServiceCommand<MediaAppInfo> request = new ServiceCommand<>(MEDIA_FOREGROUND_APP, null,
|
||||
jsonObj -> GSON.fromJson(jsonObj, MediaAppInfo.class), listener);
|
||||
sendCommand(request);
|
||||
return request;
|
||||
}
|
||||
|
||||
// APPS
|
||||
|
||||
public void getAppList(final ResponseListener<List<AppInfo>> listener) {
|
||||
|
|
|
@ -50,14 +50,17 @@ public class AppInfo {
|
|||
private String id;
|
||||
@SerializedName(value = "name", alternate = { "appName", "title" })
|
||||
private String name;
|
||||
@SerializedName(value = "playState")
|
||||
private String playState; // see MediaAppInfo for possible values
|
||||
|
||||
public AppInfo() {
|
||||
// no-argument constructor for gson
|
||||
}
|
||||
|
||||
public AppInfo(String id, String name) {
|
||||
public AppInfo(String id, String name, String playState) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.playState = playState;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
|
@ -68,9 +71,13 @@ public class AppInfo {
|
|||
return name;
|
||||
}
|
||||
|
||||
public String getPlayState() {
|
||||
return playState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AppInfo [id=" + id + ", name=" + name + "]";
|
||||
return "AppInfo [id=" + id + ", name=" + name + ", playState=" + playState + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2025 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
|
||||
package org.openhab.binding.lgwebos.internal.handler.core;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* {@link MediaAppInfo} represents the payload that describes the foreground app's media state (playState) on WebOSTV.
|
||||
*
|
||||
* @author Jimmy Tanagra - Initial contribution
|
||||
*/
|
||||
public class MediaAppInfo {
|
||||
// Example payload:
|
||||
// {"subscribed":true,"returnValue":true,"foregroundAppInfo":[{"appId":"netflix","playState":"loaded","type":"media","mediaId":"_fdTzfnKXXXXX","windowId":"_Window_Id_1"}]}
|
||||
// playState values: starting, loaded, playing, paused
|
||||
private List<AppInfo> foregroundAppInfo;
|
||||
|
||||
public MediaAppInfo() {
|
||||
// no-argument constructor for gson
|
||||
}
|
||||
|
||||
public MediaAppInfo(List<AppInfo> foregroundAppInfo) {
|
||||
this.foregroundAppInfo = foregroundAppInfo;
|
||||
}
|
||||
|
||||
public List<AppInfo> getForegroundAppInfo() {
|
||||
return foregroundAppInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MediaAppInfo [foregroundAppInfo=" + foregroundAppInfo + "]";
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue