Dashboard crashing with Node.js 16 (& Gecko based browsers)

Finished my first NR Dashboard.

But it does NOT work with my (latest version v4.1) SailFishOS phone's Brower well. :frowning:
https://sailfishos.org/wiki/Browser

  • The switch component is OK, :+1:
  • but when I try to set the slider, it shows NaN > drops to 0 > and turns the light off. :-1:
  • Gauge meters (CPU usage of RPi + Temp) is OK too, :+1:
  • but Charts do not show the line inside. :-1:

I can not control my home from my phone, because it's freezing the Browers > eating up all RAM > Crash > restarting the phone. Very frustrating. :angry:

  • Any idea, how to fix / debug it? ...
  • Would installing Node.js 16 to my phone help somehow?

Thanks!

That sounds like a browser issue, try another browser. I think sail fish is based on an older Mozilla, my old firefox had similar issues with sliders.

I've tried (webkit based) WebCat too.
Does not load the page at all ! :frowning:

... there are not too much browsers to this OS. (maybe 5) These two are "the best".

You could always create a separate 'mobile' dashboard just using the elements that you know will work with the browser, and avoiding the ones that won't.

Thanks for the great idea, but it is not possible to replace a basic 0-255 dimmer-slider with anything else is it?

  • Or do you know about any "secondary Dashboard items modules" similar to the current ones, but still compatible with older browsers?

You may try if custom made slider works. It is still based on <md-slider> but who knows what is the root cause of failure.

[{"id":"bdc44b29.79d388","type":"ui_template","z":"9f4fbba4.68ceb8","group":"20ae1040.3cf58","name":"color slider based on md-slider","order":1,"width":"6","height":"1","format":"<div class=\"slider-rgb\" id=\"{{'value_'+$id}}\"></div>\n<div id=\"{{'slider_'+$id}}\" class=\"color-sider-container\">\n    <md-slider ng-model=\"slidervalue\" step=\"0.01\" min=\"0\" max=\"1\" aria-label=\"color slider\"></md-slider>\n</div>\n<style>\n.slider-rgb{\n    position: absolute;\n    font-size: 12px;\n    left: 30px;\n    line-height: 6px;\n}\n.color-sider-container{\n\n}\n.color-sider-container > md-slider{\n    height:40px;\n    margin-left: 10px;\n    margin-right: 12px;\n    top:-1px;\n}\n.color-sider-container > md-slider .md-track-container {\n    width: 100%;\n    position: absolute;\n    top: 16px;\n    height: 16px;\n    \n}\n.color-sider-container > md-slider .md-track.md-track{\n   border-radius:10px;\n      background: linear-gradient(\n        to right,\n        rgb(255 0 0),\n        rgb(255 255 0),\n        rgb(0 255 0),\n        rgb(0 255 255),\n        rgb(0 0 255),\n        rgb(255 0 255),\n        rgb(255 0 0)\n      );\n}\n.color-sider-container > md-slider .md-track.md-track-fill{\n    visibility:hidden;\n}\n.color-sider-container > md-slider .md-thumb:after {\n    visibility:hidden;\n    \n}\n.color-sider-container > md-slider .md-thumb {\n    transform: scale(1.2) !important;\n    border:2px solid white;\n    pointer-events: none;\n\n}\n</style>\n\n<script>\n(function(scope) {\nconst spectrumRanges = [\n  { from: [255, 0, 0], to: [255, 255, 0] },\n  { from: [255, 255, 0], to: [0, 255, 0] },\n  { from: [0, 255, 0], to: [0, 255, 255] },\n  { from: [0, 255, 255], to: [0, 0, 255] },\n  { from: [0, 0, 255], to: [255, 0, 255] },\n  { from: [255, 0, 255], to: [255, 0, 0] }\n];\n\nconst findColorValue = (from, to, leftRatio) => {\n  return Math.round(from + (to - from) * leftRatio);\n};\n\nconst findRgbFromSliderValue = (sliderpos) => {\n  sliderpos = validateInput(sliderpos)\n  const wrapper = document.querySelector(\".color-sider-container\");\n  const {width } = wrapper.getBoundingClientRect();\n  const leftDistance = width * sliderpos\n  const totalRanges = spectrumRanges.length;\n  const rangeWidth = width / totalRanges;\n  const includedRange = Math.floor(leftDistance / rangeWidth);\n  const leftRatio = ((leftDistance % rangeWidth) / rangeWidth).toFixed(2);\n  const { from, to } = spectrumRanges[includedRange];\n  return {\n    r: findColorValue(from[0], to[0], leftRatio),\n    g: findColorValue(from[1], to[1], leftRatio),\n    b: findColorValue(from[2], to[2], leftRatio)\n  };\n};\n\nconst rgbToHex = (r, g, b) => {\n  const toHex = (rgb) => {\n    let hex = Number(rgb).toString(16);\n    if (hex.length < 2) {\n      hex = `0${hex}`;\n    }\n    return hex;\n  };\n  const red = toHex(r);\n  const green = toHex(g);\n  const blue = toHex(b);\n  return `#${red}${green}${blue}`;\n};\n    \nconst validateInput = (inp) => {\n    if(isNaN(inp)){\n        return 0.00001\n    }\n    if(inp <= 0 ) {\n        return 0.00001\n    }\n    if(inp >=1){\n        return 0.9999\n    }\n    return inp\n}    \nscope.$watch('slidervalue', function(slidervalue) {\n    if (slidervalue !== undefined) {\n        let { r, g, b } = findRgbFromSliderValue(slidervalue);\n        let hexValue = rgbToHex(r, g, b);\n        $(\"#slider_\"+scope.$id).find('.md-thumb').css(\"background-color\",hexValue);\n        $(\"#value_\"+scope.$id).text('RGB:('+r+','+g+','+b +') HEX:'+hexValue)\n        if(scope.incoming == true){\n            scope.incoming = false\n            return\n        }\n        scope.send({payload:slidervalue,colors:{hex:hexValue,rgb:{r,g,b}}})\n    }\n})\n    \n  scope.$watch('msg', function(msg) {\n    if (msg) {\n        if(!(\"#slider_\"+scope.$id)){\n            return\n        }\n        scope.incoming = true\n        scope.slidervalue = msg.payload\n    }\n  });\n})(scope);\n</script>","storeOutMessages":true,"fwdInMessages":false,"resendOnRefresh":true,"templateScope":"local","x":410,"y":1640,"wires":[["41bcf137.06a9e"]]},{"id":"41bcf137.06a9e","type":"debug","z":"9f4fbba4.68ceb8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":650,"y":1640,"wires":[]},{"id":"b90f245f.f2f078","type":"inject","z":"9f4fbba4.68ceb8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"0.5","payloadType":"num","x":190,"y":1600,"wires":[["bdc44b29.79d388"]]},{"id":"152c7cb7.8c8b73","type":"ui_numeric","z":"9f4fbba4.68ceb8","name":"","label":"slider val","tooltip":"","group":"20ae1040.3cf58","order":3,"width":0,"height":0,"wrap":false,"passthru":true,"topic":"topic","topicType":"msg","format":"{{value}}","min":0,"max":"1","step":"0.1","x":180,"y":1640,"wires":[["bdc44b29.79d388"]]},{"id":"20ae1040.3cf58","type":"ui_group","name":"Group 1","tab":"6b520bda.e997a4","order":1,"disp":true,"width":"6","collapse":false},{"id":"6b520bda.e997a4","type":"ui_tab","name":"Experimentieren","icon":"dashboard","order":3,"disabled":false,"hidden":false}]

Thanks! Tested:
up-down arrows are working,
but the slider does not.

Both Touch-Down + Up events generate 1-1 msg:

msg : Object
object
payload: null
colors: object
hex: "#ff0000"
rgb: object
socketid: "TItaL66-TP8qR_BSAABS"
_msgid: "336a8ff42ef6fc03"

... and the slider jumps to Left. (0)

I am really surprised NR dashboard nodes do not have a basic "browser-side try-catch code" > sending back errors to msg.error.
That way we would see if it did not really executed well, just giving back an error-produced data!

(I would really like to help enhance ALL components to be more robust and safe, but I've just started learning JS a year ago to modify some i2c nodes, so sadly my browser-side programming skill is still zero.)

@hotNipi can you maybe write a tiny code around this test-example that sends back error info to NR ?

Something like:

... so if it's possible to get send error logs to a remote server > why isn't it possible to get back those locally?

I'm trying to insert some error-catching code into your function, but no success yet:

<script>
  (function(_,e,rr,s)
  { _._errs=[s];
    var c=_.onerror;
    _.onerror=function(){
      var a=arguments;
      _errs.push(a);
      msg._errs = _errs;
      return msg;
//    c&&c.apply(this,a)
    };
    var b=function() {
      var c=e.createElement(rr), b=e.getElementsByTagName(rr)[0];
      c.async=!0;
      b.parentNode.insertBefore(c,b)
    };
    _.addEventListener?_.addEventListener("load",b,!1):_.attachEvent("onload",b)}
  )
  (window,document,"script","mytest");

(function(scope) {
...

I'm not sure how it should be done correctly.

What ever part in my code makes you worry, add try / catch block and send out the error (if the browser is still alive)
Messaging works within the scope so you just cant send it back from arbitrary places.

scope.$watch('slidervalue', function(slidervalue) {
    if (slidervalue !== undefined) {
        try{
            let { r, g, b } = findRgbFromSliderValue(slidervalue);
            let hexValue = rgbToHex(r, g, b);
            $("#slider_"+scope.$id).find('.md-thumb').css("background-color",hexValue);
            $("#value_"+scope.$id).text('RGB:('+r+','+g+','+b +') HEX:'+hexValue)
            if(scope.incoming == true){
                scope.incoming = false
                return
            }
            scope.send({payload:slidervalue,colors:{hex:hexValue,rgb:{r,g,b}}})
        }
        catch(e){
            console.log('ERROR',e)
            scope.send({payload:e.stack,topic:"ERROR"})
        }
    }
})
1 Like

Sadly, it does not catch any errors.
Also tried to encapsulate the whole (scope) function from beginning to end with a try-catch, but it did not show any errors either.

So I still need a solution to catch errors ocuring within the Browser.

A tiny good news is:

  • somebody from SFOS fanclub reported me on Telegram, that he has no problem with a newer version of the phone (4.2) .
    But it's still possible, that he is using a different Node.js version. (I've installed v16 on my RPi.)

It will take ca. a month until the new firmware comes for my phone with the newer Browser in it.

You are dealing with unknown browser for (at least) me. And the browser dealing maybe with unknown stuff for it. There is long chain of functionality and libraries before the browser takes over and tries to do something with it. and the error may be somewhere in all those hops. The crash may be so hard that no errors logged anywhere. But to find them - you need to have all tools for all levels to investigate.
I cant see more options but to report to the OS and browser owners/developers about the issue, with the example containing something to lead to smallest amount of effort to reproduce the case and then cross the fingers it will be somehow fixed.

I don't think the nodejs version makes any difference to the browser, though I may be wrong.

Upgraded my phone's firmware today to latest 4.2.
So now it's the same, what the other guy has,
but it still not working with sliders.

So we can rule out the Browser.

The only difference is:

  • he has Node.js v12
  • I have v16

I was running the browser in debug mode > but go NO ERRORS.
Basically the problem is not with JavaScript functions, but with the graphical elements.

The only warning I was able to trigger once is:

[JavaScript Warning: 
"Ignoring ‘preventDefault()’ call on event of type ‘touchmove’ from a listener registered as ‘passive’."

This is only a warning, but maybe it hints to the real problem.
It would be really great if I could run the Browser in "full-debug-mode", but that is impossible to me.

Good news!
The problem is with AngularJS on my phone's browser.

These sliders have the same error, as the Node-Red Dashboard:
https://material.angularjs.org/latest/demo/slider

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