Hey all,
I’ve seen some very cool projects others have done for displaying a live floor plan in HA with active lighting and I was hooked! I started modeling my apartment in SH3D and was ready to start rendering the floor plan.
I started out with creating the renders and manually creating the transparent PNG overlays but I quickly ran into some issues:
- I really sucked at properly creating the transparent overlay images
- Rooms with multiple light sources were even worse as I attempted to use different levels of transparency so the lights could combine together but this never came out quite right for me and the lights always seemed washed out
- Every so often, my wife likes to move things around so repeating this process every time was not really an option
My next plan was to create a plugin for SH3D that would simply render all of the possible lighting combinations but I quickly found out that’s not feasible. Even with just 10 lights, that’s 16K renders at ~1.5 minutes each at my 1024x576 target.
Finally, I set out to combine both approaches and automate creating the image overlays by comparing a base image (with the lights off) to another image (with one light on) and saving only the difference as a transparent overlay image. This produced rather nice results but caused issues in rooms with multiple (independent) light sources. To overcome this, I decided to render all lighting combinations, but limit this per-room. This means that if two rooms don’t have any “light bleed” between them, I don’t really need create renders that overlap and, that way, I won’t reach the exponential number of rendering combinations. I reached a point where, for my existing 14 lights, I only need to render 18 images. Since most only have one light source, the rendering is also simplified and it took less than 15 minutes to render them all.
With rendering out of the way, I now wanted to add the option of tapping the floor plan to toggle a light. Sure, this can be done manually by pin-pointing every light, find the offset (in percent ) from the corner and slap in the Lovelace panel YAML, but where’s the fun in that? This part took me way longer to get right than I’d like to admit, but the plugin now calculates where each light source is rendered, according to the viewing position and angle, and adds the light’s state-icon
at the relevant position. If a switch light has multiple source, e.g., spot lights, I just calculate the center of all the lights and place the icon there.
To wrap it up, before publishing, I added a simple UI to display and modify some configuration values and it’s now ready for release!
For example, using one of SH3D’s demo models:
The generated floor plan images:
And the matching YAML:
type: picture-elements
image: /local/floorplan/base.png?version=1
elements:
- type: conditional
conditions:
- entity: light.bedroom2_uplight
state: 'on'
- entity: light.bedroom2_spotlight
state: 'off'
elements:
- type: image
tap_action:
action: none
hold_action:
action: none
entity:
- light.bedroom2_uplight
- light.bedroom2_spotlight
image: /local/floorplan/light.bedroom2_uplight.png?version=1
filter: none
style:
left: 50%
top: 50%
width: 100%
- type: conditional
conditions:
- entity: light.bedroom2_uplight
state: 'on'
- entity: light.bedroom2_spotlight
state: 'on'
elements:
- type: image
tap_action:
action: none
hold_action:
action: none
entity:
- light.bedroom2_uplight
- light.bedroom2_spotlight
image: /local/floorplan/light.bedroom2_uplight_light.bedroom2_spotlight.png?version=1
filter: none
style:
left: 50%
top: 50%
width: 100%
- type: conditional
conditions:
- entity: light.bedroom2_uplight
state: 'off'
- entity: light.bedroom2_spotlight
state: 'on'
elements:
- type: image
tap_action:
action: none
hold_action:
action: none
entity:
- light.bedroom2_uplight
- light.bedroom2_spotlight
image: /local/floorplan/light.bedroom2_spotlight.png?version=1
filter: none
style:
left: 50%
top: 50%
width: 100%
- type: conditional
conditions:
- entity: light.bedroom_side1
state: 'on'
- entity: light.bedroom_side2
state: 'off'
- entity: light.bedroom_desk
state: 'off'
elements:
- type: image
tap_action:
action: none
hold_action:
action: none
entity:
- light.bedroom_side1
- light.bedroom_side2
- light.bedroom_desk
image: /local/floorplan/light.bedroom_side1.png?version=1
filter: none
style:
left: 50%
top: 50%
width: 100%
- type: conditional
conditions:
- entity: light.bedroom_side1
state: 'on'
- entity: light.bedroom_side2
state: 'on'
- entity: light.bedroom_desk
state: 'off'
elements:
- type: image
tap_action:
action: none
hold_action:
action: none
entity:
- light.bedroom_side1
- light.bedroom_side2
- light.bedroom_desk
image: /local/floorplan/light.bedroom_side1_light.bedroom_side2.png?version=1
filter: none
style:
left: 50%
top: 50%
width: 100%
- type: conditional
conditions:
- entity: light.bedroom_side1
state: 'on'
- entity: light.bedroom_side2
state: 'on'
- entity: light.bedroom_desk
state: 'on'
elements:
- type: image
tap_action:
action: none
hold_action:
action: none
entity:
- light.bedroom_side1
- light.bedroom_side2
- light.bedroom_desk
image: /local/floorplan/light.bedroom_side1_light.bedroom_side2_light.bedroom_desk.png?version=1
filter: none
style:
left: 50%
top: 50%
width: 100%
- type: conditional
conditions:
- entity: light.bedroom_side1
state: 'on'
- entity: light.bedroom_side2
state: 'off'
- entity: light.bedroom_desk
state: 'on'
elements:
- type: image
tap_action:
action: none
hold_action:
action: none
entity:
- light.bedroom_side1
- light.bedroom_side2
- light.bedroom_desk
image: /local/floorplan/light.bedroom_side1_light.bedroom_desk.png?version=1
filter: none
style:
left: 50%
top: 50%
width: 100%
- type: conditional
conditions:
- entity: light.bedroom_side1
state: 'off'
- entity: light.bedroom_side2
state: 'on'
- entity: light.bedroom_desk
state: 'off'
elements:
- type: image
tap_action:
action: none
hold_action:
action: none
entity:
- light.bedroom_side1
- light.bedroom_side2
- light.bedroom_desk
image: /local/floorplan/light.bedroom_side2.png?version=1
filter: none
style:
left: 50%
top: 50%
width: 100%
- type: conditional
conditions:
- entity: light.bedroom_side1
state: 'off'
- entity: light.bedroom_side2
state: 'on'
- entity: light.bedroom_desk
state: 'on'
elements:
- type: image
tap_action:
action: none
hold_action:
action: none
entity:
- light.bedroom_side1
- light.bedroom_side2
- light.bedroom_desk
image: /local/floorplan/light.bedroom_side2_light.bedroom_desk.png?version=1
filter: none
style:
left: 50%
top: 50%
width: 100%
- type: conditional
conditions:
- entity: light.bedroom_side1
state: 'off'
- entity: light.bedroom_side2
state: 'off'
- entity: light.bedroom_desk
state: 'on'
elements:
- type: image
tap_action:
action: none
hold_action:
action: none
entity:
- light.bedroom_side1
- light.bedroom_side2
- light.bedroom_desk
image: /local/floorplan/light.bedroom_desk.png?version=1
filter: none
style:
left: 50%
top: 50%
width: 100%
- type: conditional
conditions:
- entity: light.kitchen
state: 'on'
elements:
- type: image
tap_action:
action: none
hold_action:
action: none
entity:
- light.kitchen
image: /local/floorplan/light.kitchen.png?version=1
filter: none
style:
left: 50%
top: 50%
width: 100%
- type: conditional
conditions:
- entity: light.bathroom
state: 'on'
elements:
- type: image
tap_action:
action: none
hold_action:
action: none
entity:
- light.bathroom
image: /local/floorplan/light.bathroom.png?version=1
filter: none
style:
left: 50%
top: 50%
width: 100%
- type: conditional
conditions:
- entity: light.living_room_uplight1
state: 'on'
- entity: light.living_room_uplight2
state: 'off'
elements:
- type: image
tap_action:
action: none
hold_action:
action: none
entity:
- light.living_room_uplight1
- light.living_room_uplight2
image: /local/floorplan/light.living_room_uplight1.png?version=1
filter: none
style:
left: 50%
top: 50%
width: 100%
- type: conditional
conditions:
- entity: light.living_room_uplight1
state: 'on'
- entity: light.living_room_uplight2
state: 'on'
elements:
- type: image
tap_action:
action: none
hold_action:
action: none
entity:
- light.living_room_uplight1
- light.living_room_uplight2
image: /local/floorplan/light.living_room_uplight1_light.living_room_uplight2.png?version=1
filter: none
style:
left: 50%
top: 50%
width: 100%
- type: conditional
conditions:
- entity: light.living_room_uplight1
state: 'off'
- entity: light.living_room_uplight2
state: 'on'
elements:
- type: image
tap_action:
action: none
hold_action:
action: none
entity:
- light.living_room_uplight1
- light.living_room_uplight2
image: /local/floorplan/light.living_room_uplight2.png?version=1
filter: none
style:
left: 50%
top: 50%
width: 100%
- type: conditional
conditions:
- entity: light.corridor
state: 'on'
elements:
- type: image
tap_action:
action: none
hold_action:
action: none
entity:
- light.corridor
image: /local/floorplan/light.corridor.png?version=1
filter: none
style:
left: 50%
top: 50%
width: 100%
- type: state-icon
entity: light.bathroom
title: null
tap_action:
action: toggle
style:
top: 44.76%
left: 25.65%
border-radius: 50%
text-align: center
background-color: rgba(255, 255, 255, 0.3)
- type: state-icon
entity: light.kitchen
title: null
tap_action:
action: toggle
style:
top: 24.80%
left: 54.42%
border-radius: 50%
text-align: center
background-color: rgba(255, 255, 255, 0.3)
- type: state-icon
entity: light.bedroom2_uplight
title: null
tap_action:
action: toggle
style:
top: 28.89%
left: 44.64%
border-radius: 50%
text-align: center
background-color: rgba(255, 255, 255, 0.3)
- type: state-icon
entity: light.bedroom2_spotlight
title: null
tap_action:
action: toggle
style:
top: 27.47%
left: 27.78%
border-radius: 50%
text-align: center
background-color: rgba(255, 255, 255, 0.3)
- type: state-icon
entity: light.living_room_uplight1
title: null
tap_action:
action: toggle
style:
top: 26.37%
left: 74.10%
border-radius: 50%
text-align: center
background-color: rgba(255, 255, 255, 0.3)
- type: state-icon
entity: light.bedroom_side1
title: null
tap_action:
action: toggle
style:
top: 66.97%
left: 22.39%
border-radius: 50%
text-align: center
background-color: rgba(255, 255, 255, 0.3)
- type: state-icon
entity: light.living_room_uplight2
title: null
tap_action:
action: toggle
style:
top: 58.60%
left: 75.59%
border-radius: 50%
text-align: center
background-color: rgba(255, 255, 255, 0.3)
- type: state-icon
entity: light.bedroom_side2
title: null
tap_action:
action: toggle
style:
top: 83.78%
left: 21.18%
border-radius: 50%
text-align: center
background-color: rgba(255, 255, 255, 0.3)
- type: state-icon
entity: light.corridor
title: null
tap_action:
action: toggle
style:
top: 55.01%
left: 38.45%
border-radius: 50%
text-align: center
background-color: rgba(255, 255, 255, 0.3)
- type: state-icon
entity: light.bedroom_desk
title: null
tap_action:
action: toggle
style:
top: 73.32%
left: 38.64%
border-radius: 50%
text-align: center
background-color: rgba(255, 255, 255, 0.3)
You can find some more information, and the plugin itself for download at: GitHub - shmuelzon/home-assistant-floor-plan: Home Assistant Floor Plan Generator Plugin For Sweet Home 3D
I’d be happy to hear any feedback, and thanks to everyone for the inspiration to do this!