If(msg.payload.match(find))

#1

Hello,

I need a message payload to be the opposite (on or off) based on the current state of a sonoff device. Using (in my case) an mqtt state of tasmota/SonoffLamp1/cmnd/Power I am able to ascertain the current status of the lamp. I have come across if(msg.payload.match(find)) and believe it best suits my requirements, but I am unable to construct the javascript to get the state and send on the opposite payload.

Can anybody assist me please?

Thanks

Glenn

#2

You can use the Change node, if you add multiple rules (within the same node)

So change msg.payload. Search for X Replace with Y
change msg.payload. Search for Y Replace with X

#3

Thanks for your prompt reply.

I did try the change node but I couldn’t establish how to incorporate the state from MQTT to allow the replace from to work.

Please advise?

Thanks

Glenn

#4

You have to pass the MQTT state to the Change Node by having the Change Node after the MQTT-IN node in your flow.

Your MQTT-IN node reads the MQTT topic from your MQTT broker and passes it on to the next nodes(s) as a msg, with the value in msg.payload.

#5

Thank you again

It's a little more complicated than that, let me explain.

I have a rf toggle switch which is being read by a sonoff bridge. When pressed I want to send an 0 or 1 to the MQTT broker to switch the light on, but it needs to establish the status from the point of receiving the rf code to committing the correct 0 or 1. Hopefully the nodes above will help understand what I am doing

#6

Then take a look at the docs around storing data https://nodered.org/docs/writing-functions#storing-data

#7

Hello,

Do you think this would work in a function node followed by a change node?

var status = context.get(‘tasmota/Sonoff/Lamp1/cmnd/Power’);
context.set(‘tasmota/Sonoff/Lamp1/cmnd/Power’,status);
msg.payload = status;

#8

You showed 2 flows the switch flow and the state flow. Where are you putting this?

If it is the function in the switch flow, where are you getting the current state from?

If I understand what you are trying to do you need to store the lamp state and then use that when the switch flow is triggered. If you want to share between the two flows you cannot use context, but you could use global or flow ( see the page I linked to). You can also set and get global. and flow. using the change node ( use drop down where it normally say msg.)

#9

Apologies nodes as above

Yes you understand what I am trying to achieve.

#10

Then as I said before,
You need to store the lamp state which you can only do in the lamp state flow, and then use that in the switch flow.

If you want to share between the two flows you cannot use context. , but you could use global. or flow. ( see the page I linked to). You can also set and get global. and flow. using the change node ( use drop down where it normally say msg.)

In your switch flow you can then add a SWITCH node based on the value of the global. or flow. and then a change node

#11

Okay, I think I know what you mean but I'm not sure I have all the steps in place. Would this work please?

#12

surely the easiest way for you to see if it works is to try it?

Add some more debug nodes along your flow so if it doesn’t you can see where it deviates from what you expect

#13

Based on what I see in your change node, I don’t think this will do what you want…

You have two rules set to

  1. change 0 -> 1, and
  2. change 1 -> 0

So if your global lamp1payload is a 0, it first get set to 1, then then next rule will change it back to 0… But if the global var is already 1, the first rule will do nothing, and the second will still change it back to 0. So either way you end up with a 0 in your global var.

Besides that logic flaw, using a string replace operation to modify your numbers is not ideal (true, it should work with your limited inputs of 0 and 1, but what happens if you get the number 100? or undefined? or any JS object/array?)

Instead, I would either use a JS function with a ternary if ? then : else expression:

var last = global.get("lamp1payload") || 0;
var stat = stat == 0 ? 1 : 0;
global.set("lamp1payload", last);
return null;

or always increment the “state” value, and use the “%” modulo operator to keep the value in range (more general technique to use when you have more than 2 states):

var scnt = 2; // two states only for this example
var last = global.get("lamp1payload") || 0;
var stat = (stat + 1) % scnt;
global.set("lamp1payload", last);
return null;
1 Like
#14

Thanks for your assistance.

I have been unable to physically try this until yesterday and both the change nodes method and the JS Function node method failed to work.

I was wondering if it has something to do with the fact that there is no node after the change node on the “lamp state” flow which sets the global.lamp1payload above, as there is an output on that node? However, if this is the case, I am unsure what node would be required?

Thanks in advance

#15

The change node will change msg.payload but if you don’t send it anywhere, how do you think it will be used?

#16

Setting global.lamp1payload in a change node will set the global variable, but you must pick that up somewhere and use it at some point after setting it. Generally it is much better to avoid global and flow variables and instead set a value in the payload and pass it on to do whatever you want it to do in subsequent nodes.

#17

Arugh I should read better before I post (need more coffee…)

When you set the global in the change node, it is set, but until some other node looks at that global nothing will happen.

For example, lets say you have an inject node (A) that runs only when you press it and it sets global.X to “night”. You have another flow that has a inject node (B) that also only runs when you press it, connected to a function node (which test global.X = “night” - if yes it send a 1) which is connected to a GPIO node which is wired to a lamp.

You do a deploy at noon, and the lamp is off and you wait, the sun goes down and the house gets dark. You press inject(A), but the light remains off. Even though the global.X has been set, the function node will not run till you press the second inject (B).

Hopefuly this will help