diff --git a/bundles/org.openhab.binding.roku/README.md b/bundles/org.openhab.binding.roku/README.md index 512d94ace17..9f5d7683e29 100644 --- a/bundles/org.openhab.binding.roku/README.md +++ b/bundles/org.openhab.binding.roku/README.md @@ -46,6 +46,8 @@ The following channels are available: | playMode | String | The current playback mode ie: stop, play, pause (ReadOnly). | | timeElapsed | Number:Time | The total number of seconds of playback time elapsed for the current playing title (ReadOnly). | | timeTotal | Number:Time | The total length of the current playing title in seconds (ReadOnly). This data is not provided by all streaming apps. | +| endTime | DateTime | The date/time when the currently playing media will end (ReadOnly). N/A if timeTotal is not provided by the current streaming app. | +| progress | Dimmer | The current progress [0-100%] of playing media (ReadOnly). N/A if timeTotal is not provided by the current streaming app. | | activeChannel | String | A dropdown containing a list of available TV channels on the Roku TV. The channel currently tuned is automatically selected. The list updates every 10 minutes. | | signalMode | String | The signal type of the current TV channel, ie: 1080i (ReadOnly). | | signalQuality | Number:Dimensionless | The signal quality of the current TV channel, 0-100% (ReadOnly). | @@ -59,6 +61,7 @@ The following channels are available: Some Notes: - The values for `activeApp`, `activeAppName`, `playMode`, `timeElapsed`, `timeTotal`, `activeChannel`, `signalMode`, `signalQuality`, `channelName`, `programTitle`, `programDescription`, `programRating`, `power` & `powerState` refresh automatically per the configured `refresh` interval. +- The `endTime` and `progress` channels may not be accurate for some streaming apps especially 'live' streams where the `timeTotal` value constantly increases. **List of available button commands for Roku streaming devices:** @@ -113,32 +116,36 @@ roku:roku_tv:mytv1 "My Roku TV" [ hostName="192.168.10.1", refresh=10 ] ```java // Roku streaming media player items: -String Player_ActiveApp "Current App: [%s]" { channel="roku:roku_player:myplayer1:activeApp" } -String Player_ActiveAppName "Current App Name: [%s]" { channel="roku:roku_player:myplayer1:activeAppName" } -String Player_Button "Send Command to Roku" { channel="roku:roku_player:myplayer1:button" } -Player Player_Control "Control" { channel="roku:roku_player:myplayer1:control" } -String Player_PlayMode "Status: [%s]" { channel="roku:roku_player:myplayer1:playMode" } -Number:Time Player_TimeElapsed "Elapsed Time: [%d %unit%]" { channel="roku:roku_player:myplayer1:timeElapsed" } -Number:Time Player_TimeTotal "Total Time: [%d %unit%]" { channel="roku:roku_player:myplayer1:timeTotal" } +String Player_ActiveApp "Current App: [%s]" { channel="roku:roku_player:myplayer1:activeApp" } +String Player_ActiveAppName "Current App Name: [%s]" { channel="roku:roku_player:myplayer1:activeAppName" } +String Player_Button "Send Command to Roku" { channel="roku:roku_player:myplayer1:button" } +Player Player_Control "Control" { channel="roku:roku_player:myplayer1:control" } +String Player_PlayMode "Status: [%s]" { channel="roku:roku_player:myplayer1:playMode" } +Number:Time Player_TimeElapsed "Elapsed Time: [%d %unit%]" { channel="roku:roku_player:myplayer1:timeElapsed" } +Number:Time Player_TimeTotal "Total Time: [%d %unit%]" { channel="roku:roku_player:myplayer1:timeTotal" } +DateTime Player_EndTime "End Time: [%1$tl:%1$tM %1$tp]" { channel="roku:roku_player:myplayer1:endTime" } +Dimmer Player_Progress "Progress [%.0f%%]" { channel="roku:roku_player:myplayer1:progress" } // Roku TV items: -Switch Player_Power "Power: [%s]" { channel="roku:roku_tv:mytv1:power" } -String Player_PowerState "Power State: [%s] { channel="roku:roku_tv:mytv1:powerState" } -String Player_ActiveApp "Current App: [%s]" { channel="roku:roku_tv:mytv1:activeApp" } -String Player_ActiveAppName "Current App Name: [%s]" { channel="roku:roku_tv:mytv1:activeAppName" } -String Player_Button "Send Command to Roku" { channel="roku:roku_tv:mytv1:button" } -Player Player_Control "Control" { channel="roku:roku_tv:mytv1:control" } -String Player_PlayMode "Status: [%s]" { channel="roku:roku_tv:mytv1:playMode" } -Number:Time Player_TimeElapsed "Elapsed Time: [%d %unit%]" { channel="roku:roku_tv:mytv1:timeElapsed" } -Number:Time Player_TimeTotal "Total Time: [%d %unit%]" { channel="roku:roku_tv:mytv1:timeTotal" } -String Player_ActiveChannel "Current Channel: [%s]" { channel="roku:roku_tv:mytv1:activeChannel" } -String Player_SignalMode "Signal Mode: [%s]" { channel="roku:roku_tv:mytv1:signalMode" } -Number Player_SignalQuality "Signal Quality: [%d %%]" { channel="roku:roku_tv:mytv1:signalQuality" } -String Player_ChannelName "Channel Name: [%s]" { channel="roku:roku_tv:mytv1:channelName" } -String Player_ProgramTitle "Program Title: [%s]" { channel="roku:roku_tv:mytv1:programTitle" } -String Player_ProgramDescription "Program Description: [%s]" { channel="roku:roku_tv:mytv1:programDescription" } -String Player_ProgramRating "Program Rating: [%s]" { channel="roku:roku_tv:mytv1:programRating" } +Switch Player_Power "Power: [%s]" { channel="roku:roku_tv:mytv1:power" } +String Player_PowerState "Power State: [%s] { channel="roku:roku_tv:mytv1:powerState" } +String Player_ActiveApp "Current App: [%s]" { channel="roku:roku_tv:mytv1:activeApp" } +String Player_ActiveAppName "Current App Name: [%s]" { channel="roku:roku_tv:mytv1:activeAppName" } +String Player_Button "Send Command to Roku" { channel="roku:roku_tv:mytv1:button" } +Player Player_Control "Control" { channel="roku:roku_tv:mytv1:control" } +String Player_PlayMode "Status: [%s]" { channel="roku:roku_tv:mytv1:playMode" } +Number:Time Player_TimeElapsed "Elapsed Time: [%d %unit%]" { channel="roku:roku_tv:mytv1:timeElapsed" } +Number:Time Player_TimeTotal "Total Time: [%d %unit%]" { channel="roku:roku_tv:mytv1:timeTotal" } +DateTime Player_EndTime "End Time: [%1$tl:%1$tM %1$tp]" { channel="roku:roku_tv:mytv1:endTime" } +Dimmer Player_Progress "Progress [%.0f%%]" { channel="roku:roku_tv:mytv1:progress" } +String Player_ActiveChannel "Current Channel: [%s]" { channel="roku:roku_tv:mytv1:activeChannel" } +String Player_SignalMode "Signal Mode: [%s]" { channel="roku:roku_tv:mytv1:signalMode" } +Number Player_SignalQuality "Signal Quality: [%d %%]" { channel="roku:roku_tv:mytv1:signalQuality" } +String Player_ChannelName "Channel Name: [%s]" { channel="roku:roku_tv:mytv1:channelName" } +String Player_ProgramTitle "Program Title: [%s]" { channel="roku:roku_tv:mytv1:programTitle" } +String Player_ProgramDescription "Program Description: [%s]" { channel="roku:roku_tv:mytv1:programDescription" } +String Player_ProgramRating "Program Rating: [%s]" { channel="roku:roku_tv:mytv1:programRating" } ``` ### `roku.sitemap` Example @@ -154,6 +161,8 @@ sitemap roku label="Roku" { Text item=Player_PlayMode Text item=Player_TimeElapsed icon="time" Text item=Player_TimeTotal icon="time" + Text item=Player_EndTime icon="time" + Slider item=Player_Progress icon="time" // The following items apply to Roku TVs only Switch item=Player_Power Text item=Player_PowerState diff --git a/bundles/org.openhab.binding.roku/src/main/java/org/openhab/binding/roku/internal/RokuBindingConstants.java b/bundles/org.openhab.binding.roku/src/main/java/org/openhab/binding/roku/internal/RokuBindingConstants.java index 514c468d8f5..8b2beb2d62c 100644 --- a/bundles/org.openhab.binding.roku/src/main/java/org/openhab/binding/roku/internal/RokuBindingConstants.java +++ b/bundles/org.openhab.binding.roku/src/main/java/org/openhab/binding/roku/internal/RokuBindingConstants.java @@ -55,6 +55,8 @@ public class RokuBindingConstants { public static final String PLAY_MODE = "playMode"; public static final String TIME_ELAPSED = "timeElapsed"; public static final String TIME_TOTAL = "timeTotal"; + public static final String END_TIME = "endTime"; + public static final String PROGRESS = "progress"; public static final String ACTIVE_CHANNEL = "activeChannel"; public static final String SIGNAL_MODE = "signalMode"; public static final String SIGNAL_QUALITY = "signalQuality"; diff --git a/bundles/org.openhab.binding.roku/src/main/java/org/openhab/binding/roku/internal/handler/RokuHandler.java b/bundles/org.openhab.binding.roku/src/main/java/org/openhab/binding/roku/internal/handler/RokuHandler.java index 6e21ba49869..8e0cd7c9242 100644 --- a/bundles/org.openhab.binding.roku/src/main/java/org/openhab/binding/roku/internal/handler/RokuHandler.java +++ b/bundles/org.openhab.binding.roku/src/main/java/org/openhab/binding/roku/internal/handler/RokuHandler.java @@ -14,6 +14,8 @@ package org.openhab.binding.roku.internal.handler; import static org.openhab.binding.roku.internal.RokuBindingConstants.*; +import java.math.BigDecimal; +import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -34,8 +36,10 @@ import org.openhab.binding.roku.internal.dto.DeviceInfo; import org.openhab.binding.roku.internal.dto.Player; import org.openhab.binding.roku.internal.dto.TvChannel; import org.openhab.binding.roku.internal.dto.TvChannels.Channel; +import org.openhab.core.library.types.DateTimeType; import org.openhab.core.library.types.NextPreviousType; import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.PercentType; import org.openhab.core.library.types.PlayPauseType; import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.types.StringType; @@ -195,21 +199,32 @@ public class RokuHandler extends BaseThingHandler { PLAY.equalsIgnoreCase(playerInfo.getState()) ? PlayPauseType.PLAY : PlayPauseType.PAUSE); // Remove non-numeric from string, ie: ' ms' - String position = playerInfo.getPosition().replaceAll(NON_DIGIT_PATTERN, EMPTY); - if (!EMPTY.equals(position)) { - updateState(TIME_ELAPSED, - new QuantityType<>(Integer.parseInt(position) / 1000, API_SECONDS_UNIT)); + final String positionStr = playerInfo.getPosition().replaceAll(NON_DIGIT_PATTERN, EMPTY); + int position = -1; + if (!EMPTY.equals(positionStr)) { + position = Integer.parseInt(positionStr) / 1000; + updateState(TIME_ELAPSED, new QuantityType<>(position, API_SECONDS_UNIT)); } else { updateState(TIME_ELAPSED, UnDefType.UNDEF); } - String duration = playerInfo.getDuration().replaceAll(NON_DIGIT_PATTERN, EMPTY); - if (!EMPTY.equals(duration)) { - updateState(TIME_TOTAL, - new QuantityType<>(Integer.parseInt(duration) / 1000, API_SECONDS_UNIT)); + final String durationStr = playerInfo.getDuration().replaceAll(NON_DIGIT_PATTERN, EMPTY); + int duration = -1; + if (!EMPTY.equals(durationStr)) { + duration = Integer.parseInt(durationStr) / 1000; + updateState(TIME_TOTAL, new QuantityType<>(duration, API_SECONDS_UNIT)); } else { updateState(TIME_TOTAL, UnDefType.UNDEF); } + + if (position >= 0 && duration > 0) { + updateState(END_TIME, new DateTimeType(Instant.now().plusSeconds(duration - position))); + updateState(PROGRESS, + new PercentType(BigDecimal.valueOf(Math.round(position / (double) duration * 100.0)))); + } else { + updateState(END_TIME, UnDefType.UNDEF); + updateState(PROGRESS, UnDefType.UNDEF); + } } catch (NumberFormatException e) { logger.debug("Unable to parse playerInfo integer value. Exception: {}", e.getMessage()); } catch (RokuLimitedModeException e) { @@ -224,6 +239,8 @@ public class RokuHandler extends BaseThingHandler { updateState(PLAY_MODE, UnDefType.UNDEF); updateState(TIME_ELAPSED, UnDefType.UNDEF); updateState(TIME_TOTAL, UnDefType.UNDEF); + updateState(END_TIME, UnDefType.UNDEF); + updateState(PROGRESS, UnDefType.UNDEF); } if (thingTypeUID.equals(THING_TYPE_ROKU_TV) && tvActive) { diff --git a/bundles/org.openhab.binding.roku/src/main/resources/OH-INF/i18n/roku.properties b/bundles/org.openhab.binding.roku/src/main/resources/OH-INF/i18n/roku.properties index cc4c681250a..5f6add8a605 100644 --- a/bundles/org.openhab.binding.roku/src/main/resources/OH-INF/i18n/roku.properties +++ b/bundles/org.openhab.binding.roku/src/main/resources/OH-INF/i18n/roku.properties @@ -80,6 +80,8 @@ channel-type.roku.channelName.label = Channel Name channel-type.roku.channelName.description = The Name of the Channel Currently Selected channel-type.roku.control.label = Control channel-type.roku.control.description = Control playback e.g. Play/Pause/Next/Previous +channel-type.roku.endTime.label = End Time +channel-type.roku.endTime.description = The date/time when the currently playing media will end channel-type.roku.playMode.label = Play Mode channel-type.roku.playMode.description = The Current Playback Mode channel-type.roku.powerState.label = Power State @@ -93,6 +95,8 @@ channel-type.roku.programRating.label = Program Rating channel-type.roku.programRating.description = The TV Parental Guideline Rating of the Current TV Program channel-type.roku.programTitle.label = Program Title channel-type.roku.programTitle.description = The Name of the Current TV Program +channel-type.roku.progress.label = Media Progress +channel-type.roku.progress.description = The current progress of playing media channel-type.roku.signalMode.label = Signal Mode channel-type.roku.signalMode.description = The Signal Type of the Current TV Channel, ie: 1080i channel-type.roku.signalQuality.label = Signal Quality diff --git a/bundles/org.openhab.binding.roku/src/main/resources/OH-INF/thing/roku.xml b/bundles/org.openhab.binding.roku/src/main/resources/OH-INF/thing/roku.xml index 78e995536d5..284560cbfe1 100644 --- a/bundles/org.openhab.binding.roku/src/main/resources/OH-INF/thing/roku.xml +++ b/bundles/org.openhab.binding.roku/src/main/resources/OH-INF/thing/roku.xml @@ -19,6 +19,8 @@ + + @@ -28,7 +30,7 @@ unknown unknown unknown - 1 + 2 uuid @@ -52,6 +54,8 @@ + + @@ -69,7 +73,7 @@ unknown unknown unknown - 1 + 2 uuid @@ -185,6 +189,24 @@ + + DateTime + + The date/time when the currently playing media will end + Time + + Status + Timestamp + + + + + + Dimmer + + The current progress of playing media + + String diff --git a/bundles/org.openhab.binding.roku/src/main/resources/OH-INF/update/update.xml b/bundles/org.openhab.binding.roku/src/main/resources/OH-INF/update/update.xml index 8979f15e63c..81dac71325d 100644 --- a/bundles/org.openhab.binding.roku/src/main/resources/OH-INF/update/update.xml +++ b/bundles/org.openhab.binding.roku/src/main/resources/OH-INF/update/update.xml @@ -12,6 +12,15 @@ roku:control + + + + roku:endTime + + + roku:progress + + @@ -29,6 +38,15 @@ roku:control + + + + roku:endTime + + + roku:progress + +