Recommendations for the new guy?

Hi everyone.

New to IOT, new to home assistant and new to node red. Got it all setup and some pretty neat, but basic routines. What I have below is like a kindergarten's first art project. It works but it's a bit basic.

What recommendations do you have to tidy this up so it's more streamline and easier to maintain?

Hi and welcome to the world of Node-Red.

First thing: There is nothing wrong with what you did if it works. Don't let people tell you otherwise.

Yes, you can optimise it. That's making things better for you. But there is nothing wrong with it if it works.

Ok, so let's look at the program (flow as it is called for this system)

All the inject nodes send messages at their respective times. That's ok.
I don't know what the blue nodes are, but... that doesn't matter really.

Next: all the light on? nodes. Are they all for the same light? Do they all do the same thing?
Then: all the kitchen @.... nodes. I'm guessing they are all different and set the kitchen light at the varying levels.

Correct?

How/what can you optimise?
Well, not much as it stands.

To optimise code, you need to have a lot of the same thing being done in a lot of different places and left as is.
Like that the program is bigger than it needs to be.
Finding these repeated bits and making them all use a central piece of code optimises the code.

So, what can you do?
Question 1:
Can the kitchen light take parameters?
So you could send a message to that node with 25% (example) and it would turn the light on 25%. Of course the % sign should be redundant. So really you would send it 25.

If so, a lot of the code could be replaced and you only would need ...... (counting and negating the 3 for the office temperature, < 74 and dyson on) 11 nodes. Not 25.

I haven't set all the times (oh, BTW, check the times again. I think you made a slight mistake there.) but you get the idea, and the nodes aren't the real ones. It is but a simulation that you can do if the node allows you to send it a value for how bright you want the light.

Double click on one of the kitchen @ nodes and take a screen shot and post it.
It will be interesting to see what you can send the node.
I am very suspicious you can use parts of the msg to control things.

I don't have home assistant installed and am not going to to test a theory.

As a newbie it does not hurt to simplify things by having discrete nodes performing each function - much easier for you to troubleshoot etc

You could look at one of the more advanced timer nodes - the CronPlus node that has been very actively developed on here would enable you to centralise your schedules - but it is a much more complex beast and probably more than you need at the moment

It might also be worthwhile seperating your actions - although most are to do with lighting one is to do with heating so i would move that to a tab/flow that was called heating whilst this first flow would be called lighting.

You may as you get more advanced want to (for instance) remember the state of the light (what percentage) by storing that in a persistent context variable - so in the event that your were to restart your flow etc - it could then be restored to the same value.

Craig

1 Like

Hey thanks for the helpful advice. Here's a photo of the kitchen light.

So the function (light on @ %), how would that look generally? The trigger timestamp injects would fire at the specific times and would need to write a case statement, or something like that, to pass on the brightness_pct values?

I started myself a year ago with more or less the same environment (but using Homematic as the IoT platform). In the beginning, I was trying to make also the code "neat" and more sophisticated. However, after a few months (and many learnings later) I returned to simple coding like the one you're showing.

I agree with @Trying_to_learn; if it works, it's okay. If I got the intention of your flow, at specific times, you're checking the state of individual devices, and you act accordingly. Clear and simple.

1 Like

Some good responses here. For me the key thing is whether you will be wanting to expand your controls. What you have there is great if you only have a single lamp and a fan.

But what if you wanted to control lighting all over the building? That is when you would want to optimise things. Optimising too early is generally a mistake.

To optimise, as others have implied, you want to start parameterising things. So perhaps that control node allows you to pick up data from the input msg? If so, you do only need a single node for each device, you can use change nodes or even the inject data to change the parameters. Maybe even the device id could be picked up from an input msg? If so, you might only need a single control node fed by inject/change nodes.

Then you could parameterise further by using CRON+ as suggested by Craig.

Ultimately, you may wish to think about how you can disaggregate the inputs from the outputs.

In my own setup (I don;t use Home Assistant), my inputs come from a number of different types of source: ESP devices, LightwaveRF and other 433MHz devices and so on.

Each input has its data "normalised" and sent to MQTT in one set of flows.

Another set of flows listens for changes and does any appropriate processing. If that needs to result in a switch or light changing, I have another set of MQTT topics for that - still disaggregated from the physical outputs.

Finally an output set of flows listens for the commands and translates the logical device ID's (or even whole rooms) into the appropriate physical outputs.

Now it becomes easy to add new inputs even if they come from a completely different type of hardware (Zigbee or ZWaver for example). Just as easy to add new outputs and types. Also, if I need to replace a broken device, also easy, just a change of some reference data.

In all of that physical change, I don't have to touch the logic. Similarly, when changing logic, I don't have to track down where that is scattered amongst many flows and tied to specific hardware. It is all together.

But what you've done is a great start and a perfectly valid use for Node-RED. It's just that this stuff is a bit addictive! Hard to stop tweaking once you've started - you've been warned :smile:

You need to study and understand what the data field is and how it works.

Once you get that, you will be able to use only 1 home assistant node and send the brightness in the message. Yes that will require the addition of another node. But nothing is free in programming.

Again: not critical to make it work any better. But to make it smaller and more optimised.

Some other things to consider:
Yes, a cron node would be good for what you are doing. One node holds all the times.
Alas there is a drawback with this.

I'll get to that later.

This is your existing scheme: (example)
and shown after an extra node is added for the brightness of the light.

We will go at this a few different ways.

But first let's look at how to optimise the code.
I am helping someone else and as it is being discussed, I thought I would bring it up here too.

There are many ways to do a job. None more right than the other so long as they all do the same thing in the end.

But as you go on, things get bigger and the code explodes in size and suddenly you are looking at a monster!

This can be daunting. But have no fear, you then start to optimise the code.
But how?

Well, One way I suggest you do it is by starting at a known point and working backwards.
Why? Why not go forwards? That seems more intuitive.

You can, but with Node-Red, I would suggest going backwards because you are building on known things, rather than building to a goal.

You want to turn on/off the lights. The first thing you need to do is establish this can be done.
So you get the home assistant node set it up to control that light and connect some inject nodes to it to send it messages to turn the light on or off.

Once that is working: it is a known thing. To control it you know what you need to send it to get the desired result/s.

Another way to optimise the flow is to look for repeated things that are there and see if you can replace them with fewer/simpler nodes. And there is another trick here too!

Originally you have the trigger node that sends an output at a given time.
Then the program (flow) tests if the light is on.
Then the flow sets the brightness. (a suggestion by me)
and finally it sends it to the home assistant node.

But that is not the way I would do it.
Is yours a way better?
No. It is different and has an advantage.
What?

Well, the way you do it, it isn't as optimised as possible.

Let's go backwards in the flow and think about it.

  • Turn on the light to a given brightness. This is a fixed function as your node specifies the brightness.
  • Is the light on? This too is a fixed function.
  • Send a message to turn the light on. Same.

Now we have looked at the home assistant node it is determined that you can send the brightness as a variable and not set in the node.
Variables are important in programming as it allows optimisation.

Let's change the order a bit and make it more like:

This may look stilly (and/or trivial) but I hope you will see the advantage shortly.

Now we can better optimise the flow and reduce the number of nodes easier than we could before.

This is because we now have two parts to the flow:
1 - the control
2 - the event
The control is the different times to trigger the light to be on/off and the brightness.
The second part is conditional to the light being in the on condition and sending the brightness to it. Though it could be argued that the first part is control, please indulge me with this line of thought.

So, really all we need for things to work is this flow layout:

If the test for the light being on was as it was before, we couldn't do that.

Advantages:
Fewer nodes. That's really about it.

Disadvantages: There is still a lot of nodes compared to if we use a cron type node.

And now we will look at that option as suggested by others.
And again I shall stress: There is no right or wrong way to do it.
You do it the way you think is best.

Now, let's go back to the start. I will put things back to how they were.

The brightness part can be negated if you want and included in the home assistant node. It doesn't matter too much for the sake of seeing the alternative layout.

So, rather than having a lot of inject nodes set to inject at given times you replace it with a cron type node:

We go to something like this:
(Introduction)

But we only have one output! How do we connect it to the correct branch?

Well, that's where the switch node comes in and it looks like:

Is this better?
I can't say.

Either way has its good and bad sides.
The bad side of this is every time you make a new entry you have to edit the switch node and add a condition, and then add a change node to set the new brightness.

The first way, you just add another inject node with the time set for injection and a change node with the brightness of the lamp.

Of course you may have seen yet another thing we could do here to reduce the number of nodes:

This way:

And here we have the testing for the light being on back to where it was originally when you posted the flow.

Again:

There is no right or wrong way. Just the way you feel best doing. Given it works.

Good luck and all the best.

P.S.
There is (yet) another way but I shall leave that to you to see. It is a compromise of the two ways I have shown you.

@ Trying_to_learn

I really really appreciate the amount of time you put into your response. There's a lot to take in as a newbie but appreciate your thorough response.

Here's another base routine I came up with regarding my dyson:
image

If temp sensor on dyson is above 74f send that to the 'in use time' which has a time range that is on my office. if also true, turn on dyson. If below 74f turn off, if above 74 but outside of in use time, turn off.

So your advice was good here, this is a nice base routine to expand on. What I want to do now is tweak this some like when it's below 69f turn heat on. The trouble I'm having with at the moment is some of the features of the dyson, specifically oscillation; I have read in the HA documentation there's an attribute for it but doesn't work or i'm doing it wrong. I'll get there.

This is some really cool stuff; i'm going to have to find the line where I'm not driving my wife crazy with IOT stuff all over the house :slight_smile:

You will have to elaborate on that. Do you mean it is heating, then cooling, then heating, etc.
Or making the veins move up and down to distribute the air over more area in the room?

The first node which looks like a time controlled node......
That is confusing (to me) because (seeing the clock on the node) I can't quite get how it is detecting the temperature. But if it works.
Then the in use time node. That too is confusing because: that function should/looks like it should have been done in the previous node - the one with the clock.

Anyway:
As it is now, if the room is too hot/warm, it turns on the A/C (Dyson) and cools the room.

Question:

  • When does it start to determine this is needed? Before you start work; after you start work; by other means?
  • Do you foresee a day when it will need to do both? Cool and heat.

Just these things need to be established so you can make an establish routine for that day.

You have also gone completely away from the lights now.
What happened?

No I haven't as I'm been trying to balance many things including learning another language (reading/speaking). That said, I am re-reviewing your input again and will post later tonight an update to the light flow (hopefully). Stay tuned. I'll come back to the dyson flow (or routine?) later.

Ok - one of the clues you left me is related to data and the flow. So I came up with what I thought would be a slick flow.

image

When I installed the cron-plus node I noticed that it had the ability per schedule to write a json. My thought here was, why not trigger the schedule and include it's data payload the attribute required for the light. Some reason that's not working so I thought I'd toss what I have out here while in parallel try to figure out on my own.

Screens shots:
cron-plus properties

debug values show me two things:
schedule4 : msg.payload : Object
{ brightness_pct: 100 }

and "on"

When the schedule is triggered, the lights come on but the light isn't taking the attribute brightness_pct. My assumption is I'm missing something very fundamental here and haven't discovered it yet :slight_smile:

Well, let's look at it.

First thing is you need to read more about the debug nodes.
Looking at them in the screen shot, you won't see the other data like the brightness_pct part.

This is because you need to edit the debug node to show the entire message.

Screenshot from 2020-07-01 08-36-16

This will only show you the msg.payload

This way you will see it all.

And please name your debug nodes.
It really helps you when you see their messages on the right of the screen to know from which node the message is coming.

So: that first debug node: Set it to show the entire message and force the cronplus node to send a message.
Check that you are getting all the parts of the message.

So, it is the node you don't have selected in the screen shot you just posted.
(the one of the left)

Here is an example of what you get from the node:

But you must have the debug set as I show or it just won't be visible.

When showing output of the debug node....

See the red arrow on the right?

copy value. Click there and paste in here as code.
Easy as.

And people will see this:

{"brightness_pct":65}

Or you can do the entire message - which isn't that much more difficult.

{"triggerTimestamp":1593567058075,"status":{"type":"static","modified":false,"isRunning":true,"count":1,"limit":0,"nextDescription":"in 9 minutes 1 second","nextDate":"2020-07-01T01:40:00.000Z","nextDateTZ":"Jul 01, 2020, 11:40:00 GMT+10","timeZone":"Australia/Sydney","serverTime":"2020-07-01T01:30:58.079Z","serverTimeZone":"Australia/Sydney","description":"Every 10 minutes"},"config":{"topic":"schedule1","name":"schedule1","payloadType":"json","payload":"{\"brightness_pct\":65}","limit":null,"expressionType":"cron","expression":"0 */10 * * * *"}}

here's updated debug.

I noticed in the light check node, that state location was set to msg.payload that upon querying the light (if it was on) that node gave back the brightness_pct value that the light was currently at. So i changed that to flow.payload and now I can see that in both debugs the value is at 100.

That said; the service is not leveraging this attribute. Did i hit a dead end here?

So if you look at the entire payload you will see:

{"brightness_pct":65}

Or your value....

It kind of bugs me that it is really msg.payload.brightness_pct. But that is the point.

All you need to do is add a change node like this (example)

[{"id":"1ef81669.d98dca","type":"cronplus","z":"b9924a74.4d98f8","name":"","outputField":"payload","timeZone":"","persistDynamic":false,"commandResponseMsgOutput":"output1","outputs":1,"options":[{"name":"schedule1","topic":"schedule1","payloadType":"json","payload":"{\"brightness_pct\":65}","expressionType":"cron","expression":"0 */10 * * * *","location":"","offset":"0","solarType":"all","solarEvents":"sunrise,sunset"}],"x":220,"y":3190,"wires":[["ad6a3b6.6b6ee48","8c138b50.5fbc68"]]},{"id":"ad6a3b6.6b6ee48","type":"debug","z":"b9924a74.4d98f8","name":"PAYLOAD","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":400,"y":3190,"wires":[]},{"id":"8c138b50.5fbc68","type":"change","z":"b9924a74.4d98f8","name":"Move stuff","rules":[{"t":"move","p":"payload.brightness_pct","pt":"msg","to":"brightness_pct","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":400,"y":3240,"wires":[["e5500203.e37b9"]]},{"id":"e5500203.e37b9","type":"debug","z":"b9924a74.4d98f8","name":"WANTED","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":570,"y":3240,"wires":[]}]

Click on the cronplus button to get an output.

Look at the WANTED node.

Send that to the node to set the brightness.

The change node will take the message from msg.payload.brightness_pct and make it msg.brightness_pct which is what the next node wants.

Which is why the brightness things weren't doing anything. Because they weren't labelled correctly.

ok. I tried the change node except i moved flow.payload.brightness_pct (instead of ms.payload...)

If i understand fully; the msg payload in the last node now has the appropriate attribute. As you can see, the light again was triggered to come on but made no change to the brightness %

[{"id":"bb4d83c3.2a0068","type":"cronplus","z":"357f7858.e2e768","name":"","outputField":"payload","timeZone":"","persistDynamic":false,"commandResponseMsgOutput":"output1","outputs":1,"options":[{"name":"7am","topic":"schedule1","payloadType":"json","payload":"{\"brightness_pct\":25}","expressionType":"cron","expression":"0 7 * * 1-5","location":"","offset":"0","solarType":"all","solarEvents":"sunrise,sunset"},{"name":"8am","topic":"schedule2","payloadType":"json","payload":"{\"brightness_pct\":50}","expressionType":"cron","expression":"0 8 * * 1-5","location":"","offset":"0","solarType":"all","solarEvents":"sunrise,sunset"},{"name":"9am","topic":"schedule3","payloadType":"json","payload":"{\"brightness_pct\":75}","expressionType":"cron","expression":"0 9 * * 1-5","location":"","offset":"0","solarType":"all","solarEvents":"sunrise,sunset"},{"name":"9pm","topic":"schedule4","payloadType":"json","payload":"{\"brightness_pct\":100}","expressionType":"cron","expression":"37 21 * * 1-5","location":"","offset":"0","solarType":"all","solarEvents":"sunrise,sunset"},{"name":"9:30pm","topic":"schedule5","payloadType":"json","payload":"{\"brightness_pct\":25}","expressionType":"cron","expression":"30 21 * * 1-5","location":"","offset":"0","solarType":"all","solarEvents":"sunrise,sunset"},{"name":"10pm","topic":"schedule6","payloadType":"default","payload":"","expressionType":"cron","expression":"0 22 * * 1-5","location":"","offset":"0","solarType":"all","solarEvents":"sunrise,sunset"}],"x":880,"y":1180,"wires":[["ff8c074a.25ed38"]]},{"id":"ff8c074a.25ed38","type":"api-current-state","z":"357f7858.e2e768","name":"light on?","server":"8b533b83.ade2f8","version":1,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"light.kitchen","state_type":"str","state_location":"payload","override_payload":"flow","entity_location":"data","override_data":"msg","blockInputOverrides":false,"x":1060,"y":1180,"wires":[["540aa9c9.660b18"],[]]},{"id":"eb00ea97.0b332","type":"api-call-service","z":"357f7858.e2e768","name":"kitchen - on @25%","server":"8b533b83.ade2f8","version":1,"debugenabled":false,"service_domain":"light","service":"turn_on","entityId":"light.kitchen","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1330,"y":1220,"wires":[["f11a33ba.b0edf"]]},{"id":"550c2645.1dc0e","type":"debug","z":"357f7858.e2e768","name":"info after light check","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","x":1460,"y":1060,"wires":[]},{"id":"f11a33ba.b0edf","type":"debug","z":"357f7858.e2e768","name":"message after light","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1560,"y":1160,"wires":[]},{"id":"540aa9c9.660b18","type":"change","z":"357f7858.e2e768","name":"Move stuff","rules":[{"t":"move","p":"payload.brightness_pct","pt":"flow","to":"brightness_pct","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1270,"y":1160,"wires":[["eb00ea97.0b332","550c2645.1dc0e"]]},{"id":"8b533b83.ade2f8","type":"server","z":"","name":"Home Assistant","addon":true}]

Is there something about the light where the action of turning on and setting attributes must happen at the same time? I assume because I've passed the variable it would work.

You are throwing screen shots at me and I am supposed to magically read them. I can't.

Coming out of the move stuff you should see something like:

{"cronplus":{"triggerTimestamp":1593571397117,"status":{"type":"static","modified":false,"isRunning":true,"count":8,"limit":0,"nextDescription":"in 6 minutes 42 seconds","nextDate":"2020-07-01T02:50:00.000Z","nextDateTZ":"Jul 01, 2020, 12:50:00 GMT+10","timeZone":"Australia/Sydney","serverTime":"2020-07-01T02:43:17.124Z","serverTimeZone":"Australia/Sydney","description":"Every 10 minutes"},"config":{"topic":"schedule1","name":"schedule1","payloadType":"json","payload":"{\"brightness_pct\":65}","limit":null,"expressionType":"cron","expression":"0 */10 * * * *"}},"topic":"schedule1","manualTrigger":true,"scheduledEvent":false,"payload":{},"_msgid":"a70425df.2aa768","brightness_pct":65}

Screen grab:

Screenshot from 2020-07-01 12-43-59

See the bottom line.

Now, before we both go nuts, let's establish if you have ever been able to adjust the brightness of the lights.

Yes/No.

If so, we need to work backwards from the node to what is needing to be injected into it to make it work.

Put a debug node after the light on? node. Full message and crop the message to make it as big and readable as possible.

What I am seeing, there is something else going on.
I think.

What?

Why?
(Puts head in hands and weeps.)

because msg.payload when when querying the light (light on node) resets the brightness_pct with the light's current brightness_pct. So for example, if cron says brightness_pct: 100 and the light's current brightness_pct value is 20, it changes cron's 100 value to 20.

I read that using flow persists that value across the flow through all nodes in the routine. Maybe I'm misunderstanding some things here.