¿ªÔÆÌåÓý

Locked Problem calling one script from another #scripting


 

Could someone please advise why the following python scripts work together in RPi Thonny, but not from within PanelPro.

The script for the initiating programme, testsend.py :

import subprocess
import sys
x=678
print(x)
subprocess.run(["python3","testreceive.py", str(x)])


and this is the script for the receiving programme, testreceive.py "

import serial
import sys
if len(sys.argv)>1:
? ? y= int(sys.argv[1])
? ? print(1+ y)
else:
? ? print("no argument received")


Thank you in anticipation
Toni


 

The ¡°subprocess.run¡± line is meant to run sometime as, well, a subprocess. This is attempting to run the 2nd script outside JMRI. It¡¯s not set up for that.

If your goal is to run a separate script file, you can use ¡°execfile(..)¡± to do that.



More generally, JMRI¡¯s scripting uses a Python derivative called Jython. The good news is that Jython works with underlying Java code well. The bad news is that it¡¯s Python 2.5, i.e. old, and doesn¡¯t have many of the nice Python packages that can do cool things.

There¡¯s been some limited work on using native Python3 for scripting, but that¡¯s really not ready for general use yet.

Bob

On Dec 10, 2023, at 11:27?PM, Toni Mury <toni@...> wrote:

Could someone please advise why the following python scripts work together in RPi Thonny, but not from within PanelPro.

The script for the initiating programme, testsend.py :

import subprocess
import sys
x=678
print(x)
subprocess.run(["python3","testreceive.py", str(x)])


and this is the script for the receiving programme, testreceive.py "

import serial
import sys
if len(sys.argv)>1:
y= int(sys.argv[1])
print(1+ y)
else:
print("no argument received")


Thank you in anticipation
Toni

¡ª
Bob Jacobsen
rgj1927@...


 

Thanks for the prompt reply Bob. I'll play with it today and let you know how I go.
Toni


 

Hi Bob

I have successfully modified my codes as you suggested however I need the receiving programme to include a serial connection to drive a stepper motor. If I comment out the serial code part as shown below all works well but if I include those lines it does not work.

?

Does JMRI not like serial code? If so how could I automatically send commands to the stepper motor. (The stepper motor driver is on a Pico with a USB connection to the RPi but I don¡¯t think the stepper motor is the problem just the serial connection to the Pico.)

?

The successful script for the initiating programme, testsend.py is:

?

import sys

xyz=100

print(xyz)

execfile(jmri.util.FileUtil.getExternalFilename("scripts:testreceive.py"))

#execfile("testreceive.py")

print("data transferred")

?

?

The successful script for the receiving programme, testreceive.py? is:

?

import sys

¡®¡¯¡¯

import serial

port = "/dev/ttyACM2"

baudrate = 115200

ser = serial.Serial(port,baudrate)

if ser.isOpen():

? ? print(ser.name + ' is open')

¡®¡¯¡¯

print (xyz+1)


Thanks
Toni


 

You need to use a different Serial library to work within JMRI. For an example of receiving (done with an independent thread to avoid blocking JMRI) and sending, see

jython/SerialPortTest.py


Extracting the parts needed to just send:

import jmri
import purejavacomm

# find the port info and open the port
print "opening ",portname
portID = purejavacomm.CommPortIdentifier.getPortIdentifier(portname)
port = self.portID.open("JMRI", 50)
# set options on port
baudrate = 9600
port.setSerialPortParams(baudrate, purejavacomm.SerialPort.DATABITS_8, purejavacomm.SerialPort.STOPBITS_1, purejavacomm.SerialPort.PARITY_NONE)
# get I/O connection for later
outputStream = port.getOutputStream()
print "Port opened OK¡±


# to write some characters
´Ç³Ü³Ù±è³Ü³Ù³§³Ù°ù±ð²¹³¾.·É°ù¾±³Ù±ð(¡®´¡¡¯)
´Ç³Ü³Ù±è³Ü³Ù³§³Ù°ù±ð²¹³¾.·É°ù¾±³Ù±ð(¡®µþ¡¯)
´Ç³Ü³Ù±è³Ü³Ù³§³Ù°ù±ð²¹³¾.·É°ù¾±³Ù±ð(¡®°ä¡¯)
´Ç³Ü³Ù±è³Ü³Ù³§³Ù°ù±ð²¹³¾.·É°ù¾±³Ù±ð(¡®°À²Ô¡¯)
outputStream.flush()

It might be easier to wrap the outputStream in a DataOutputStream which lets you write out strings, integers, etc:

dataStream = java.io <>.DataOutputStream(outputStream)
dataStream.writeBytes(str(12))



Bob

On Dec 11, 2023, at 7:05?PM, Toni Mury <toni@...> wrote:

Hi Bob

I have successfully modified my codes as you suggested however I need the receiving programme to include a serial connection to drive a stepper motor. If I comment out the serial code part as shown below all works well but if I include those lines it does not work.

Does JMRI not like serial code? If so how could I automatically send commands to the stepper motor. (The stepper motor driver is on a Pico with a USB connection to the RPi but I don¡¯t think the stepper motor is the problem just the serial connection to the Pico.)

The successful script for the initiating programme, testsend.py is:

import sys
xyz=100
print(xyz)
execfile(jmri.util.FileUtil.getExternalFilename("scripts:testreceive.py"))
#execfile("testreceive.py")
print("data transferred")


The successful script for the receiving programme, testreceive.py is:

import sys
¡®¡¯¡¯
import serial
port = "/dev/ttyACM2"
baudrate = 115200
ser = serial.Serial(port,baudrate)
if ser.isOpen():
print(ser.name + ' is open')
¡®¡¯¡¯
print (xyz+1)

Thanks
Toni

¡ª
Bob Jacobsen
rgj1927@...


 

Thanks Bob, I need to get my head around this and will get back to you.
First reading suggests I might also be able to wrap this all up in the script that gets called from a logix.
cheers
Toni


 

Hi Bob

I think I might be missing something. I've run the following code which include print statements so I can monitor where it is up to and it seems to stop after the 'portID= ...' line and before the 'port=...' line.

The only print results I am getting so far are"
portname = ?/dev/ttyACM2
portID = ?purejavacomm.CommPortIdentifier@22dbe717

The code I am running is:

import jmri

import purejavacomm

?

# find the port info and open the port

portname = "/dev/ttyACM2"

print "portname = " , portname

?

portID = purejavacomm.CommPortIdentifier.getPortIdentifier(portname)

print "portID = ", portID

?

port = self.portID.open("JMRI",50)

print "testing"

?

#set options on port

print "setting port options"

baudrate = 9600

port.setSerialPortParams(baudrate,purejavacomm.SerialPort.DATABITS_8, purejavacomm.SerialPort.STOPBITS_1, purejavacomm.SerialPort.PARITY_NONE)

print "port options set"

?

#get I/O connection for later

outputStream = port.getOutputStream()

?

#to write some characters

outputStream.write(str(50))

print("character written")



Thanks
Toni


 

Is there anything in the log? You reach that via Help -> System Console.

Bob

¡ª
Bob Jacobsen
rgj1927@...


 

Does this help?

NameError: name 'self' is not defined in <script> at line number 11


 

Yes. When I copy, paste and edited that script, I left a ¡°self.¡± in that shouldn¡¯t have been. Change line 11 to

port = portID.open("JMRI",50)

(i.e. remove the ¡°self.¡±).

In general, if a script hits an error, it¡¯ll put something in the log that refers to the line number, then stop. So that¡¯s a good first place to look.

Bob

On Dec 12, 2023, at 4:17?PM, Toni Mury <toni@...> wrote:

Does this help

NameError: name 'self' is not defined in <script> at line number 11
¡ª
Bob Jacobsen
rgj1927@...


 

Thanks Bob, your help and knowledge is really appreciated. I'll now move on to the next step.

Just for interest, the project involves a stepper motor driving ?a 2 track into 5 track traverser. The required traverser position is selected from a layout panel which initiates a logix which then runs this script.?

Cheers and Happy Christmas

Toni
Canberra, Australia


 

Happy New Year Bob

Further to our previous discussions I have tailored your code to match the connected Pico port as follows and then created a script as main.py on the Pico to test the process.

The Pico (csv file) is showing no signs of receiving the output stream from JMRI and I'm wondering what I'm missing. Are you able to help?

The scripts are:

# main.py
csv_filename = "data.csv"

def save_to_csv(data):

? ? with open(csv_filename,"a") as f:

? ? ? ? f.write(data +"\n")

while True:

? ? select_result = uselect.select([stdin], [], [], 0)

? ? buffer = ''

? ? while select_result[0]:

? ? ? ? input_character = stdin.read(1)

? ? ? ? if input_character != ',':

? ? ? ? ? ? buffer += input_character

? ? ? ? else:

? ? ? ? ? ? save_to_csv(buffer)

? ? ? ? ? ? buffer=''

? ? select_result = uselect.select([stdin], [], [], 0)


and, with print statements added to ensure that the script runs completely:

# testserialport.py

import jmri

import purejavacomm

print "purejavacomm started"

# find the port info and open the port

portname = "/dev/ttyACM2"

print "portname = " , portname

portID = purejavacomm.CommPortIdentifier.getPortIdentifier(portname)

print "portID = ", portID

port = portID.open("JMRI",50)

#set options on port

print "setting port options"

baudrate = 9600

print "baudrate = ",baudrate

port.setSerialPortParams(baudrate,purejavacomm.SerialPort.DATABITS_8, purejavacomm.SerialPort.STOPBITS_1, purejavacomm.SerialPort.PARITY_NONE)

print "port options set"

#get I/O connection for later

outputStream = port.getOutputStream()

print "port opened OK"

#to write some characters

outputStream.write('A')

outputStream.write('B')

outputStream.write('C')

outputStream.write('\n')

outputStream.flush()

#close the port

time.sleep(2)

port.close()

print "port closed"

?

Many thanks
Toni

?


 

I don¡¯t fully understand your Pico script, but it looks like it¡¯s reading from stdin instead of from a serial port.

Does the Pico¡¯s version of Python have PySerial?



Bob

On Jan 11, 2024, at 9:28?PM, Toni Mury <toni@...> wrote:

Happy New Year Bob

Further to our previous discussions I have tailored your code to match the connected Pico port as follows and then created a script as main.py on the Pico to test the process.

The Pico (csv file) is showing no signs of receiving the output stream from JMRI and I'm wondering what I'm missing. Are you able to help?

The scripts are:

# main.py
csv_filename = "data.csv"
def save_to_csv(data):
with open(csv_filename,"a") as f:
f.write(data +"\n")
while True:
select_result = uselect.select([stdin], [], [], 0)
buffer = ''
while select_result[0]:
input_character = stdin.read(1)
if input_character != ',':
buffer += input_character
else:
save_to_csv(buffer)
buffer=''
select_result = uselect.select([stdin], [], [], 0)


and, with print statements added to ensure that the script runs completely:

# testserialport.py
import jmri
import purejavacomm
print "purejavacomm started"
# find the port info and open the port
portname = "/dev/ttyACM2"
print "portname = " , portname
portID = purejavacomm.CommPortIdentifier.getPortIdentifier(portname)
print "portID = ", portID
port = portID.open("JMRI",50)
#set options on port
print "setting port options"
baudrate = 9600
print "baudrate = ",baudrate
port.setSerialPortParams(baudrate,purejavacomm.SerialPort.DATABITS_8, purejavacomm.SerialPort.STOPBITS_1, purejavacomm.SerialPort.PARITY_NONE)
print "port options set"
#get I/O connection for later
outputStream = port.getOutputStream()
print "port opened OK"
#to write some characters
outputStream.write('A')
outputStream.write('B')
outputStream.write('C')
outputStream.write('\n')
outputStream.flush()
#close the port
time.sleep(2)
port.close()
print "port closed"


Many thanks
Toni

¡ª
Bob Jacobsen
rgj1927@...


 

I'll check that out


 

Apparently?MicroPython does not include the pyserial library.?There?is a suggestion that?the serial communication functionality is provided by the machine.UART module.

Do you think this?is worth a try?

Toni


 

All I know is what I¡¯ve read here:



But it looks like it would work.

Bob

On Jan 14, 2024, at 6:06?PM, Toni Mury <toni@...> wrote:

Apparently MicroPython does not include the pyserial library. There is a suggestion that the serial communication functionality is provided by the machine.UART module.

Do you think this is worth a try?

Toni
¡ª
Bob Jacobsen
rgj1927@...


 

Thanks, I'll give it a go and let you know.