Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js's python child script outputting on finish, not real time

I am new to node.js and socket.io and I am trying to write a small server that will update a webpage based on python output.

Eventually this will be used for a temperature sensor so for now I have a dummy script which prints temperature values every few seconds:

Thermostat.py

import random, time
for x in range(10):
    print(str(random.randint(23,28))+" C")
    time.sleep(random.uniform(0.4,5))

Here's a cut down version of the server:

Index.js

var sys   = require('sys'), 
    spawn = require('child_process').spawn, 
    thermostat = spawn('python', ["thermostat.py"]),
    app = require('express')(),
    http = require('http').Server(app),
    io = require('socket.io')(http);

thermostat.stdout.on('data', function (output) { 
    var temp = String(output);
    console.log(temp);
    io.sockets.emit('temp-update', { data: temp});
}); 

app.get('/', function(req, res){
    res.sendFile(__dirname + '/index.html');
    });

And finally the web page:

Index.html

<!doctype html>
<html>
    <head>
        <title>Live temperature</title>
        <link rel="stylesheet" type="text/css" href="styles.css">
    </head>
    <body>
    <div id="liveTemp">Loading...</div>

    <script src="http://code.jquery.com/jquery-1.11.1.js"></script>
    <script src="/socket.io/socket.io.js"></script>
    <script>
        var socket = io();
        socket.on('temp-update', function (msg) {
        $('#liveTemp').html(msg.data)
    });
    </script>

    </body>
</html>

The problem is nodejs seems to recieve all of the temperature values at once, and instead of getting 10 temperature values at random intervals, I get all of the values in one long string after the script has finished:

lots of temp valuesconsole output

like image 224
mbdavis Avatar asked Sep 01 '14 14:09

mbdavis


1 Answers

You need to disable output buffering in python. This can be done many different ways, including:

  • Setting the PYTHONUNBUFFERED environment variable
  • Passing the -u switch to the python executable
  • Calling sys.stdout.flush() after each write (or print() in your case) to stdout
  • For Python 3.3+ you can pass flush=true to print(): print('Hello World!', flush=True)

Additionally, in your node code, (even though you have a sleep in your python code and you are now flushing stdout) you really should not assume that output in your 'data' handler for thermostat.stdout is always going to be just one line.

like image 122
mscdex Avatar answered Nov 01 '22 17:11

mscdex