r/openhab • u/Extension-Still-1520 • 4d ago
another Pokemon Style Floor-Plan (just with OpenHAB)
Inspired by this genius I made my own Pokémon-Floorplan. But with OpenHAB and some individual features. It is not perfect, but I feel very comfortable by using it.
I used Inkscape and Notepad++.
I am working on documentation of how I did it and if there is interest, I will be happy to share it here =)
Features
in the SVG
- Automatic day-night switch
- No duplicate images required
- Individual and combined light sources in night mode
- Light cone can be adjusted in general
- Light cone intensity can be adjusted per light source
- Light cone can be limited to rooms
- Fog effect per room (to represent high humidity)
through widgets (I will document these on separate pages)
- Camera widget: button to open a camera stream in HLS or MJPEG
- Lamp widget
- On/Off with short tap (mobile) / left click (desktop)
- Extended menu with long tap (mobile) / right click (desktop)
- Lamp icon color corresponds to actual light color
- Thermostat widget (reuse of the lamp widget with different symbol and color scale)
- Extended information on click
- Color change according to measurement values
- Pokémon widget (for visualizing environmental effects)
- Display of measurements or forecasts as a health bar, including units
- Max HP absolute or extended with additional item
- Show additional values over time, e.g. forecasts for following days
- Evolution / change when thresholds are exceeded
- Special: Direction circle, e.g. for visualizing wind directions
- Extended information on click
- Display of measurements or forecasts as a health bar, including units
- Glow widget (for visualizing glow effects, e.g. for heating and screens)
- Simple glow aura around an object (e.g. blue for active screens, red for running heaters)
- Extended menu on click (to control the objects, e.g. heating control)
- First of all, I designes this as an Canva-Layout in Openhab with an SVG-Floorplan and added some widget for this. Some items needs both: for example the light-switch is a widget, but the light-effect works on the floorplan.
2. SVG Floorplan Creation with SVG
- Create the layout in Inkscape:
- Design rooms as separate groups.
- Ensure pixel dimensions match actual scaling for easier manual editing later.
- Tip: Each room must be a distinct
<g>
group, optionally containing subgroups for furniture or details. - You can use tiles from any tilesets in the internet. But there are some furniture variants, which does not exist. Like beds in some angles. You have to make them yourself.
3. Editing with Notepad++: <defs> Section Configuration
- Room Definitions: Rooms are moved to
<defs>
with a uniqueid
and attributeopenhab="true"
so openHAB can interact with them. Moving to<defs>
is important, so you can reuse it and do not need to create an additional night-version.
<!-- Room-Definitions: reusable for light and dark modes -->
<g id="livingroom" openhab="true">...</g>
- Centralized Patterns (optional): Reusable floor textures are defined once to simplify code:
<!-- Floor-Pattern Definitions -->
<pattern id="floor_livingroom_pattern" patternUnits="userSpaceOnUse" width="32" height="32">
<use href="#tile385"/>
</pattern>
<image id="tile385" width="32" height="32" xlink:href=".../tile385.png"/>
4. Editing with Notepad++: Visual Effects
- Rain Effect: this is just a box for defining some drops and to reuse is multiple times on the map
<!-- Rain -->
<g id="raingroup">
<circle cx="0" cy="0" r="2" fill="blue">
<animate attributeName="cy" from="0" to="170" dur="0.6s" repeatCount="indefinite"/>
<animate attributeName="opacity" values="1;0" dur="0.6s" repeatCount="indefinite"/>
</circle>
<!-- Additional animated drops... -->
</g>
- Night Mode Lighting & Shadows:
- Apply a color filter to switch to night mode:
<filter id="nightFilter"> <feColorMatrix type="matrix" values="0.05 0.05 0.05 0 0 ..."/> </filter>
- Define a radial gradient for lighting:
<radialGradient id="light_gradient"> <stop offset="0%" stop-color="black" stop-opacity="1"/> <stop offset="100%" stop-color="black" stop-opacity="0"/> </radialGradient>
- Mark light sources in rooms with
openhab="true"
:<circle cx="450" cy="172" r="256" fill="url(#light_gradient)" id="office_light" openhab="true"/>
- Use masking to restrict lighting to each room:
<mask id="office_colorRestoreMask"> <rect width="100%" height="100%" fill="white"/> <use href="#office_light"/> </mask>
- Finally, render both "light" (day) and "night" versions using
<use>
, applying masks:<use class="light" href="#office"/> <use class="night" href="#office" mask="url(#office_colorRestoreMask)"/>
- Apply a color filter to switch to night mode:
5. Central Style & Control Classes
Define CSS-like rules in SVG to control visibility and modes:
<style id="style1">
.nighttime ~ .night { filter: url(#nightFilter); }
.hide { display: none; }
.fog { filter: url(#fogFilter); }
.opacity0 { opacity: 0; }
.opacity1 { opacity: 1; }
</style>
.nighttime
class (added by openHAB) toggles night mode..hide
can hide elements like rain until activated..fog
applies the fog effect..opacity0
/.opacity1
manage glow effects.
6. SVG Composition & openHAB Integration
- Listener for Day/Night Mode:
- openHAB adds the
.nighttime
class when it's night<circle cx="2" cy="2" r="2" id="daytime_listener" openhab="true"/>
- openHAB adds the
- Rendering the Components: Use both light and night versions:
<use class="light" href="#outside"/> <use class="night" href="#outside" mask="url(#outside_colorRestoreMask)"/> <!-- Repeat for each room -->
- Rain Layer:openHAB can toggle
class="hide"
to show rainfall<g id="rain" openhab="true" class="hide"> <!-- Instances of raingroup placed around the layout --> </g>
I would like to show you a very simplified version of this as an example. I tried to break it down as much as possible. I will maintain more examples and details on my own site, if thats possible here: https://smarthome.edv-hacker.de/en/smarthome-en/cores-centrals-en/interaktiver-floorplan-in-openhab-mit-effekten-2/
Please feel free to ask. I know, i am very operationally blind.
I know, this might not be perfect. I will be very thankful for suggestions to make this project better and reusable.
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="console.log('modified')" width="672" height="832" viewBox="0 0 672 832" version="1.1" id="svg1" xml:space="preserve">
<style id="style1">
.nighttime ~ .night {
filter: url(#nightFilter);
}
.night {
filter: url(#grayFilter);
}
.hide { display: none; }
.opacity0 { opacity: 0; }
.opacity1 { opacity: 1; }
</style>
<defs id="defs1">
<!-- Color-Definition for the Night-Mode -->
<filter id="nightFilter">
<feColorMatrix type="matrix"
values="0.05 0.05 0.05 0 0
0.05 0.05 0.05 0 0
0.05 0.05 0.05 0 0
0 0 0 1 0"
id="feColorMatrix1" />
</filter>
<!-- Gradient definition (be strong at the center and weak at the edge: this definition approximates a logarithmic gradient) -->
<radialGradient id="light_gradient">
<stop offset="0%" stop-color="black" stop-opacity="1" />
<stop offset="10%" stop-color="black" stop-opacity="0.7" />
<stop offset="25%" stop-color="black" stop-opacity="0.4" />
<stop offset="50%" stop-color="black" stop-opacity="0.15" />
<stop offset="80%" stop-color="black" stop-opacity="0.05" />
<stop offset="100%" stop-color="black" stop-opacity="0" />
</radialGradient>
<linearGradient id="blackToGray" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="black" stop-opacity="1" />
<stop offset="20%" stop-color="black" stop-opacity="1" />
<stop offset="100%" stop-color="black" stop-opacity="0" />
</linearGradient>
<!-- Light-Area definitions (where are your light sources?) -->
<!-- (more light sources) -->
<circle cx="420" cy="60" r="512" fill="url(#light_gradient)" id='terace_garden_light' openhab="true" />
<g id='terace_perch_light' openhab="true">
<circle cx="620" cy="330" r="192" fill="url(#light_gradient)" />
<circle cx="520" cy="430" r="192" fill="url(#light_gradient)" />
</g>
<!-- Room sepatations (to prevent, that light areas are seen in other rooms) -->
<!-- (more masks for more rooms) -->
<mask id="outside_colorRestoreMask">
<rect width="100%" height="100%" fill="white" />
<use href="#terace_garden_light" />
<use href="#terace_perch_light" />
</mask>
<!-- Rain -->
<g id="raingroup">
<circle cx="0" cy="0" r="2" fill="blue">
<animate attributeName="cy" from="0" to="170" dur="0.6s" repeatCount="indefinite" />
<animate attributeName="opacity" values="1;0" dur="0.6s" repeatCount="indefinite" />
</circle>
<!-- (just some more circles) -->
</g>
<!-- Floor-Pattern Definitions, to save some code -->
<image id="tile385" width="32" height="32" xlink:href="/static/floorplan/icons/Pokemon/Tilesets/Interior%20general/tile385.png" />
<pattern id="floor_terace_stone_pattern" patternUnits="userSpaceOnUse" width="32" height="32">
<use href="#stone_floor" />
</pattern>
<image id="stone_floor" width="32" height="32" xlink:href="/static/floorplan/icons/Pokemon/Tilesets/Game%20Corner%20interior/steone_floor.PNG" />
<pattern id="floor_terace_tiles_pattern" patternUnits="userSpaceOnUse" width="32" height="32">
<use href="#tile200" />
</pattern>
<image id="tile200" width="32" height="32" xlink:href="/static/floorplan/icons/Pokemon/Tilesets/Interior%20general/tile200.png" />
<!-- (more patterns and reusable images) -->
<!-- Room-Definitions, to make the rooms reusable and avoid defining them twice: light mode and dark mode -->
<g id="outside" openhab="true">
<path d="M 384,0 H 576 V 160 H 528 V 112 H 384 Z" id="terace1" class='floor' fill="url(#floor_terace_tiles_pattern)" />
<path d="m 608,80 h 64 V 320 H 528 v -64 h 48 v -96 h 32 z" id="terace2" class='floor' fill="url(#floor_terace_stone_pattern)" />
<path d="M 528,336 H 672 V 528 H 576 V 496 H 528 Z" id="terace3" class='floor' fill="url(#floor_terace_stone_pattern)" />
<image width="32" height="32" xlink:href="/static/floorplan/icons/Pokemon/Tilesets/Outside/row-98-column-3.png" id="image1-52" x="-160" y="576" transform="rotate(-90)" />
<image width="32" height="32" xlink:href="/static/floorplan/icons/Pokemon/Tilesets/Outside/Outside.png" id="image1-221-46" x="576" y="0" />
<image width="32" height="32" xlink:href="/static/floorplan/icons/Pokemon/Tilesets/Outside/Outside.png" id="image1-221-91" x="576" y="32" />
<image width="32" height="32" xlink:href="/static/floorplan/icons/Pokemon/Tilesets/Outside/Outside.png" id="image1-221-919" x="576" y="64" />
<image width="32" height="32" xlink:href="/static/floorplan/icons/Pokemon/Tilesets/Outside/Outside.png" id="image1-221-3" x="576" y="96" />
<g id="g1" inkscape:label="grass">
<image width="32" height="32" xlink:href="/static/floorplan/icons/Pokemon/Tilesets/Outside/row-1-column-6.png" id="image1-416" x="608" y="16" />
<image width="32" height="32" xlink:href="/static/floorplan/icons/Pokemon/Tilesets/Outside/row-1-column-6.png" id="image1-416-7" x="640" y="32" />
<image width="32" height="32" xlink:href="/static/floorplan/icons/Pokemon/Tilesets/Outside/row-1-column-7.png" id="image1-183" x="640" y="48" />
<image width="32" height="32" xlink:href="/static/floorplan/icons/Pokemon/Tilesets/Outside/row-1-column-7.png" id="image1-183-8" x="640" y="0" />
<image width="32" height="32" xlink:href="/static/floorplan/icons/Pokemon/Tilesets/Outside/row-1-column-5.png" id="image1-92" x="608" y="48" />
<image width="32" height="32" xlink:href="/static/floorplan/icons/Pokemon/Tilesets/Outside/row-1-column-3.png" id="image1-350" x="608" y="0" />
</g>
<g>
<rect fill="black" width="48" height="96" x="528" y="160" />
<image width="32" height="96" xlink:href="/static/floorplan/icons/moderninteriors-win/1_Interiors/32x32/Theme_Sorter_Singles_32x32/26_Condominium_Singles_32x32/Condominium_Singles_32x32_26.png" x="-568" y="-270" transform="rotate(180)" />
<rect fill="url(#blackToGray)" width="48" height="96" x="528" y="160" />
</g>
</g>
<!-- (more rooms, made with inkscape) -->
<g id="Walls" style="opacity:0.652;image-rendering:auto">
<!-- (I defined the walls in an extra group, so they are not affected from light or fog) -->
<!-- (wall images an positions...) -->
</g>
</defs>
<sodipodi:namedview id="namedview1" pagecolor="#000000" bordercolor="#000000" borderopacity="0.25" showgrid="true" showguides="true">
<inkscape:grid id="grid1" units="px" originx="0" originy="0" spacingx="16" spacingy="16" empcolor="#0099e5" empopacity="0.30196078" color="#0099e5" opacity="0.14902" empspacing="2" dotted="false" gridanglex="30" gridanglez="30" visible="true" />
</sodipodi:namedview>
<!-- Listener for the daytime-Switch. To set the plan automatically to daytime-mode during daytime. -->
<circle cx="2" cy="2" r="2" id='daytime_listener' openhab="true" />
<!-- Setup the rooms -->
<use class="light" href="#outside" />
<use class="night" href="#outside" mask="url(#outside_colorRestoreMask)" />
<!-- (repeat that for all of your rooms) -->
<!-- Rain -->
<g id="rain" openhab="true" class="hide">
<use href="#raingroup" x="0" y="0" />
<use href="#raingroup" x="400" y="-250" />
<use href="#raingroup" x="544" y="0" />
<!-- ... -->
</g>
</svg>
For all of the elements with openhab="true" there has to be an openhab item to control that element. I will just list mine, for datatype documentation.
Dimmer Outside_Brightness "Light" <DimmableLight> (igOutsideLight) ["Control", "Brightness"] { autoupdate="false", channel="mqtt:topic:myMosquitto:HueBulbOutside:brightness" }
For a single light
Switch siDaytime "Day" { channel="astro:sun:local:position#elevation" [profile="system:hysteresis", lower="0 °"] }
For the daytime_listener
Switch siRain "Weather condition" (sgEnvironment) { channel="openweathermap:onecall:api:myHome:current#condition-id" [profile="transform:MAP", function="OWM_rainSwitch.map", sourceFormat="%s" ] }
For the rain
1
1
1d ago
[deleted]
1
u/RemindMeBot 1d ago
I will be messaging you in 1 month on 2025-09-26 11:41:53 UTC to remind you of this link
CLICK THIS LINK to send a PM to also be reminded and to reduce spam.
Parent commenter can delete this message to hide from others.
Info Custom Your Reminders Feedback
1
u/HiamoviHD 1d ago
Waiting for the docs since this looks amazing. Also, what are you doing with a booking.com switch? xD
RemindMe! 4 weeks
2
u/subwoofage 3d ago
Yes, this is amazing, I'd love to see how it was made!