Source Code Line Wrap

Sorry for asking JS related matters again. Up on now, I use the NodeRed editor. The features are not thrilling, but it is doing its job for simple node related code snippets. Mainly, my concern is to keep all source lines short an simple. Sometimes there are non trivial lines. Longer JSONS might be distributed to several lines as the members are inside curly braces {}. Strings are inside "hyphens" and might line wrap using the C-style backslash. For other source code I failed.

msg.out =   (Kp * error) + (Ki * msg.errsum) + Kd * (error - msg.errold);          // This PID Regulator is a long line although we use only short symbol names and almost not comment behind.

I tried to wrap the formula in three lines, one for each term. Although the formula code is not interrupted by any comments, the JIT compiler seems not executing everything collected between cr and limit colon; There are also no syntax error hints while editing or execution. It simply does not work.

msg.out =   (Kp * error) + 
            (Ki * msg.errsum) + 
             Kd * (error - msg.errold);          // PID Regulator

How is the trick to wrap lines for JS?

The trick is to make valid syntax :wink:

BTW, what you have is valid syntax (assuming Kp, error, Ki and Kd are defined somewhere):

No errors:

Errors when syntax is incorrect

In what way? Have you verified input msg contains .errsum and .errold?

Try adding some node.warns in your code and they will give you interal runtime values:

node.warn({
    _info: "Calculating out from these values",
    Kp,
    Ki,
    Kd,
    error,
    "msg.errsum": msg.errsum,
    "msg.errold": msg.errold,
});

msg.out = (Kp * error) +
          (Ki * msg.errsum) +
           Kd * (error - msg.errold);

node.warn(`New value for msg.out = ${msg.out}`)

Perhaps

msg.out  = (Kp * error) 
msg.out += (Ki * msg.errsum)
msg.out += Kd * (error - msg.errold)

Ok, there seems nothing for line wrap like in C. Node works like expected, with formula inside one line but does not with same formula inside three lines. Round braces are optional, only to recognize the terms for humans. Error seems predefined anywhere accidently but I use error. Here is complete flow within the const Kp, Ki, Kd.

[{"id":"eb2930e347521e17","type":"function","z":"a9b943e599c9cad0","name":"PID","func":"//msg.out = Manipulated Value is grid setpoint, Stellgroesse ist die Netzeinspeisung\n//flow.sv = Setpoint Value, Sollwert ist gewuenschter SOC Batterie Ladezustand\n//flow.pv = Process Value, Ist wert ist der aktuelle SOC Batterie Ladezustand\n\nconst Kp = 300;                                     // proportional parameter\nconst Ki = 100;                                     // integraion parameter\nconst Kd = 1;                                       // differential parameter\n\nlet error = (flow.get(\"sv\") - flow.get(\"pv\"))*-1;   // difference between setpoint value and process value\nmsg.errsum += error;                                // integral difference\n\nflow.set (\"ERRSUM\" , msg.errsum);\n\nmsg.out =   (Kp * error) + (Ki * msg.errsum) + Kd * (error - msg.errold); // PID Regulator\nmsg.errold = error;                             // save Error for next cycle\n\nif (msg.out > 33000) msg.out = 33000;           // top saturation\nif (msg.out < 300) msg.out = 300;               // bottom saturation\nmsg.out = Math.round(msg.out *-1);              // small SOC requires high negative grid power\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":850,"y":260,"wires":[["f42587e7a286daf9","a7527499cb68a56e"]]},{"id":"a7527499cb68a56e","type":"delay","z":"a9b943e599c9cad0","name":"PT1","pauseType":"delay","timeout":"250","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":710,"y":260,"wires":[["eb2930e347521e17"]]},{"id":"b298fdb9d94a8061","type":"inject","z":"a9b943e599c9cad0","name":"Reset","props":[{"p":"out","v":"3","vt":"num"},{"p":"errsum","v":"4","vt":"num"},{"p":"errold","v":"5","vt":"num"}],"repeat":"","crontab":"","once":true,"onceDelay":"0","topic":"","x":710,"y":200,"wires":[["eb2930e347521e17"]]},{"id":"f42587e7a286daf9","type":"debug","z":"a9b943e599c9cad0","name":"debug 1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"out","targetType":"msg","statusVal":"","statusType":"auto","x":1000,"y":260,"wires":[]}]

Please post a failing flow that we can test. The one you posted expects flow context to be setup and does not have any wrapped lines.

Here is the version with the wrapped text. It does something else than the non wrapped version.
Obviosly JS does not allow this. There is no sense to run the nodes without the flow global sv and pv signals provided by hardware.

[{"id":"7140d8687e7864a9","type":"function","z":"a9b943e599c9cad0","name":"PID","func":"//msg.out = Manipulated Value is grid setpoint, Stellgroesse ist die Netzeinspeisung\n//flow.sv = Setpoint Value, Sollwert ist gewuenschter SOC Batterie Ladezustand\n//flow.pv = Process Value, Ist wert ist der aktuelle SOC Batterie Ladezustand\n\nconst Kp = 300;                                     // proportional parameter\nconst Ki = 100;                                     // integraion parameter\nconst Kd = 1;                                       // differential parameter\n\nlet error = (flow.get(\"sv\") - flow.get(\"pv\"))*-1;   // difference between setpoint value and process value\nmsg.errsum += error;                                // integral difference\n\nflow.set (\"ERRSUM\" , msg.errsum);\n\nmsg.out =   (Kp * error) + \n            (Ki * msg.errsum) +\n             Kd * (error - msg.errold); // PID Regulator\n\nmsg.errold = error;                             // save Error for next cycle\n\nif (msg.out > 33000) msg.out = 33000;           // top saturation\nif (msg.out < 300) msg.out = 300;               // bottom saturation\nmsg.out = Math.round(msg.out *-1);              // small SOC requires high negative grid power\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":930,"y":420,"wires":[["293e3cf665d9a44d","649946cc3381c822"]]},{"id":"649946cc3381c822","type":"delay","z":"a9b943e599c9cad0","name":"PT1","pauseType":"delay","timeout":"250","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":790,"y":420,"wires":[["7140d8687e7864a9"]]},{"id":"95be46f8dd212fd0","type":"inject","z":"a9b943e599c9cad0","name":"Reset","props":[{"p":"out","v":"3","vt":"num"},{"p":"errsum","v":"4","vt":"num"},{"p":"errold","v":"5","vt":"num"}],"repeat":"","crontab":"","once":true,"onceDelay":"0","topic":"","x":790,"y":360,"wires":[["7140d8687e7864a9"]]},{"id":"293e3cf665d9a44d","type":"debug","z":"a9b943e599c9cad0","name":"debug 1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"out","targetType":"msg","statusVal":"","statusType":"auto","x":1080,"y":420,"wires":[]}]

The sense is that you must provide an example flow that shows that the line wrap is failing. Add a Change node that sets the flow variables to appropriate values so that we can test it, and tell us what you see in the debug node and what it should be. We don't know what are appropriate values.

Still trying to test this, I'm not getting valid output at the moment.

One thing to note is that "standard" JS formatting requires the +, -, =, etc at the START of a continuation line not at the end of the previous line. Don't think this actually impacts execution though, trying to test now.

Also, your examples appear to be auto-starting infinite loops which is not friendly to those of us trying to help.

That is odd, I have always put it at the end of the first line so that it is obvious that there is a continuation.

1 Like

Yes, me too, by instinct really, but eslint in full VS Code is telling me otherwise when loaded with standard js settings.

1 Like

We need the sv and pv example values please. It is generally best practice to to the flow.get's on a separate line with a fallback default using ??.

Sorry to bother you with everything around. This post started with only one line of code. I am going to make a test project with valid inputs and output visualisation to visualize what the PID node is doing. This will take a while as the code works in one line and I am proceeding with the project next few hours. After this, I am going to strip the PID node to insert in a working example what does not depend from hardware. Thanks.

I'm a bit confused now (not hard after a long day), but both examples seem to work - though I've disconnected the annoying loop.

All we need is an inject node, a Function node and a debug node showing the problem.

1 Like