bennYx0x
(Benjamin)
October 30, 2017, 2:04pm
1
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 :
Weird that Spotify doesn’t have a websocket or similar to track playback events…
To answer your question, yes probably. I would build a directive using $interval (https://docs.angularjs.org/api/ng/service/$interval ) and lazy load the file and use it in my template. It would send a command to an item with a rule attached to it like @Michael_Stjerna - sendCmd('spotify_forceupdate', 'REFRESH')
Something like (disclaimer, may not work, haven’t tested):
angular
.module('app.widgets')…
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!
bennYx0x
(Benjamin)
November 20, 2017, 10:12am
2
Hm, did nobody tried this yet?
Could you help me out here, @ysc ?
Would be appreciated!
Thanks,
Ben
ysc
(Yannick Schaus)
November 20, 2017, 10:15am
3
Your controller is looking OK, please post your widget template.
bennYx0x
(Benjamin)
November 20, 2017, 5:52pm
4
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
ysc
(Yannick Schaus)
November 21, 2017, 12:46am
5
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>
...
bennYx0x
(Benjamin)
November 21, 2017, 7:42am
6
Awesome!
Thanks, that really did it! I would never have thought that could be the reason…
Just one thing is still mysterious to me:
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
ysc
(Yannick Schaus)
November 21, 2017, 12:44pm
7
My example definitely shouldn’t be taken as face value
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
bennYx0x
(Benjamin)
November 21, 2017, 2:03pm
8
It shouldn’t? Your reputation says otherwise.
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