Change a value into a text file

Good evening, I need some help. I want to change a value in this file.

$ cat /etc/raspiwifi/raspiwifi.conf
ssid_prefix=SmartPhotons
auto_config=1
auto_config_delay=300
ssl_enabled=0
server_port=80
wpa_enabled=0
wpa_key=0

I read it, then split it into an array.


In this array at payload[2] , the value 300 should be changed with the value injected with one of the inject nodes (for example 1000).
Then the array should be rewritten with this new value to the same file.
Concretely if I send 1000, I want to get auto_config_delay=1000 instead of auto_config_delay=300.
image

I can see a function node, but my javascript skills have not evolved.
I've seen and read some examples but I just can't do it.
Thanks for advises.

Hello Jean,

I came up with this JS

let lines = msg.payload.split("\n")
node.warn(lines)

lines.forEach((line, index) => {
    if (line.startsWith("auto_config_delay")) {
        lines[index] = "auto_config_delay=" + msg.delay;
    }
})

msg.payload = lines.join("\n")

return msg;

[EDIT] Or by using regular expressions

msg.payload = msg.payload.replace(/(auto_config_delay=)(\d+)/, `$1${msg.delay}` )
return msg;

Test flow (... change the path in the File read node)

[{"id":"cbd871c9b60dd253","type":"inject","z":"54efb553244c241f","name":"1000","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"delay","v":"1000","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payloadType":"date","x":210,"y":780,"wires":[["3fe504116b9214f4"]]},{"id":"3fe504116b9214f4","type":"file in","z":"54efb553244c241f","name":"","filename":"c:\\users\\user\\desktop\\raspiwifi.conf","format":"utf8","chunk":false,"sendError":false,"encoding":"none","allProps":false,"x":480,"y":820,"wires":[["48d7e0382b2e1ae0","e4b016f58f37a2b4"]]},{"id":"10b68ecfef925297","type":"debug","z":"54efb553244c241f","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":870,"y":780,"wires":[]},{"id":"58171be59591a3a9","type":"inject","z":"54efb553244c241f","name":"3000","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"delay","v":"3000","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payloadType":"date","x":210,"y":880,"wires":[["3fe504116b9214f4"]]},{"id":"e4b016f58f37a2b4","type":"function","z":"54efb553244c241f","name":"forEach","func":"let lines = msg.payload.split(\"\\n\")\n//node.warn(lines)\n\nlines.forEach((line, index) => {\n    if (line.startsWith(\"auto_config_delay\")) {\n        lines[index] = \"auto_config_delay=\" + msg.delay;\n    }\n})\n\nmsg.payload = lines.join(\"\\n\")\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":720,"y":780,"wires":[["10b68ecfef925297"]]},{"id":"a04535d87d3024f8","type":"debug","z":"54efb553244c241f","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":870,"y":860,"wires":[]},{"id":"48d7e0382b2e1ae0","type":"function","z":"54efb553244c241f","name":"Regex","func":"msg.payload = msg.payload.replace(/(auto_config_delay=)(\\d+)/, `$1${msg.delay}` )\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":710,"y":860,"wires":[["a04535d87d3024f8"]]}]
1 Like

You could also use the "sed" command, which you could call from an exec node with relevant parameters.

1 Like

2 exciting solutions. The first one is well integrated and the other one opens new horizons. Which one to choose in this case. There are many possibilities to use this kind of need again. The linux command is obviously easier to understand at first but the first one is well integrated in NR.
I'm now on the night train to sleep. I will test tomorrow morning. A nice goal when I wake up.
Tanks to @UnborN and @ghayne for the solutions.Top !

I would probably go for the exec node and linux tools too.
Edit: changed this line to preformatted text so the backslash isn't removed. (or is it a forward slash?)
sed -i '/auto_config_delay/ s/[0-9]\+/555/' /etc/raspiwifi/raspiwifi.conf

An example of constructing the command in a function and passing it to exec:

[
    {
        "id": "610783a98cdbdc04",
        "type": "exec",
        "z": "a5c379cc01191edc",
        "command": "sed -i ",
        "addpay": "payload",
        "append": "",
        "useSpawn": "false",
        "timer": "",
        "winHide": false,
        "oldrc": false,
        "name": "",
        "x": 430,
        "y": 140,
        "wires": [
            [],
            [],
            []
        ]
    },
    {
        "id": "eec76c67df63ade2",
        "type": "function",
        "z": "a5c379cc01191edc",
        "name": "",
        "func": "let file = \"/home/pi/foo\";\nlet key = \"auto_config_delay\"\nlet newvalue = 555\nmsg.payload = \"'/\" + key + \"/ s/[0-9]\\\\+/\" + newvalue + \"/' \"+ file;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 280,
        "y": 140,
        "wires": [
            [
                "610783a98cdbdc04"
            ]
        ]
    },
    {
        "id": "20e3fcd9a22e8711",
        "type": "inject",
        "z": "a5c379cc01191edc",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 120,
        "y": 140,
        "wires": [
            [
                "eec76c67df63ade2"
            ]
        ]
    }
]

But since the file is in /etc you might need to use sudo.

2 Likes

:smiley:
So I tested the 2 solutions, the simplest being the Linux command.
It is clear that if I am under Windows it is not the right plan.
The JS proposal would be the best.
As pointed out, the user doesn't need to enter a password, so:

sudo visudo and insert at the section #includedir /etc/sudoers.d
pi ALL=(ALL) NOPASSWD:ALL in the section 

image

That's great, thank you gentlemen for your help. I will be able to implement this this morning in my hybrid inverter management software.
A software that I will present to you soon in the projects section.
It will be free because it is thanks to Node Red and this forum that I made it.

Edit: It should be possible to select several solutions :clap:

1 Like

I have to point out that that will let the default user running node red or any s/w you may install or gets onto your machine, run any system command, including, for a example, a command to erase the complete disc. You, might be better to use something like
pi ALL=NOPASSWD:/bin/sed
That only allows that command to be run without pwd.

1 Like

Yes @Colin you are perfectly right to point out this command, I will immediately change these rights. I didn't know you could be granular with this order.

But one could do plenty of damage with sed. eg sed 's/.*//' /etc/passwd

Better if possible to have the file owned by the Node-red user and in a directory below ~/.node-red

The file I have to change comes from this great software that allows to put the Pi in wifi A.P. mode.
So I don't have the hand on its location.

1 Like

You may be able to create a symbolic link from one location to the other - but yes for your situation given that it is a private network and hopefully not exposed to the internet then sed having elevated privileges is probably low on the list of concerns if intruders get in.

1 Like