Floorplan for Home Assistant

Ahh… I think you have named your custom_ui folder as custom-ui. Needs to have the underscore.

That must be it.

hold on let me double check on that

you guys are the best. And also I hope you don’t me using your plan

@mistrovly No problem. Keep us posted on how you go.

Thank you sir

One more question guys, how can I have my groups appear on the plan?

I’m not really sure what you mean exactly but you have to change the object id’s within the svg file (I use Inkscape) to match the components in your floorplan.yaml

Thank you; I’m working on it now

Hello,

I am trying to make a air conditioner automation using input_selects. I’ve connected the svg object to the input_selects, then also I’ve created the suitable classes. The floorplan screen shows the states of the object correctly when hovered upon but I can’t get a color change off the object.

Floorplan.yaml page:

- name: AirCon
  entities:
    - input_select.scene_aircon_room1
    - input_select.scene_aircon_room2
  states:
    - state: '-'
      class: 'aircon_none'
    - state: 'Off'
      class: 'aircon_off'
    - state: 'Auto'
      class: 'aircon_auto'
    - state: 'Silent18'
      class: 'aircon_silent18'
    - state: 'Silent22'
      class: 'aircon_silent22'
    - state: 'Powerful'
      class: 'aircon_powerful'

floorplan.css file:

.aircon_none {
  fill: #a0a0a0 !important;
}

.aircon_off {
  fill: #191919 !important;
}

.aircon_auto {
  fill: #40e0a8 !important;
}

.aircon_silent18 {
  fill: #40e065 !important;

}

.aircon_silent22 {
  fill: #5fe040 !important;
}

.aircon_powerful {
  fill: #0099ff !important;
}

Trying to implement this, I’ve put a box named input_select.arm_debug in my main svg-file and then a few svg-files (other than in the example above) in my folder. I’m getting this error

Do the files used in the animation have to be in a specific format or contain something I’m missing?

ha-floorplan.html:463 Uncaught TypeError: Cannot read property 'getBBox' of undefined
    at HTMLElement.<anonymous> (ha-floorplan.html:463)
    at i (jquery-3.2.1.min.js:2)
    at Object.fireWith [as resolveWith] (jquery-3.2.1.min.js:2)
    at A (jquery-3.2.1.min.js:4)
    at XMLHttpRequest.<anonymous> (jquery-3.2.1.min.js:4)

@ggravlingen Can you grab the latest file? I needed to fix something.

www/custom_ui/floorplan/ha-floorplan.html

Let me know how you go.

BTW, did you add a rect type of element to your SVG, to represent your entitiy? I only tried doing it that way, but I think any type of SVG element should work in order to serve as a placeholder for the SVG images that get dynamically embedded.

Also, make sure that the SVGs you’re embedding contain the viewBox attribute in the <svg> tag, and make that the letter ‘B’ is upper case. This attribute is necessary in order for the embedded SVG to scale and fit within the placeholder element.

viewBox="0 0 64 64"
1 Like

Thanks! No luck when updating and I do have a rect. Also checked that thare is a viewBox in the svg file I’m referencing.

What is the id of the dummy rect in your main svg-file and what are the ids of the svg-files bearing the weather icons?

I tested to just load the floorplan-screen, updating the state of my sensor and the updating it back again (it goes from true to false to true) and that rendered the following error (I don’t have an Empty.svg in order to trace what is going on):

core-d4a7cb8….js:1 Uncaught (in promise) DOMException: Only secure origins are allowed (see: https://goo.gl/Y0ZkNV).
(anonymous) @ core-d4a7cb8….js:1
ha-floorplan.html:463 Uncaught TypeError: Cannot read property 'getBBox' of undefined
    at HTMLElement.<anonymous> (ha-floorplan.html:463)
    at i (jquery-3.2.1.min.js:2)
    at Object.fireWith [as resolveWith] (jquery-3.2.1.min.js:2)
    at A (jquery-3.2.1.min.js:4)
    at XMLHttpRequest.<anonymous> (jquery-3.2.1.min.js:4)
(anonymous) @ ha-floorplan.html:463
i @ jquery-3.2.1.min.js:2
fireWith @ jquery-3.2.1.min.js:2
A @ jquery-3.2.1.min.js:4
(anonymous) @ jquery-3.2.1.min.js:4
jquery-3.2.1.min.js:4 GET http://:8123/local/custom_ui/floorplan/buttonbars/Empty.svg 404 (Not Found)
send @ jquery-3.2.1.min.js:4
ajax @ jquery-3.2.1.min.js:4
loadImage @ ha-floorplan.html:458
handleEntities @ ha-floorplan.html:392
hassChanged @ ha-floorplan.html:94
_observerEffect @ frontend-a7d4cb8….html:2
_effectEffects @ frontend-a7d4cb8….html:2
_propertySetter @ frontend-a7d4cb8….html:2
__setProperty @ frontend-a7d4cb8….html:2
_applyEffectValue @ frontend-a7d4cb8….html:2
_annotationEffect @ frontend-a7d4cb8….html:2
_effectEffects @ frontend-a7d4cb8….html:2
_propertySetter @ frontend-a7d4cb8….html:2
s @ frontend-a7d4cb8….html:2
updateAttributes @ frontend-a7d4cb8….html:5
_observerEffect @ frontend-a7d4cb8….html:2
_effectEffects @ frontend-a7d4cb8….html:2
_propertySetter @ frontend-a7d4cb8….html:2
__setProperty @ frontend-a7d4cb8….html:2
_applyEffectValue @ frontend-a7d4cb8….html:2
_annotationEffect @ frontend-a7d4cb8….html:2
_effectEffects @ frontend-a7d4cb8….html:2
_propertySetter @ frontend-a7d4cb8….html:2
__setProperty @ frontend-a7d4cb8….html:2
__setPropertyImpl @ frontend-a7d4cb8….html:4
_applyEffectValue @ frontend-a7d4cb8….html:2
_annotationEffect @ frontend-a7d4cb8….html:2
_effectEffects @ frontend-a7d4cb8….html:2
_propertySetter @ frontend-a7d4cb8….html:2
__setProperty @ frontend-a7d4cb8….html:2
__setPropertyImpl @ frontend-a7d4cb8….html:4
_forwardParentProp @ frontend-a7d4cb8….html:4
(anonymous) @ frontend-a7d4cb8….html:4
_functionEffect @ frontend-a7d4cb8….html:2
_effectEffects @ frontend-a7d4cb8….html:2
_propertySetter @ frontend-a7d4cb8….html:2
__setProperty @ frontend-a7d4cb8….html:2
_applyEffectValue @ frontend-a7d4cb8….html:2
_annotationEffect @ frontend-a7d4cb8….html:2
_effectEffects @ frontend-a7d4cb8….html:2
_propertySetter @ frontend-a7d4cb8….html:2
s @ frontend-a7d4cb8….html:2
(anonymous) @ frontend-a7d4cb8….html:5
r @ core-d4a7cb8….js:1
S._handleMessage @ core-d4a7cb8….js:1
ha-floorplan.html:463 Uncaught TypeError: Cannot read property 'getBBox' of undefined
    at HTMLElement.<anonymous> (ha-floorplan.html:463)
    at i (jquery-3.2.1.min.js:2)
    at Object.fireWith [as resolveWith] (jquery-3.2.1.min.js:2)
    at A (jquery-3.2.1.min.js:4)
    at XMLHttpRequest.<anonymous> (jquery-3.2.1.min.js:4)

@ggravlingen I simply added a single rect to my floorplan SVG:

  <rect
     style="fill:#fff;fill-opacity:1;stroke:#b9b9b9;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
     width="25"
     height="25"
     x="10.98802"
     y="36.192341"
     inkscape:label="sensor.melbourne_dark_sky_icon"
     id="sensor.melbourne_dark_sky_icon" />

Of course, in HA, I have a Dark Sky weather sensor called sensor.melbourne_dark_sky_icon whose id matches up with the rect above.

As for the weather icons, they do not even need any particular ids within them. These icons are loaded into the main SVG, and their size is determined by the rect mentioned above. The only thing connecting them to the floorplan is their URL.

Is your floorplan config returning the correct URL for the child SVGs that you’re embedding?

The key thing here is to make sure your floorplan config (the group that you have set up using image_template) returns the correct URL for the SVG to embed.

In your case, could it be that you are generating a URL that isn’t correct?

http://hem.gammelgravlingen.com:8123/local/custom_ui/floorplan/buttonbars/Empty.svg

Can you paste in your image_template from your floorplan config? Are you maybe including the http:// in the URL? There is no need to do that, as that will be added automatically (either http:// or https://).

Let me know how you go.

BTW, if you use the free weather icons that I mentioned, below is where I stored them in my installation. As I mentioned in my other post, in each file, I had to rename viewbox to viewBox.

Source: https://www.amcharts.com/free-animated-svg-weather-icons/

1 Like

What I’m trying to do is leverage on this new feature and have a button bar appear when I click another button. I reckon it’ll allow for some sleak buttons on the man screen that open more detailed control abilities. :slight_smile:

This is the rect from floorplan.svg:

  <g
     inkscape:groupmode="layer"
     id="layer2"
     inkscape:label="Background"
     transform="translate(0,-24)">
    <rect
       style="opacity:1;fill:#ececec;fill-opacity:1;stroke:none;stroke-width:0.72934163;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="input_select.floorplan_buttons_ceiling"
       width="210"
       height="48"
       x="88.801971"
       y="155.34889"
       inkscape:label=""
       transform="translate(0,24)" />
  </g>

This is from the floorplan.yaml:

        - name: Buttons Ceiling
          entities:
            - input_select.floorplan_buttons_ceiling
          image_template: '
            var imageName = "";
            switch (entity.state) {
              case "True":
                imageName = "Home";
                break;
              case "False":
                imageName = "Empty";
                break;
            }
            return "/local/custom_ui/floorplan/buttonbars/" + imageName + ".svg";
            '

This is where I’m keeping the files to be loaded:

/home/homeassistant/.homeassistant/www/custom_ui/floorplan/buttonbars

And finally, this is the Home.svg

<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   width="280"
   height="64"
   viewBox="0 0 74.083332 16.933333"
   version="1.1"
   id="input_select.floorplan_buttons_ceiling"
   inkscape:version="0.92.1 r15371"
   sodipodi:docname="Home.svg">
  <defs
     id="defs6087" />
  <sodipodi:namedview
     id="base"
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1.0"
     inkscape:pageopacity="0.0"
     inkscape:pageshadow="2"
     inkscape:zoom="87.6422"
     inkscape:cx="3.2799057"
     inkscape:cy="60.560363"
     inkscape:document-units="mm"
     inkscape:current-layer="layer1"
     showgrid="false"
     inkscape:window-width="1600"
     inkscape:window-height="837"
     inkscape:window-x="-8"
     inkscape:window-y="-8"
     inkscape:window-maximized="1"
     units="px" />
  <metadata
     id="metadata6090">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
        <dc:title />
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <g
     inkscape:label="Layer 1"
     inkscape:groupmode="layer"
     id="layer1"
     transform="translate(0,-280.06659)">
    <rect
       style="opacity:1;fill:#a4adeb;fill-opacity:1;stroke:none;stroke-width:0.25729552;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect5289-0"
       width="74.083336"
       height="16.933332"
       x="-3.2464316e-006"
       y="280.06677" />
    <g
       style="fill:#ffffff;fill-opacity:1"
       inkscape:label=""
       id="group.floorplan_misc-1"
       transform="matrix(0.15648986,0,0,0.15648986,1.3428971,280.9709)">
      <path
         style="fill:#ffffff;fill-opacity:1"
         id="path6590-5"
         d="m 94.9,23.4 c 0,3.8 -3.1,7 -7,7 H 77.5 c -3.8,0 -7,-3.1 -7,-7 V 11.8 c 0,-3.8 3.1,-7 7,-7 H 88 c 3.8,0 7,3.1 7,7 v 11.6 z"
         inkscape:connector-curvature="0" />
      <path
         style="fill:#ffffff;fill-opacity:1"
         id="path6592-8"
         d="m 61.5,23.4 c 0,3.8 -3.1,7 -7,7 H 12 c -3.8,0 -7,-3.1 -7,-7 V 11.8 c 0,-3.8 3.1,-7 7,-7 h 42.5 c 3.8,0 7,3.1 7,7 z"
         inkscape:connector-curvature="0" />
      <path
         style="fill:#ffffff;fill-opacity:1"
         id="path6594-0"
         d="m 94.9,55.8 c 0,3.8 -3.1,7 -7,7 H 77.5 c -3.8,0 -7,-3.1 -7,-7 V 44.2 c 0,-3.8 3.1,-7 7,-7 H 88 c 3.8,0 7,3.1 7,7 v 11.6 z"
         inkscape:connector-curvature="0" />
      <path
         style="fill:#ffffff;fill-opacity:1"
         id="path6596-2"
         d="m 61.5,88.2 c 0,3.8 -3.1,7 -7,7 H 44.1 c -3.8,0 -7,-3.1 -7,-7 v -44 c 0,-3.8 3.1,-7 7,-7 h 10.4 c 3.8,0 7,3.1 7,7 z"
         inkscape:connector-curvature="0" />
      <path
         style="fill:#ffffff;fill-opacity:1"
         id="path6598-9"
         d="m 94.9,88.2 c 0,3.8 -3.1,7 -7,7 H 77.5 c -3.8,0 -7,-3.1 -7,-7 V 76.6 c 0,-3.8 3.1,-7 7,-7 H 88 c 3.8,0 7,3.1 7,7 v 11.6 z"
         inkscape:connector-curvature="0" />
      <path
         style="fill:#ffffff;fill-opacity:1"
         id="path6600-8"
         d="m 29.5,55.8 c 0,3.8 -3.1,7 -7,7 H 12 c -3.8,0 -7,-3.1 -7,-7 V 44.2 c 0,-3.8 3.1,-7 7,-7 h 10.4 c 3.8,0 7,3.1 7,7 v 11.6 z"
         inkscape:connector-curvature="0" />
      <path
         style="fill:#ffffff;fill-opacity:1"
         id="path6602-3"
         d="m 29.5,88.2 c 0,3.8 -3.1,7 -7,7 H 12 c -3.8,0 -7,-3.1 -7,-7 V 76.6 c 0,-3.8 3.1,-7 7,-7 h 10.4 c 3.8,0 7,3.1 7,7 v 11.6 z"
         inkscape:connector-curvature="0" />
    </g>
    <g
       style="fill:#ffffff;fill-opacity:1"
       inkscape:label=""
       id="group.floorplan_misc-1-4"
       transform="matrix(0.15648986,0,0,0.15648986,30.633971,280.78443)">
      <path
         style="fill:#ffffff;fill-opacity:1"
         id="path6590-5-4"
         d="m 94.9,23.4 c 0,3.8 -3.1,7 -7,7 H 77.5 c -3.8,0 -7,-3.1 -7,-7 V 11.8 c 0,-3.8 3.1,-7 7,-7 H 88 c 3.8,0 7,3.1 7,7 v 11.6 z"
         inkscape:connector-curvature="0" />
      <path
         style="fill:#ffffff;fill-opacity:1"
         id="path6592-8-0"
         d="m 61.5,23.4 c 0,3.8 -3.1,7 -7,7 H 12 c -3.8,0 -7,-3.1 -7,-7 V 11.8 c 0,-3.8 3.1,-7 7,-7 h 42.5 c 3.8,0 7,3.1 7,7 z"
         inkscape:connector-curvature="0" />
      <path
         style="fill:#ffffff;fill-opacity:1"
         id="path6594-0-6"
         d="m 94.9,55.8 c 0,3.8 -3.1,7 -7,7 H 77.5 c -3.8,0 -7,-3.1 -7,-7 V 44.2 c 0,-3.8 3.1,-7 7,-7 H 88 c 3.8,0 7,3.1 7,7 v 11.6 z"
         inkscape:connector-curvature="0" />
      <path
         style="fill:#ffffff;fill-opacity:1"
         id="path6596-2-7"
         d="m 61.5,88.2 c 0,3.8 -3.1,7 -7,7 H 44.1 c -3.8,0 -7,-3.1 -7,-7 v -44 c 0,-3.8 3.1,-7 7,-7 h 10.4 c 3.8,0 7,3.1 7,7 z"
         inkscape:connector-curvature="0" />
      <path
         style="fill:#ffffff;fill-opacity:1"
         id="path6598-9-4"
         d="m 94.9,88.2 c 0,3.8 -3.1,7 -7,7 H 77.5 c -3.8,0 -7,-3.1 -7,-7 V 76.6 c 0,-3.8 3.1,-7 7,-7 H 88 c 3.8,0 7,3.1 7,7 v 11.6 z"
         inkscape:connector-curvature="0" />
      <path
         style="fill:#ffffff;fill-opacity:1"
         id="path6600-8-9"
         d="m 29.5,55.8 c 0,3.8 -3.1,7 -7,7 H 12 c -3.8,0 -7,-3.1 -7,-7 V 44.2 c 0,-3.8 3.1,-7 7,-7 h 10.4 c 3.8,0 7,3.1 7,7 v 11.6 z"
         inkscape:connector-curvature="0" />
      <path
         style="fill:#ffffff;fill-opacity:1"
         id="path6602-3-0"
         d="m 29.5,88.2 c 0,3.8 -3.1,7 -7,7 H 12 c -3.8,0 -7,-3.1 -7,-7 V 76.6 c 0,-3.8 3.1,-7 7,-7 h 10.4 c 3.8,0 7,3.1 7,7 v 11.6 z"
         inkscape:connector-curvature="0" />
    </g>
    <g
       style="fill:#ffffff;fill-opacity:1"
       inkscape:label=""
       id="group.floorplan_misc-1-7"
       transform="matrix(0.15648986,0,0,0.15648986,57.425496,280.9709)">
      <path
         style="fill:#ffffff;fill-opacity:1"
         id="path6590-5-1"
         d="m 94.9,23.4 c 0,3.8 -3.1,7 -7,7 H 77.5 c -3.8,0 -7,-3.1 -7,-7 V 11.8 c 0,-3.8 3.1,-7 7,-7 H 88 c 3.8,0 7,3.1 7,7 v 11.6 z"
         inkscape:connector-curvature="0" />
      <path
         style="fill:#ffffff;fill-opacity:1"
         id="path6592-8-4"
         d="m 61.5,23.4 c 0,3.8 -3.1,7 -7,7 H 12 c -3.8,0 -7,-3.1 -7,-7 V 11.8 c 0,-3.8 3.1,-7 7,-7 h 42.5 c 3.8,0 7,3.1 7,7 z"
         inkscape:connector-curvature="0" />
      <path
         style="fill:#ffffff;fill-opacity:1"
         id="path6594-0-7"
         d="m 94.9,55.8 c 0,3.8 -3.1,7 -7,7 H 77.5 c -3.8,0 -7,-3.1 -7,-7 V 44.2 c 0,-3.8 3.1,-7 7,-7 H 88 c 3.8,0 7,3.1 7,7 v 11.6 z"
         inkscape:connector-curvature="0" />
      <path
         style="fill:#ffffff;fill-opacity:1"
         id="path6596-2-16"
         d="m 61.5,88.2 c 0,3.8 -3.1,7 -7,7 H 44.1 c -3.8,0 -7,-3.1 -7,-7 v -44 c 0,-3.8 3.1,-7 7,-7 h 10.4 c 3.8,0 7,3.1 7,7 z"
         inkscape:connector-curvature="0" />
      <path
         style="fill:#ffffff;fill-opacity:1"
         id="path6598-9-2"
         d="m 94.9,88.2 c 0,3.8 -3.1,7 -7,7 H 77.5 c -3.8,0 -7,-3.1 -7,-7 V 76.6 c 0,-3.8 3.1,-7 7,-7 H 88 c 3.8,0 7,3.1 7,7 v 11.6 z"
         inkscape:connector-curvature="0" />
      <path
         style="fill:#ffffff;fill-opacity:1"
         id="path6600-8-59"
         d="m 29.5,55.8 c 0,3.8 -3.1,7 -7,7 H 12 c -3.8,0 -7,-3.1 -7,-7 V 44.2 c 0,-3.8 3.1,-7 7,-7 h 10.4 c 3.8,0 7,3.1 7,7 v 11.6 z"
         inkscape:connector-curvature="0" />
      <path
         style="fill:#ffffff;fill-opacity:1"
         id="path6602-3-2"
         d="m 29.5,88.2 c 0,3.8 -3.1,7 -7,7 H 12 c -3.8,0 -7,-3.1 -7,-7 V 76.6 c 0,-3.8 3.1,-7 7,-7 h 10.4 c 3.8,0 7,3.1 7,7 v 11.6 z"
         inkscape:connector-curvature="0" />
    </g>
  </g>
</svg>

Edit: forgot to add the input select:

floorplan_buttons_ceiling:
  options:
   - True
   - False
1 Like

At first glance, it all looks OK. Did you definitely grab the most recent floorplan HTML file from GitHub, and also clear the browser cache?

What I cannot account for is the URL that your browser was trying to fetch:

http://hem.gammelgravlingen.com:8123/local/custom_ui/floorplan/buttonbars/Empty.svg

I assume your HA is running with HTTPS? If so, I don’t why the above URL was generated wiith just HTTP).

Are you still getting that same error you posted earlier?

1 Like

Bloody caching… That was the error! Many thank you for assisting me :blush::slight_smile: I can now see the svg-file I’m trying to load on my screen.

I’m using the base_url-setting of Home Assistant so that’s probably why the whole address shows up.

By the way, have you considered adding a version number as a comment on top of your files?

Thanks again! :slight_smile:

2 Likes

@ggravlingen Not sure if this may help, but have you set the base_url option in your http config in HA?

http:
  base_url: https://<YOUR_HOST_NAME>:8123
  ssl_certificate: <YOUR_SSL_CERTIFICATE>
  ssl_key: <YOUR_SSL_KEY>

@ggravlingen Great to hear that it’s OK now. I think you are the first person to try the new dynamic SVG images, so keep us posted on your progress, and share some screenshots too!

And yes, I’ve been planning on adding a version number to the top of the HTML file. Will start doing that.

1 Like

There’s currently not a lot to see but I’m getting there :slight_smile:

The general idea is that I click the light button and then the following panel shows up in the white area:

These three icons are supposed to set three different scenes for my ceiling lights.

Do I need to do anything in particular to get the image to fill the placeholder?

@ggravlingen This functionality is brand new, so it might take a bit of tweaking for us to get it working optimally.

I tried quite a few different options, but in the end, I managed to get the embedded SVG to fill the placeholder. Having said that, the floorplan code tries to preserve the embedded SVG 's aspect ratio, so it won’t stretch out of shape if the placeholder ratio is different.

Does your placeholder aspect ratio match up with your embedded SVG’s aspect ratio? That would be the best way to do it.

Not meaning to get too technical, but the code below is from the floorplan. As you can see, the embedded SVG is given the height and width of the placeholder, but its aspect ratio is retained (therefore height and width act more like max height and max width).

          embeddedSvg.attr('id', `image.${entityId}`);
          embeddedSvg.attr('preserveAspectRatio', 'xMinYMin meet')
          embeddedSvg
            .attr('height', bbox.height)
            .attr('width', bbox.width)
            .attr('x', bbox.x)
            .attr('y', bbox.y)