17

I need to call this python script in NodeJs.

Read.py

#!/usr/bin/env python
# -*- coding: utf8 -*-

import RPi.GPIO as GPIO
import MFRC522
import signal

continue_reading = True

# Capture SIGINT for cleanup when the script is aborted
def end_read(signal,frame):
    global continue_reading
    print "Ctrl+C captured, ending read."
    continue_reading = False
    GPIO.cleanup()

# Hook the SIGINT
signal.signal(signal.SIGINT, end_read)

# Create an object of the class MFRC522
MIFAREReader = MFRC522.MFRC522()

# Welcome message
print "Welcome to the MFRC522 data read example"
print "Press Ctrl-C to stop."

# This loop keeps checking for chips. If one is near it will get the UID and authenticate
while continue_reading:

    # Scan for cards    
    (status,TagType) = MIFAREReader.MFRC522_Request(MIFAREReader.PICC_REQIDL)

    # If a card is found
    if status == MIFAREReader.MI_OK:
    # Get the UID of the card
    (status,uid) = MIFAREReader.MFRC522_Anticoll()

    # If we have the UID, continue
    if status == MIFAREReader.MI_OK:

        # Print UID
        print "Card read UID: "+str(uid[0])+","+str(uid[1])+","+str(uid[2])+","+str(uid[3])

        # This is the default key for authentication
        key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF]

        # Select the scanned tag
        MIFAREReader.MFRC522_SelectTag(uid)

        # Authenticate
        status = MIFAREReader.MFRC522_Auth(MIFAREReader.PICC_AUTHENT1A, 8, key, uid)

        # Check if authenticated
        if status == MIFAREReader.MI_OK:
            MIFAREReader.MFRC522_Read(8)
            MIFAREReader.MFRC522_StopCrypto1()
        else:
            print "Authentication error"

I used python-shell, here is the NodeJs code for that

Test.js

var PythonShell = require('python-shell');

var options = {
scriptPath: '/home/pi/gpio-admin/MFRC522-python/'
};
var pyshell = new PythonShell('Read.py',options);


pyshell.on('message', function (message) {

    console.log(message);
});

But when I ran this code I didn't see anything in Node side. I think problem occurs when python script comes to this level.

   (status,TagType) = MIFAREReader.MFRC522_Request(MIFAREReader.PICC_REQIDL)

Because I just ran with while loop which has only print statement then it works. After that I tried another way to achieve this. But I got same problem which I have with above.Here is another method

AltTest.js

var python = require('child_process').spawn(
 'python',
 // second argument is array of parameters, e.g.:
 ["/home/pi/gpio-admin/MFRC522-python/Read.py"]
 );
 var output = "";
 python.stdout.on('data', function(){ 

    output += data ;
    console.log(data);
});
 python.on('close', function(code){ 

   console.log("Here you are there...");
 });

Any help would be appreciated

GPrathap
  • 7,336
  • 7
  • 65
  • 83
  • 1
    PyNode package allows for calling Python functions and getting JS packages back. https://thecodinginterface.com/blog/bridging-nodejs-and-python-with-pynode/ – SciGuyMcQ Aug 22 '19 at 16:09
  • you can use following functions available in `child_process` nodejs package to execute any terminal commands: `exec`, `execSync`, `spawn`, `spawnSync` – Arjun Singh Jun 20 '21 at 17:25

6 Answers6

24

There are multiple ways of doing this.

  • first way is by doing npm install python-shell

and here's the code

var PythonShell = require('python-shell');
//you can use error handling to see if there are any errors
PythonShell.run('my_script.py', options, function (err, results) { 
//your code

you can send a message to python shell using pyshell.send('hello');

you can find the API reference here- https://github.com/extrabacon/python-shell

a few more references - https://www.npmjs.com/package/python

if you want to use service-oriented architecture - http://ianhinsdale.com/code/2013/12/08/communicating-between-nodejs-and-python/

Community
  • 1
  • 1
Tejus Prasad
  • 6,322
  • 7
  • 47
  • 75
  • Hello @Tejus Prasad, i want to use the 1st way. But my Node JS code is AWS Lambda function and my Python code save in a raspberry pi. My question is where i should Python shell. If in AWS how to do that? – TAMIM HAIDER May 09 '18 at 10:45
11
  • install python-shell :- npm install python-shell

    Index.js

    let {PythonShell} = require('python-shell')
    
    function runPy(){
        return new Promise(async function(resolve, reject){
              let options = {
              mode: 'text',
              pythonOptions: ['-u'],
              scriptPath: './test.py',//Path to your script
              args: [JSON.stringify({"name": ["xyz", "abc"], "age": ["28","26"]})]//Approach to send JSON as when I tried 'json' in mode I was getting error.
             };
    
              await PythonShell.run('test.py', options, function (err, results) {
              //On 'results' we get list of strings of all print done in your py scripts sequentially. 
              if (err) throw err;
              console.log('results: ');
              for(let i of results){
                    console.log(i, "---->", typeof i)
              }
          resolve(results[1])//I returned only JSON(Stringified) out of all string I got from py script
         });
       })
     } 
    
    function runMain(){
        return new Promise(async function(resolve, reject){
            let r =  await runPy()
            console.log(JSON.parse(JSON.stringify(r.toString())), "Done...!@")//Approach to parse string to JSON.
        })
     }
    
    runMain() //run main function
    

test.py

    import sys #You will get input from node in sys.argv(list)
    import json
    import pandas as pd #Import just to check if you dont have pandas module you can comment it or install pandas using pip install pandas

    def add_two(a, b):
        sum = 0
        for i in range(a, b):
            sum += i
        print(sum)  

    if __name__ == "__main__":
        print("Here...!")
        # print(sys.argv)
        j = json.loads(sys.argv[1]) #sys.argv[0] is filename
        print(j)
        add_two(20000, 5000000) #I make this function just to check 
    # So for all print done here you will get a list for all print in node, here-> console.log(i, "---->", typeof i)
6

Adopt a micro-services approach. Host the Python script as a HTTP REST API service. Consume the API from node.js - you do not need to integrate the technologies; it's not scalable.

Adam
  • 1,932
  • 2
  • 32
  • 57
  • 3
    sometime yes, it depends on the context – GPrathap Jun 19 '19 at 08:04
  • is this only true if the python output is serializable data? can JS code be used to signal python to update the API in some way, then access the updated API once done? – Ryan Skene Sep 02 '19 at 18:57
2

Well yoy can run python script from node.js in way like this. Use child_process.spawn (this is build in node.js library)

router.get('/', (req, res) => {
    const {spawn} = require('child_process');
    const path = require('path');
    function runScript(){
        return spawn('python', [
              path.join(__dirname, '../../scripts/myscript.py'),
              '-some_arg',
              '--another_arg',
        ]);
    }
    const subprocess = runScript();
    // print output of script
    subprocess.stdout.on('data', (data) => {
            console.log(`data:${data}`);
    });
    subprocess.stderr.on('data', (data) => {
           console.log(`error:${data}`);
    });
    subprocess.stderr.on('close', () => {
               console.log("Closed");
    });
    // const subprocess = runScript()
    res.set('Content-Type', 'text/plain');
    subprocess.stdout.pipe(res);
    subprocess.stderr.pipe(res);
});
Archil Labadze
  • 4,049
  • 4
  • 25
  • 42
0

If you like to avoid package managers / bloat, consider writing a shell script function to run the python, stream results locally to a txt file, collect and send on e.g. using http:

    const { exec } = require("child_process");
    
    function runShellScript(script, callback) {
        exec(script, (error, stdOut, stderr) => {
            
            var result = {status: true};
            
            if (error) {
                result.status = false;
                result.error = error.message;
            }
            if (stderr) {
                result.status = false;
                result.stderr = stderr;
            }
    
            if(stdOut){
                result.result = stdOut;
            }
            
    
            callback(result);
        });
    }
    
    runShellScript("python3 myscript.py >> output.txt", function(res) {
        console.log(res);
fs.readFileSync('output.txt');
    });
Randhir Rawatlal
  • 365
  • 1
  • 3
  • 13
0

My node js code

const { spawn }=require('child_process')

const child_python=spawn('python',['hello.py']);

child_python.stdout.on('data',(data)=> {
    console.log(`stdout :${data}`);
})

child_python.stderr.on('data',(data)=>{
    console.log(`stderr : ${data}`);
})

child_python.on('close',(code)=>{
    console.log(`child process exited with code ${code}`)
})

You can check this video to run your Python script from Nodejs It tells how to pass arguments also

Link https://www.youtube.com/watch?v=eN0nMuS8ur8

GPrathap
  • 7,336
  • 7
  • 65
  • 83