How to enter a line after an exec node is started

Hello
I need to launch a command.
so, i use an exec node.
But in this command (it's gactions,and I need it to publish my Google Actions), when gactions is launched, it gives me an url.
Then, i must paste this url in a web browser, and the web site returns a king of token
Then, must return this token to the gactions application

when i do this behaviour in a terminal, there is no problem because I can copy the url, go to the web, enter the url, and then copy the token
hen, I just have to paste the token in the terminal, as gactions is still running and waits for this token

But I need to make the same opertaion with nodeRed.
With nodeRed, and the exec node, I can get and extract the url.
But I don't know how to paste the token.
Is this possible, and can you show me how?
Thanks a lot.

You can use an http request node to make the request for the token.

the exec node accepts parameters when you call it... after that it expects to run until it finishes.... If you need a command that listens for more typed input then you need the node-red-node-daemon node that starts - then accepts input as if you were typing it. Combine this with a request as Colin suggests to get the token and it may be doable.

Hello

Using the demain, when inserting the token (second phase) does the PID of the Exec change? I tried it with a simple exec node, and I got an rc=2 and the token input failed.

I suppose it is because the PID of the exec node changes each time a new value is input in the node. Am I right?

Envoyé de mon iPhone

with exec yes it will change as it's a new process each call. With Daemon, no as it's still running.

Alternatively, assuming gactions is a well behaved program, you should be able to exec something like
gactions [options] < path/to/some/file
to get it to read its input from a file.

1 Like

While it may sound crude, it is a really powerful method. I use it to read Bluetooth LE beacons. I exec a command script to poll for the beacons and print the results to a file which node-red parses and takes action upon. Since it only needs to happen three or four times per minute it was an effective and easy to test/debug solution.

Hello
Unfortunately, this is not possible
I alreday pass some parameteres to gaction command line, but then, gactions return me an url
Then, i must use this url to connect (I must type a login/password) and then the web site gives me a token
Then, i must give this token to gactions.

So I also tried to use the daemon, but, that alos doens't work.
Can you tell me exactly how to use this deamon node. The documentation is not so clear.

attached you will find my flow.
So, in the daemon node, there is the original command and the parameters for this command.
Then, if the inject node (with a string), there is the token.
Please notice that i must inject the token only after gactions has given me the url to connect to.
This url and the token change each time they are used (I think)

[{"id":"3db3a684.57f32a","type":"daemon","z":"2919047c.10fe3c","name":"","command":"/opt/plcnext/CCN/gactions","args":"test -preview_mins 9999999 -action_package /opt/plcnext/CCN/action1.json -project my-test-app-xxxxxx","autorun":false,"cr":false,"redo":false,"op":"string","closer":"SIGTERM","x":630,"y":1460,"wires":[["bd31ca53.ecf318","d744cbbb.434a58"],["d744cbbb.434a58"],["d744cbbb.434a58"]]},{"id":"5367c66f.aa0e28","type":"inject","z":"2919047c.10fe3c","name":"Inject token","topic":"","payload":"4/bwH3SsTwHRjnZZ4m6Qzw7_fwrxpVuq-LeE_o6mMdWMO-OXXXXXXXXXX","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":350,"y":1480,"wires":[["3db3a684.57f32a"]]},{"id":"b622292.032e5d8","type":"inject","z":"2919047c.10fe3c","name":"Start command","topic":"","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":340,"y":1420,"wires":[["3db3a684.57f32a"]]}]
I hope that i clear enough

Hello
Unfortunately, this is not possible
I alreday pass some parameteres to gaction command line, but then, gactions return me an url
Then, i must use this url to connect (I must type a login/password) and then the web site gives me a token
Then, i must give this token to gactions.

So I also tried to use the daemon, but, that alos doens't work.
Can you tell me exactly how to use this deamon node. The documentation is not so clear.

attached you will find my flow.
So, in the daemon node, there is the original command and the parameters for this command.
Then, if the inject node (with a string), there is the token.
Please notice that i must inject the token only after gactions has given me the url to connect to.
This url and the token change each time they are used (I think)

[{"id":"3db3a684.57f32a","type":"daemon","z":"2919047c.10fe3c","name":"","command":"/opt/plcnext/CCN/gactions","args":"test -preview_mins 9999999 -action_package /opt/plcnext/CCN/action1.json -project my-test-app-xxxxxx","autorun":false,"cr":false,"redo":false,"op":"string","closer":"SIGTERM","x":630,"y":1460,"wires":[["bd31ca53.ecf318","d744cbbb.434a58"],["d744cbbb.434a58"],["d744cbbb.434a58"]]},{"id":"5367c66f.aa0e28","type":"inject","z":"2919047c.10fe3c","name":"Inject token","topic":"","payload":"4/bwH3SsTwHRjnZZ4m6Qzw7_fwrxpVuq-LeE_o6mMdWMO-OXXXXXXXXXX","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":350,"y":1480,"wires":[["3db3a684.57f32a"]]},{"id":"b622292.032e5d8","type":"inject","z":"2919047c.10fe3c","name":"Start command","topic":"","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":340,"y":1420,"wires":[["3db3a684.57f32a"]]}]
I hope that is clear enough

Hello.
I have discored a parameter in the gaction command line wich permits to output all the intermediate responses : --verbose

so, here is the responses of the command sent with the 'terminal'.

admin@axcf2152:~$ /opt/plcnext/gactions --verbose update --action_package /opt/plcnext/action.txt --project my-test-app-xxxxx
Checking for updates...
Successfully fetched update metadata
Error: No compatible updates found for your OS.
Unable to self-update. Please update manually by visiting: https://developers.google.com/actions/tools/gactions-cli
POST /v2/agents/my-test-app-xxxxx:batchUpdateAllDraftActionPackages HTTP/1.1
Host: actions.googleapis.com
User-Agent: Gactions-CLI/2.1.3 (linux; arm; stable/dff629ae63fd0b047d19687b79274524569714e6)
Content-Length: 464
Content-Type: application/json
Accept-Encoding: gzip

{"localizedActionPackages":{"en":{"actions":[{"description":"Default Welcome Intent","fulfillment":{"conversationName             ":"nodeRedApp"},"intent":{"name":"actions.intent.MAIN","trigger":{"queryPatterns":["talk to Node Red"]}},"name":"MAIN             "}],"conversations":{"nodeRedApp":{"fulfillmentApiVersion":2,"in_dialog_intents":[{"name":"actions.intent.CANCEL"}],"             name":"nodeRedApp","url":"https://your.server.address:8081/"}},"locale":"en"}},"name":"agents/my-test-app-xxxxx"}
Reading credentials from: creds.data
Successfully updated the app for the Assistant
Your app for the Assistant for project my-test-app-xxxxx was successfully updated with your actions. Visit the Action             s on Google console to finish registering your app and submit it for review at https://console.actions.google.com/project/my-test-app-xxxxx/overview

And now, here is the result of the command sent by node-red

24/06/2019 à 16:18:13node: 6be2d2f9.45c88c
msg : Object
object
_msgid: "6f247be6.4f9444"
topic: ""
payload: string
Checking for updates...
24/06/2019 à 16:18:15node: 6be2d2f9.45c88c
msg : Object
object
_msgid: "6f247be6.4f9444"
topic: ""
payload: string
Successfully fetched update metadata
24/06/2019 à 16:18:15node: 6be2d2f9.45c88c
msg : Object
object
_msgid: "6f247be6.4f9444"
topic: ""
payload: string
Error: No compatible updates found for your OS.
Unable to self-update. Please update manually by visiting: https://developers.google.com/actions/tools/gactions-cli
24/06/2019 à 16:18:15node: 6be2d2f9.45c88c
msg : Object
object
_msgid: "6f247be6.4f9444"
topic: ""
payload: string
Pushing the app for the Assistant for testing...
24/06/2019 à 16:18:15node: 6be2d2f9.45c88c
msg : Object
object
_msgid: "6f247be6.4f9444"
topic: ""
payload: string
POST /v2/users/me/previews/my-test-app-xxxxx:batchUpdatePreviewFromAgentDraft HTTP/1.1
Host: actions.googleapis.com
User-Agent: Gactions-CLI/2.1.3 (linux; arm; stable/dff629ae63fd0b047d19687b79274524569714e6)
Content-Length: 545
Content-Type: application/json
Accept-Encoding: gzip

{"localizedPreviewActionPackages":{"en":{"actionPackage":{"actions":[{"description":"Default Welcome Intent","fulfillment":{"conversationName":"nodeRedApp"},"intent":{"name":"actions.intent.MAIN","trigger":{"queryPatterns":["talk to Node Red"]}},"name":"MAIN"}],"conversations":{"nodeRedApp":{"fulfillmentApiVersion":2,"in_dialog_intents":[{"name":"actions.intent.CANCEL"}],"name":"nodeRedApp","url":"https://your.server.address:8081/"}},"locale":"en"},"name":"users/me/previews/my-test-app-xxxxx"}},"name":"users/me/previews/my-test-app-xxxxx"}
24/06/2019 à 16:18:15node: 6be2d2f9.45c88c
msg : Object
object
_msgid: "6f247be6.4f9444"
topic: ""
payload: string
Reading credentials from: creds.data
Gactions needs access to your Google account. Please copy & paste the URL below into a web browser and follow the instructions there. Then copy and paste the authorization code from the browser back here.
Visit this URL: 
 https://accounts.google.com/o/oauth2/auth?access_type=offline&client_id=237807841406-o6vu1tjkq8oqjub8jilj6vuc396e2d0c.apps.googleusercontent.com&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&response_type=code&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Factions.builder&state=state 
Enter authorization code:

So, even if the command sent by the terminal and node-red are copy/pasted (so, they should give the same result), the final result is different.
First, you can see that the POST is quiet different.

POST /v2/agents/my-test-app-xxxxx:batchUpdateAllDraftActionPackages HTTP/1.1
<>
POST /v2/users/me/previews/my-test-app-xxxxx:batchUpdatePreviewFromAgentDraft HTTP/1.1

And then, at the end, the terminal command seems to have a correct access to the file creds.data, while the exec node command seems to not be able to access to this file, and so, requests for a new token
Of course, the creds.data file is ownaed by the same user as node-red (admin), and the file is selected 'r' everywhere.
So, can anybody help me to make node-red exec node react in the same way as the terminal?

Note that I haven't tested this from a node-red environment yet, but I'm successfully using scripts built on top of /usr/bin/expect to interact with prompts on the terminal. I'm using this with Ansible scripts in other projects, for example one where I encrypt some potentially sensitive files before committing them with git, so my prototypes are stored on (private) git repos too.
Using expect allows you to search the prompt for known text, and send text as if it was entered by a user. Here's a basic tutorial if you would like to know more about it.

However, for your situation that might not be the preferred solution. Looking at the response it requires you to enter an authorisation code. For this, Google uses OAuth2. OAuth2 is a system where you log in to google with your normal account, you then have to verify that you want to give this application, in this case gactions access to your account to complete actions on its own, without user interaction. This is done by going to a certain url that the application generates for you, with a specific client id and some basic information. If you are logged in to google at that moment it will use that account to specify that yes you want to give gactions access to your account, after a manual [read: in the browser] verification that you want to give access. It will then come up with an authorisation code, that will have to be entered into the gactions prompt again. It is then able to send that token back to google again, and get in return a so called consumer key, and a consumer secret. These last 2 values can then be used again, until you tell google to cancel the validity of them, to connect through gactions.

My suggestion would be to run the gactions command with these actions manually, so it can configure these two keys, and figure out where you have to store them, either in a configuration file for gactions, or perhaps as payload on the exec-node. Doing that means you won't have to mess around with entering text into the running program, nor having to mess with /usr/bin/expect.

Thanks for your help.
I will try to understand how that works.
Nevertheless, that doesn't answer the real question I asked in the prevous post :slight_smile:
Why don't the exactly same command launched in the terminal or in an exec node don't return the same things.
I ask this to the specialists/develloppers of node-red.
Normally, is the rights are correct, and the files accessible, the same command should return the same things... no?

Exactly. What happens in your situation is that running a command on the terminal does something else when running it from the exec note. Have you checked the requirements of gactions before. Like, does it need environment variables to be set that point to locations of configuration files, is it running under the same user/group as node-red? Is it running from the same working directory as node-red? Whether or not an environment variable is set and available to the environment the command is executed in can already make the difference between the command working or not.

From what I can find about gactions, the credentials for the oauth 2.0 are stored in this file creds.data. Where is that file located on your system? It might be the case that the node-red exec node can't find that file. I'm not using gactions myself, and almost obviously it's not documented where that file is usually located. If it's stored under a dot directory in the home folder, node-red should be able to find it if it runs under the same user. If it is instead stored in the working directory, that might be different from where node-red runs it.

I'm afraid that to answer what happens/why it happens you need to answer those questions first. I saw people on stackoverflow and on the github issue tracker of another project mention that switching to a different connection, for example a different wifi network, then delete the creds.data file and authenticate again through the regular command so a new creds.data gets created. Here's one of those sets of instructions. Try starting there, then see where creds.data is located, and if node-red has access to it because of the working directory and (relative) paths to it.

Hello

  • Yes, I'm sure the node-red has got an access to creds.data, because i can open it simply with the file Open node
  • I followed the post on stackoverflow, but I still have the same behaviour. As long as the command is entered in a terminal, gactions requests a token if the creds.data doesn't exists. but if it exists, it connect directly. This means that everything works fine in the terminal.
    But when the command is not launched in the terminal, even if the creds.data already exists, it is ignored.
    you tell me to check the requirements of gactions. but where can i find them?
    And I have put gactions in the same directory than where creds.data is written.
    In Linux, is there any directory wich is accessible by everyone, with no restriction? Maybe i should be able to put the files there...

I’m going to set up gactions myself somewhere in the next days and do a deep inspect of the exec source to see if I can find differences. It might take even longer before I can get back to you, I had a physically hard day today and went far beyond my pain limits, I’m expecting a recovery of about a week but in the meantime I should be able to set up a sample. I’m able to set up a pi from my bed, which I might actually do if I get too bored :slight_smile:

Thanks a lot for your support

Envoyé de mon iPhone

One more hint : please notice that the problem only occurs when node-red is strated automatically (with a file in init.d)
when it is launched with a simple 'node-red' in a terminal, that works perfectly.

And everything makes exactly the kind of sense that I thought it would beforehand. Key word here is “working directory”, I’m going to work it out in a longer post probably tomorrow or Wednesday.

I need a bit more information until I can verify it is indeed related to the working directory.

@mike67 could you please post the script you use to start node-red, as in, the file in /etc/init.d/ that is called to start it?

Couple questions:
the flow you posted a week and a half ago uses the /opt/plcnext/CCN/gactions as path to the gactions-cli application. Google's docs mention that the creds.data file is supposed to be present in the same directory as the executable gactions. The next post with the terminal output uses /opt/plcnext/gactions as base command, with the action package in the same folder (as opposed to inside a CCN subfolder before).

  • Can you check if both /opt/plcnext/CCN/ as well as /opt/plcnext/ have a creds.data file?
  • Is the path to the gactions script correct?

Hello afelix
Yes, in my post it can be a little bit confusing, because I did not write them in the same moment. so I made several tests in several situations.

But yes, I'm sure that gactions and creds.data are in the same directory.
No matter if it is in /opt/plcnext/ or /opt/plcnext/CCN/ : same result.
Here is the init.d file :slight_smile:

#! /bin/sh
### BEGIN INIT INFO
# Provides:          node-red
# Required-Start:    $local_fs $remote_fs $network
# Required-Stop:     $local_fs $remote_fs $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 6
# Short-Description: Start or stop the node-red server
### END INIT INFO

# Script to start node-red with PLCnext from Phoenix Contact using init.d 
# Execute these commands:
# sudo chmod 755 start_nodered
# sudo update-rc.d start_nodered defaults 99

USER=admin

USER_DIR='/opt/plcnext/.node-red'

PATH=/bin:/usr/bin:/usr/sbin:/opt/plcnext/apps/60002172000051/opt/node-v10.15.3-linux-armv7l/bin:/opt/plcnext

NAME=node-red
DAEMON=/opt/plcnext/appshome/data/60002172000051/bin/node-red
OPTIONS="--max-old-space-size=128"

if [ -n "$USER_DIR" ];  then
	OPTIONS="$OPTIONS --userDir=$USER_DIR"
fi

LOG='/opt/plcnext/node-red.log'

PIDFILE=/var/run/node-red.pid

. /etc/init.d/functions

start_daemon () {
        start-stop-daemon --start --background \
        --chuid $USER --name $NAME \
                $START_STOP_OPTIONS --make-pidfile --pidfile $PIDFILE \
        --startas /bin/sh -- -c "$DAEMON $OPTIONS >> $LOG 2>&1"
	echo "Logging to "$LOG
}

case "$1" in
        start)
             echo "Starting daemon" "$NAME"
             start_daemon
        ;;
        stop)
             echo "Stopping daemon" "$NAME"
             start-stop-daemon --stop \
             --user $USER \
             --name $NAME --pidfile $PIDFILE --retry 30 \
             --oknodo
        ;;
        restart)
	     $0 stop
	     sleep 5
	     $0 start
	;;
	
	status)
             status "$DAEMON" "$NAME"
             exit $?
        ;;

        *)
             echo "Usage: $0 {start|stop|restart}"
             exit 1
esac
exit 0

I already tried with different value for the PATH, including or not /opt/plcnext/(CCN)/, it's always the same result.
As you saw, I wrote in details what the command line returns and what the exec node returns in the step 9 of this post
But the returns are identical no matter in I put the files in /CCN or not

no matter if gActions and the creds.data are in /opt/plcnext/ or /opt/plcnext/CCN/ : with the exec node, it seems that the creds.data is not seen/accessible.
But I checked with the command ls -l, who was the owner of the files : admin, and gaction is executable, and creds.data has got all the rw option true.

Many thanks to spend your time to support me.