Design your SVG floorplan or dashboard for HABPanel with Inkscape

floorplan
svg
inkscape
Tags: #<Tag:0x00007fd32223e158> #<Tag:0x00007fd32223e018> #<Tag:0x00007fd32223ded8>

(Yannick Schaus) #41

That would be something like:

{ "fill-red": itemState('Item_Name') == 'State1', "fill-blue": itemState('Item_Name') == 'State2', "fill-green": itemState('Item_Name') == 'State3' }

Tutorial here: https://appendto.com/2016/03/ng-class-use-cases-action/


(Nisse Nilsson) #42

I don’t know if you solved it but try putting your rectangle in a group and zero it… then move your group where you want it…

<g
       id="g935"
       transform="translate(23,358)">
      <rect
         ng-class="{&quot;open_door&quot;: itemState('DoorStatus') == 'ON' }"
         y="0"
         x="0"
         height="23.823421"
         width="200.11674"
         id="door"
         style="opacity:1;fill:#ff37ff;fill-opacity:0.8738739;fill-rule:nonzero;stroke:#a0a0a0;stroke-width:8;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
    </g>

(Nisse Nilsson) #43

just wanted to show what I’ve done so far…
In particular the dynamic sensor info, floating in from the left…
This is stil under testing… so the code is very ugly…
and alot of the code isn’t relevant…
if you have any pointers please let me know :slight_smile:
And a question… is this the right way to manipulate variables in svg?? (it doesn’t look right to me, but it works)

// in HABPanel

<div oc-lazy-load="['/static/js/jquery-3.2.1.min.js','/static/pressableTest.js']">
  <div oc-lazy-load="'/static/floorplan.css'">
    <div ng-include="'/static/floorplan.svg'" ng-controller="MainCtrl"></div>
  </div>
</div>

// pressableTest.js …I made a long press action…
// This is stil in testing … alot of code is just test code
// $scope.testing is the part where the control off css animations is…
https://pastebin.com/SWz3BrMT

// floorplan.css (just the relevant stuff)
https://pastebin.com/pPTcQ7y4

// in inkscape… ng-click on the sensors

move=true;
move2=true;
move3=true;
testing('Temperature_Xiaomi_13');
varitem=(itemState('Temperature_Xiaomi_13') | number:1) + '°C';
varitem2=(itemState('Humidity_Xiaomi_14') | number:1) + '%';
varitem3=(itemState('Pressure_Xiaomi_15') | number:1) + 'kPa';

// in inkscape… ng-class on the different ‘bubbles’ floating out
// first bubble

{test_out : move}

//second bubble

{test_out2 : move2}

… and so on
let me know what you think… :crazy_face:


(Dome) #44

Is it possible to utilize dynamic SVGs without the use of HABpanel? I think there’s a use case for an html file with the svg embedded as a low overhead alternative if none of the other features of HABpanel are needed, but I’m not sure if this is even possible.


(Kjetil Asdal) #45

It certainly is! I am working on something like this to be used as a dynamic floor plan of my house (i.e. e floor plan with dynamic information elements like temperature in rooms, status on doors, etc.).

Using Inkscape (or some other editor) you can draw whatever you like, and then add identifiers to the elements that you would like to be dynamic in some sense.

Including the SVG as an object in your HTML file, you can use JavaScript (possibly with the help of JQuery) to manipulate the SVG DOM (by referencing the dynamic elements of your SVG by the aforementioned identifiers).

I am more or less doing this as a project to teach myself some HTML5, so it is far from usable, but I have come far enough to understand that it is possible to do fairly complex stuff without too much hassle, so it looks promising.


(Dome) #46

Awesome! I’d love to see some of your code if/when you’re willing to share!


(John Sable) #47

Nisse,

That is awesome, I am just getting started with this and I have a question for you… Is it possible to have one of those slide outs with an image linked from a web address? I’d like to incorporate an ng-click/ng-class for my security cameras and have a slide out when you click on the camera icon to show the current static image?


(Dome) #48

Yes, it is. I have it set up just as you described. There may be a faster or easier way to do it but this is how I did it.

First, go to File > Import, and import a placeholder file in the same format as your camera or software (I use Shinobi) outputs stills (probably jpg). Open the XML editor for the picture. Change the height and width to the values you’d like while trying to preserve your aspect ratio. Change “xlink:href” to the path to your camera feed. Then, add a new “ng-click” attribute with the following text:

sendCmd('Dashboard', 'Security Video')

For this to work properly, you’ll need an Item named Dashboard, to configure HABpanel to switch to dashboards based on the Dashboard item, and a panel called “Security Video.” Feel free to change names to suit your needs.

It won’t show up properly in Inkscape, just showing a “Linked Image Not Found” error. However, it should display a snapshot of the video wherever you put the image, and clicking it will open the linked dashboard where you can create a full page web frame.

I put all of the video feeds in a “video” layer which I can then show or hide as desired.


(Ben Geens) #49

Hi everyone!

First of all, thanks to everyone involved here. It is very nice to be able to draw your own visualization.
However I am stuck at something right now. What I’m trying to do is letting an arrow change from red to green and the other way around depending on a value stored in an item in OH. That works perfect but I would like to rotate the arrow 180 degrees when the arrow is in the red state. I managed to get that working as well but here comes the problem:

As you can see, the arrow is way too big after the transformation.

This is the css code I used.

.negativePower {
    fill: #ff0000 !important;
    transform-origin: center !important;
    -webkit-transform: rotateY(180deg) !important; /* Safari */
    transform: rotateY(180deg) !important;
}
.positivePower {
    fill: #00d400 !important;
}

Has somebody the ultimate answer? Thanks!


(Dome) #50

I don’t have a perfect answer, but one solution is to make two arrows, one red and one green, and change their opacity depending on the openHAB value.


(Ben Geens) #51

I did it like that for now.
In fact I would have liked to go a step further and use gif’s for the arrows but unfortunately that is not possible with Inkscape.

So with that said, next question. I’m trying to show numbers but would like them to be formatted in the European way. Like so: 10.000,45 . Now it is shown like this: 10,000.45 . I used (itemState(‘Lux’) | number:1) + ’ Lux’ to limit the numbers but then the formatting goes “wrong”.

Is there an easy solution?

Thanks again


(John Sable) #52

Hi Dome,

Thanks for the pointers. I tried it the way you describe, but I am using MotionEye to manage all of my cameras and my HabPanel actually shows the live feed from the camera. I also tried with the current image (.jpg), but I have to refresh the page every time I want an updated image.
I am now researching a way to show/hide with an ng-click… this should do what I’d like to with HabPanel if I can figure it out!


(Dome) #53

This is how I did it: I made a habpanel.itmems file with a dummy Switch item for each layer. Then, I made a “transparent” class in my CSS file with opacity:0. Set each layer to use that class when the corresponding switch is off. Finally, set your switch item to toggle when you click a rectangle or whatever shape. Configure this with ng-click as described above. I am on my phone so let me know if code is examples would help.


(John Sable) #54

Dome, any code you could supply would be helpful!

~John


(Dome) #55

Here’s my relevant items:

// HABPanel SVG Items

Switch SVGDisplayMotion
Switch SVGDisplayDoors
Switch SVGDisplayVideo
Switch SVGDisplayDiagnostics
Switch SVGDisplayLights
String SVGDisplayPanel

In my CSS file, I made these attributes:

.transparent {
opacity: 0 !important;
}
.button-selected {
fill: #0000FF !important;
}

Then in Inkscape I grouped all the similar elements by layer. Make a layer, name it, and adjust it so it’s above the background (I made a background layer as well), and then open the layer itself in the XML editor. Then add an SVG attribute to the layer itself. In my example, I added the following ng-class attribute:

{'transparent': itemState('SVGDisplayVideo') == 'OFF' }

If viewing my video layer in code, it looks like this (URL API keys redacted):

<g
     inkscape:groupmode="layer"
     id="layer11"
     inkscape:label="Video"
     style="display:inline"
     ng-class="{'transparent': itemState('SVGDisplayVideo') == 'OFF' }">
    <image
       y="1240"
       x="1640"
       id="image10029"
       xlink:href="http://192.168.1.180:8082/camera1url.jpg"
       height="220"
       width="280"
       ng-click="sendCmd('Dashboard', 'Security Video')" />
    <image
       width="220"
       height="140"
       xlink:href="http://192.168.1.180:8082/camera2url.jpg"
       id="image10153"
       x="1380"
       y="1060"
       inkscape:transform-center-x="2.7436242"
       inkscape:transform-center-y="-74.077853" />
  </g>

Then make a button using the rectangle tool. I added text over it and used added the following ng-click attributes to both the text and the rectangle:

sendCmd('SVGDisplayVideo', (itemState('SVGDisplayVideo') == 'ON') ? 'OFF' : 'ON')

I also added this ng-classattribute to the rectangle:

{"button-selected": itemState('SVGDisplayVideo') == 'ON' }

Hopefully this is helpful.

I need to do some more work with the cameras but it’s not at the top of my priority list right now. I’m thinking I’ll use a proxy item that will both change to the live view dashboard and change the source for a web frame to show the proper camera.

I did note that limitation - in my use case the picture is little more than a thumbnail so it didn’t really matter, but I can see where that would be frustrating if you’re looking to use it to view a live feed.


(John Sable) #56

@Dome,

Thanks for all the help! This worked out very well for me. I ended up putting each camera on it’s own layer, I only wanted the selected camera to show up when activated.
One thing that took me a while to figure out was that even though the camera image was hidden, I could not tap/click on the item under it (even though it is visible when the image is hidden).
Here is what I have so far:
1st%20Floor%20Cameras

~John


(Dome) #59

Yes, I noticed that too. It’s a bit of work, but you can always add a transparent rectangle over the video if you want a region to be clickable.


(John Sable) #60

@Dome,
I got the items sorted. by lowering the layer for the images. I still need to do some more work on this, one thing that took me a few weeks to notice is that no matter what time of day I click on the link for a camera, it does not refresh the image when clicked later in the day. So, if I look at a camera at 8 am, then check it again at 3 pm, it is still the same image from 8 am, that is, until I refresh the page. I have to re-think how I list the images because the camera stream does not work with the existing code… I think it would be better to have these images as the live camera feed. I may to have to borrow some code from the security camera carousel widget…


(shane kevin) #61

hey guys and @ysc
How to make the svg “pan-able”(or should I say “drag-able”)?
I found the github python lib for svg pan and zoom, but I have no idea how to use in habpanel, currently I make the svg responsive but in habpanel it looks too small and hard to touch the lights. Could someone please take a look at it and make this happen? Thanks!


(Thomas) #62

Hi,

could it be that there is a character limitation in the ng-class?
Everytime when my ng-class string is larger than 60 character the class asignment doesn’t work.

This string (60 chars) works:
{‘presence-on’: itemState(‘abcdefghijklmnopqrstuv’) == ‘ON’}

This string (61 chars) doesn’t work:
{‘presence-on’: itemState(‘abcdefghijklmnopqrstuvw’) == ‘ON’}

Did anyone of you have a similar issue?