Holding readings for gauges

Hello all, just joined the forum as I have more time to explore.
(scenerio) I have been using Node Red Dashboard for a while, coupled with Mosquitto as an mqtt broker on a Raspberry Pi 2B. In short, the Pi receives readings from sensors attached to ESP8266's published to the mosquitto broker, then subscribed to with the mqtt input node, and on to the appropriate gauge. There are multiple temperature and humidity sensors, and a remote ultrasonic sensor to measure a heating oil tank level. The Dashboard UI is then accessible to everything on my network so visible via tablets, smartphones, etc. All that has been running continuously quite satisfactorily for a few years. I haven't done much since setting that up. OK, now onward....
I've since updated the Node Red and Mosquitto software to the latest versions.
I then discovered the great looking template guages produced by members of the forum, and thought I'd give them a go.
Quite pleased with the look I starting playing with the look (lots to learn there!) and inso doing I discovered a bit of a snag that with my level of understanding I could use some help.
The issue is in a nutshell the difference in behavior between the "standard" dashboard gauges and the ones produced by *hotNipi and the forum.
On the old system, the standard gauges held the readings when the dashboard webpage was left and returned to. The template gauges loose that last reading and start at zero. This is not a major issue for the temperature guages, because they are being updated anywere from 10 seconds to 1 minute intervals. But the tank guage is different. It is remote and on battery. The ESP8266 takes a reading, publishes it to the mqtt broker, then goes to deep sleep for ~hour. (it is not necessary to read mre frequently) This prolongs battery life. But as you can guess, If the dashboard is accessed between readings...it reads 0. Is there a node that would allow me to hold the reading until a new one comes in? Sorry for the long narritive, just wanted the situation understood.

Hello and welcome :slight_smile:

If you are talking about the those gauges

image

I'm very aware that code does not contain all what is needed to avoid the issue you have described. And I can explain in detail why and when but it is boring and long story, mostly doesn't help much.
But I'm happy to give you an example code with fix.
As you may have configured or changed your gauges differently, you have to apply the fix for all of them separately. Explore the code and see the differences.

One change you may miss easily is this, so you know..
image

And here's the example

<div class="g-wrapper g-wrapper-label-0">

<div id="{{'gauge_'+$id}}" class="g-container" ng-init="init()" style="--gauge-value:0; --container-size:4; --gn-distance:13; --ga-tick-count:10; --ga-subtick-count:100; --g-unit:'°C'">
    <div id="bgr" class="g-body">
        <div class="g-ring">
            <div class="g-rivets">
                <div class=g-rivet></div>
                <div class=g-rivet></div>
                <div class=g-rivet></div>
                <div class=g-rivet></div>
            </div>
            <div class="g-plate">
                <div class="g-ticks">
                    <div class="g-tick" style="--ga-tick:1;"></div>
                    <div class="g-tick" style="--ga-tick:2;"></div>
                    <div class="g-tick" style="--ga-tick:3;"></div>
                    <div class="g-tick" style="--ga-tick:4;"></div>
                    <div class="g-tick" style="--ga-tick:5;"></div>
                    <div class="g-tick" style="--ga-tick:6;"></div>
                    <div class="g-tick" style="--ga-tick:7;"></div>
                    <div class="g-tick" style="--ga-tick:8;"></div>
                    <div class="g-tick" style="--ga-tick:9;"></div>
                    <div class="g-tick" style="--ga-tick:10;"></div>
                    <div class="g-tick" style="--ga-tick:11;"></div>
                </div>
                <div class="g-ticks">
                    <div class="g-subtick" style="--ga-tick:2;"></div>
                    <div class="g-subtick" style="--ga-tick:3;"></div>
                    <div class="g-subtick" style="--ga-tick:4;"></div>
                    <div class="g-subtick" style="--ga-tick:5;"></div>
                    <div class="g-subtick" style="--ga-tick:6;"></div>
                    <div class="g-subtick" style="--ga-tick:7;"></div>
                    <div class="g-subtick" style="--ga-tick:8;"></div>
                    <div class="g-subtick" style="--ga-tick:9;"></div>
                    <div class="g-subtick" style="--ga-tick:10;"></div>
                    
                    <div class="g-subtick" style="--ga-tick:12;"></div>
                    <div class="g-subtick" style="--ga-tick:13;"></div>
                    <div class="g-subtick" style="--ga-tick:14;"></div>
                    <div class="g-subtick" style="--ga-tick:15;"></div>
                    <div class="g-subtick" style="--ga-tick:16;"></div>
                    <div class="g-subtick" style="--ga-tick:17;"></div>
                    <div class="g-subtick" style="--ga-tick:18;"></div>
                    <div class="g-subtick" style="--ga-tick:19;"></div>
                    <div class="g-subtick" style="--ga-tick:20;"></div>
                    
                    <div class="g-subtick" style="--ga-tick:22;"></div>
                    <div class="g-subtick" style="--ga-tick:23;"></div>
                    <div class="g-subtick" style="--ga-tick:24;"></div>
                    <div class="g-subtick" style="--ga-tick:25;"></div>
                    <div class="g-subtick" style="--ga-tick:26;"></div>
                    <div class="g-subtick" style="--ga-tick:27;"></div>
                    <div class="g-subtick" style="--ga-tick:28;"></div>
                    <div class="g-subtick" style="--ga-tick:29;"></div>
                    <div class="g-subtick" style="--ga-tick:30;"></div>
                    
                    <div class="g-subtick" style="--ga-tick:32;"></div>
                    <div class="g-subtick" style="--ga-tick:33;"></div>
                    <div class="g-subtick" style="--ga-tick:34;"></div>
                    <div class="g-subtick" style="--ga-tick:35;"></div>
                    <div class="g-subtick" style="--ga-tick:36;"></div>
                    <div class="g-subtick" style="--ga-tick:37;"></div>
                    <div class="g-subtick" style="--ga-tick:38;"></div>
                    <div class="g-subtick" style="--ga-tick:39;"></div>
                    <div class="g-subtick" style="--ga-tick:40;"></div>
                    
                    <div class="g-subtick" style="--ga-tick:42;"></div>
                    <div class="g-subtick" style="--ga-tick:43;"></div>
                    <div class="g-subtick" style="--ga-tick:44;"></div>
                    <div class="g-subtick" style="--ga-tick:45;"></div>
                    <div class="g-subtick" style="--ga-tick:46;"></div>
                    <div class="g-subtick" style="--ga-tick:47;"></div>
                    <div class="g-subtick" style="--ga-tick:48;"></div>
                    <div class="g-subtick" style="--ga-tick:49;"></div>
                    <div class="g-subtick" style="--ga-tick:50;"></div>
                    
                    <div class="g-subtick" style="--ga-tick:52;"></div>
                    <div class="g-subtick" style="--ga-tick:53;"></div>
                    <div class="g-subtick" style="--ga-tick:54;"></div>
                    <div class="g-subtick" style="--ga-tick:55;"></div>
                    <div class="g-subtick" style="--ga-tick:56;"></div>
                    <div class="g-subtick" style="--ga-tick:57;"></div>
                    <div class="g-subtick" style="--ga-tick:58;"></div>
                    <div class="g-subtick" style="--ga-tick:59;"></div>
                    <div class="g-subtick" style="--ga-tick:60;"></div>
                    
                    <div class="g-subtick" style="--ga-tick:62;"></div>
                    <div class="g-subtick" style="--ga-tick:63;"></div>
                    <div class="g-subtick" style="--ga-tick:64;"></div>
                    <div class="g-subtick" style="--ga-tick:65;"></div>
                    <div class="g-subtick" style="--ga-tick:66;"></div>
                    <div class="g-subtick" style="--ga-tick:67;"></div>
                    <div class="g-subtick" style="--ga-tick:68;"></div>
                    <div class="g-subtick" style="--ga-tick:69;"></div>
                    <div class="g-subtick" style="--ga-tick:70;"></div>
                    
                    <div class="g-subtick" style="--ga-tick:72;"></div>
                    <div class="g-subtick" style="--ga-tick:73;"></div>
                    <div class="g-subtick" style="--ga-tick:74;"></div>
                    <div class="g-subtick" style="--ga-tick:75;"></div>
                    <div class="g-subtick" style="--ga-tick:76;"></div>
                    <div class="g-subtick" style="--ga-tick:77;"></div>
                    <div class="g-subtick" style="--ga-tick:78;"></div>
                    <div class="g-subtick" style="--ga-tick:79;"></div>
                    <div class="g-subtick" style="--ga-tick:80;"></div>
                    
                    <div class="g-subtick" style="--ga-tick:82;"></div>
                    <div class="g-subtick" style="--ga-tick:83;"></div>
                    <div class="g-subtick" style="--ga-tick:84;"></div>
                    <div class="g-subtick" style="--ga-tick:85;"></div>
                    <div class="g-subtick" style="--ga-tick:86;"></div>
                    <div class="g-subtick" style="--ga-tick:87;"></div>
                    <div class="g-subtick" style="--ga-tick:88;"></div>
                    <div class="g-subtick" style="--ga-tick:89;"></div>
                    <div class="g-subtick" style="--ga-tick:90;"></div>
                    
                    <div class="g-subtick" style="--ga-tick:92;"></div>
                    <div class="g-subtick" style="--ga-tick:93;"></div>
                    <div class="g-subtick" style="--ga-tick:94;"></div>
                    <div class="g-subtick" style="--ga-tick:95;"></div>
                    <div class="g-subtick" style="--ga-tick:96;"></div>
                    <div class="g-subtick" style="--ga-tick:97;"></div>
                    <div class="g-subtick" style="--ga-tick:98;"></div>
                    <div class="g-subtick" style="--ga-tick:99;"></div>
                    <div class="g-subtick" style="--ga-tick:100;"></div>
                </div>
               <div class="g-nums">
                    <div class="g-num" style="--ga-tick:1;" >0</div>
                    <div class="g-num" style="--ga-tick:2;">10</div>
                    <div class="g-num" style="--ga-tick:3;">20</div>
                    <div class="g-num" style="--ga-tick:4;">30</div>
                    <div class="g-num" style="--ga-tick:5;">40</div>
                    <div class="g-num" style="--ga-tick:6;">50</div>
                    <div class="g-num" style="--ga-tick:7;">60</div>
                    <div class="g-num" style="--ga-tick:8;">70</div>
                    <div class="g-num" style="--ga-tick:9;">80</div>
                    <div class="g-num" style="--ga-tick:10;">90</div>
                    <div class="g-num" style="--ga-tick:11;">100</div>
                </div>
                <div class="g-label">Temperature</div>
                <div class="g-needle"></div>
                <div class="g-needle-ring"></div>
                <div id="{{'gauge_val_'+$id}}" class="g-val"></div>
            </div>
        </div>
    </div>
</div>
</div>
<script>
(function(scope) {
    
    const min = 0;
    const max = 100;    
    scope.inited = false
    scope.latestPayload = null
    
    scope.init = function(){
        if($("#gauge_"+scope.$id).length){
            actuallyInit()
        }
        else{
            setTimeout(function(){
                actuallyInit()
            },100)
        }
    }

    function actuallyInit(){
        scope.inited = true
        if(scope.latestPayload){
            render()
        }        
    }

    function render(){
        const val = scope.latestPayload
        const v = ((val - min) / (max - min)) * 100;
        document.getElementById('gauge_'+scope.$id).style.setProperty('--gauge-value', v);
        document.getElementById('gauge_val_'+scope.$id).innerText = val.toFixed(1);
        scope.latestPayload = null;    
    }
    
  scope.$watch('msg', function(msg) {
    if (msg) {
        scope.latestPayload = msg.payload
        if(!scope.inited){            
            return
        }        
        render()
    }   
  });
})(scope);
</script>

Hi hotNipi, yep those are the ones. Thanks so much for the response, I’ll see if my old brain can make sense of it, and post any success (or lack thereof LOL). Thanks again!

Alternatively you may want to just look at taking the incoming MQTT values and storing them as a Flow/Global context variable - you basically have your MQTT node that subscribes to the topic output to a change node that writes the context variable.

You then run a tight loop (every 10 seconds) that reads the context variable(s) and sends the values to the dashboard gauges

You can also incorporate something like this into a startup routine so whenever you reinitialise the flows (redeploy) - you can read a persistent context variable and write that to the same gauge - so you are not waiting an hour for it to update.

Finally you could make the MQTT topic as a retained one and just query that from your flow and update the gauge that way

Craig

Thank you Craig pointing out those techniques. They are all relevant and help us to make whole system (data sources -> server -> dashboard) reliable and responsive. Still, none of them will fix the gauge.

Short explanation what is going on.

Dashboard has replayMessage system. It tries to send last known payload to widgets when dashboard connects to the server.
Thing is that if dashboard gets "heavy" enough, the widget creation takes more time. During the initialization phase the replayMessage arrives but widget is not yet ready to show it. So it shows 0 or what ever is the initial state.

The fix is to store data from latest msg and use it when widget is ready.

I added comments to the script so the changes may be make more sense.

<script>
(function(scope) {
    
    const min = 0;
    const max = 100;    
    scope.inited = false
    scope.latestPayload = null
    
    // When widget html part is created, the init function is called.
    // Still it does not qurantee that the element is ready in DOM
    // thus we try to access that element and if it is not ready, the
    // actual intialization will be called with delay.
    // NB! it is not bulletproof solution (only one level of warranting) but works in most cases
    scope.init = function(){
        if($("#gauge_"+scope.$id).length){
            actuallyInit()
        }
        else{
            setTimeout(function(){
                actuallyInit()
            },100)
        }
    }

    // actual initialization
    function actuallyInit(){
        // make init phase complete
        scope.inited = true
        // Check if msg has received during the init phase.
        // If so, call the function to show value.
        if(scope.latestPayload){
            render()
        }        
    }

    // function to show the value
    function render(){
        const val = scope.latestPayload // using stored value 
        const v = ((val - min) / (max - min)) * 100;
        document.getElementById('gauge_'+scope.$id).style.setProperty('--gauge-value', v);
        document.getElementById('gauge_val_'+scope.$id).innerText = val.toFixed(1);
        scope.latestPayload = null;    
    }
    
  scope.$watch('msg', function(msg) {
    if (msg) {
        // store payload 
        scope.latestPayload = msg.payload
        if(!scope.inited){ 
            // DOM is not ready so there is no reason
            //to even try to show the value                       
            return
        }
        // show the value        
        render()
    }   
  });
})(scope);
</script>
1 Like

Thanks to all for the valuable input. @hotNipi, I'm not too sure as to what I was to do with the example you gave me, simply copying it into a template only rendered a flatened "something". However I did take the "importent" snipets from it and plugged them in.to the existing meter in the flow, and it worked beautifully. There was a strange behavior at startup, where the needle spun around a full 369 deg, Then settled in. But I had been fooling with the code prior which I suspect had a great deal to do with that (wink). Your work-around suits my needs very well, and gives this old dog incentive to learn more new tricks, Thanks again

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.