Matrix Theme for HABPanel

Thank you for your fast return. First of all, I don’t know if it changes something but I have Xiaomi Yeelights at home.

If I use your code with my current items definitions :

As I didn’t defined my groups / items like you, I had to made few modification inside the code. It’s not finished yet but : https://github.com/Aletor93/openhab2/blob/master/light_control.html

My items are currently difined like this for example :

/* Groups Dimmer */
Group:Switch:OR(ON,OFF) gLights_appartement     "Lumières"                 <light>
Group:Switch:OR(ON,OFF) gLights_chambre         "Lumières Chambre"         <light> (gLights_appartement)

/* Items Chambre */
Switch  chambre_yeelight1                       "Plafonier Chambre"             <Light>         (gLights)       {channel="yeelight:Wonder:0x00000000035edb9f:Brightness"}
Dimmer  chambre_yeelight1_brightness            "Brightness"            <DimmableLight>                         {channel="yeelight:Wonder:0x00000000035edb9f:Brightness"}
Color   chambre_yeelight1_color                 "Color"                 <colorlight>    (gLightsRgb_chambre)    {channel="yeelight:Wonder:0x00000000035edb9f:Color"}
Dimmer  chambre_yeelight1_colorTemp             "ColorTemperature"      <DimmableCT>                            {channel="yeelight:Wonder:0x00000000035edb9f:Color_Temperature"}

(For example, here I had to make some modifications in order to create a Switch which is a duplication of the Dimmer channel)

Thing is, it would be easier to debug myself if I (or everybody instered in your theme) could have an example of your items definition.

Edit : I also saw a problem with the color picker “hueSelect”. Example for : { hsb: '140,100,100', hex: '#b2c225' }, the color inside the “hueSelect” is “green” but inside the “hue” (the circle to display actual color set) is blue.
I checked inside a web converter http://www.workwithcolor.com/color-converter-01.htm, hsb value for HEX ‘B2C225’ should be HSB ‘66°,81%,57%’.

@pmpkk

Hi Patrick

I really appreciate your work in this template.
I have done some tweaks that I soon will share.

But I have one direct question/issue with the Spotify plugin:
It only fetches the album cover when i start och change track from the habPanel, when the next song is played there are no auto update. Is it possible to do this automatically? (5sek auto refresh in any rules file maybe?)
The other thing I would love to do from the habPanel is to select output device, it currently shows where it plays but would it be possible to change the output from your example?

Br
Michael Stjerna

@pmpkk

Found a simple way just to put in the cron into your spotify.rules

rule "Spotify run script"
when
        Time cron "0/5 * * * * ?" or
        Item spotify_forceupadte received update
                then
                        val resp =  executeCommandLine("/usr/bin/python /etc/openhab2/scripts/spotify.py", 5000)
                        logInfo("Spotify", resp)
end

rule "Spotify Action"
when
                Item spotify_action received update
        then
                        val resp =  executeCommandLine("/usr/bin/python /etc/openhab2/scripts/spotify.py " + spotify_action.state.toString, 5000)
                        logInfo("Spotify", resp)
end

1 Like

Hey,

Yes, I thought about the same thing but in the end I’m not sure if it would be useful to implement a full Spotify player in HabPanel. My objective was so I can start scenes upon certain events including light, TV, music, etc. Through openhab.

Pining the API every 5min all day long seems like overkill.

I’m not sure if it’s possible to fire a rule only when HabPanel is open. Only then we could ping the API every 10s … not sure how to do that though. @ysc, is that possible?

Thanks,
Patrick

Hi,

The widget only uses the channel color. Through color it sets hue, saturation, brightness, temp, etc

I don’t have the other items set up and don’t need them.

Two questions:

  1. Can you send a HSB setting to your light item manually through openhab CLI?
  2. What happens when you click/touch the item? Does the color selector appear?

Here are the items:


Group gGroundFloorHue
Group:Switch:OR(ON, OFF) gHue

Color light_hue_tv "TV Strip" (gHue,gGroundFloorHue) {channel = "hue:0210:nnnn:9:color"}
String light_hue_tv_rgb

EDIT:

I just realized that you may miss this rule to set the RGB string values:


rule "Set RGB Values"
when 
	Item gHue received update
then

	var HSBType hsb 

	gHue.members.forEach [ item | 
		hsb = item.state as HSBType
		var red = Math::round(hsb.red.intValue * 2.55)
		var green = Math::round(hsb.green.intValue * 2.55)
		var blue = Math::round(hsb.blue.intValue * 2.55)
		postUpdate(item.name + "_rgb",red.toString + "," + green.toString + "," + blue.toString)  
		logInfo("Hue","Updating Hue Colors (" + item.name + "_rgb)")
	]	

end


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')
        .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);
                }
            };
        }]);

then <div oc-lazy-load="'/static/sendcmdatinterval.directive.js'" send-cmd-at-interval class="..."> somewhere in the template around the Spotify stuff. Check the “Injecting custom JavaScript code” in HABPanel Development & Advanced Features: Start Here!

1 Like

@pmpkk

Ok, thanks. Will play with this.
Will you merge the code to select output device to your master branch?
Would be nice with a dropdown on your panel example :wink:

Hi,

Thank you for the time you took to explain me :slight_smile: Now I understand the “thing” about the colour difference and why you don’t need Brightness and Color temp channels.
I’ll add that rule and retry.

I’ll also try to add a slider inside the hue-select in order to handle the Brightness as I need it.

Awesome!

awesome work with this custom theme!

i tried creating some custom widgets for my vacuum robot and my onkyo receiver.
works fine so far, but im struggling in getting it in a good looking format :frowning:
maybe anyone can help?

onkyo control:

  <div class="section">
	<div class="sectionIconContainer"><div class="sectionIcon"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/icons.svg#radio"></use></svg></div></div>
  <div class="title">Receiver Wohnzimmer</div>
  <div class="controls">
      <div class="widget" ng-if="itemValue('OnkyoTXNR626AVReceiver_Zone1_Power')=='ON'" ng-click="sendCmd('OnkyoTXNR626AVReceiver_Zone1_Power', 'OFF')">
      <div class="icon on" ><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/matrixicons.svg#on"></use></svg></div>
      <div class="name">POWER</div>
      </div>
      <div class="widget" ng-if="itemValue('OnkyoTXNR626AVReceiver_Zone1_Power')=='OFF'" ng-click="sendCmd('OnkyoTXNR626AVReceiver_Zone1_Power', 'ON')">
      <div class="icon on" ><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/matrixicons.svg#off"></use></svg></div>
      <div class="name">POWER</div>
      </div>
 		<div class="widget">
			<div class="icon on"><svg viewBox="0 0 35 35"><use xlink:href="/static/matrix-theme/icons.svg#radio"></use></svg></div>
			<div class="name">Source</div>
      <div class="sceneGroup">
			  <div class="scene" style="color: {{itemValue('OnkyoTXNR626AVReceiver_Zone1_InputSource')=='35' ? '#26bf75' : '#565f58'}}" ng-click="sendCmd('OnkyoTXNR626AVReceiver_Zone1_InputSource', '35')">TV</div>
				<div class="scene" style="color: {{itemValue('OnkyoTXNR626AVReceiver_Zone1_InputSource')=='36' ? '#26bf75' : '#565f58'}}" ng-click="sendCmd('OnkyoTXNR626AVReceiver_Zone1_InputSource', '36')">FM</div>
        <div class="scene" style="color: {{itemValue('OnkyoTXNR626AVReceiver_Zone1_InputSource')=='1' ? '#26bf75' : '#565f58'}}" ng-click="sendCmd('OnkyoTXNR626AVReceiver_Zone1_InputSource', '1')">PC</div>
		</div></div>
<div class="slider-div" ng-init='volumeModel={"name": "volume", "item": "OnkyoTXNR626AVReceiver_Zone1_Volume", 
                    "floor" : 0, "ceil": 60, "step": 1, "hidelabel" : "true", "hidelimits": "true" }'>
  <widget-slider ng-model="volumeModel"/>
</div>
  </div>
      </div>
  <div class="section">
	<div class="sectionIconContainer"><div class="sectionIcon"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/icons.svg#radio"></use></svg></div></div>
  <div class="title">Receiver Küche</div>
  <div class="controls">
          <div class="widget" ng-if="itemValue('OnkyoTXNR626AVReceiver_Zone2_Power')=='ON'" ng-click="sendCmd('OnkyoTXNR626AVReceiver_Zone2_Power', 'OFF')">
      <div class="icon on" ><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/matrixicons.svg#on"></use></svg></div>
      <div class="name">POWER</div>
      </div>
      <div class="widget" ng-if="itemValue('OnkyoTXNR626AVReceiver_Zone2_Power')=='OFF'" ng-click="sendCmd('OnkyoTXNR626AVReceiver_Zone2_Power', 'ON')">
      <div class="icon on" ><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/matrixicons.svg#off"></use></svg></div>
      <div class="name">POWER</div>
      </div>
     		<div class="widget">
			<div class="icon on"><svg viewBox="0 0 35 35"><use xlink:href="/static/matrix-theme/icons.svg#radio"></use></svg></div>
			<div class="name">Source</div>
          <div class="sceneGroup">
  			<div class="scene" style="color: {{itemValue('OnkyoTXNR626AVReceiver_Zone2_InputSource')=='36' ? '#26bf75' : '#565f58'}}" ng-click="sendCmd('OnkyoTXNR626AVReceiver_Zone2_InputSource', '36')">FM</div>
        <div class="scene" style="color: {{itemValue('OnkyoTXNR626AVReceiver_Zone2_InputSource')=='1' ? '#26bf75' : '#565f58'}}" ng-click="sendCmd('OnkyoTXNR626AVReceiver_Zone2_InputSource', '1')">PC</div>
		</div></div>
		</div>
<div class="slider-div" ng-init='volumeModel2={"name": "volume2", "item": "OnkyoTXNR626AVReceiver_Zone2_Volume", 
                    "floor" : 0, "ceil": 60, "step": 1, "hidelabel" : "true", "hidelimits": "true" }'>
  <widget-slider ng-model="volumeModel2"/>
</div>
  </div>

vacuum robot:

<div oc-lazy-load="['/static/matrix-theme/jquery-3.2.1.min.js','/static/matrix-theme/matrix.js']"></div>

  <div class="section">
	<div class="sectionIconContainer"><div class="sectionIcon"><svg viewBox="0 0 48 48"><use xlink:href="/static/matrix-theme/icons.svg#vacuumcleaningrobot"></use></svg></div></div>
  <div class="title">Xiaomi Vacuum Robot</div>
  <div class="controls">
			<div class="widget">Status</div><div class="vacuumvalue">{{itemValue('statusStatus')}}</div>
      <div class="widget">Error</div><div class="vacuumvalue">{{itemValue('statusError')}}</div>
      <div class="widget">Battery Level</div><div class="vacuumvalue">{{itemValue('statusBat')}} %</div>
      <div class="widget">Cleaning Time</div><div class="vacuumvalue">{{itemValue('statusTime')}} min</div>
      <div class="widget">Cleaned Area</div><div class="vacuumvalue">{{itemValue('statusArea') | number: 1}} qm</div>

 		<div class="widget">
			<div class="icon on"><svg viewBox="0 0 35 35"><use xlink:href="/static/matrix-theme/icons.svg#vacuumcleaningrobot"></use></svg></div>
			<div class="name">Vacuum Control</div>
      <div class="sceneGroup">
				<div class="scene" style="color: {{itemValue('actionControl')=='dock' ? '#26bf75' : '#565f58'}}" ng-click="sendCmd('actionControl', 'dock')">Dock</div>
				<div class="scene" style="color: {{itemValue('actionControl')=='spot' ? '#26bf75' : '#565f58'}}" ng-click="sendCmd('actionControl', 'spot')">Spot</div>
				<div class="scene" style="color: {{itemValue('actionControl')=='pause' ? '#26bf75' : '#565f58'}}" ng-click="sendCmd('actionControl', 'pause')">Pause</div>
				<div class="scene" style="color: {{itemValue('actionControl')=='vacuum' ? '#26bf75' : '#565f58'}}" ng-click="sendCmd('actionControl', 'vacuum')">Vacuum</div>
		</div>
    
     		<div class="widget">
			<div class="icon on"><svg viewBox="0 0 35 35"><use xlink:href="/static/matrix-theme/icons.svg#vacuumcleaningrobot"></use></svg></div>
			<div class="name">Fan</div>
          <div class="sceneGroup">
				<div class="scene" style="color: {{itemValue('actionFan')=='90' ? '#26bf75' : '#565f58'}}" ng-click="sendCmd('actionFan', '90')">Full</div>
				<div class="scene" style="color: {{itemValue('actionFan')=='77' ? '#26bf75' : '#565f58'}}"ng-click="sendCmd('actionFan', '77')">Power</div>
				<div class="scene" style="color: {{itemValue('actionFan')=='60' ? '#26bf75' : '#565f58'}}"ng-click="sendCmd('actionFan', '60')">Normal</div>
				<div class="scene" style="color: {{itemValue('actionFan')=='38' ? '#26bf75' : '#565f58'}}"ng-click="sendCmd('actionFan', '38')">Silent</div>
		</div>
  </div>
</div>

Hey,

I tried you rules and item configuration but I didn’t worked as expected, “ON/OFF” button for hue doesn’t change his states, even when I click to the “off” preset inside the hue selector. The rule you gave me work, color inside the “round” was the good one.

Well, I’ve made few modifications to adapt your code to my item definition, and here is the result :
image
Github : https://github.com/Aletor93/openhab2/blob/master/light_control.html

It allow to handle both white bulb (entrée) and color bulb (like the others). I still need to add for white bulb the brightness slider.
I also have a problem on the <div class="summary"> which filter values like “ON” or “100” (because it’s a dimmer and not a switch). I found a way to filter values “greater than 0” but I don’t know if and where I can define a custom function like this : https://stackoverflow.com/questions/29208242/angular-ng-repeat-filter-with-greater-than

If someone knows that, it will be awesome.

Hi @pmpkk

Would it be possible to stor the spotify token in to a variable?
When the OpenHAB is restarted the value is set to “NULL” and every time the PI looses power I need to SSH to it to reset the value…

Br
Michael Stjerna

MHi Michael,

They are stored as OH items. I recommend turning on persistance and restoring item state upon restart. That’s pretty straight forward and works well.

I restart my Pi once in a while and the Spotify values are recovered.

Hope this helps!
P

EDIT: FYI, I use influxdb for persistance. It can be installed from the openhabian config tool. Really easy to set up and also great for graphing (e.g. with Grafana)

1 Like

@pmpkk
Hi Patrick

Thanks for all the support. Just one final thing.
I have installed UnifyController on the same server as OpenHAB and changed the port to 8090 for openhab instead of 8080.

I can reach the script on: http://192.168.1.20:8090/static/spotify-auth.htm
This gives the output and stores the variable to OpenHAB.
Spotify whitelist URL is updated.

spotify.pl is updated with this URL:
REDIRECT_URI = ‘http://192.168.1.20:8090/static/spotify-auth.html

When i run the spotify.pl to get the id it outputs:

[11:43:17] openhabian@openHABianPi:/etc/openhab2/scripts$ /usr/bin/python /etc/openhab2/scripts/spotify.py
Error getting state from OpenHab: spotify_client_id (HTTP Response 404)
Error getting state from OpenHab: spotify_client_secret (HTTP Response 404)
Error getting state from OpenHab: spotify_access_token (HTTP Response 404)
Error getting state from OpenHab: spotify_refresh_token (HTTP Response 404)
Error getting state from OpenHab: spotify_token_issued (HTTP Response 404)
Error getting state from OpenHab: spotify_token_expiry (HTTP Response 404)
Traceback (most recent call last):
  File "/etc/openhab2/scripts/spotify.py", line 329, in <module>
    main()
  File "/etc/openhab2/scripts/spotify.py", line 296, in main
    c = spotify()
  File "/etc/openhab2/scripts/spotify.py", line 46, in __init__
    if (time.time() > float(self.token_expiry)):
ValueError: could not convert string to float:

Is there any other references to 8080 in the code that need to be updated?

Br
Michael Stjerna

1 Like

Problem solved :slight_smile:
Found a reference in the file: myopenhab.py
self.openhab_ip = “127.0.0.1:8090”

Working fine now

Cool! Did you manage to set up persistance?

@pmpkk

No I didn’t get it to work.
Will try some more but this is what I did, (installed rrd4j Persistence from papperUI)

Strategies {
    everyMinute : "0 * * * * ?"
    everyHour   : "0 0 * * * ?"
    everyDay    : "0 0 0 * * ?"

    default = everyChange
}
Items {
    spotify_* : strategy = everyChange, restoreOnStartup
}

By the way, there was an updated version for the spotify.pl where you could select output device. This code colided with your latest update on the “Playlist”.
Will you merge them together so both the playlist and selection of output device would work?
I really enjoy the plugin! I only need to select the output since the player starts at the latest device :frowning:

//Michael Stjerna

1 Like

Ok, RRD4J should work as well. But still, influxdb and Grafana are awesome so I wouldn’t give up :slight_smile:

Yes, I’m in the process of merging the changes. Should have an update in the next few days!

1 Like

@pmpkk

I got it to work now, found an easy way
Patrick, can you please put this into your documentation:

You need to “persist” the OpenHAB values and restore them when restarting the system.
If you don’t have a solution in place you can simply add the “MapDB Persistence” from the PaperUI -> AddOns --> PERSISTENCE.

You need to create a file that stores all the vaiables into the MapDB. You will only store values that are updated and ONLY the latest value.

Create the file:
/etc/openhab2/persistence/mapdb.persist

Strategies {
    default = everyUpdate
}

Items {
    // persist all Items on every change and restore them from the MapDB at startup
    * : strategy = everyChange, restoreOnStartup
}

//Michael Stjerna

1 Like

Just make a widget with a frame pointed to the authorisation html. So you can access it from habpannel. I’ve also got another panel that displays and and deletes all the auth ids so you can start from a fresh start if needed.

Cross post:

I thought I’ll share a picture of my customised version of Patric’s awesome skin and spotify api’s.

7 Likes