Template Example: Multimedia / Menu Navigation

Design challenge:

  • Insufficient space on my Tivo panel layout to incorporate all the required media playback buttons,navigation buttons (and all the other stuff :grinning:) needed without scrolling.
  • I want to lay these out in an intuitive way (same 3 by 3 grid layout as the original remote uses).

Idea:

  • Create a ā€œminiā€ panel widget that would allow me to scroll between individual ā€œpagesā€ of controls for each function (much like the image carousel within the templates example post).
  • Ideally I could swipe on my tablet to move between ā€œpagesā€.
  • Could re-use for panels where there are lots of buttons / functions that donā€™t get used much but still need to be available i.e. cleaner less cluttered layouts etc.

Result:

To implement:

  • Create a template widget on the required panel.
  • I wanted my buttons to be close to the same size as the standard button widgets on my panel so I sized this to 3 x 3 grid sections.
  • Remove the check mark from the Don't wrap in container option and check the No background option
  • Copy the code below.
<style>
	.tivobutton {width: 100%; height: 4em; border: 0; color: white; background: #424242;}
	.modgrid {padding-left: 2px; padding-right: 2px; padding-top: 2px; padding-bottom: 2px;}
	.butticon {font-size:2em;}
</style>
<div id="tivo-mediaplay"  class="table" ng-show="!showActions" ng-swipe-left="showActions = true" ng-swipe-right="showActions = true">
	<div class="row">
		<div class="col-xs-4 modgrid">
		</div>
		<div class="col-xs-4 modgrid">
			<button class="tivobutton" ng-click="sendCmd('TiVo_IRCmd', 'PLAY')">
				<i class="glyphicon glyphicon-play butticon" alt="Play"></i>
			</button>
		</div>
		<div class="col-xs-4 modgrid">
		</div>
	</div>
	<div  class="row">
		<div class="col-xs-4 modgrid">
			<button class="tivobutton" ng-click="sendCmd('TiVo_IRCmd', 'REVERSE')">
				<i class="glyphicon glyphicon-backward butticon" alt="Backward"></i>
			</button>
		</div>
		<div class="col-xs-4 modgrid">
			<button style="background: #FFCC00; color:black" class="tivobutton" ng-click="sendCmd('TiVo_IRCmd', 'PAUSE')">
				<i class="glyphicon glyphicon-pause butticon" alt="Pause"></i>
			</button>
		</div>
		<div class="col-xs-4 modgrid">
			<button class="tivobutton" ng-click="sendCmd('TiVo_IRCmd', 'FORWARD')">
				<i class="glyphicon glyphicon-forward butticon" alt="Forward"></i>
			</button>
		</div>
	</div>
	<div  class="row">
		<div class="col-xs-4 modgrid">
		<button class="tivobutton" style="background: #666666; color:black;" ng-click="sendCmd('TiVo_IRCmd', 'REPLAY')">
				<i class="glyphicon glyphicon-step-backward butticon" alt="Step Backward"></i>
			</button>
		</div>	
		<div class="col-xs-4 modgrid">
			<button class="tivobutton" ng-click="sendCmd('TiVo_IRCmd', 'STOP')">
				<i class="glyphicon glyphicon-stop butticon" alt="Stop"></i>
			</button>
		</div>
		<div class="col-xs-4 modgrid">
			<button class="tivobutton" style="background: #666666; color:black;" ng-click="sendCmd('TiVo_IRCmd', 'ADVANCE')">
				<i class="glyphicon glyphicon-step-forward butticon" alt="Step Forward"></i>
			</button>
		</div>
	</div>
	<div  class="row" style="padding-top: 18px">
		<div class="col-xs-12">
			<button  style="width: 2em; height: 2em; border: 0; color: white; background: #0db9f0" ng-click="showActions = false">
			1
			</button>
			  
			<button style="width: 2em; height: 2em; border: 0; color: white; background: #666666" ng-click="showActions = true">
			2
			</button>
		</div>
	</div>
</div>

<div id="tivo-mediaplay"  class="table"  ng-show="showActions" ng-swipe-left="showActions = false" ng-swipe-right="showActions = false">
	<div  class="row">
		<div class="col-xs-4 modgrid">
		</div>
		<div class="col-xs-4 modgrid">
			<button class="tivobutton" ng-click="sendCmd('TiVo_IRCmd', 'UP')">
				<i class="glyphicon glyphicon-triangle-top butticon" alt="Up"></i>
			</button>
		</div>
		<div class="col-xs-4 modgrid">
		</div>
	</div>
	<div class="row">
		<div class="col-xs-4 modgrid">
			<button class="tivobutton" ng-click="sendCmd('TiVo_IRCmd', 'LEFT')">
				<i class="glyphicon  glyphicon-triangle-left butticon" alt="Left"></i>
			</button>
		</div>
		<div class="col-xs-4 modgrid">
			<button class="tivobutton" style="background: #666666" ng-click="sendCmd('TiVo_IRCmd', 'SELECT')">
				OK
			</button>
		</div>
		<div class="col-xs-4 modgrid">
			<button class="tivobutton" ng-click="sendCmd('TiVo_IRCmd', 'RIGHT')">
				<i class="glyphicon  glyphicon-triangle-right butticon" alt="Right"></i>
			</button>
		</div>
	</div>
	<div class="row">
		<div class="col-xs-4 modgrid">
		</div>
		<div class="col-xs-4 modgrid">
			<button class="tivobutton" ng-click="sendCmd('TiVo_IRCmd', 'DOWN')">
				<i class="glyphicon  glyphicon-triangle-bottom butticon" alt="Down"></i>
			</button>
		</div>
		<div class="col-xs-4 modgrid">
		</div>
	</div>
		<div class="row"style="padding-top: 18px">
		<div class="col-xs-12">
			<button  style="width: 2em; height: 2em; border: 0; color: white; background: #666666" ng-click="showActions = false">
			1
			</button>
			  
			<button style="width: 2em; height: 2em; border: 0; color: white; background: #0db9f0" ng-click="showActions = true">
			2
			</button>
		</div>
	</div>
</div>

Notes / Limitations:

  • The code implements the ng-swipe-left and ng-swipe-right functionality / code. This allows you to swipe on a supported browser / touch based device to change the ā€œpageā€ that is displayed.

  • You can also navigate between pages simply select the appropriate grey page button (smaller numbered buttons at base of cluster).

  • You may need to tweak the values within the <style> section to change the vertical height of the objects to get a good fit for your panel layout. The .tivobutton style definition, height: 4em property can be increased / decreased as required.

  • You may also want to modify the padding adjustment within the .modgrid style (I needed this to line up items with the standard widgets).

Customizing:

  • Simply change the ng-click action for each of the buttons to modify the usage for other media devices etc.

The widget in place within the Tivo panel (page 1 of 2 shown):

Enjoy and if anyone has any suggestions for improvements / better ways to achieve things (especially the vertical ā€˜justificationā€™ of stuff within the widget container) let me know.

Andy

6 Likes

@AndyMB great stuff again, and a very detailed tutorial no less!
Iā€™ll add ng-touch later this week (not able to code now) - it was a matter of time and priorities anyway, and Iā€™m curious to see how this ng-swipe-left behaves.

Do I dare admit that one part of the ā€œday jobā€ is to write technical design docs for non-techinal audiencesā€¦ I always seem to slip into comprehensive mode when documenting stuff :wink:

Superb and thanks :triumph: Iā€™m loving this little space saver, already doing a version for my Kodi / XBMC setup in the bedroomā€¦

Andy

Iā€™m back and was in the mood so ā€œlater this weekā€ means now :slight_smile:

I tried it with both your template and the carousel example and it seems to work nicely, with no apparent side effects to the rest of the appā€¦ so there you go.

You might change to a ng-swipe-right in your tivo-mediaplay div, it feels more natural :wink:

@ysc, thanks for making the enhancement for me / the community. Sorry for the delay in responding, Iā€™ve been away for a week doing some DIY tasks for Dad. Updated OpenHAB yesterday, tested and the code is working great.

Iā€™m going to add the ng-swipe-right to the original code / post in addition to the ng-swipe-left as this provided the most intuitive UI experience.

Thanks again, Andy

@AndyMB Would you be able to share your entire habpanel? Specifically Iā€™m interested in how you implemented Auto Pause and Standby, but I like the full design.

@jahubba, really sorry I missed your request. This is quite complicated, but here goesā€¦

Here is the JSON for the TiVo panel (requires a 6 column grid set-up). Study the JSON structure and take care when you are pasting into the advanced editor and take suitable backups etc. Learn from MY mistakes :wink:

Dohā€¦ brain failure, easier to use the link below to download and import etc. This is the single panel for Tivo.
Exported HabPannel

and a download of the location.rules:
location.rules

   {
        "id": "Multimedia",
        "name": "Tivo",
        "widgets": [
            {
                "name": "My Shows",
                "sizeX": 2,
                "sizeY": 2,
                "item": "TiVo_IRCmd",
                "type": "button",
                "row": 9,
                "col": 6,
                "command": "NOWSHOWING",
                "background": "#666666",
                "background_active": "#666666"
            },
            {
                "name": "Tivo Status",
                "sizeX": 10,
                "sizeY": 2,
                "item": "TiVo_Command_Result",
                "type": "dummy",
                "row": 1,
                "col": 0,
                "iconset": "freepik-household",
                "icon": "television-2",
                "icon_size": 32,
                "icon_nolinebreak": true
            },
            {
                "name": "TV Power",
                "sizeX": 2,
                "sizeY": 2,
                "item": "Power1_GF_Living",
                "type": "switch",
                "row": 1,
                "col": 10,
                "iconset": "freepik-housethings",
                "icon": "electric-socket",
                "icon_size": 32
            },
            {
                "name": "Home",
                "sizeX": 2,
                "sizeY": 2,
                "item": "TiVo_IRCmd",
                "type": "button",
                "row": 9,
                "col": 4,
                "command": "TIVO",
                "background": "#666666",
                "background_active": "#666666"
            },
            {
                "name": "Window",
                "sizeX": 2,
                "sizeY": 2,
                "item": "TiVo_IRCmd",
                "type": "button",
                "row": 9,
                "col": 10,
                "command": "WINDOW",
                "background": "#666666",
                "background_active": "#666666"
            },
            {
                "name": "Volume",
                "sizeX": 2,
                "sizeY": 6,
                "item": "SaTV_Volume",
                "type": "slider",
                "row": 3,
                "col": 0,
                "vertical": true,
                "floor": 0,
                "ceil": 25,
                "step": 1
            },
            {
                "name": "TV",
                "sizeX": 2,
                "sizeY": 2,
                "item": "TiVo_IRCmd",
                "type": "button",
                "row": 9,
                "col": 2,
                "command": "TV",
                "background": "#666666",
                "background_active": "#666666"
            },
            {
                "name": "Guide",
                "sizeX": 2,
                "sizeY": 2,
                "item": "TiVo_IRCmd",
                "type": "button",
                "row": 9,
                "col": 8,
                "command": "GUIDE",
                "background": "#666666",
                "background_active": "#666666"
            },
            {
                "name": "Mute",
                "sizeX": 2,
                "sizeY": 2,
                "item": "TiVo_IRCmd",
                "type": "button",
                "row": 9,
                "col": 0,
                "command": "MUTE",
                "background": "#666666",
                "background_active": "#666666"
            },
            {
                "name": "Lamp",
                "sizeX": 2,
                "sizeY": 2,
                "item": "Power2_GF_Living",
                "type": "switch",
                "row": 11,
                "col": 0,
                "hidelabel": false,
                "iconset": "freepik-household",
                "icon": "lamp-5",
                "icon_size": 32
            },
            {
                "name": "BBC 1 HD",
                "sizeX": 2,
                "sizeY": 1,
                "item": "TiVo_Fav_Channel",
                "type": "button",
                "row": 14,
                "col": 0,
                "command": "SETCH 108",
                "background": "#0099CC",
                "background_active": "#0099CC"
            },
            {
                "name": "Auto Pause",
                "sizeX": 2,
                "sizeY": 2,
                "item": "Tivo_AutoPause",
                "type": "switch",
                "row": 3,
                "col": 10,
                "hideicon": true
            },
            {
                "name": "CH4 HD",
                "sizeX": 2,
                "sizeY": 1,
                "item": "TiVo_Fav_Channel",
                "type": "button",
                "row": 14,
                "col": 6,
                "command": "SETCH 142",
                "background": "#0099CC",
                "background_active": "#0099CC"
            },
            {
                "name": "SyFi",
                "sizeX": 2,
                "sizeY": 1,
                "item": "TiVo_Fav_Channel",
                "type": "button",
                "row": 15,
                "col": 2,
                "command": "SETCH 135",
                "background": "#0099CC",
                "background_active": "#0099CC"
            },
            {
                "name": "Film4 HD",
                "sizeX": 2,
                "sizeY": 1,
                "item": "TiVo_Fav_Channel",
                "type": "button",
                "row": 15,
                "col": 10,
                "command": "SETCH 429",
                "background": "#0099CC",
                "background_active": "#0099CC"
            },
            {
                "name": "Sky 1",
                "sizeX": 2,
                "sizeY": 1,
                "item": "TiVo_Fav_Channel",
                "type": "button",
                "row": 15,
                "col": 0,
                "command": "SETCH 110",
                "background": "#0099CC",
                "background_active": "#0099CC"
            },
            {
                "name": "Channel",
                "sizeX": 2,
                "sizeY": 6,
                "item": null,
                "type": "template",
                "row": 3,
                "col": 8,
                "template": "<button style=\"width: 100%; height: 100%;\nborder: 0; color: white; background: #FFCC00;\nfont-size: 30px\" ng-click=\"sendCmd('TiVo_SetPoint', (itemValue('TiVo_SetPoint')-0+1))\">\n<i class=\"glyphicon glyphicon-menu-up\"></i>\n</button>\n\n<p>Channel<br/>\n{{itemValue('TiVo_SetPoint')}}</p>\n\n<button style=\"width: 100%; height: 100%;\nborder: 0; color: white; background: #FFCC00;\nfont-size: 30px\" ng-click=\"sendCmd('TiVo_SetPoint', (0 + itemValue('TiVo_SetPoint')-1))\">\n<i class=\"glyphicon glyphicon-menu-down\"></i>\n</button>"
            },
            {
                "name": "New Widget",
                "sizeX": 2,
                "sizeY": 2,
                "item": null,
                "type": "template",
                "row": 5,
                "col": 10,
                "template": "<div ng-if=\"itemValue('Tivo_PlayPause')==1\">\n  <button class=\"btn btn-dg\" style=\"width: 100%; height: 100%\"\n  ng-click=\"sendCmd('Tivo_PlayPause', 2)\">\n  <small>Pause</small>\n  </button>\n</div>\n\n<div ng-if=\"itemValue('Tivo_PlayPause')==2\">\n  <button class=\"btn btn-dg\" style=\"width: 100%; height: 100%\"\n  ng-click=\"sendCmd('Tivo_PlayPause', 1)\">\n  <small>Play</small>\n  </button>\n</div>"
            },
            {
                "name": "BBC R1",
                "sizeX": 2,
                "sizeY": 2,
                "item": "TiVo_Fav_Channel",
                "type": "button",
                "row": 16,
                "col": 0,
                "command": "SETCH 901",
                "background": "transparent",
                "background_active": "transparent"
            },
            {
                "name": "BBC R2",
                "sizeX": 2,
                "sizeY": 2,
                "item": "TiVo_Fav_Channel",
                "type": "button",
                "row": 16,
                "col": 2,
                "command": "SETCH 902",
                "background": "transparent",
                "background_active": "transparent"
            },
            {
                "name": "BBC R4",
                "sizeX": 2,
                "sizeY": 2,
                "item": "TiVo_Fav_Channel",
                "type": "button",
                "row": 16,
                "col": 4,
                "command": "SETCH 904",
                "background": "transparent",
                "background_active": "transparent"
            },
            {
                "name": "E4",
                "sizeX": 2,
                "sizeY": 1,
                "item": "TiVo_Fav_Channel",
                "type": "button",
                "row": 15,
                "col": 4,
                "command": "SETCH  144",
                "background": "#0099CC",
                "background_active": "#0099CC"
            },
            {
                "name": "Absolute 80s",
                "sizeX": 2,
                "sizeY": 2,
                "item": "TiVo_Fav_Channel",
                "type": "button",
                "row": 16,
                "col": 6,
                "command": "SETCH 951",
                "background": "transparent",
                "background_active": "transparent"
            },
            {
                "name": "Classic FM",
                "sizeX": 2,
                "sizeY": 2,
                "item": "TiVo_Fav_Channel",
                "type": "button",
                "row": 16,
                "col": 8,
                "command": "SETCH 922",
                "background": "transparent",
                "background_active": "transparent"
            },
            {
                "name": "Favourites",
                "sizeX": 12,
                "sizeY": 1,
                "item": null,
                "type": "label",
                "row": 13,
                "col": 0,
                "background": "#999999"
            },
            {
                "name": "Tivo",
                "sizeX": 12,
                "sizeY": 1,
                "item": null,
                "type": "label",
                "row": 0,
                "col": 0,
                "background": "#999999"
            },
            {
                "name": "BBC 2 HD",
                "sizeX": 2,
                "sizeY": 1,
                "item": "TiVo_Fav_Channel",
                "type": "button",
                "row": 14,
                "col": 2,
                "command": "SETCH 162",
                "background": "#0099CC",
                "background_active": "#0099CC"
            },
            {
                "name": "ITV 1 HD",
                "sizeX": 2,
                "sizeY": 1,
                "item": "TiVo_Fav_Channel",
                "type": "button",
                "row": 14,
                "col": 4,
                "command": "SETCH  113",
                "background": "#0099CC",
                "background_active": "#0099CC"
            },
            {
                "name": "CH 5 HD",
                "sizeX": 2,
                "sizeY": 1,
                "item": "TiVo_Fav_Channel",
                "type": "button",
                "row": 14,
                "col": 8,
                "command": "SETCH 150",
                "background": "#0099CC",
                "background_active": "#0099CC"
            },
            {
                "name": "BBC 4 HD",
                "sizeX": 2,
                "sizeY": 1,
                "item": "TiVo_Fav_Channel",
                "type": "button",
                "row": 14,
                "col": 10,
                "command": "SETCH 163",
                "background": "#0099CC",
                "background_active": "#0099CC"
            },
            {
                "name": "Standby",
                "sizeX": 2,
                "sizeY": 2,
                "item": "TiVo_IRCmd",
                "type": "button",
                "row": 7,
                "col": 10,
                "command": "STANDBY",
                "iconset": "smarthome-set",
                "icon": "power-button",
                "icon_size": 32
            },
            {
                "name": "TivoControl",
                "sizeX": 6,
                "sizeY": 6,
                "item": null,
                "type": "template",
                "row": 3,
                "col": 2,
                "template": "<style>\n\t.tivobutton {width: 100%; height: 4em; border: 0; color: white; background: #424242;}\n\t.modgrid {padding-left: 2px; padding-right: 2px; padding-top: 2px; padding-bottom: 2px;}\n\t.butticon {font-size:2em;}\n</style>\n<div id=\"tivo-mediaplay\"  class=\"table\" ng-show=\"!showActions\" ng-swipe-left=\"showActions = true\">\n\t<div class=\"row\">\n\t\t<div class=\"col-xs-4 modgrid\">\n\t\t</div>\n\t\t<div class=\"col-xs-4 modgrid\">\n\t\t\t<button class=\"tivobutton\" ng-click=\"sendCmd('TiVo_IRCmd', 'PLAY')\">\n\t\t\t\t<i class=\"glyphicon glyphicon-play butticon\" alt=\"Play\"></i>\n\t\t\t</button>\n\t\t</div>\n\t\t<div class=\"col-xs-4 modgrid\">\n\t\t</div>\n\t</div>\n\t<div  class=\"row\">\n\t\t<div class=\"col-xs-4 modgrid\">\n\t\t\t<button class=\"tivobutton\" ng-click=\"sendCmd('TiVo_IRCmd', 'REVERSE')\">\n\t\t\t\t<i class=\"glyphicon glyphicon-backward butticon\" alt=\"Backward\"></i>\n\t\t\t</button>\n\t\t</div>\n\t\t<div class=\"col-xs-4 modgrid\">\n\t\t\t<button style=\"background: #FFCC00; color:black\" class=\"tivobutton\" ng-click=\"sendCmd('TiVo_IRCmd', 'PAUSE')\">\n\t\t\t\t<i class=\"glyphicon glyphicon-pause butticon\" alt=\"Pause\"></i>\n\t\t\t</button>\n\t\t</div>\n\t\t<div class=\"col-xs-4 modgrid\">\n\t\t\t<button class=\"tivobutton\" ng-click=\"sendCmd('TiVo_IRCmd', 'FORWARD')\">\n\t\t\t\t<i class=\"glyphicon glyphicon-forward butticon\" alt=\"Forward\"></i>\n\t\t\t</button>\n\t\t</div>\n\t</div>\n\t<div  class=\"row\">\n\t\t<div class=\"col-xs-4 modgrid\">\n\t\t<button class=\"tivobutton\" style=\"background: #666666; color:black;\" ng-click=\"sendCmd('TiVo_IRCmd', 'REPLAY')\">\n\t\t\t\t<i class=\"glyphicon glyphicon-step-backward butticon\" alt=\"Step Backward\"></i>\n\t\t\t</button>\n\t\t</div>\t\n\t\t<div class=\"col-xs-4 modgrid\">\n\t\t\t<button class=\"tivobutton\" ng-click=\"sendCmd('TiVo_IRCmd', 'STOP')\">\n\t\t\t\t<i class=\"glyphicon glyphicon-stop butticon\" alt=\"Stop\"></i>\n\t\t\t</button>\n\t\t</div>\n\t\t<div class=\"col-xs-4 modgrid\">\n\t\t\t<button class=\"tivobutton\" style=\"background: #666666; color:black;\" ng-click=\"sendCmd('TiVo_IRCmd', 'ADVANCE')\">\n\t\t\t\t<i class=\"glyphicon glyphicon-step-forward butticon\" alt=\"Step Forward\"></i>\n\t\t\t</button>\n\t\t</div>\n\t</div>\n\t<div  class=\"row\" style=\"padding-top: 18px\">\n\t\t<div class=\"col-xs-12\">\n\t\t\t<button  style=\"width: 2em; height: 2em; border: 0; color: white; background: #0db9f0\" ng-click=\"showActions = false\">\n\t\t\t1\n\t\t\t</button>\n\t\t\t  \n\t\t\t<button style=\"width: 2em; height: 2em; border: 0; color: white; background: #666666\" ng-click=\"showActions = true\">\n\t\t\t2\n\t\t\t</button>\n\t\t</div>\n\t</div>\n</div>\n\n<div id=\"tivo-mediaplay\"  class=\"table\"  ng-show=\"showActions\" ng-swipe-left=\"showActions = false\">\n\t<div  class=\"row\">\n\t\t<div class=\"col-xs-4 modgrid\">\n\t\t</div>\n\t\t<div class=\"col-xs-4 modgrid\">\n\t\t\t<button class=\"tivobutton\" ng-click=\"sendCmd('TiVo_IRCmd', 'UP')\">\n\t\t\t\t<i class=\"glyphicon glyphicon-triangle-top butticon\" alt=\"Up\"></i>\n\t\t\t</button>\n\t\t</div>\n\t\t<div class=\"col-xs-4 modgrid\">\n\t\t</div>\n\t</div>\n\t<div class=\"row\">\n\t\t<div class=\"col-xs-4 modgrid\">\n\t\t\t<button class=\"tivobutton\" ng-click=\"sendCmd('TiVo_IRCmd', 'LEFT')\">\n\t\t\t\t<i class=\"glyphicon  glyphicon-triangle-left butticon\" alt=\"Left\"></i>\n\t\t\t</button>\n\t\t</div>\n\t\t<div class=\"col-xs-4 modgrid\">\n\t\t\t<button class=\"tivobutton\" style=\"background: #666666\" ng-click=\"sendCmd('TiVo_IRCmd', 'SELECT')\">\n\t\t\t\tOK\n\t\t\t</button>\n\t\t</div>\n\t\t<div class=\"col-xs-4 modgrid\">\n\t\t\t<button class=\"tivobutton\" ng-click=\"sendCmd('TiVo_IRCmd', 'RIGHT')\">\n\t\t\t\t<i class=\"glyphicon  glyphicon-triangle-right butticon\" alt=\"Right\"></i>\n\t\t\t</button>\n\t\t</div>\n\t</div>\n\t<div class=\"row\">\n\t\t<div class=\"col-xs-4 modgrid\">\n\t\t</div>\n\t\t<div class=\"col-xs-4 modgrid\">\n\t\t\t<button class=\"tivobutton\" ng-click=\"sendCmd('TiVo_IRCmd', 'DOWN')\">\n\t\t\t\t<i class=\"glyphicon  glyphicon-triangle-bottom butticon\" alt=\"Down\"></i>\n\t\t\t</button>\n\t\t</div>\n\t\t<div class=\"col-xs-4 modgrid\">\n\t\t</div>\n\t</div>\n\t\t<div class=\"row\"style=\"padding-top: 18px\">\n\t\t<div class=\"col-xs-12\">\n\t\t\t<button  style=\"width: 2em; height: 2em; border: 0; color: white; background: #666666\" ng-click=\"showActions = false\">\n\t\t\t1\n\t\t\t</button>\n\t\t\t  \n\t\t\t<button style=\"width: 2em; height: 2em; border: 0; color: white; background: #0db9f0\" ng-click=\"showActions = true\">\n\t\t\t2\n\t\t\t</button>\n\t\t</div>\n\t</div>\n</div>",
                "dontwrap": false,
                "nobackground": true
            },
            {
                "name": "Bookshelf",
                "sizeX": 2,
                "sizeY": 2,
                "item": "EG4_Switch_1_1",
                "type": "switch",
                "hidelabel": false,
                "iconset": "freepik-household",
                "icon": "lights",
                "icon_size": 32,
                "row": 11,
                "col": 2
            },
            {
                "name": "Jongo",
                "sizeX": 2,
                "sizeY": 2,
                "item": "VOB_Jongo",
                "type": "switch",
                "hidelabel": false,
                "iconset": "freepik-gadgets",
                "icon": "audio-speaker",
                "icon_size": 32,
                "row": 11,
                "col": 4
            },
            {
                "name": "Vegas",
                "sizeX": 2,
                "sizeY": 2,
                "item": "EG4_Switch_1_3",
                "type": "switch",
                "hidelabel": false,
                "iconset": "freepik-household",
                "icon": "light-bulb-2",
                "icon_size": 32,
                "row": 11,
                "col": 6
            },
            {
                "name": "Pinball TVs",
                "sizeX": 2,
                "sizeY": 2,
                "item": "VOB_VirtualPinball",
                "type": "switch",
                "hidelabel": false,
                "iconset": "freepik-gadgets",
                "icon": "computer-monitor",
                "icon_size": 32,
                "row": 11,
                "col": 8
            },
            {
                "name": "Pinball PC",
                "sizeX": 2,
                "sizeY": 2,
                "item": "EG4_Switch_2_1",
                "type": "switch",
                "hidelabel": false,
                "iconset": "freepik-gadgets",
                "icon": "screen-and-tower",
                "icon_size": 32,
                "row": 11,
                "col": 10
            }
        ],
        "row": 0,
        "col": 3,
        "sizeX": 3,
        "tile": {
            "backdrop_iconset": "freepik-household",
            "backdrop_icon": "television-4"
        },
        "sizeY": 1,
        "$$hashKey": "object:47"
    }

The AutoPause functionality is linked to a set of items + rules integrated with the motion senors that I have. Obviously you would need to edit this to suit your own items etc.

The basic design idea was to:

Work out where I am based on the last motion sensor that was triggered in the house 'VAR_WhereIsAndyā€™
Do nothing if the house is empty VAR_Mode
If I am in the lounge, set the Tivo to play(if paused)
If I am anywhere else set the TiVo to pause (if playing)

It works if you are the only one in the house, annoying as hell if you are not! Hence the ability to turn the functionality on and off. Itā€™s a complicated as I need, so does the job until I can come up with something better.

Here are the key rules that so all of that. The rules are broken up as they will be extended when I get a chance to also turn on / off lights depending on where I am wandering at the timeā€¦ :wink:

The standby functionality is driven by the power to my TV. When I turn this off the TiVo gets put into standby. When powered on the ā€œTIVOā€ menu option is sent which wakes it up. You may find you need to add a sleep command before you wake up the TiVo. BTW a WOL packet to TiVo does nothing, the network interface stays up even in standby i.e. it is still awake.

Hope this helps, shout if you have any questions.

// Variables
var wakeUpDimmer = 0

// Rules

rule "Initialise Location"
	when
		System started
	then
		// set values so that the scripts below do not fail due to null values
		logInfo("location.InitialiseLocation", "Script start...")
		Thread::sleep(120000)
		if(Tivo_PlayPause.state == NULL) { postUpdate(Tivo_PlayPause, 1) }
		if(Tivo_AutoPause.state == NULL) { postUpdate(Tivo_AutoPause, ON) }
		if(VAR_Mode.state == NULL) { postUpdate(VAR_Mode, 1) }
		if(VAR_WhereIsAndy.state == NULL) { postUpdate(VAR_WhereIsAndy, "AWAY") }

end

rule "Prescence"
	when 
		Item FGMS_Hall_Motion changed from OFF to ON or
		Item FGMS_Dinning_Motion changed from OFF to ON or
		Item FGMS_Lounge_Motion changed from OFF to ON or
		Item AMS_Bath_Motion changed from OFF to ON or
		Item VAR_Mode changed
	then 
		logInfo("location.prescence", "Script start...")
		logInfo("location.prescence", ".AutoPause: " + Tivo_AutoPause.state)
		logInfo("location.prescence", ".AutoPause: " + VAR_Mode.state)
		if(VAR_Mode.state==1 || VAR_Mode.state==2) {
			// find the last motion sensor that triggered the change
			val lastItem = grpMotionSens.members.sortBy[lastUpdate].last
			// Grab name of item
			val nameOfItem = lastItem.name
			logInfo("location.prescence", ".Motion trigger: " + nameOfItem)

			if (nameOfItem=="FGMS_Hall_Motion") {
				VAR_WhereIsAndy.postUpdate("HALL")
				if(Tivo_PlayPause.state==1 && Tivo_AutoPause.state==ON && TiVo_SetPoint.state < 900) {
						logDebug("location.prescence", ".Set TIVO Play Pause: PAUSE")
						postUpdate(Tivo_PlayPause, 2)
				}
			}

			if (nameOfItem=="FGMS_Dinning_Motion") {
				VAR_WhereIsAndy.postUpdate("KITCHEN / DINNING")
				if(Tivo_PlayPause.state==1 && Tivo_AutoPause.state==ON && TiVo_SetPoint.state < 900) {
					logDebug("location.prescence", ".Set TIVO Play Pause: PAUSE")
					postUpdate(Tivo_PlayPause, 2)
				}
			}
			if (nameOfItem=="FGMS_Lounge_Motion") {
				VAR_WhereIsAndy.postUpdate("LOUNGE")
				if(Tivo_PlayPause.state==2 && Tivo_AutoPause.state==ON && TiVo_SetPoint.state < 900) {
					logDebug("location.prescence", ".Set TIVO Play Pause: PLAY")
					postUpdate(Tivo_PlayPause, 1)
				}
			}	
			if (nameOfItem=="AMS_Bath_Motion") {
				VAR_WhereIsAndy.postUpdate("1st Floor")
				if(Tivo_PlayPause.state==1 && Tivo_AutoPause.state==ON && TiVo_SetPoint.state < 900) {
					logDebug("location.prescence", ".Set TIVO Play Pause: PAUSE")
					postUpdate(Tivo_PlayPause, 2)
				}
			}	
		}
		else {
			VAR_WhereIsAndy.postUpdate("Away")
			sendCommand(TiVo_IRCmd,"STANDBY")
		}
end
 
// Forces the Tivo into PLAY mode if AUTO pause is turned off
rule "Tivo AutoPauseOff"
when
	Item Tivo_AutoPause changed from ON to OFF
then
	if (Tivo_PlayPause.state==2) {
		postUpdate(Tivo_PlayPause, 1)
	}
end

 
rule "Tivo Play / Pause"
when
	Item Tivo_PlayPause changed
then
	logInfo("location.Tivo Play / Pause", "Tivo_PlayPause.state: " + Tivo_PlayPause.state)
	if (Tivo_PlayPause.state==1) {
		// PLAY active Tivo media
		sendCommand(TiVo_IRCmd,"PLAY")
	}
	else {
		// PAUSE active Tivo media
		// Workaround: Issue a play before pause as sending the PAUSE command when the media is already 
		// paused causes the media to play... there is no way to determine current state of media play 
		//sendCommand(TiVo_IRCmd,"PLAY")
		sendCommand(TiVo_IRCmd,"PAUSE")
	}
end

rule "TivoPowerSaver"
when
	Item Power1_GF_Living changed
then
	logInfo("TivoPowerSaver", "Tivo power state updated to " + Power1_GF_Living.state)
	if (Power1_GF_Living.state == ON){
		logInfo("TivoPowerSaver", "...Power up")
		sendCommand(TiVo_ChangeScreen, "TIVO")
		}
	else
		{
			logInfo("TivoPowerSaver", "...Power down")
			sendCommand(TiVo_IRCmd, "STANDBY")
		}
end

Hey Andy,

How would I go about to change the code to use with my plex items? is it possible?

cheers

Hi @matt_shepherd,

Basically the code for each of the buttons is this:

<button style="background: #FFCC00; color:black" class="tivobutton" ng-click="sendCmd('TiVo_IRCmd', 'PAUSE')">

it is the ng-click="sendCmd('TiVo_IRCmd', 'PAUSE') section that dictates what commands are sent back to openHAB. So all you would need to do is change each of the sendCmd actions to the Plex ones.

Assuming you had the same item names defined in the example here you would set it up as something like:

<style>
	.plexbutton {width: 100%; height: 4em; border: 0; color: white; background: #424242;}
	.modgrid {padding-left: 2px; padding-right: 2px; padding-top: 2px; padding-bottom: 2px;}
	.butticon {font-size:2em;}
</style>
<div id="tivo-mediaplay"  class="table" ng-show="!showActions" ng-swipe-left="showActions = true" ng-swipe-right="showActions = true">
	<div class="row">
		<div class="col-xs-4 modgrid">
		</div>
		<div class="col-xs-4 modgrid">
			<button class="plexbutton" ng-click="sendCmd('PlexTVPlay', 'ON')">
				<i class="glyphicon glyphicon-play butticon" alt="Play"></i>
			</button>
		</div>
		<div class="col-xs-4 modgrid">
		</div>
	</div>
	<div  class="row">
		<div class="col-xs-4 modgrid">
			<button class="plexbutton" ng-click="sendCmd('PlexTVReverse', 'ON')">
				<i class="glyphicon glyphicon-backward butticon" alt="Backward"></i>
			</button>
		</div>
		<div class="col-xs-4 modgrid">
			<button style="background: #FFCC00; color:black" class="plexbutton" ng-click="sendCmd('PlexTVPause', 'ON')">
				<i class="glyphicon glyphicon-pause butticon" alt="Pause"></i>
			</button>
		</div>
		<div class="col-xs-4 modgrid">
			<button class="plexbutton" ng-click="sendCmd('PlexTVForward', 'ON')">
				<i class="glyphicon glyphicon-forward butticon" alt="Forward"></i>
			</button>
		</div>
	</div>
	<div  class="row">
		<div class="col-xs-4 modgrid">
		</div>	
		<div class="col-xs-4 modgrid">
			<button class="plexbutton" ng-click="sendCmd('PlexTVStop', 'ON')">
				<i class="glyphicon glyphicon-stop butticon" alt="Stop"></i>
			</button>
		</div>
		<div class="col-xs-4 modgrid">
		</div>
	</div>
	<div  class="row" style="padding-top: 18px">
		<div class="col-xs-12">
			<button  style="width: 2em; height: 2em; border: 0; color: white; background: #0db9f0" ng-click="showActions = false">
			1
			</button>
			  
			<button style="width: 2em; height: 2em; border: 0; color: white; background: #666666" ng-click="showActions = true">
			2
			</button>
		</div>
	</div>
</div>

<div id="tivo-mediaplay"  class="table"  ng-show="showActions" ng-swipe-left="showActions = false" ng-swipe-right="showActions = false">
	<div  class="row">
		<div class="col-xs-4 modgrid">
		</div>
		<div class="col-xs-4 modgrid">
			<button class="plexbutton" ng-click="sendCmd('PlexTVUp', 'ON')">
				<i class="glyphicon glyphicon-triangle-top butticon" alt="Up"></i>
			</button>
		</div>
		<div class="col-xs-4 modgrid">
		</div>
	</div>
	<div class="row">
		<div class="col-xs-4 modgrid">
			<button class="plexbutton" ng-click="sendCmd('PlexTVLeft', 'ON')">
				<i class="glyphicon  glyphicon-triangle-left butticon" alt="Left"></i>
			</button>
		</div>
		<div class="col-xs-4 modgrid">
			<button class="plexbutton" style="background: #666666" ng-click="sendCmd('TiVo_IRCmd', 'SELECT')">
				OK
			</button>
		</div>
		<div class="col-xs-4 modgrid">
			<button class="plexbutton" ng-click="sendCmd('PlexTVSelect', 'ON')">
				<i class="glyphicon  glyphicon-triangle-right butticon" alt="Right"></i>
			</button>
		</div>
	</div>
	<div class="row">
		<div class="col-xs-4 modgrid">
		</div>
		<div class="col-xs-4 modgrid">
			<button class="plexbutton" ng-click="sendCmd('PlexTVDown', 'ON')">
				<i class="glyphicon  glyphicon-triangle-bottom butticon" alt="Down"></i>
			</button>
		</div>
		<div class="col-xs-4 modgrid">
		</div>
	</div>
		<div class="row"style="padding-top: 18px">
		<div class="col-xs-12">
			<button  style="width: 2em; height: 2em; border: 0; color: white; background: #666666" ng-click="showActions = false">
			1
			</button>
			  
			<button style="width: 2em; height: 2em; border: 0; color: white; background: #0db9f0" ng-click="showActions = true">
			2
			</button>
		</div>
	</div>
</div>

The only problem I can forsee is that the 1.9 binding implements each of these items as switches. So these have an ON / OFF value. The buttons will set the item to ON, but there is nothing to set them to OFF. That may happen in the binding.

If it does not happen within the binding, then you may need a rule or two to set the items back to OFF. If this is required I would create two groups:

  1. Add all the media action items (play, pause, fwd etc)

  2. Add all the navigation items (up, down, select etc.)

Then I would use the technique illustrated in the previous post to a) work out which was the last button in the group was pressed and then b) setting any other items in the group to OFF. Hopefully the binding just takes care of this :wink:

I do not have a Plex server to test this with, so please bear that in mind. But if you do give it a go and it works, please post some feedback so others can benefit.

Regards, Andy

PS: Iā€™ve just got my Kodi binding working, so at some stage Iā€™ll do a version of the HTML that works with thatā€¦ watch this space :slight_smile:

That works perfect mate. Iā€™ve actually got it working on RasPlex on my PiZero.

Thanks for the help

Nice one fella

This is great Andy, thanks. One of my pet peeves of Tivo is the lack of HDMI-CEC so if Iā€™m watching a series on Netflix and turn off my Tivo, it just keeps playing and itā€™s episodes past where I stopped. I have a chromecast connected to the Tivo powered by the TVā€™s USB, so once OpenHab detects chromecast is no longer there it sends the suspend to Tivo. It works well except if Tivo is already in suspend it actually wakes it up, but its still good enough for me.

I like the WheresAndy idea. Thanks again.

Hi @stotes Dave,

My Kodi rsaspi server has been re-purposed for a while as a host for my LCD based 3d printer build, so I canā€™t test for youā€¦ but looking at https://github.com/openhab/openhab2-addons/tree/master/addons/binding/org.openhab.binding.kodi the solution would appear to be to use the Input item (rather than the control item used for play back commands). As it happens this has been one of the added advantages of this approach i.e. you can bind lots of buttons to as many different items as you need to :slight_smile:

If the Input was mapped to an Item:
String myKodi_input "Input" { channel="kodi:kodi:myKodi:input" }

So the html for the button to navigate UP would then be:
<button class="kodibutton" ng-click="sendCmd('myKodi_input', 'Up')">

Where:
Kodibutton = the style applied to the button
myKodi_input = name of your Input item
Up = command, one of Up, Down, Left, Right, Select, Back, Home, ContextMenu, Info, ShowCodec, ShowOSD

If the above does not work, then the first thing I would try is to change Up (as documented) to UP. Sometimes the commands are case sensitive within a binding (like the TiVo one I have worked on)ā€¦ can you tell that I got burnt by this mistake myself :wink:

Hope this helps, sorry I canā€™t test this for you. Andy

Hi Andy,

Thanks, this is awesome. I deleted my post last night after figuring out another way using Kodiā€™s API, but this might be a better way overall. Thanks so much!!

Hi @stotes Dave,
No problems. Responded from email, so did not realise you had deleted.

Now that has me intriguedā€¦ do share :wink: Andy

So Iā€™ve been unable so far to get the Kodi binding to work, but hereā€™s a little about the api workaround I found:

Kodi has a pretty extensive API available. Itā€™s all listed here: Kodi JSON-RPC API (Krypton) This particular linked version is specific to ā€œKryptonā€ Kodi builds, which I run as my primary media center solution on an Amazon FireTV 4k box.

Once I decided what buttons I wanted to map, I started out making some switches for the KODI buttons.

Switch KodiSelectButton	"Kodi Select Button"
Switch KodiUpButton	    "Kodi Up Button"	
Switch KodiDownButton	"Kodi Down Button"	
Switch KodiLeftButton	"Kodi Left Button"	
Switch KodiRightButton	"Kodi Right Button"	

The following parts I leared from from another HAB user at this post: https://community.openhab.org/t/open-tv-channel-in-xbmc-kodi/17330/21
Using that post, I made a rule for each button I wanted to map:

rule "KodiSelectButtonRule"
	when
		Item KodiSelectButton changed to ON
	then
		var String json = "%7B%22jsonrpc%22%3A+%222.0%22%2C+%22id%22%3A+1%2C+%22method%22%3A+%22Input.Select%22%7D"
		sendHttpGetRequest("http://user:password@192.168.1.237:8182/jsonrpc?request=" + json)
		
		sendCommand(KodiOKButton, OFF)
end

Basically, when the switch is triggered ā€œONā€, it sends an http get request to the KODI API, and then turns the switch back OFF immediately after.

From that post I linked above:

Once youā€™ve got your switch, and your rule, itā€™s time to insert it into your widget:

<button class="kodibutton" ng-click="sendCmd('KodiUpButton', 'ON')">

After changing the sendCmd, I tested it out on my HABPanel, and sure enough it worked. The KODI API is pretty extensive, so I would expect there is a lot more that can be realized here. I hope you find this as useful as I did. Iā€™m not a coder by any means, but I pick up on things pretty quick.

Now if I could just get Bluetooth workingā€¦ Iā€™m runing 2.0 on a Rasberry Pi 3 and I REALLY want to get Bluetooth presence detecting workingā€¦ Network detection is crap because our phoneā€™s dont stay connected to our WiFi very well. :disappointed_relieved:

Can anyone tell me how to make three sub pages? ^^
I feel kind a stupid because iam not able to get it done.

Kind regards,

Hi @hExPY Marvyn,

Have a look at this thread https://community.openhab.org/t/template-widget-tutorial-examples-make-your-own-widget/ which explains the concept of a template widget. This is a specific implementation of this sort of widget.

The first post should then make more sense. If you are still having problems can you explain what you are struggling with so I can provide some more specific help.

Regards, Andrew