0

I am working on an Embedded application which uses some precompiled binaries from the CANBOAT repository.

There are two binaries available for usage:

  1. actisense-serial
  2. analyzer

In a shell, one requires to execute actisense -r /dev/ttyUSB0 | analyzer -json to obtain information from a device connected to the USB port. The above mentioned command dumps JSON information to STDOUT.

Sample output:

{"timestamp":"2018-08-30T16:27:23.629Z","prio":2,"src":3,"dst":255,"pgn":128259,"description":"Speed","fields":{"SID":106,"Speed Water Referenced Type":"Paddle wheel"}}

{"timestamp":"2018-08-30T16:27:23.629Z","prio":2,"src":6,"dst":255,"pgn":128259,"description":"Speed","fields":{"SID":106,"Speed Water Referenced Type":"Paddle wheel"}}

The above mentioned values keep being displayed on the STDOUT.

I wish to use the above mentioned shell commands in a python script to obtain the JSON values, to parse them and save them to a database.

Initially I want to start out with subprocess.check_output.

I tried:

import subprocess

if __name_ == "__main__":

     while True:
         value = subprocess.check_output(['actisense-serial -r /ttyUSB0',
                                           '|',
                                           'analyzer -json'],
                                        shell=True)
         print(value)

But there is no output available. I am not sure how do I route the output of the STDOUT to the check_output.

How do I achieve this, where the continuous JSON information coming from the shell commands can be parsed and used further in the application?

4
  • I'd start by fixing the command so it actually works before worrying about streaming the output. shell=True doesn't work the way you expect here -- only the first list element is parsed as a shell script. Commented Aug 30, 2018 at 17:35
  • 1
    ['''actisense-serial -r "$1" | analyzer -json''', '_', "/ttyUSB0"] is an example of an argument list that would work with shell=True (the first list entry is the shell script to run, the second is the $0 that script is run with, the third is the $1 it's run with). Commented Aug 30, 2018 at 17:44
  • ...actual continuous streaming is a separate issue, and one we already have Q&A for. Commented Aug 30, 2018 at 17:44
  • 1
    stackoverflow.com/questions/46592284/… is a Windows-y answer to the directly-asked question; stackoverflow.com/questions/2715847/… is a more generic one. Commented Aug 30, 2018 at 17:51

1 Answer 1

1

You can pass in a pipe to stdout and stderr when you're using Popen like this:

actisense_proc = subprocess.Popen(['actisense-serial', '-r', '/ttyUSB0'], 
                                  stdout=subprocess.PIPE)
analyzer_proc = subprocess.Popen(['analyzer', '-json'], stdin=actisense_proc.stdout,
                                 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
while analyzer_proc.poll() is None:
    print(analyzer_proc.stdout.readline())

Also note that instead of using shell=True, I used two Popen calls and piped the stdout of the first into the stdin of the second.

EDIT: Missed the streaming part of the question. Updated so it will constantly read from the stdout pipe. This will run until the subprocesses terminate though.

Sign up to request clarification or add additional context in comments.

3 Comments

This addresses a different problem in the OP's code, but I'm not convinced that it's relevant to the question that's directly asked; communicate() is collecting content all at once rather than reading a continuous stream, which is what the question specifically asks for.
...for the question answered here, stackoverflow.com/questions/10405515/… is a duplicate
@CharlesDuffy Yikes, totally missed that streaming part.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.