Hacking BasicUI: My current Theme / OH2 Setup *Update with Repo*

2018-12-06
Implemented a really nice interactive SVG floorplan in BasicUI using SSE, Refactored Injection method so we can use sitemap sub-pages and not lose our injected code on reload etc. Put up some more NodeMCU sensors and shellys around the house, fixed a bunch of stuff, i don’t remember. Gonna commit later today.

2018-11-22
fixed some js template code, added 2 new echo dots, shelly fixes, refactored wifi presence code, added 3d printer status through ocotoprint mqtt, updated tuyapi, refactored css/js injection so it works on a sitemap’s sub page, broke up my rather large sitemap into sections, misc minor fixes

2018-11-08
event scheduling through google calendar, for heating, alarms, tts volume, etc

2018-10-29
I thought i’d post some more up to date pics:
Changelog, see repo link above

2018-07-25
Hey, i thought it’s time to post some more recent screenshots, i’m making good progress, the UI is very flexible and responsive, works really nicely with all of my devices. Performance seems to be good too, despite all the gradients and transparency going on, it’s all css btw (even the background!), no images except the icons which are all extremely optimized svgs. I just switched everything over to JSR223 Javascript too, feeling really good about the stability and performance now. It may look like i focus mostly on the UI Layout, but there are a lot of feature you can’t actually see, mostly involving Alexa Speech commands and TTS. Next on my To Do List is making a public repo, adding Received E-Mail and To Do List Notifications via Echo TTS (It already reminds me of Google calendar events), add second mapdb persistence to cache UI stuff i don’t need in influxdb, add actual browser playback to my TuneIn thingie (currently it sends the selected radio channel to my Echo devices), implementing more energy logging/graphing/statistics once i got my power meter hooked up to OH in the next couple days, oh and more Lights Lights Lights. Anyways, here are some screens:

Google Map, RSS Reader, Logreader, TuneIn list and some other panel content are actually scrollable iframes. Pretty nifty eh? and despite all the iframe hackery, everything works very well over myopenhab too.

here’s an example with some panels collapsed and popped out, you can move everything around and expand/collapse panels etc, they remember state too

2018-06-02
Just wanted to share my current Layout to show what’s possible with BasicUI. I’m using Openhab for about a month now so it’s still a work in progress. There isn’t really much light or floor heating automation yet, i’m still deciding on the right hardware.

I’m not really getting warm with HabPanel because i prefer to write code and not design UIs with drag and drop etc, I do want to give it another try soon though. I wish it was possible to get more into BasicUI’s panties to have more control over the html and js instead of resorting to this hacky iframe css injection method. Anyways, Questions welcome! I am currently tearing it apart using jquery, adding visibility toggle buttons to panels etc, saving settings in a cookie, i plan to add new UI controls like keypads etc, LEFT UP DOWN RIGHT OK arrow controls etc…

Older Images

full view

#basicuiisnotdead

32 Likes

Nice !

I would love if you explain more how you did it.
Would you mind sharing some code ?

Amazing, great work!

The code for echo is? (:thinking:)

Do you by change have the persited data or a chart-Picture of the openaHAB Memory usage? Just to compare with my observations.

chart-Picture of the openaHAB Memory usage?

hope that helps

1 Like

Thanks!

i’m using the Amazon Echo Control Binding and am controlling Stuff via myopenhab / OpenHAB’s Alexa Skill. I should probably set up a repo to share my code, as it is growing quite quickly. Please bear with me, i’m pretty busy with work and family so it might take a while to strip private things and release this.Here’s another Screenshot, it actually has a gradient grey->black background which isn’t visible due to the screenshot technique.

The spike-ups are processes that commit the whole thing to bitbucket btw, which seems to keep my little RasPi 3+ pretty busy, The spike-downs are server/service resets

On my Raspi3 I’m logging the percentage used and I’m observing a (continuously?) rising value, however I’m not up to 50% yet. I started OH Tuesday evening.

I wouldn’t be surprised if there were a bunch of nasty memory leaks in some bindings. I believe OH2 itself isn’t actually using all the allocated memory too, it just takes all it can for later use and never seems to free it up again. Which is one of the reason i might have to get myself some better hardware to run OpenHAB on. Maybe this kind of aggressive memory consumption is just a Java thing? I’m not a big fan of Java and i’m not pissed off enough to have a look at the OpenHAB Code myself yet, but one day i might :slight_smile:

As for the “offical” parts, i.e. the parts that went through the approval process on GitHub, I would not say something like that.
Having run my OH2.2 for several month without any problem does in the direction that OH takes as much as it can, but doesn’t release. Now that I’m persisting that value I haven’t seen the maximum yet.

Just hacked in some nice panel collapse code, but the wife is nagging and wants to go to bed :<

In case someone wants to try out my UI changes, here’s some work-in-progress-code, you need:
html/js/jquery.min.js
html/js/jquery.cookie.js
html/css/Roboto-Regular.woff2
html/css/Roboto-Regular2.woff2
html/css/overrides.css:

/* cyrillic-ext */
@font-face {
    font-family: 'Roboto Condensed';
    font-style: normal;
    font-weight: 400;
    src: local('Roboto Condensed'), local('RobotoCondensed-Regular'), url(Roboto-Regular.woff2) format('woff2');
    unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
    font-family: 'Roboto Condensed';
    font-style: normal;
    font-weight: 400;
    src: local('Roboto Condensed'), local('RobotoCondensed-Regular'), url(Roboto-Regular.woff2) format('woff2');
    unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
    font-family: 'Roboto Condensed';
    font-style: normal;
    font-weight: 400;
    src: local('Roboto Condensed'), local('RobotoCondensed-Regular'), url(Roboto-Regular.woff2) format('woff2');
    unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
    font-family: 'Roboto Condensed';
    font-style: normal;
    font-weight: 400;
    src: local('Roboto Condensed'), local('RobotoCondensed-Regular'), url(Roboto-Regular.woff2) format('woff2');
    unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
    font-family: 'Roboto Condensed';
    font-style: normal;
    font-weight: 400;
    src: local('Roboto Condensed'), local('RobotoCondensed-Regular'), url(Roboto-Regular.woff2) format('woff2');
    unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
    font-family: 'Roboto Condensed';
    font-style: normal;
    font-weight: 400;
    src: local('Roboto Condensed'), local('RobotoCondensed-Regular'), url(Roboto-Regular.woff2) format('woff2');
    unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
    font-family: 'Roboto Condensed';
    font-style: normal;
    font-weight: 400;
    src: local('Roboto Condensed'), local('RobotoCondensed-Regular'), url(Roboto-Regular2.woff2) format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

body[data-theme="dark"] {
    --primary-color: #111111;
}

body
{
	background: linear-gradient(33deg,#222, #111);
}

.mdl-shadow--2dp {
	box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 
				0 3px 1px -2px rgba(0,0,0,.2), 
				0 1px 5px 0 rgba(0,0,0,.62);
}

body,h5,.mdl-layout-title
{
	font-family: 'Roboto Condensed', sans-serif !important;
}

.mdl-form__title {
    padding-top: 15px;
    padding-bottom: 15px;
}
.mdl-form__control
{
	padding: 0;
}

.mdl-form__row:not(.mdl-form__row--height-auto)
{
    height: 28px !important;
}

.mdl-form .mdl-form 
{
	margin: 0 !important;
}

.mdl-form .mdl-form h5
{
	font-size: 16px;
	padding-bottom:15px;
	margin-bottom:10px;
	border-bottom: 1px solid #333333;
}

.mdl-form__control .mdl-button--accent
{
	background-color: #888888 !important;
}

.mdl-switch__thumb
{
	background: #aaaaaa !important;
}
.is-checked .mdl-switch__thumb
{
	background: #ffffff !important;
}

.mdl-switch__track
{
	background: #333333 !important;
}
.is-checked .mdl-switch__track
{
	background: #666666 !important;
}

.mdl-slider.is-upgraded 
{
	color: #333333 !important;
}

.mdl-slider__background-lower 
{
    background: #666666 !important;
}

.mdl-slider::-webkit-slider-thumb {
	background: #666666 !important;
}

.mdl-slider::-moz-range-thumb, 
.mdl-slider::-ms-thumb  {
	background: #666666 !important;
}

.mdl-button
{
	height: 26px !important;
    min-width: 44px !important;
	border-radius: 4px !important;
	line-height: 26px !important;
}

.mdl-radio__group .mdl-radio__label 
{
    padding-top: 3px !important;
    height: 1px;
}

.mdl-radio__outer-circle, .mdl-radio__inner-circle, .mdl-radio__ripple-container {
    margin-top: 5px;
}

.mdl-modal__wrapper 
{
    max-width: 500px;
}

.mdl-form
{
    border-top: 1px solid rgba(255,255,255,0.1) !important;
    border-left: 1px solid rgba(255,255,255,0.1) !important;
    background-color: rgba(44,44,44,0.3) !important;
    border-radius: 5px;
    overflow:hidden;
}

.mdl-form h5 
{
    padding-top: 12px !important;
    padding-bottom: 15px !important;
    color:rgba(180,180,180,0.6);
    width:100%;
}

.mdl-form > h5, .collapse_btn, .top_btn
{
    cursor: pointer;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
     -khtml-user-select: none;
       -moz-user-select: none;
        -ms-user-select: none;
            user-select: none;
}

.collapse_btn
{
    /*position: relative;*/
    float:right;
    width: 23px;
    height: 23px;
    right: 3px;
    text-align: center;
    color: rgba(255,255,255,0.2);
    -moz-transition: all 0.4s ease;
    -webkit-transition: all 0.4s ease;
    -o-transition: all 0.4s ease;
    transition: all 0.4s ease;
    transform-origin: center center;
    /*border: 1px solid;*/
    margin-top:-11px;
}

.collapse_btn:hover
{
    transform: rotate(180deg);
}

.collapse_btn_rotated
{
    transform: rotate(180deg);
}

.bg_olive
{
	background-color: rgba(89, 99, 63, 0.166) !important;
}
.bg_tomato
{
	background-color: rgba(221, 80, 37, 0.207) !important;
}
.bg_eggplant
{
	background-color: rgba(76, 93, 155, 0.2) !important;
}
.bg_sony
{
	background-color: rgba(76, 94, 102, 0.3) !important;
}
.bg_ac
{
	background-color: rgba(222, 222, 222, 0.1) !important;
}
.bg_echos
{
	background-color: rgba(49, 89, 104, 0.13) !important;
}
.bg_klima
{
	background-color: rgba(92, 70, 50, 0.2) !important;
}
.bg_net
{
	background-color: rgba(79, 58, 58, 0.199) !important;
}
.bg_sys
{
	background-color: rgba(16, 198, 211, 0.1) !important;
}
.bg_alarm
{
	background-color: rgba(211, 45, 16, 0.076) !important;
}
/*
.mdl-form:hover
{
	border-top: 1px solid rgba(255,255,255,0.2) !important;
	border-left: 1px solid rgba(255,255,255,0.2) !important;
	background-color: rgba(66,66,66,0.2) !important;
}
*/

.mdl-form__setpoint .mdl-button, .mdl-form__colorpicker .mdl-button, .mdl-form__rollerblind .mdl-button {
    min-width: 0;
    padding-top: 2px;
}

.colorpicker 
{
    background-color: #333333;
}

.colorpicker__controls {
    border-bottom: none; /*1px solid #000;*/
}
.mdl-modal--colorpicker {
    max-width: 300px;
    border: 11px solid #333;
    border-radius: 11px;
}
.mdl-button.mdl-button--colored {
    color: #000000;
}
.colorpicker__buttons {
    padding: 5px;
    text-align: right;
}
.colorpicker__image {
    border-radius: 8px;
}

html/overrides.html

<head>
    <script src="../static/js/jquery.min.js"></script>
    <script src="../static/js/jquerycookie.js"></script>
</head>
<body>
    <script type="text/javascript">
        $( document ).ready(function()
        {
            setTimeout(function() { initEvents(); },200);

            var $parentdoc = window.parent.document;
            var $body = $("body",$parentdoc), $head = $("head",$parentdoc)
            var $animationspeed = 200;

            function initEvents() 
            {
                //var i = 0;
                //setInterval(function(){console.log(i++);},1000);
                $(".mdl-form",$parentdoc).each(function()
                {
                    $panel = $(this);
                    var id = $panel.data("widget-id")
                    $panel.attr("data-height",$panel.height());

                    if (($.cookie('panelid_'+id+'_state')) && ($.cookie('panelid_'+id+'_state') != "true"))
                    {
                        $panel.css({"height": "46px"});
                        $panel.find(".collapse_btn").addClass("collapse_btn_rotated");
                    }
                    console.log("setting up panel "+id+" height: " + $panel.data("height"));
                });

                if ($(".mdl-form > h5",$parentdoc).length >= 1)
                {
                    console.log("setting up click events: " + $(".mdl-form > h5",$parentdoc).length);
                    $($parentdoc).on("click",".mdl-form > h5", function() //.collapse_btn
                    {
                        //console.warn("click");
                        $panel = $(this).parent();

                        var id = $panel.data("widget-id")
                        var state

                        if (($.cookie('panelid_'+id+'_state')) && ($.cookie('panelid_'+id+'_state') == "false")) state = false;
                        else state = true;

                        state = !state; //actual toggle
                        $.cookie('panelid_'+id+'_state', state);
                        console.warn("panelid",id,"state",state,"height",$panel.data("height")); //"cookie",$.cookie(),

                        if (state)
                        {
                            $panel.find(".collapse_btn").removeClass("collapse_btn_rotated");
                            $panel.animate({"height": $panel.data("height")},$animationspeed);
                        }
                        else
                        {
                            $panel.find(".collapse_btn").addClass("collapse_btn_rotated");
                            $panel.animate({"height": "46px"},$animationspeed);
                        }
                    });
                }

                $($parentdoc).on("click","#all_min", function() //.collapse_btn
                {
                    console.log("all_min");
                    $(".mdl-form",$parentdoc).each(function()
                    {
                        $panel = $(this);
                        var id = $panel.data("widget-id")
                        $.cookie('panelid_'+id+'_state', false);

                        $panel.css({"height": "46px"});
                        $panel.find(".collapse_btn").addClass("collapse_btn_rotated");
                    });
                });


                $($parentdoc).on("click","#all_max", function() //.collapse_btn
                {
                    console.log("all_max");
                    $(".mdl-form",$parentdoc).each(function()
                    {
                        $panel = $(this);
                        var id = $panel.data("widget-id")
                        $.cookie('panelid_'+id+'_state', true);

                        $panel.css({"height": $panel.data("height")});
                        $panel.find(".collapse_btn").removeClass("collapse_btn_rotated");
                    });
                });
            }

            if ($body.data("injected") != true)
            {
                $head.append("<meta name=\"theme-color\" content=\"#999999\" />");
                $head.append("<link rel=\"stylesheet\" href=\"../static/css/overrides.css\">");
                $(".mdl-form__colorpicker--pick i",$parentdoc).css({fontSize:20}).text("colorize");
                $(".mdl-layout__header-row",$parentdoc).append("<div class=\"top_btn\" id=\"all_max\"><i class=\"material-icons\">keyboard_arrow_up</i></div>");//class=\"mdl-layout__header-button navigation__button-home\"
                $(".mdl-layout__header-row",$parentdoc).append("<div class=\"top_btn\" id=\"all_min\"><i class=\"material-icons\">keyboard_arrow_down</i></div>");
                $(".mdl-form",$parentdoc).each(function()
                {
                    $panel = $(this);
                    var id = $panel.data("widget-id")
                    $panel.find("h5").append("<div class=\"collapse_btn\"><i class=\"material-icons\"></i></div>")

                    //console.log($(this).find("h5").text());
                    if ($panel.find("h5").text().toLowerCase().indexOf("fritz") >= 0 ) $panel.addClass("panel_custom bg_olive");
                    else if ($panel.find("h5").text().toLowerCase().indexOf("samsung") >= 0 ) $panel.addClass("panel_custom bg_tomato");
                    else if ($panel.find("h5").text().toLowerCase().indexOf("sat receiver") >= 0 ) $panel.addClass("panel_custom bg_eggplant");
                    else if ($panel.find("h5").text().toLowerCase().indexOf("sony av") >= 0 ) $panel.addClass("panel_custom bg_sony");
                    else if ($panel.find("h5").text().toLowerCase().indexOf("a/c") >= 0 ) $panel.addClass("panel_custom bg_ac");
                    else if ($panel.find("h5").text().toLowerCase().indexOf("echo") >= 0 ) $panel.addClass("panel_custom bg_echos");
                    else if ($panel.find("h5").text().toLowerCase().indexOf("klima") >= 0 ) $panel.addClass("panel_custom bg_klima");
                    else if ($panel.find("h5").text().toLowerCase().indexOf("network") >= 0 ) $panel.addClass("panel_custom bg_net");
                    else if ($panel.find("h5").text().toLowerCase().indexOf("system") >= 0 ) $panel.addClass("panel_custom bg_sys");
                    else if ($panel.find("h5").text().toLowerCase().indexOf("alarm") >= 0 ) $panel.addClass("panel_custom bg_alarm");
                });
                console.log("injecting js/css finished");
            }
            $body.attr("data-injected","true");
        });
    </script>
</body>

then load overrides.html in a Webview item on sitemap, like this:

Webview url="/static/overrides.html" height=0

enjoy!

2 Likes

You know you can write Angular widgets with Javascript inside Habpanel right?

OK… thank…
I will check it

Just updated the OP with some recent screenies, enjoy :two_hearts:

1 Like

Me likes! :laughing:
This frame folding is just perfect for a wall-mounted tablet with Fully Kiosk app!
When will you consider setting up a git repository to put everything together?

By the way… Would it be possible to use some ‘inject’ (sorry, no web programmer here :smile:) to turn the left side of the UI in a back button like the one in the header?
For my use, the wall tablet case, it would be an improvement…

Later edit: …or make the header fixed? So that the page srolls under it?

Updated the OP with github repo link!

1 Like

How i can change On to Online (I’m using network binding)

Sitemap mappings: