Need help with how to do this

There is a Gremlin in this somewhere.

I have narrowed it down to messages being received which are not correctly formatted.

A valid message should look something like this:

{"payload":"16:14:37@6,1","topic":"alarm_clock/text","_msgid":"efc6bef8.efa76","_event":"node:e8276ab2.052ef8"}

The part/s of interest are:
the time (eg: 16:14:37) and the @6,1

That is sent by MQTT to a script.

I modified the script and if a message arrives and there is no @ in it, it sends the entire message - I hope - back.

So here's my problem:

Every second I am sending a message.
I want it cached. If another message (source) isn't received in a couple of seconds the message is dropped.

If another message (from else where) IS received, BOTH messages are kept and then on sent to the next node.

How would I do that?
I'm stuck on the mechanics of doing it in NR just now.

P.S.
While writing this question, the code has detected 8 instances of wrongly formatted messages, but the code I have to see them leaving node-red has not detected any.

But I think it would still be good to see them both.

I bashed this together but it isn't doing what I think it should.

I am always getting an output (on left most DEBUG node) even if I press only the top inject node.

[{"id":"64e63da6.313d8c","type":"function","z":"8bb4de19.f72c88","name":"","func":"if (msg.topic == undefined)\n{\n    context.set(\"LAST\",msg.payload);\n    //return;\n} else\n{\n    msg.payload = msg.payload + \" \" + context.get(\"LAST\");\n    return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","x":3180,"y":2300,"wires":[["be93236a.377f3"]]},{"id":"fd7e579.a379028","type":"random","z":"8bb4de19.f72c88","name":"","low":"1","high":"10","inte":"true","property":"payload","x":3000,"y":2300,"wires":[["9fb96f49.2f72","64e63da6.313d8c"]]},{"id":"af990b30.acd4c8","type":"inject","z":"8bb4de19.f72c88","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"capture","payload":"I want this","payloadType":"str","x":2880,"y":2390,"wires":[["64e63da6.313d8c"]]},{"id":"be93236a.377f3","type":"debug","z":"8bb4de19.f72c88","name":"CAUGHT","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":3350,"y":2300,"wires":[]},{"id":"a140900e.5f3c4","type":"inject","z":"8bb4de19.f72c88","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":2850,"y":2300,"wires":[["fd7e579.a379028"]]},{"id":"9fb96f49.2f72","type":"debug","z":"8bb4de19.f72c88","name":"","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":3010,"y":2330,"wires":[]}]

This is the code in the function node:

if (msg.topic == undefined)
{
    context.set("LAST",msg.payload);
    //return;
} else
{
    msg.payload = msg.payload + " " + context.get("LAST");
    return msg;
}

So, as is, a message comes in.
No topic.

I'm guessing the first line:
if (msg.topic == undefined)
is wrong.

I've since tried null. Same.

So == ""?

I thought that was .... null or undefined.

Sorry.

Someone, again, explain what this is called.

This simple test works for me - returns "no topic" when there isn't one - otherwise just passes msg thru so must be something else to do with your logic (or you do have a topic)

I put a debug node at the input to that function node and the topic was shown as "".

So I went down that road and changed it form undefined to "" and it works.

But what is undefined, null and "".

I again seem to be stuck on their definitions.

image

You would be better off with

if (msg.topic) {
  ...
}

that will handle null, undefined & ""

1 Like

Aw! It's not a picture. I can't save it and use it locally in the future.

I'll work on how to get a copy of it though.

Thanks.

1 Like

screenshot?

Yeah, ok. Sorry.

Firefox is being a bit difficult to me just now as well.
(never rains, it pours!)

undefined, null and "".

"" is a String object that contains no characters

null is the null object. It exists as a thing and contains no data of any type.

undefined means there no object of any sort.

As Steve has shared, when you do a Boolean test of them using == they all are equivalent to false.

This rather long web page explains it all, but you can skip down to the "sameness" table that gives a similar summary to the picture above.

1 Like

it s the opposite

use if (!msg.topic) {

or

if (msg.topic) {
  ...has topic
} else {
  ... no topic
}

Or visually (from various places on internet) :wink:


they all == no paper

2 Likes

Love it!
:wink:

Simon, for that particular instance (your picture) , remove the ! from the first line and it will work.

if ( ! msg.topic ) { should read if ( no topic ) { then

where as

if ( msg.topic ) { should read if ( has topic ) { then

you shouldnt for the if(msg.topic) test as "" and missing will both fail the test.

Perhaps I am missing the requirement? I thought Andrew wanted to check a topic was "something" hence the if(msg.topic) suggestion?

If I missed something (sorry) and Andrew actually wants a blank topic "" to be OK (but not null and not undefined) then if(msg.topic == null) will satisfy that.

Quick demo...

[{"id":"b7c94cb.651b7b","type":"inject","z":"b8d87de8.2e416","name":"topic missing","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":1730,"y":160,"wires":[["90d9cc7f.6fd07","9962672.cb75598"]]},{"id":"292a6082.a2937","type":"inject","z":"b8d87de8.2e416","name":"topic == \"\"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":1720,"y":200,"wires":[["90d9cc7f.6fd07","9962672.cb75598"]]},{"id":"90d9cc7f.6fd07","type":"function","z":"b8d87de8.2e416","name":"if(msg.topic) {","func":"if(msg.topic) {\n    msg.payload = \"msg has a valid topic: \" + msg.topic;\n} else {\n    msg.payload = \"msg is empty\"\n}\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1980,"y":160,"wires":[["32bcb95b.37df46"]]},{"id":"9962672.cb75598","type":"function","z":"b8d87de8.2e416","name":"if( msg.topic == null ) {","func":"if( msg.topic == null ) {\n    msg.payload = \"msg is null or undefined\"\n} else {\n    msg.payload = \"msg has a topic: \" + msg.topic;\n}\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":2000,"y":200,"wires":[["646ccb55.9d2514"]]},{"id":"32bcb95b.37df46","type":"debug","z":"b8d87de8.2e416","name":"if(msg.topic) {","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":2200,"y":160,"wires":[]},{"id":"646ccb55.9d2514","type":"debug","z":"b8d87de8.2e416","name":"if(msg.topic == null) {","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":2220,"y":200,"wires":[]},{"id":"76bc23e2.b2326c","type":"inject","z":"b8d87de8.2e416","name":"topic is \"hello topic\"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"hello topic","payload":"","payloadType":"date","x":1750,"y":240,"wires":[["90d9cc7f.6fd07","9962672.cb75598"]]}]

Ok, just to clarify - sorry folks.

If a message is going through the system I need to catch it if things go awry.

So I have an output (input... what ever) which is the message which is non-compliant to a condition.

If it is, I want to see what the original message is/was that was sent.

So:
The Original message may (or not) have a defined topic. Not sure if it is null, undefined or "".

If I get a message of a non compliant message, I set the topic to "SOMETHING" (as in it has something in its field.)
That is sent into a node that has kept the original message, and sends the two out.

These two nodes now seem to do it.

Given the first input is the signal that the message was non compliant to needs.

[{"id":"1548c7fd.e430b8","type":"change","z":"eff5d6e6.236338","name":"","rules":[{"t":"set","p":"topic","pt":"msg","to":"catch this","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1625,"y":1360,"wires":[["64e63da6.313d8c"]],"l":false},{"id":"64e63da6.313d8c","type":"function","z":"eff5d6e6.236338","name":"Catch","func":"if (msg.topic == \"\")\n{\n    context.set(\"LAST\",msg.payload);\n    //return;\n} else\n{\n    msg.payload = msg.payload + \" \" + context.get(\"LAST\");\n    return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1740,"y":1360,"wires":[["ea85326b.2d4148"]]}]

The original message is sent into the second node.

The output will ONLY happen if there is a message sent to the change node.

I can post a better example is needed.

In the sense that ...

if (msg.topic) {
  //the topic is something more than "" - lets use it
} else {
  //the topic is either "", null or undefined
}

As i said Simon, I might have missed Andrews requirement.

Nothing to see here folks, move along :crazy_face:

In which case, as I said before...

if (msg.topic) {
  //the topic is something more than "" - OK
} else {
  //the topic is either "", null or undefined
  msg.topic = "SOMETHING";
}

or

if (!msg.topic) {
  //the topic is either "", null or undefined
  msg.topic = "SOMETHING";
}

Its too early, and I am losing the will ...

Time to get the :crayon: :crayon: :crayon: out for me.

1 Like

Ok, a better example of what I want to do:

[{"id":"a140900e.5f3c4","type":"inject","z":"8bb4de19.f72c88","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":2850,"y":2300,"wires":[["fd7e579.a379028"]]},{"id":"fd7e579.a379028","type":"random","z":"8bb4de19.f72c88","name":"","low":"1","high":"10","inte":"true","property":"payload","x":3000,"y":2300,"wires":[["9fb96f49.2f72","64e63da6.313d8c","d52ad08a.3da53"]]},{"id":"9fb96f49.2f72","type":"debug","z":"8bb4de19.f72c88","name":"","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":3010,"y":2330,"wires":[]},{"id":"64e63da6.313d8c","type":"function","z":"8bb4de19.f72c88","name":"","func":"if (msg.topic == \"\")\n{\n    context.set(\"LAST\",msg.payload);\n    //return;\n} else\n{\n    msg.payload = msg.payload + \" \" + context.get(\"LAST\");\n    return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","x":3180,"y":2300,"wires":[["be93236a.377f3"]]},{"id":"d52ad08a.3da53","type":"debug","z":"8bb4de19.f72c88","name":"look at this","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":3160,"y":2240,"wires":[]},{"id":"af990b30.acd4c8","type":"inject","z":"8bb4de19.f72c88","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"capture","payload":"I want this","payloadType":"str","x":2880,"y":2390,"wires":[["64e63da6.313d8c"]]},{"id":"be93236a.377f3","type":"debug","z":"8bb4de19.f72c88","name":"CAUGHT","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":3350,"y":2300,"wires":[]}]

Press the top inject node.

Things are good.
Keep pressing.

Say one of the messages cause what ever to happen, then a signal is sent and the bottom inject button is pressed.

That then creates a message to send on the original message with the other message concatenated together.

Clearer?

I've deleted all my posts so your edited post can stand alone :slight_smile: