Help with structure of code. (Javascript)

I don't want the answer given to me. Though I accept I am doing it the wrong way (maybe long would be a better word) I want to go through the motions and hope this helps me understand better what it is I am wanting to do.

3 machines sending in reports of what they see - all looking at the same thing.
Machine 1, machine 2 and machine 3
They are looking at: uplink and modem.
(I know modem is an old word and not really correct, but it shall suffice for what I am doing)

So each send a message out into the network for the other two to receive and process, as well as their own version on the state of the nation.

Machine 1: uplink: good modem: good
Machine 2: uplink: good modem: good
Machine 3: uplink: good modem: good

(and any combination there of good/bad)

This is kind of getting into IP routing kind of stuff, but I am still only learning about that and so I won't say this again.

Machine 1 can see the modem (and up link). All is fine. It also sees that both 2 and 3 see the modem and uplink.
Because (say) 3 sees it, the colour is lime. (irrespective of what it and 2 say.)
Say 3 doesn't see then, but 2 does: the colour would be green (irrespective of what it sees.)
If neither 2 or 3 see the modem (I'll forget about the uplink, as the logic there is the same anyway) but it does: the colour would be light blue.
That is an example.

Now, machine 2:
Similar.
But say 1 is higher weight this time and 3 is the next.

Then machine 3:
It's external weight is 2 then 1 - then itself.

The kink:
If none can see the modem the uplink become **unknown** for obvious reasons.

To make it .... a function I want to do this in a function node and edit the weight of each machine's message to derive the outgoing message's colour.

As each machine sends its message and all 3 machine's messages are stored in context - I'm guessing - then I can't just save the "un/seen" message for the device. I have to assign it a value at that stage - yes?

Then compare it to thresholds when it is read and if it is above a value (4, 2, 1) then that determines the colour.

That's how I am seeing it at this stage.

Update:

This is some code I wrote and it works but I have found a quirk with it.

(more after the code)
Sorry about all the // lines.

msg1 = {};

machine1 = "BedPi";
machine2 = "TimePi";
machine3 = "TelePi";

//node.warn("Look for this " + msg.payload.Who);

var machine = msg.payload.Who;
//var link = msg.link;
var mstate = msg.payload.Modem;
var ustate = msg.payload.Uplink
var modem;
var uplink;

//node.warn("********");
//node.warn("Machine is " + machine);
//node.warn("link is " + link);
//node.warn("Modem state is " + mstate);
//node.warn("Uplink state is " + ustate);

if (mstate == "Offline")
{
    mstate = 0;
} else
{
    mstate = 1;
}
if (ustate == "Offline")
{
    ustate = 0;
} else
{
    ustate = 1;
}

//node.warn("Modem state is " + mstate);
//node.warn("Uplink state is " + ustate);


//node.warn("State is value " + state);


if (machine == machine1)
{
    //  Machine 1
//    node.warn("Machine 1 routine active");
    ustate = ustate + 1;
    mstate = mstate + 1;
//    if (link == "modem")
//    {
        //  Modem
        context.set("modem",mstate);
//    } else
//    if (link == "uplink")
//    {
        //
        context.set("uplink",ustate);
//    }
} else
if (machine == machine2)
{
    //  Machine 2
//    node.warn("Machine 2 routine active");
    ustate = ustate + 2;
    mstate = mstate + 2;
//    node.warn("New state value is " + state);
//    if (link == "modem")
//    {
        //  Modem
        context.set("modem",mstate);
//    } else
//    if (link == "uplink")
//    {
        //
        context.set("uplink",ustate);
//    }
} else
if (machine == machine3)
{
    //  Machine 3
//    node.warn("Machine 3 routine active");
    ustate = ustate + 4;
    mstate = mstate + 4;
//    if (link == "modem")
//    {
        //  Modem
        context.set("modem",mstate);
//    } else
//    if (link == "uplink")
//    {
        //
        context.set("uplink",ustate);
//    }
}
//  Contexts set.  Now determine the output.

if (msg.payload != "HEARTBEAT")
{
    return;
}



modem  = context.get("modem") || 0;
uplink = context.get("uplink") || 0;

if (modem === 0)
{
    uplink = "UNKNOWN";
    msg = {payload:'<font color = "red"> <i class="fa fa-bullseye fa-2x" ></i></font>'};
} else

if (modem > 4)
{
    node.status({fill: "green",text:machine1});
    msg = {payload:'<font color = "lime"> <i class="fa fa-bullseye fa-2x"></i></font>'};
} else

if (modem > 2)
{
    node.status({fill: "yellow",text:machine2});
    msg = {payload:'<font color = "green"> <i class="fa fa-bullseye fa-2x" ></i></font>'};
} else

if (modem > 1)
{
    node.status({fill: "red",text:machine3});
    msg = {payload:'<font color = "springgreen"> <i class="fa fa-bullseye fa-2x" ></i></font>'};
}

if (uplink === 0)
{
    msg1 = {payload:'<font color = "red"> <i class="fa fa fa-bullseye fa-2x" ></i></font>'};
} else


if (uplink > 4)
{
    msg1 = {payload:'<font color = "lime"> <i class="fa fa-bullseye fa-2x" ></i></font>'};
} else

if (uplink > 2)
{
    msg1 = {payload:'<font color = "green"> <i class="fa fa-bullseye fa-2x" ></i></font>'};
} else

if (uplink > 1)
{
    msg1 = {payload:'<font color = "springgreen"> <i class="fa fa-bullseye fa-2x" ></i></font>'};
} else

if (uplink == "UNKNOWN")
{
    msg1 = {payload:'<font color = "black"> <i class="fa fa-question-circle fa-2x" ></i></font>'};
}



return [msg,msg1];

This works as far as I can see.

But the quirk is that the input from all machine is async'.

So the output toggles between the higher two states.

Thoughts?

Update:

I've updated the code posted and this seems a bit better.

But I am still suspicious it is still hiding a problem.

Third update:

Yes, there are still problems.

It works on one machine and not on another and I think it is to do with the messages coming in.

(If you have got this far: Thanks)

To make it so it can work anywhere/how here are the problems as I see them:
1 - the messages are coming in asynchronously and that is the problem. (the/a)
2 - to get around that, I included another input to the node (message) which is the heartbeat and clocks the message through if all three messages are received.
3 - The incoming message is true or false to indicate the state.
I change that to 1 and 0 and take than number through the code, adding to it depending on who sent the message - or: from whom the message came.

This works nice but because of timing, the stored value is wiped at the wrong time.

I see the value go from 0 (fresh deploy of the node) to 2, 3, 5 and back to 0.
5 means all three machines are seeing things as good.

When all three machines have sent their message, and that is received the value is sent.

I see two machines have sent their messages and the value is 3. (I see the flags saying the two message are received.)

When the third one is received, the flags are wiped and I have a value of 5 stored, but only one machine's flag is set.

ARGH!

I can see how I want it to work, but with contexts and setting the value depending on the incoming message - I think - is where it is being wiped.

It is a trick to getting 3 valid messages before sending the resulting message.

Is that any clearer?

Firstly, to handle async messages you might be best storing the modem and uplink states separately for each machine, and then using this information to determine the resulting message. That way each machine's state will only change when the relevant message arrives.

Secondly, I don't think your code is doing what you think it is. If I'm reading it correctly you're "encoding" the state and machine ID in a single variable, but you've used the same bit for state and "machine1". i.e. if ustate is 1 and it's machine1, ustate becomes 2. If ustate is zero and it's machine2, ustate becomes 2.

You should use e.g. 2, 4, and 8 for the machine ID bits. (My tendency would be to use obviously different values such as 0x100, 0x200 and 0x400.)

One other comment, from my years of working with strongly-typed languages, is to keep variables to a single type, i.e. string or integer. I know JavaScript lets you get away with it, but it makes the code harder to understand (for me anyway).

Thanks for the time to read and reply.

Before I forget, this is a piece of code which had me stumped for a long time.

if (mstate == "Offline")
{
    mstate = 0;
} else
{
    foo = context.get("mstate");
    if (foo == undefined)
        mstate = 1;
    else
        mstate = foo;
}

Duplicated of course as needed.

Yes, I am really not good with variables these days. I used to write crazy BASIC stuff back in the 80's when there was little else to use.

Anyway:

The idea is this:
The message comes in.
It has these parts:

  • which machine sent the message
  • the state of the link to the modem
  • the state of the link to the uplink

Who sent it is pretty easy.
The state is Boolean - which is kind of good, kind of bad.

Originally I just translated the true/false to 1/0

Then, if it was 0, I knew it was not possible to know the state.
If it was ok, it would be a 1. Slight hitch, how to deal with that.

Yes, I could go to bit setting, but I don't know how to do that, so I thought I would do it this way:

+1, +2 and +4.

Given: 1 + 1 = 2
1 + 2 = 3
1 + 4 = 5

Calling the 3 machines 1, 2 and 3 for the number they add. (1 = 1, 2 = 2, 3 = 4)

Thinking this way:
If machine 1, 2 and 3 are good, the total would be 8. (>4)
If machine 1 and 3 are good, the total would be 6. (>4)
If machine 3 (only) is good, the total would be 5. (>4)

So if the value is >4 the message colour is lime

That works for the comparisons in the code. But for some reason the value wasn't being kept/honoured and on sent.

Partly because the values were always set to 1 (given good) when a new message arrives.
That shouldn't be a problem. The maths works even if only one machine is giving a good message.

But it seems to be sticking with 3 and not sending a 5 when the last message arrives.

I have been chasing my tail with the context setting for .... hours.
I thought I had it fixed, but it is being (typically) difficult and cantankerous even after that last bit of code went in.

What is really throwing me is that it works on one machine - alas it is ... (anyway). The other two: it alternates on which it works and which it doesn't.
If I am lucky it works on both, and if really unlucky: neither.
But that isn't to say it fails but just gives the wrong output colour.

I am not sure if my making this clocking (HEARTHBEAT signal) is helping or not.
Without it, the colours change from "all good" to "2/3 good" colours. Which isn't the end of the world.

I just thought I would try to capture the messages (cache them?) and when all 3 are received: send the result to the next stage and then determine who is doing what and make the colour reflect it then, rather than dynamically.

It is 20:44 here and I think I deserve a break. Not that I don't like your help.
Again: I am torn between the course to take:
I can take the easy way out and get a working bit of code from someone which I don't understand, or just knuckle down and try to get my head around this and do it my way.

Either way: I may not understand what is given to me .... now. But in the future I may, and so I still think that constitutes learning, but by an easy way. Or, I have to contend with the monster I just created and defeat it and learn.
That way is a lot harder and will take a lot more time. But isn't that part of the learning?
(Though I do get there are extremes and it isn't always the best to do the hardest way.)

I'll shut up now as I think I am starting to rant.
:wink:

Ok, that's interesting. Hang on. I'll look.

Ok....
I used machine and machine1, machine2 and machine3 because I had code working - kinda - and was writing test code in bare bones style.

So I transposed (right word?) the message parts to the names I used in the raw code.
You can see that at/near the top.

ustate is the uplink state.
Way back at the start ustate is set to 0 or 1 depending if it is false or true.
Then, the message is filtered to who sent it. machine1, 2 or 3.

Given machine1 it adds 1 to the ustate value of 1 (as the uplink is detected in the message).

That is then saved as 2 to context.

If it were machine2, the context would then be set to 3, and if machine3, it would be set to 5

if ustate is zero and its machine2 ustate becomes 2.

No problems there. . . . . . Oh! Ok.
Yeah. Ok. Not good. I hadn't even got to that point in the tracking yet.
I need to add code so if it is 0 then it doesn't add anything.
Another trap I hadn't seen.

Thanks!

1 Like

I'd say figuring it out yourself is a better option than using something you might not fully understand. If you have problems in the future, knowing your own code will make it easier to solve them.

I'm not sure I fully understand what exactly you want to get as the output from this function, but my approach would be to step back and look carefully at all the possible inputs and (expected) outputs. Then work out the most logical, and hopefully simplest, way to get from one to the other. I fear you may have over-complicated things here, trying to encode multiple pieces of information in a single variable, when using separate message fields might be easier, and more useable by nodes further along the flow.

Having a break and taking a fresh look later does sound like a good plan :wink:

Indeed - I must admit I would tend to keep the 6 (3 machines x 2 variables) states separate from each other - and then treat it as a priority question rather than a weighting question... by that I mean a simple cascade of if statements almost exactly as you wrote it.. " if (say) 3 sees it, the colour is lime. ".. "else but 2 does: the colour would be green" etc
and just make sure the comparison order is in the priority order you want for each machine.

1 Like

Thanks.

@molesworth,

One thing I have done wrong is adding the value. I'm not sure why I went that way when initially I wanted to multiply it.

That way if the state was 0, multiplying it would still get a 0. Adding introduces the problem you mentioned and I hadn't seen/realised.

Yes, I agree with the idea of keeping them separate. However at some stage all of them are going to have to meet up in one way or another.

I can go with the idea - well actually I sort of am already - of each machine broadcasts its state and the others see that. But that has to be done in any case.

@dceejay
You are correct in the last part of what you say.
Granted the priority would change from machine to machine, as their inter relationship would be different machine to machine.

What I am wanting is a way to queue the messages received from all machines.
Every 20 seconds all three machines should have sent in their message/s with what they see.
That is looked at and the best answer is sent.

This is because (as I explained) allowing the messages to go through to the output as they arrive causes the indicator/s to change as the messages come in.
Although it could be argued this is a real time representation of what is going on, it also isn't.
It is obfuscated because the messages are arriving at different times.

I am obviously missing something with the if and else statements.

Having only if..... if..... and if...... all have to be done - yes?
But having the else after each if means it exits once a match is made - yes?

Anyway, its a new day. I'll sit here and see if I can get it working better now in light of what has been said and a good night's sleep.

Ok, after other help I got this code and it is working now as desired.

I still need to add other external nodes to ensure messages are received - if not saying "Offline".

This is changed from machine to machine so the weight always has that machine as machine1.

Sorry I didn't tidy up the comments.

//Set Bit
function setBit(number, bitPosition) {
  return number | (1 << bitPosition);
}

//Clear Bit
function clearBit(number, bitPosition) {
  const mask = ~(1 << bitPosition);
  return number & mask;
}
/////////////////////////////////

msg1 = {};
msg2 = {};
machine1 = "TimePi";
machine2 = "BedPi";
machine3 = "TelePi";

//node.warn("Look for this " + msg.payload.Who);

var machine = msg.payload.Who;
//var link = msg.link;
var mstate = msg.payload.Modem;
var ustate = msg.payload.Uplink
var modem;
var uplink;
var value;
var m1 = context.get("m1") || 0;
var m2 = context.get("m2") || 0;
var m3 = context.get("m3") || 0;
var debug = context.get("debug") || 0;

if (debug == 1)
{
    node.warn("********");
    node.warn("Machine is " + machine);
    //node.warn("link is " + link);
    node.warn("Modem state is " + mstate);
    node.warn("Uplink state is " + ustate);
}

if (msg.payload == "DEBUG")
{
    context.set("debug",msg.onoff);
    if (msg.onoff == 0)
    {
        node.status({fill:"red"});
    } else
    {
        node.status({fill:"green"});
    }
    return;
}

//node.warn("mstate " + mstate);

if (machine == machine1)
{
    //  Machine 1
//    node.warn("Machine 1");
    context.set("m1",1);
    if (mstate == "Offline")
    {
        value = context.get("mstate") || 0;
        newval = clearBit(value,0);
        context.set("mstate",newval);
    } else
    if (mstate == "Online")
    {
        value = context.get("mstate") || 0;
        newval = setBit(value,0);
        context.set("mstate",newval);
    }
    if (ustate == "Offline")
    {
        value = context.get("ustate") || 0;
        newval = clearBit(value,0);
        context.set("ustate",newval);
    } else
    if (ustate == "Online")
    {
        value = context.get("ustate") || 0;
        newval = setBit(value,0);
        context.set("ustate",newval);
    }
}

if (machine == machine2)
{
    //  Machine 2
//    node.warn("Machine 2");
    context.set("m2",1);
    if (mstate == "Offline")
    {
        value = context.get("mstate") || 0;
        newval = clearBit(value,1);
        context.set("mstate",newval);
    } else
    if (mstate == "Online")
    {
        value = context.get("mstate") || 0;
        newval = setBit(value,1);
        context.set("mstate",newval);
    }
    if (ustate == "Offline")
    {
        value = context.get("ustate") || 0;
        newval = clearBit(value,1);
        context.set("ustate",newval);
    } else
    if (ustate == "Online")
    {
        value = context.get("ustate") || 0;
        newval = setBit(value,1);
        context.set("ustate",newval);
    }
}

if (machine == machine3)
{
    //  Machine 3
//    node.warn("Machine 3");
    context.set("m3",1);
    if (mstate == "Offline")
    {
        value = context.get("mstate") || 0;
        newval = clearBit(value,2);
        context.set("mstate",newval);
    } else
    if (mstate == "Online")
    {
        value = context.get("mstate") || 0;
        newval = setBit(value,2);
        context.set("mstate",newval);
    }
    if (ustate == "Offline")
    {
        value = context.get("ustate") || 0;
        newval = clearBit(value,2);
        context.set("ustate",newval);
    } else
    if (ustate == "Online")
    {
        value = context.get("ustate") || 0;
        newval = setBit(value,2);
        context.set("ustate",newval);
    }
}

m1 = context.get("m1") || 0;
m2 = context.get("m2") || 0;
m3 = context.get("m3") || 0;

modem  = context.get("mstate") || 0;
uplink = context.get("ustate") || 0;
msg2.payload = {modem,uplink,m1,m2,m3};


if (m1 == 1 && m2 == 1 && m3 == 1)
{
    //
    //node.warn("All set");
    context.set("m1",0);
    context.set("m2",0);
    context.set("m3",0);
    context.set("mstate",0);
    context.set("ustate",0);
//    modem  = context.get("modem") || 0;
//    uplink = context.get("uplink") || 0;
    //  Now send the message
    
//}

    if (modem === 0)
    {
        uplink = "UNKNOWN";
        msg = {payload:'<font color = "red"> <i class="fa fa-bullseye fa-2x" ></i></font>'};
    } else

    if (modem > 3)
    {
        //node.status({fill: "green",text:machine3});
        msg = {payload:'<font color = "lime"> <i class="fa fa-bullseye fa-2x"></i></font>'};
    } else

    if (modem > 2)
    {
        //node.status({fill: "yellow",text:machine2});
        msg = {payload:'<font color = "green"> <i class="fa fa-bullseye fa-2x" ></i></font>'};
    } else

    if (modem > 0) //  should be `> 1`
    {
        //node.status({fill: "red",text:machine1});
        msg = {payload:'<font color = "springgreen"> <i class="fa fa-bullseye fa-2x" ></i></font>'};
    }

    if (uplink === 0)
    {
        msg1 = {payload:'<font color = "red"> <i class="fa fa fa-bullseye fa-2x" ></i></font>'};
    } else

    if (uplink > 3)
    {
        msg1 = {payload:'<font color = "lime"> <i class="fa fa-bullseye fa-2x" ></i></font>'};
    } else

    if (uplink > 2)
    {
        msg1 = {payload:'<font color = "green"> <i class="fa fa-bullseye fa-2x" ></i></font>'};
    } else

    if (uplink > 0) //  should be `> 1`
    {
        msg1 = {payload:'<font color = "springgreen"> <i class="fa fa-bullseye fa-2x" ></i></font>'};
    } else

    if (uplink == "UNKNOWN")
    {
        msg1 = {payload:'<font color = "black"> <i class="fa fa-question-circle fa-2x" ></i></font>'};
    }

//    msg2.payload = {"Modem":modem,"Uplink":uplink};
    return [msg,msg1,msg2];

}

return [null,null,msg2];

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