Maths problem - stuck

I have in my flow a node which compares the RTC and the RPI clock.

It looks for a difference.

If it is greater than a set value, it sends a message indicating that.
But to check I need to do the check both ways.
Have a look at the code and I hope you will see the problem.

Basically I have:

difference = rtc - software_clock
if difference > value
{
....
}
difference = software_clock - rtc
if difference > value
{
....
}

That seems a poor way of doing it.

In BASIC I would/could do this:
difference = ABS(rtc - software_clock)
And it would always be a positive result.

Basically it resolves to:

difference = SQRT(rtc^2 - software_clock^2)

I don't know if there is an equivalent in JS.
(Yeah, "go away and read")

Sorry, I am asking here because it is a forum.

Code:

(db = debug for debugging)

var threshold = context.get('threshold')|| 60;
var a;
var b;
var r;
context.set('threshold', threshold);
msg3 = {payload: threshold};

if (msg.topic == 'Debug')
{
    if (msg.payload === true)
    {
        context.set('db', 1);
    } else
    if (msg.payload === false)
    {
        context.set('db', 0);
    }
}
var db = context.get('db');

//---------------------
if (msg.topic == 'slip')
{
    if (db == 1)
    {
        node.warn("**************************");
        node.warn("Threshold set to " + msg.payload);
    }
    context.set('threshold', msg.payload);
}
//---------------------
if (msg.topic == "RTC")
{
    context.set('RTC',msg.payload);
    //node.warn("RTC   " + context.get('RTC'));
}
if (msg.topic == "local")
{
    context.set('local', msg.payload);
    //node.warn("Local " + context.get('local'));
}
if (db == 1)
{
    node.warn("Stored RTC value " + context.get('RTC'));
    node.warn("Stored RPI value " + context.get('local'));
    node.warn("Stored threshold value " + context.get('threshold'));
}

if (context.get('RTC') !== 0)
{
    if (context.get('local') !== 0)
    {
        a = context.get('RTC');
        b = context.get('local');
        r = a - b;
    }
    if (db == 1)
    {
        node.warn("Error is " + r);
    }
    if (r > threshold)
    {
        //  ** We have a problem! **
        if (db == 1)
        {
            node.warn("Part 1");
        }
        node.status({fill:"red",shape:"dot",text:"Time error"});
        msg1 = {payload: false};
        msg2 = {payload: r};
        flow.set("Time_error",r);
        return [msg1, msg2, msg3];
    } 
    if (r < 0)
    {
        r = b - a;
        if (r > threshold)
        {
            //  ** We have a problem! **
            if (db == 1)
            {
                node.warn("Part 2");
            }
            node.status({fill:"red",shape:"dot",text:"Time error"});
            msg1 = {payload: false};
            msg2 = {payload: r};
            flow.set("Time_error",r);
            return [msg1, msg2, msg3];
        }
    }
    else
    {
        //   All Good!
        if (db == 1)
        {
            node.warn("Part 3");
        }
        node.status({fill:"green",shape:"dot",text:"Time good"});
        msg1 = {payload: true};
        msg2 = {payload: r};
        return [msg1, msg2, msg3];
    }
}

(yeah........ ok.)

Line 55:

r = Math.abs(a - b);

That should work?

Ok, so, the next problem:

Alas I have lost a bit of data over the last couple of days because yesterday NR spat the dummy.
:frowning:

All ok now.

But it seems that every midnight it throws up an error and I am not exactly sure why.
An error: as in it says there is too much of a time difference.

Any thoughts on that?

Show us the exact and full message please

At this point I don't have one.

As stated: "NR spat the dummy" and I have to wait - probably 24 hours - to get another report/error on that.

If it was a significant error it should be in syslog

You don't say where you get your clock values or what units they are in. I assume/hope you are using something like milllisecs since epoch (ie, what Date.now() returns).

There is a signal sent and the "system clock" is read. At the same time the RTC time is read.
They are sent into a function node and the two times compared.

Depending if they are less than the set value different all is good.

I shall hope (weirdly) that I can catch an error tonight and post what I get from it there after.

That doesn't actually answer the format question. Are you comparing values that are constantly increasing (milllisecs since epoch) or values that reset at midnight everyday (eg 24 hour clock: 235959)

This is most of the flow that does it.

Understand that the inject node is from another thing which is basically a timed pulse happening every 'x' seconds. A sort of heart beat for the entire system.

The last function node has 3 outputs.
The first one goes to a bit more stuff which looks at the true/false output.

If it is false it creates a message (into a queue - not included) so I can see when it is happening.

You need some global, flow and context variables.

Code:

[{"id":"90849cb5.ea66d8","type":"function","z":"61a474ed.8f915c","name":"","func":"msg.payload = new Date().toLocaleString();\nreturn msg;","outputs":1,"noerr":0,"x":320,"y":580,"wires":[["324860a2.b6d818"]]},{"id":"e8a8a4dd.b000d","type":"exec","z":"61a474ed.8f915c","command":"sudo hwclock -r","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"HWC time","x":300,"y":630,"wires":[["7ea41cc2.48ec7c"],[],[]]},{"id":"324860a2.b6d818","type":"string","z":"61a474ed.8f915c","name":"","methods":[{"name":"left","params":[{"type":"num","value":"19"}]},{"name":"replaceAll","params":[{"type":"str","value":"-"},{"type":"str","value":"/"}]}],"prop":"payload","propout":"payload","object":"msg","objectout":"msg","x":440,"y":580,"wires":[["80929a9.1c63968"]]},{"id":"7ea41cc2.48ec7c","type":"string","z":"61a474ed.8f915c","name":"","methods":[{"name":"replaceAll","params":[{"type":"str","value":"-"},{"type":"str","value":"/"}]},{"name":"left","params":[{"type":"num","value":"19"}]}],"prop":"payload","propout":"payload","object":"msg","objectout":"msg","x":450,"y":660,"wires":[["fc070eae.6b31f8"]]},{"id":"fc070eae.6b31f8","type":"delay","z":"61a474ed.8f915c","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":450,"y":720,"wires":[["f7cbe7c7.3dea48"]]},{"id":"80929a9.1c63968","type":"string","z":"61a474ed.8f915c","name":"","methods":[{"name":"right","params":[{"type":"num","value":"8"}]}],"prop":"payload","propout":"payload","object":"msg","objectout":"msg","x":640,"y":610,"wires":[["ce5d268.6ebb558"]]},{"id":"f7cbe7c7.3dea48","type":"string","z":"61a474ed.8f915c","name":"","methods":[{"name":"right","params":[{"type":"num","value":"8"}]}],"prop":"payload","propout":"payload","object":"msg","objectout":"msg","x":640,"y":650,"wires":[["f6dee7f8.875228"]]},{"id":"ce5d268.6ebb558","type":"function","z":"61a474ed.8f915c","name":"","func":"var hour = parseInt(msg.payload.slice(0,2));\nvar minute = parseInt(msg.payload.slice(3,5));\nvar second = parseInt(msg.payload.slice(6,8));\n//node.warn(\"Hour \" + hour);\n//node.warn(\"Minute \" + minute);\n//node.warn(\"Second \" + second);\nvar time = hour*3600 + minute * 60 + second;\nmsg = {payload: time, topic: 'local'};\nreturn msg;","outputs":1,"noerr":0,"x":780,"y":610,"wires":[["a63629bf.4f1a58"]]},{"id":"f6dee7f8.875228","type":"function","z":"61a474ed.8f915c","name":"","func":"var hour = parseInt(msg.payload.slice(0,2));\nvar minute = parseInt(msg.payload.slice(3,5));\nvar second = parseInt(msg.payload.slice(6,8));\n//node.warn(hour);\n//node.warn(minute);\n//node.warn(second);\nvar time = hour*3600 + minute * 60 + second;\nmsg = {payload: time, topic: 'RTC'};\nreturn msg;","outputs":1,"noerr":0,"x":780,"y":650,"wires":[["a63629bf.4f1a58"]]},{"id":"a63629bf.4f1a58","type":"function","z":"61a474ed.8f915c","name":"","func":"var threshold = context.get('threshold')|| 60;\nvar a;\nvar b;\nvar r;\ncontext.set('threshold', threshold);\nmsg3 = {payload: threshold};\n\nif (msg.topic == 'Debug')\n{\n    if (msg.payload === true)\n    {\n        context.set('db', 1);\n    } else\n    if (msg.payload === false)\n    {\n        context.set('db', 0);\n    }\n}\nvar db = context.get('db');\n\n//---------------------\nif (msg.topic == 'slip')\n{\n    if (db == 1)\n    {\n        node.warn(\"**************************\");\n        node.warn(\"Threshold set to \" + msg.payload);\n    }\n    context.set('threshold', msg.payload);\n}\n//---------------------\nif (msg.topic == \"RTC\")\n{\n//    context.set('RTC',msg.payload);\n    flow.set(\"RTC\",msg.payload);\n    //node.warn(\"RTC   \" + context.get('RTC'));\n}\nif (msg.topic == \"local\")\n{\n//    context.set('local', msg.payload);\n    flow.set(\"local\", msg.payload);\n    //node.warn(\"Local \" + context.get('local'));\n}\nif (db == 1)\n{\n//    node.warn(\"Stored RTC value \" + context.get('RTC'));\n//    node.warn(\"Stored RPI value \" + context.get('local'));\n    node.warn(\"Stored RTC value \" + flow.get(\"RTC\"));\n    node.warn(\"Stored RPI value \" + flow.get(\"local\"));\n    node.warn(\"Stored threshold value \" + context.get('threshold'));\n}\n\n//if (context.get('RTC') !== 0)\nif (flow.get(\"RTC\") !== 0)\n{\n//    if (context.get('local') !== 0)\n    if (flow.get(\"local\") !== 0)\n    {\n//        a = context.get('RTC');\n//        b = context.get('local');\n        a = flow.get(\"RTC\");\n        b = flow.get(\"local\");\n        r = Math.abs(a - b);\n        flow.set(\"Time_error\",r);\n    }\n    if (db == 1)\n    {\n        node.warn(\"Error is \" + r);\n    }\n    if (r > threshold)\n    {\n        //  ** We have a problem! **\n        if (db == 1)\n        {\n            node.warn(\"Part 1\");\n        }\n        node.status({fill:\"red\",shape:\"dot\",text:\"Time error\"});\n        msg1 = {payload: false};\n        msg2 = {payload: r};\n//        flow.set(\"Time_error\",r);\n        return [msg1, msg2, msg3];\n    } \n//    if (r < 0)\n//    {\n//        r = b - a;\n//        if (r > threshold)\n//        {\n//            //  ** We have a problem! **\n//            if (db == 1)\n//            {\n//                node.warn(\"Part 2\");\n//            }\n//            node.status({fill:\"red\",shape:\"dot\",text:\"Time error\"});\n//            msg1 = {payload: false};\n//            msg2 = {payload: r};\n//            flow.set(\"Time_error\",r);\n//            return [msg1, msg2, msg3];\n//        }\n//    }\n    else\n    {\n        //   All Good!\n        if (db == 1)\n        {\n            node.warn(\"Part 3\");\n        }\n        node.status({fill:\"green\",shape:\"dot\",text:\"Time good\"});\n        msg1 = {payload: true};\n        msg2 = {payload: r};\n        return [msg1, msg2, msg3];\n    }\n}\n","outputs":3,"noerr":0,"x":930,"y":630,"wires":[["b6a68b43.52e79"],[],[]],"outputLabels":["state","difference","threshold"]},{"id":"77bbc478.ba861c","type":"inject","z":"61a474ed.8f915c","name":"","topic":"","payload":"Trigger","payloadType":"str","repeat":"20","crontab":"","once":false,"onceDelay":0.1,"x":100,"y":600,"wires":[["90849cb5.ea66d8","e8a8a4dd.b000d"]]},{"id":"b6a68b43.52e79","type":"switch","z":"61a474ed.8f915c","name":"","property":"payload","propertyType":"msg","rules":[{"t":"false"}],"checkall":"true","repair":false,"outputs":1,"x":800,"y":740,"wires":[["61fd8c0d.15249c"]]},{"id":"61fd8c0d.15249c","type":"function","z":"61a474ed.8f915c","name":"Time stamp","func":"msg.payload = flow.get(\"Time_error\");\nmsg.RTC = flow.get(\"RTC\");\nmsg.local = flow.get(\"local\");\nmsg.time = new Date().toLocaleString();\nreturn msg;","outputs":1,"noerr":0,"x":960,"y":740,"wires":[[]]}]

As mentioned I have not (yet) caught any of those packets to see what the problem is and when it happens.

Though the ones I have seen are at mid-night.

Thus I added extra stuff on the last function node to get the two time values and include them in the message.

It isn't so much an error, but the code I wrote claims there is a problem with the two times it is seeing.

Are you able to answer my question? What is the format of the time values you are comparing?

1 Like

I think it is seconds since midnight.....

So I think I now understand why it is failing.

This is what I get if I pulse the flow and get the "local time"

{"payload":64956,"topic":"local","_msgid":"916910dd.555a3"}

Or maybe milliseconds since midnight.

And so in light of that, I need a way to exempt the node from saying there is a problem daily at midnight to avoid that problem.

But now I guess I know that which I am chasing.

If you are only expecting to cope with drift (having set them correctly to start with), then you could just ignore very large changes (say greater than 23 hours) the same way you ignore small ones.

1 Like

dceejay.

You are probably correct.

I had just not thought that far ahead of myself.

As I am only doing the "day's time" every mid-night it will spit the dummy as it were.

I shall apply an upper limit and see what happens.

Thanks.

(and to you Nick too.)

Why are you doing this anyway?

2 Likes

Short answer: to learn.

Well good news!

Seems that adding a bit more code

        r = Math.abs(a - b);
        flow.set("Time_error",r);
    }
    if (r > 1000)       //  nominal ammount for day change.
    {
        //  New day error.  Skip this time.
        r = 0;
    }

Fixed it.