$interval usage for automatic refresh if habpanel page is open

Hello community,

my usecase:

To avoid unnecessary functions calls, I want to fire some commands only if I am browsing a specific view on habpanel.

Examples:

  • Refresh the spotify web player
  • Refresh the TV status (on/off, which input, and so on)

Of course this could be done via a rule which uses a cron job, but it would be overkill to e.g. refresh every 5 seconds my TV status all day long.

Approach by @ysc :

With this code:

    angular
        .module('app.widgets')
        .directive('sendCmdAtInterval', ['$interval', function ($interval) {
            return {
                link: function (scope, element, attrs) {
                    var handler = $interval(function () {
                        scope.sendCmd('spotify_forcerefresh', 'REFRESH');
                    }, 10000);

                    scope.$on('$destroy', handler);
                }
            };
        }]);

He suggests to inject javascript code with oc lazy loading and a $interval directive, which acts as a scheduler AFAIK. (He mentioned that the code above is not tested)

I succeeded in injecting the code itself, but the interval seems not to work. (My breakpoint inside the interval function is never reached)

The angular code itself exceeds my skills with angular js, so help is appreciated.

Did anyone already succeeded with this or found an alternative approach?

Thanks in advance!

Hm, did nobody tried this yet?

Could you help me out here, @ysc? :slight_smile:

Would be appreciated!

Thanks,
Ben

Your controller is looking OK, please post your widget template.

Thanks for looking into this.

This is the part of my widget template, where I added the lazy loading:

<div class="section" oc-lazy-load="'/static/sendcmdatinterval.directive.js'" send-cmd-at-interval>

	<div class="sectionIconContainer"><div class="sectionIcon"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/squidink.svg#line-visuals"></use></svg></div></div>
	<div class="title">Musik</div>
	<div class="controls">

		<div class="widget">
			<div class="icon off"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/squidink.svg#line-visuals"></use></svg></div>
			<div class="name">Track</div>
			<div class="appLogo"><svg viewBox="0 0 440 100"><use xlink:href="/static/matrix-theme/AppIcons.svg#spotify"></use></svg></div>        
			<div class="valueGroup">
				<div class="value">{{itemValue('spotify_current_track')}}</div>
				<div class="value">{{itemValue('spotify_current_artist')}}</div>
			</div>

			<div class="music">
				<div class="cover" ng-style="{'background-image': 'url(' + itemValue('spotify_current_cover') + ')'}"></div>
				<div class="playback">
					<div class="playbackTime">{{ 946684800000 + itemValue('spotify_current_progress')*1 | date:'mm:ss'}}</div>
					<div class="playbackBar"><div class="playbackBarDone" ng-style="{'width': itemValue('spotify_current_progress_percent') + '%'}"></div></div>
					<div class="playbackTime">{{ 946684800000 + itemValue('spotify_current_duration')*1 | date:'mm:ss'}}</div>
				</div>
				<div class="controlGroup">
					<div class="control" ng-click="sendCmd('spotify_action', 'next')"><svg viewBox="0 0 80 80"><use xlink:href="/static/matrix-theme/squidink.svg#right-arrow-2"></use></svg></div>
					<div class="control" ng-click="sendCmd('spotify_action', 'play')" ng-if="itemValue('spotify_current_playing')!='ON'"><svg viewBox="0 0 80 80"><use xlink:href="/static/matrix-theme/squidink.svg#right-play"></use></svg></div>
					<div class="control" ng-click="sendCmd('spotify_action', 'pause')" ng-if="itemValue('spotify_current_playing')=='ON'"><svg viewBox="0 0 80 80"><use xlink:href="/static/matrix-theme/squidink.svg#stop_1_"></use></svg></div>
					<div class="control" ng-click="sendCmd('spotify_action', 'previous')"><svg viewBox="0 0 80 80"><use xlink:href="/static/matrix-theme/squidink.svg#left-arrow-2"></use></svg></div>
				</div>
			</div>      
		</div>


   <div class="widget">
      <div class="icon off" ng-click="sendCmd('spotify_action', 'playlists')"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/squidink.svg#double-arrow"></use></svg></div>
      <div class="nameGroup"><div class="name">Playlists</div></div>
      <div class="valueGroup"><div class="value"><div class="btn-group" dropdown-append-to-body="true" uib-dropdown>            
        <button id="single-button" type="button" class="btn btn-primary" uib-dropdown-toggle>
          Auswahl <span class="caret"></span>
        </button>
        <ul class="dropdown-menu" uib-dropdown-menu role="menu" style="overflow: auto; max-height:300px; overflow-x:hidden" aria-labelledby="single-button">
          <div ng-init="playlistsSet=itemValue('spotify_playlists')"></div>
          <div ng-init="playlists=$eval(playlistsSet).items"></div>
          <div ng-repeat="item in playlists" ng-if="item.state!='NULL'">
            <li role="menuitem"><a ng-click='sendCmd("spotify_action", "play \"" + item.uri + "\"")'>{{item.name}}</a></li>
          </div>         
        </ul></div></div>
      </div>
    </div>
    
		<div class="widget">
			<div class="icon off"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/squidink.svg#volume"></use></svg></div>
			<div class="name">Volume<div class="value">{{itemValue('spotify_current_volume')}}</div></div>
			<div class="controlGroup">
				<div class="control" ng-click="sendCmd('spotify_action', 'volume_up')"><svg viewBox="0 0 80 80"><use xlink:href="/static/matrix-theme/squidink.svg#top-arrow-2"></use></svg></div>
				<div class="control" ng-click="sendCmd('spotify_action', 'volume_down')"><svg viewBox="0 0 80 80"><use xlink:href="/static/matrix-theme/squidink.svg#down-arrow-2"></use></svg></div>
			</div>
		</div>

 		<div class="widget">
			<div class="icon off"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/squidink.svg#box"></use></svg></div>
			<div class="name">Aktuelles Gerät</div>
     	<div class="valueGroup"><div class="value">{{itemValue('spotify_current_device')}}</div></div>			
		</div>
    
    <div class="widget">
      <div class="icon off" ng-click="sendCmd('spotify_actions', 'devices')"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/squidink.svg#double-arrow"></use></svg></div>
      <div class="nameGroup"><div class="name">Geräte</div></div>
     <div class="valueGroup"><div class="value"> <div class="btn-group" dropdown-append-to-body="true" uib-dropdown>            
        <button id="single-button" type="button" class="btn btn-primary" uib-dropdown-toggle>
          {{itemValue('spotify_current_device')}} <span class="caret"></span>
        </button>
        <ul class="dropdown-menu"  uib-dropdown-menu role="menu" aria-labelledby="single-button">
          <div ng-init="devicesSet=itemValue('spotify_devices')"></div>
          <div ng-init="devices=$eval(devicesSet).devices"></div>
          <div ng-repeat="item in devices" ng-if="item.state!='NULL'">
            <li role="menuitem"><a ng-click='sendCmd("spotify_action", "play \"" + item.id + "\"")'>{{item.name}}</a></li>
          </div>
        </ul></div></div>
      </div>
    </div>
		<div class="widget" ng-click="sendCmd('spotify_forceupadte', 'ON')">
			<div class="icon off"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/squidink.svg#double-arrow"></use></svg></div>
			<div class="name">Update</div>
     	<div class="valueGroup"><div class="value">{{itemValue('spotify_lastConnectionDateTime') | date:'MMM d, HH:mm:ss'}}</div></div>			
		</div>

  </div>

</div>

if the debugger shows up, it looks like this:

as you can see, I added a console.log statement, which is never seen in the console…

Thanks,
Ben

Ah yes, looks like you can’t lazy-load a directive and use it on the same element.
I know that was what I suggested in my earlier post and I was wrong - sorry.

The directive has to be invoked on another element down the tree. in your particular case, since it doesn’t really matter where you put it, instead of adding another <div> you can simply move it to the sectionIconContainer, title or controls one.

<div class="section" oc-lazy-load="'/static/sendcmdatinterval.directive.js'">

	<div class="sectionIconContainer"><div class="sectionIcon"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/squidink.svg#line-visuals"></use></svg></div></div>
	<div class="title">Musik</div>
	<div class="controls" send-cmd-at-interval>
...

Awesome! :slight_smile:

Thanks, that really did it! I would never have thought that could be the reason…

Just one thing is still mysterious to me:

image

The type error appears when I change the view - and the $interval is still alive. Seems like the $interval isn’t destroyed because of the error?

I tried removing the array in the JS described as here: https://stackoverflow.com/questions/34276841/typeerror-dh-apply-is-not-a-function but that didn’t help.

Cheers

My example definitely shouldn’t be taken as face value :slight_smile:

According to https://docs.angularjs.org/api/ng/service/$interval you should call $interval.cancel(handler) to cancel the repeated task; so something like

scope.$on('$destroy', function () {
    $interval.cancel(handler);
});

might work better.

1 Like

It shouldn’t? Your reputation says otherwise. :wink:

Again a big thank your for looking into this, since Im only using habpanel and having quite some logic there, this here gives a great benefit.

BR
Ben

1 Like