Design your SVG floorplan or dashboard for HABPanel with Inkscape

Hi all,

Today a friend using Home Assistant showed me ha-floorplan - basically a way to display interactive SVGs in the web UI. Some skilled people got very creative with it - this goes far beyond floorplans since you can design your dashboard entirely with SVG!

But did you know you can already achieve a similar result for your openHAB system with HABPanel? :slight_smile:
SVG can be included in templates without problems using ng-include!

Hereā€™s a little quick start guide:

  • Install Inkscape from https://inkscape.org/ (Linux users will find it in their distributionā€™s package repositories, Windows 10 users can also install it from the Microsoft Store)
  • Create a new document, go to File > Document properties and change to an appropriate size (for instance 1024x768). You can also create the document with File > New from templateā€¦ and use the Desktop template with your preferred size.

image

  • Design your floorplan. :slight_smile:
    Now, Iā€™m no Inkscape guru so I wonā€™t get into details too much here, but there are a lot of resources on the Internet on that subject. You can import SVG icon files from e.g. flaticon.com with File > Import or add entire packs into Inkscape with this repository: https://github.com/Xaviju/inkscape-open-symbols

  • To add dynamic text, you simply use AngularJS expressions like you would do in a HTML template (read HABPanel Development & Advanced Features: Start Here! to learn more about this), so you basically have 2 options:

    1. Use the double-curly braces notation:
      {{itemState('Your_Item_Name')}}
      Your expression will be displayed on the drawing while youā€™re editing itā€¦ it can be little bit annoying;

    2. Put a generic placeholder as you see fit for editing purposes, and use the ng-bind directive:

      a. Open the XML Editor with Edit > XML Editor (or use Ctrl-Shift-X);

      b. Click on your text;

      c. Add a new attribute named ā€œng-bindā€ and put in the code you would place inside the double curly braces, like this:

      d. Donā€™t forget to click ā€œSetā€ or use Ctrl-Enter to commit the change!

  • Similarly, here is how you could make a simple switch - this is a little painful, but surely writing an AngularJS directive and lazy-loading it would work too (and be a little easier):

    1. Open the XML Editor with Edit > XML Editor (or use Ctrl-Shift-X);

    2. Click on your shape;
      (note that this works on any shape, not only icons but also the entire room if you wish!)

    3. Add a ā€œng-classā€ attribute with the value below (adapt with your itemā€™s name) and click Set:
      {"light-on": itemState('Your_Switch_Item') == 'ON' }
      This will apply the light-on CSS class to the element whenever the state of the item is equal to ON. Weā€™ll define this class later.

    4. Add a ā€œng-clickā€ attribute with the value below (adapt with your itemā€™s name) and click Set:
      sendCmd('Your_Switch_Item', (itemState('Your_Switch_Item') == 'ON') ? 'OFF' : 'ON')
      This will send either the command OFF to the item if its state is equal to ON, or the command ON otherwise.

    5. Add a cursor attribute with this value: pointer and click Set;

    6. Finally, create a CSS file and put in conf/html/floorplan.css with the content below - you can do lots of complex things, but this will simply define the CSS class light-on with a yellowish fill color (!important is here to override whatever fill color Inkscape would have applied directly to the element or its children):

.light-on {
    fill: #ffe600 !important;
}
  • When youā€™re happy with your design, save your SVG file in conf/html/floorplan.svg

  • In HABPanel, add a template widget to a dashboard and edit it with this code (pretty straightforward!):
<div oc-lazy-load="'/static/floorplan.css'">
  <div ng-include="'/static/floorplan.svg'"></div>
</div>
  • Click Run and enjoy :slight_smile:

You can keep working on the SVG and the CSS file in conf/html, and simply reload the HABPanel page to pick up the changes! There are a lot of things in the CSS and SVG specs to render animations, color gradients, glow effects and shadows etc. For instance, take a look at the Filter menu in Inkscape. It will define filters and reference them in the style attribute. You can then use for example ng-style to add or remove a filter depending on a condition. Inkscape allows importing PDFs or images and embedding them in the SVG too.

Hope it helps - if you build something with SVG, please show off your results here!

72 Likes

Amazing! I thought that HABPanel was nice but this is becoming unbelievable. Now I have to start learning CSS to all the other stuff :smiley:

1 Like

Great work! I tried to create my own floorplan and it worked well thanks to your good tutorial.
I had not problem using the double-curly braces notation. However, when I alternatively try to use the placeholder with the ng-binding, I cannot format my output.

itemValue('rweTemp5a6130')  +" Ā°C"

shows too many decimals. I would like to show my room temperature with only one decimal. With double-curly braces notation this looks like

{{itemValue('rweTemp5a6130') | number:1}} Ā°C

and works. When I want to use ng-bind, how do I need to adapt this? I tried same expression with and without double-curly braces, but neither works.
Any idea?

You can use parentheses to apply a filter only to a certain part of an expression (the ng-bind value or the contents inside the double curly braces), like this:

ng-bind="(itemState('rweTemp5a6130') | number:1) + ' Ā°C'"

or

{{(itemState('rweTemp5a6130') | number:1) + ' Ā°C'}}
1 Like

Works perfectly. Thanks for the quick solution.

@ysc hey man, could u please share a code of how to make the light glow when on?
I try to follow This Link but itā€™s for HA, I have no idea of how to make this css thing work, thanks!

Iā€™m no expert but there are some tutorials on wikiHow: https://www.wikihow.com/wikiHowTo?search=inkscape

This one shows thereā€™s a ā€œblurā€ option in the ā€œfill & strokeā€ tool: https://www.wikihow.com/Use-the-Fill-and-Stroke-Functions-in-Inkscape

What it seems to do is define a SVG ā€œfilterā€ and apply it to the style of the object with something like filter:url(#something)

You can then probably apply it conditionally with ng-style with a value of:

{ filter: itemState('Light1') == 'ON' ? 'url(#yourfilterid)' : '', fill: itemState('Light1') == 'ON' ? '#ffff00' : '#000000' }

Alternatively you could also add a class to your CSS file:

.light-glow {
    fill: #ffff00 !important;
    filter: url(#yourfilterid) !important;
}

and apply the class conditionally with ng-class:

{ 'light-glow': itemState('Light1') == 'ON' }
1 Like

Sorry for babysit a noob ^^, but AWESOME tutorial, thanks man! Tested it and worked like a charm!

Is there an easy way to show current date time on the SVG floorplan using angular (without creating an OH item for that)?

My current HabPanel Floorplan:

9 Likes

Sadly not in the SVG itself :frowning:

You can however add an angular-clock, already built into HABPanel and used for clock widgets, on top of it. You would need to position it and style it manually with CSS, unfortunately.
Add something like this below the <div ng-include="(your SVG)"></div> in your template:

<ds-widget-clock theme="dark" show-digital="true" show-analog="false"
                 style="position: absolute; width: 200px; height: 200px; left: 250px; top: 250px;
                        font-size: 24px; color: black;"></ds-widget-clock>

Thanks Yannick! This generally works fine but I want to adapt that (like written in documentation) to display the date and time in specific format:

  <ds-widget-clock theme="dark" show-digital="true" show-analog="false" digital-format="dd.MM.yyyy HH:mm"
                 style="position: absolute; width: 200px; height: 200px; left: 700px; top: 35px;
                        font-size: 24px; color: black;"></ds-widget-clock>

But that doesnā€™t seem to work. Could you help me how to change the date/time formatting in this case?

You forgot to add simple quotes inside the double quotes to specify itā€™s a literal string (this digital-format attribute expects an expression) :slight_smile:

2 Likes

Nice work, Yannick! Great howto.

Is there any way to get ng-click to interact with another element/layer?! IĀ“d like to add some kind of overlay message if theres a click on a certain area.

Thanks in advance
Simon

Yes, you can assign values to scope variables on the fly with ng-click, for instance:

  • showOverlay=true
  • showOverlay=!showOverlay (toggle)

Then you can use ng-if, ng-show and even ng-class or ng-style on the overlay using this variable. All these are valid:

  • ng-if="showOverlay"
  • ng-show="showOverlay"
  • ng-class="{ hidden: !showOverlay }" (with an associated 'hidden' CSS class)
  • ng-style="{ visibility: showOverlay ? 'visible' : 'hidden' }"

SVG is a Document Object Model much like HTML, therefore all of AngularJSā€™ directives that arenā€™t designed to work with specific HTML elements will work on SVG elements as well.

3 Likes

I tried to place some elements for blind control ā€¦ Up, Stop, Downā€¦
However the whole SVG is too crowded and I would rather use a Slider for this.
Can a slider be used in the SVG?
Thanks!

Current:
image

Would like to:
maybe a slider like thisā€¦ which could replace the ā€œwindowā€ itself and could control the blind and the same time show the current %state

image

This is just plain awesome! I have a question about having an item react to an update from OpenHAB. For example, I have door sensors on all exterior doors, is there a way that I can make the object for my doors fill red when the door is opened?
I created a ā€œng-classā€ attribute for:

{"door-open": itemState('ContactOfficeDoor') == 'ON' }

I added this to my css file:

.door-open {
        fill: #ff0000 !important;
}

When I open the door, the panel does not changeā€¦ I did not create an ng-click for a send command, because I donā€™t want to be able to click on the door and turn the sensor on, I would prefer it to react from an update from the device itself. Is this possible?

@jsable This is perfectly possible and your css and ng-class looks good already.

Maybe, you have a svg group selected instead of only one specific element?! If so, then you can simply assign ng-class to all of the grouped elements and it should work.

1 Like

@Simson,

Thanks for the encouragement! I figured it out, forgot I had a translation set, so the ā€˜ONā€™ didnā€™t work for me, had to change it to ā€˜is Openā€™ and they all started glowing red like I wanted!

Quick tip from HABPanel Development & Advanced Features: Start Here!

itemState(itemname, [ignoreTransform]): retrieves the state of an item by its name;
ignoreTransform (optional, false by default) will return the raw state (e.g. ā€˜CLOSEDā€™) instead of the transformed state (ā€˜zuā€™)

So if you have transformations you can explicitely ignore them:
itemState('ContactOfficeDoor', true) == 'ON'
(note the ā€œtrueā€ as 2nd argument)

1 Like

Iā€™m a little stuck and Iā€™m hoping you can point out what mistake Iā€™m making. I created the .css file just as shown above and I created a really simple file:

I put both files in the HTML folder and when I go to 192.168.1.151:8080/static/Test.svg it shows up but when I add it to HABPanel all I get is this:
image

Is there something Iā€™m missing? Any pointers are appreciated.

Thanks!