user3185748
user3185748

Reputation: 2538

How do I call a Python function from Node.js?

I'm working on making a Homebridge plugin for a project. Homebridge is a Node.js server which I have running on a Raspberry Pi which emulates an Apple HomeKit Bridge.

Using this link, I was able to execute Python code from the following Node.js code:

var Service, Characteristic;

var spawn = require('child_process').spawn;
var py = spawn('python', ['/home/pi/Desktop/RFbulb/nRF24L01PLUS.py']);
var data = [10,10,10];
var dataString = '';

var RFstatus = true;

module.exports = function(homebridge) {
    Service = homebridge.hap.Service;
    Characteristic = homebridge.hap.Characteristic;

    homebridge.registerAccessory("homebridge-RFbulb", "RFbulb", RFbulbAccessory);
}

function RFbulbAccessory(log, config) {
    this.log = log;
    this.config = config;
    this.name = config["name"];
    this.address = config["address"];

    this.service = new Service.Lightbulb(this.name);
    this.service
        .getCharacteristic(Characteristic.On)
        .on('get', this.getOn.bind(this))
        .on('set', this.setOn.bind(this));
}

RFbulbAccessory.prototype.setOn = function(on, callback) { // This is the function throwing the error
    var state = on ? "on": "off";
    if (state == "on") {
        data = [1,parseInt(this.address, 10),100];
        dataString = '';
        py.stdout.on('data', function(data) {
            dataString += data.toString();
        });
        py.stdout.on('end', function() {
            console.log(dataString);
        });
        py.stdin.write(JSON.stringify(data));
        py.stdin.end();
        RFstatus = true;
    }
    callback(null);
}

RFbulbAccessory.prototype.getServices = function() {
    return [this.service];
}

Interestingly enough, when I activate the setOn function the first time (for example, to turn the device on) it works fine, but when I activate the setOn function a second time (to turn the device off) I get the following errors and the server exits:

events.js:141
      throw er; // Unhandled 'error' event
      ^

Error: write after end
    at writeAfterEnd (_stream_writable.js:166:12)
    at Socket.Writable.write (_stream_writable.js:211:5)
    at Socket.write (net.js:642:40)
    at RFbulbAccessory.setOn (/usr/lib/node_modules/homebridge-RFbulb/index.js:47:12)
    at emitThree (events.js:97:13)
    at emit (events.js:175:7)
    at Characteristic.setValue (/usr/lib/node_modules/homebridge/node_modules/hap-nodejs/lib/Characteristic.js:155:10)
    at Bridge.<anonymous> (/usr/lib/node_modules/homebridge/node_modules/hap-nodejs/lib/Accessory.js:710:22)
    at Array.forEach (native)
    at Bridge.Accessory._handleSetCharacteristics (/usr/lib/node_modules/homebridge/node_modules/hap-nodejs/lib/Accessory.js:655:8)

What could be causing this error? Especially since the function appears to work fine for a single use.

Upvotes: 0

Views: 2040

Answers (1)

Mike Cluck
Mike Cluck

Reputation: 32511

You're getting that error because you're closing the input stream:

py.stdin.end();

After a stream has been closed, you can no longer write to it like you are here:

py.stdin.write(JSON.stringify(data));

If the Python program you're running accepts multiple commands over STDIN then simply remove the py.stdin.end() line.

However, it's likely that your Python program runs once then completes. If that's the case, you will need to respawn the process every time you want the program to run.

if (state === "on") {
    py = spawn('python', ['/home/pi/Desktop/RFbulb/nRF24L01PLUS.py']);
    ...
}

Upvotes: 1

Related Questions