House plan custom panel

Hello,
In my last job, I used Nagvis (http://www.nagvis.org/screenshots) to visualize current states of servers/routers …
So I would like to create a custom panel to reproduce the same features for HA.

The following steps explain how this could be working:

  1. Chose a background image. This could be a map of your house or a photo of your living room
  2. Select an entity and set position on the background. This will only show the entity icon
  3. Mouse hover the entity icon displays details of the entity
  4. Click on the entity icon interacts with the entity

Here some visual examples:


If your are interested, I’m looking some polymer/javascript help to understand how to interact with HA. For example how to get entity icons or states, how to control entity from a custom panel.

3 Likes

You might want to take a look at this…

I could see this being done with skinning; it wouldn’t be entirely easy, but it could be done.

The floor plan would be the dash background and then you would create widgets in the spaces where you wanted control or monitoring.

I also have a list item to add a house floorplan widget at some stage

5 Likes

Do you think this could be done using only a custom panel ?

Hi there,

Not sure how useful it might be to others, but I have created a custom house plan panel that shows which zones are currently active or not (i.e. based on the binary sensors).

First of all, I created our house plan as an SVG file, and named each zone (i.e. shape) such that the name exactly matches the zone’s entity ID in Home Assistant (i.e. binary_sensor.back_hallway). I then saved this SVG file to the www folder within HA. I then created the HTML file for the custom panel, and saved it to the panels folder within HA.

To get the custom panel into the HA web interface, I added the following to configuration.yaml:

panel_custom:
  - name: zones
    sidebar_title: Zones
    sidebar_icon: mdi:hand-pointing-right
    url_path: zones

After restarting HA, the Zones link appeared in the left menu of the HA interface.

It would be good to have this functionality embedded into a widget so that it could appear within the HA views, but I haven’t gotten that far yet. Also, it would be good to make it more generic so that the SVG image could be used to represent different kinds of components, other than just binary sensors.

BTW, below are the HTML and SVG file I used.

panels/zones.html

<script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
  crossorigin="anonymous"></script>

<dom-module id="ha-panel-zones">
  <template>
    <style include="ha-style">
      .content {
        padding: 16px;
      }

      paper-input {
        max-width: 200px;
      }

      [hidden] {
        display: none !important;
      }

      .svg-container {
        display: inline-block;
        position: relative;
        max-width: 800px;
        width: 100%;
        vertical-align: middle;
        overflow: hidden;
        margin: 10px;
      }

      .svg-content {
        display: inline-block;
        position: absolute;
        top: 0;
        left: 0;
      }

      #floorplan svg path,
      #floorplan svg rect {
        stroke: #646464;
        stroke-width: 0.02px;
      }
    </style>

    <app-header-layout has-scrolling-region>

      <app-header fixed>
        <app-toolbar>
          <ha-menu-button narrow='[[narrow]]' show-menu='[[showMenu]]'></ha-menu-button>
          <div main-title>Zones</div>
        </app-toolbar>
      </app-header>

      <div class="flex content">
        <ha-zones hass="[[hass]]" entries="[[entries]]" hidden$="[[isLoading]]">
        </ha-zones>

        <div id="floorplan" class="svg-container"></div>
      </div>

    </app-header-layout>

  </template>
</dom-module>

<script>
  Polymer({
    is: 'ha-panel-zones',
    properties: {
      hass: {
        type: Object,
      },
      narrow: {
        type: Boolean,
        value: false,
      },
      showMenu: {
        type: Boolean,
        value: false,
      },
      isLoading: {
        type: Boolean,
      },
      entries: {
        type: Array,
      },
    },

    attached: function () {
    },

    ready: function () {
      var wsUri = ((window.location.protocol === 'https:') ? 'wss:' : 'ws:') + '//' + window.location.host + '/api/websocket';
      HAWS.createConnection(wsUri, { authToken: 'HA_PASSWORD_HERE' }).then(conn => {
        HAWS.subscribeEntities(conn, entities => this.handleEntities(entities));
      }, err => { console.log(err); });

      this.loadFloorPlan();
    },

    detached: function () {
    },

    handleEntities(entities) {
      this.displayZones(entities);
    },

    displayZones(entities) {
      var groups = HAWS.splitByGroups(entities).groups;
      var zoneGroup;
      for (var group of groups) {
        if (group.entity_id === 'group.zones') {
          zoneGroup = group;
          break;
        }
      }

      var zones = [];
      if (zoneGroup) {
        for (var i = 0; i < zoneGroup.attributes.entity_id.length; i++) {
          var zoneId = zoneGroup.attributes.entity_id[i];
          zones.push(entities[zoneId]);
        }
      }

      for (zone of zones) {
        if (zone.state.toLowerCase() === 'on') {
          console.log(zone.entity_id, '=', zone.state);
        }

        var svg = $('#floorplan svg');
        if (!svg[0]) {
          svg = $(this.shadowRoot.querySelector('#floorplan svg'));
        }

        var shape = svg.find('[id="' + zone.entity_id + '"]');
        if (shape) {
          shape.css('fill', (zone.state.toLowerCase() === 'on') ? '#F8B9BE' : '#C4EDB1');
        }
        else {
          console.error('Could not find SVG shape element for', zone.entity_id);
        }
      }
    },

    loadFloorPlan() {
      $.ajax({
        url: '/local/floorplan.svg',
        success: function (result) {
          svg = $(result).find('svg');

          var floorplan = $('#floorplan');
          if (!floorplan[0]) {
            floorplan = $(this.shadowRoot.querySelector('#floorplan'));
          }

          floorplan.hide();
          floorplan.append(svg);

          svg.height('100%');
          svg.width('100%');
          svg.addClass('svg-coantent');

          svg.find('rect').css('fill', '#e0e0e0');
          svg.find('path').css('fill', '#e0e0e0');

          floorplan.show();
        }.bind(this)
      });
    },
  });

</script>

www/floorplan.svg

<?xml version="1.0" standalone="no"?>
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
 width="119.000000pt" height="100.000000pt" viewBox="0 0 119.000000 100.000000"
 preserveAspectRatio="xMidYMid meet">

<g transform="translate(0.000000,100.000000) scale(0.100000,-0.100000)" fill="#000000" stroke="none">

<path id="background" d="M790 780 l0 -170 -160 0 -160 0 0 -70 0 -70 -110 0 -110 0 0 70 0 70
-105 0 -105 0 0 -285 0 -285 500 0 500 0 0 75 0 75 50 0 50 0 0 80 0 80 -39 0
c-31 0 -41 4 -46 20 -9 30 4 60 26 60 18 0 19 10 19 260 l0 260 -155 0 -155 0
0 -170z"/>

<path id="binary_sensor.back_hallway" d="M190 200 c0 -19 7 -20 155 -20 148 0 155 1 155 20 0 19 -7 20 -155
20 -148 0 -155 -1 -155 -20z"/>

<path id="binary_sensor.front_hallway" d="M650 396 c0 -30 4 -34 31 -40 17 -3 107 -6 200 -6 l169 0 0 40 0 40
-200 0 -200 0 0 -34z"/>

<path id="binary_sensor.kitchen" d="M250 383 c0 -130 -6 -123 126 -123 95 0 114 -3 114 -15 0 -12 15 -15
75 -15 l75 0 0 100 0 100 -80 0 c-64 0 -80 3 -80 15 0 12 -19 15 -115 15
l-115 0 0 -77z"/>

<path id="binary_sensor.master_bedroom" d="M826 248 c-3 -50 -6 -115 -6 -145 l0 -53 105 0 105 0 0 80 c0 79 0
80 -25 80 -24 0 -25 2 -25 65 l0 65 -74 0 -73 0 -7 -92z"/>

<path d="M792 823 l2 -128 3 123 4 122 144 0 145 0 0 -250 0 -250 -107 -2
c-106 -2 -107 -2 -23 -5 51 -3 87 -9 92 -16 6 -9 8 -9 8 1 0 6 9 12 20 12 19
0 20 7 20 260 l0 260 -155 0 -155 0 2 -127z"/>

<path id="binary_sensor.theatre_room" d="M50 490 l0 -110 95 0 95 0 0 110 0 110 -95 0 -95 0 0 -110z"/>

</g>

</svg>
6 Likes

I’d love to see a screen shot of this…

3 Likes

Yes! Please…

1 Like

Meeeeee too please

Here is a screenshot. As you can see, the zone shown in red is currently triggered (my son just entered that room). This is a very simple example of an SVG file, but there is nothing stopping you from creating a much more detailed version, extending the use of shapes, colours, outlines for rooms, etc. When creating the SVG file, I simply gave the shapes (rooms) the same name as my binary sensors in Home Assistant, and that was enough to ‘hook them up’ so that they display in the correct colour based on their states (‘off’ is green, ‘on’ is red). Grey represents the areas that are not covered by binary sensors.

What I like about SVG files is that they scale really nicely. This floorplan looks great on any device and orientation, as it scales to fit the available space. I also like the fact that an SVG file is just plain text, so you can open it using any editor and change stuff if needed.

Let me know if you need any more info. Any of you that have added your binary sensors can create a simple SVG file to represent your zones / houseplan, and this should just work.

12 Likes

WOW !
This is really helpful !!!
Thanks !

Has anyone else tried this? Looks extremely interesting. I too would like to have a visual representation of any ‘zone’ triggered. I have built 2 of BRUH’s $15 sensors (in addition to a few Aeotec) and will most likely add to each room before I am done.

What software do you suggest or use?.. I tried using BoxSVG (Chrome) but do not see a way to name the objects. I’m only looking at free software since this is my only use for this type of program.

I use Inkscape to create the SVG files. I can’t remember if I was able to name the shapes within the application though.

https://inkscape.org/en/develop/about-svg/

Regardless of that, you can open your SVG in any text editor (i.e. NotePad++) and simply add id=“some-name” to each shape you want to name,

BTW, in the meantime, I have improved this functionality.I now have the floorplan showing as a regular state card within the tabs, so it no longer needs to be on a totally separate page. It now also shows the most recent zone triggered, and also gradually fades the triggered zones from red to green, so you if you walk through your house, you will see a trail of gradient colour showing all the zones you triggered. It also lets you choose any colours for the ‘on’ and ‘off’ states. Each zone has its own hover-overt tooltip showing some info (i.e. current state, when it was last triggered, etc.).

I will soon put this on GitHub to make it more easily available, with instructions too.

Below is what it looks like now. I removed all 6 of my binary sensors from the group, since the floorplan now displays those sensors instead. I only left the Last Motion binary sensor there. This is also shown in the image using the grey outline.

7 Likes

This is awesome!!, the power of open source…
Thank you for sharing.

I created a new thread for this, and the code is now on GitHub along with instructions.

https://community.home-assistant.io/t/floorplan-for-home-assistant/17394

4 Likes

The link does not work anymore and has changed to Floorplan for Home Assistant

Thank you. Link updated.

Thank you for sharing this. I think I’ll need to take your advice when I fully equip my house. Because now we have just come to the choice of the final design of the house, and it looks just like in my home plans. We also developed such a project at home together with a designer from the company, and it turned out to be convenient and fast. There are many details that the designer suggested to us and they sound extremely convenient, which is what I need in a house with two children. Such various things that will contribute to the fact that I’ll be able to rest more pleases me. Therefore, I’m waiting more and more for this plan to come to life.