¿ªÔÆÌåÓý

Locked jmri_bindings.py #scripting


 

Hi, can I ask what there is no equivalent turnouts definition the?jmri_bindings.py? and if this is why I can? only control the throttle from inside a class that inherits from jmri.jmrit.automat.AbstractAutomaton

thanks jim


 

The jmri_bindings.py file has been obsolete for a while, so I¡¯m not sure what that part of your question is asking



It¡¯s easier to handle a throttle within AbstractAutomaton because there¡¯s specific code there to handle the necessary waits and callbacks.

Unlike a turnout operation, which is ¡°set the command and go on with what you¡¯re doing¡±, throttle operations require back-and-forth with the hardware. That can be directly coded in a script, but it¡¯s tricky to get right.

Bob

On Jan 5, 2020, at 9:00 AM, James Anderson <james_anderson_999@...> wrote:

Hi, can I ask what there is no equivalent turnouts definition the jmri_bindings.py and if this is why I can only control the throttle from inside a class that inherits from jmri.jmrit.automat.AbstractAutomaton

thanks jim
--
Bob Jacobsen
rgj1927@...


 

Thanks, I was curious as to why I could not use a throttle in a similar way to sensors and turnouts. So looked around and found the?jmri_bindings.py file and put 2 and 2 together and came up with 5. Thanks for the explanation.

Jim


 

Sorry to come back on this again.

I have a small script?

import routes
route=routes.testRoute1()
route.setTurnoutSensor("ISTS-1",ACTIVE)

and on disk I have this module called routes shown at the bottom of this note.?

If i use self.sensor=sensors.provideSensor(self.turnoutSensorName) I get?NameError: global name 'sensors' is not defined but it works with
jmri.InstanceManager.getDefault(jmri.SensorManager).provideSensor(self.turnoutSensorName)?

Is there something else I should be loading?

?import jmri
?class automationRoutesBaseClass(jmri.jmrit.automat.AbstractAutomaton) :
? ? def init(self):
? ? ? ? return
? ? def handle(self):
? ? ? ?return 0
? ? def setTurnoutSensor(self,turnoutSensorName,state):
? ? ? ? self.turnoutSensorName=turnoutSensorName
? ? ? ? self.turnoutState=state
#? ? ? self.sensor=jmri.InstanceManager.getDefault(jmri.SensorManager).provideSensor(self.turnoutSensorName)
? ? ? ? self.sensor=sensors.provideSensor(self.turnoutSensorName)
? ? ? ? if self.sensor !=None :
? ? ? ? ? ?self.sensor.setState(self.turnoutState)
? ? ? ? else:
? ? ? ? ? print("error unable to obtain sensor object for "+str(self.turnoutSensorName))
? ? ? ? return
?#-----------------------------------------------------------------------------------
?# Class? :? define a route. Inherits methods from automationRoutesBaseClass
?#-----------------------------------------------------------------------------------
?class testRoute1(automationRoutesBaseClass) :
? ? def init(self):
? ? ? ? return
? ? def handle(self):
? ? ? ? return
? ? def __init__(self,routeDescription=None,routeName=""):
? ? ? ? self.routeDescription=routeDescription
? ? ? ? self.routeName=routeName
? ? ? ? automationRoutesBaseClass.__init__(self)
? ? ? ? return
?


 

James,

By importing your module you lose the global variables.



An alternate approach is to load the module instead of import and modify the route line.

import jmri
execfile(jmri.util.FileUtil.getExternalFilename("preference:routes.py"))
route=testRoute1()
route.setTurnoutSensor("ISTS-1",ACTIVE)

Dave Sand


----- Original message -----
From: James Anderson <james_anderson_999@...>
Subject: Re: [jmriusers] jmri_bindings.py
Date: Monday, January 06, 2020 7:56 AM

Sorry to come back on this again.

I have a small script?


import routes
route=routes.testRoute1()
route.setTurnoutSensor("ISTS-1",ACTIVE)

and on disk I have this module called routes shown at the bottom of this note.?

If i use self.sensor=sensors.provideSensor(self.turnoutSensorName) I get?NameError: global name 'sensors' is not defined but it works with
jmri.InstanceManager.getDefault(jmri.SensorManager).provideSensor(self.turnoutSensorName)?

Is there something else I should be loading?


?import jmri
?class automationRoutesBaseClass(jmri.jmrit.automat.AbstractAutomaton) :
? ? def init(self):
? ? ? ? return
? ? def handle(self):
? ? ? ?return 0
? ? def setTurnoutSensor(self,turnoutSensorName,state):
? ? ? ? self.turnoutSensorName=turnoutSensorName
? ? ? ? self.turnoutState=state
#? ? ? self.sensor=jmri.InstanceManager.getDefault(jmri.SensorManager).provideSensor(self.turnoutSensorName)
? ? ? ? self.sensor=sensors.provideSensor(self.turnoutSensorName)
? ? ? ? if self.sensor !=None :
? ? ? ? ? ?self.sensor.setState(self.turnoutState)
? ? ? ? else:
? ? ? ? ? print("error unable to obtain sensor object for "+str(self.turnoutSensorName))
? ? ? ? return
?#-----------------------------------------------------------------------------------
?# Class? :? define a route. Inherits methods from automationRoutesBaseClass
?#-----------------------------------------------------------------------------------
?class testRoute1(automationRoutesBaseClass) :
? ? def init(self):
? ? ? ? return
? ? def handle(self):
? ? ? ? return
? ? def __init__(self,routeDescription=None,routeName=""):
? ? ? ? self.routeDescription=routeDescription
? ? ? ? self.routeName=routeName
? ? ? ? automationRoutesBaseClass.__init__(self)
? ? ? ? return
?


 

Thanks Dave.?

unfortunately I also use this function so that I can have a dynamic name which gets in the way. Is there a way to? have testRoute1 as a string, something like route=eval("testRoute1()") ?

? ? ? def importClass(self,className):
? ? ? ? ? self.name=className
? ? ? ? ? self.components = self.name.split('.')
? ? ? ? ? self.module = __import__(self.components[0])
? ? ? ? ? for self.component in self.components[1:]:
? ? ? ? ? ? ?self.module=getattr(self.module, self.component)
? ? ? ? ? return self.module
? ? ? #---------------------------------------------------------------------------------------------------------
? ? ? # set the route for this driver
? ? ? #---------------------------------------------------------------------------------------------------------
? ? ? def setRoute(self,route,throttle):
? ? ? ? ? self.route_name="automationRoutes."+route
? ? ? ? ? print("setting route to "+self.route_name)
? ? ? ? ? self.route=self.importClass(self.route_name)
? ? ? ? ? self.route_instance=self.route
? ? ? ? ? self.route_instance.throttle=throttle
? ? ? ? ? return self.route_instance()
?


 

One way I can? get it to work is by passing a copy of the sensors object

self.route? ? =? self.trainDriver.setRoute(self.new_route,self.throttle,sensors)

Can i ask if? this is acceptable or if I am heading for trouble further down the line?

Thanks Jim


Randall Wood
 

Note that future versions of Jython are going to remove execFile() (this function was removed from Python in 3.0).

We might just have to plan on not relying on a set of convenience bindings and use foos = jmri.InstanceManager.getDefault(jmri.FooManager) for whichever manager is wanted.


 

Thanks, for now I have passed copy of the sensor manager to the function which has solved my immediate problem. Should I code as you suggest above or wait for an official process?


 

I expect the function

exec(open(jmri.util.FileUtil.getExternalFilename("preference:routes.py")).read())

will work the same way.

--
Petr ?¨ªdlo
Czech Republic


Randall Wood
 

That exec() function does work the same way as execFile(), but does two things that using import does not:

  • always reinterprets the script, ignoring any compilation caching that Jython has performed. If a script gets executed repeatedly, this can have a performance impact (especially on a system like a Raspberry Pi)
  • shares the global Jython interpreter (not JMRI) state with the executed script and allows the executed script to modify the global Jython state. Care must be taken in the executed script that anything it does in the global space does not negatively impact any other script, and that no other executed script changes the global state in a way it does not expect

Put another way, if a script does:

turnouts = jmri.InstanceManager.getDefault(jmri.TurnoutManager).getNamedBeansSet() # get all turnouts
# do something with the turnouts ...
  • when exec()ed, this script will overwrite the default binding for turnouts to be something else, and any other script that relies on the default binding will fail
  • when imported, this script will have no effect on other scripts

For historical reasons, all scripts run from the Panels->Run Script... menu item, and as startup items, run in the same global state (scripts run from other triggers may or may not share that state, I don't necessarily know), so there is no assurance, other than running that script by importing it, that a script will not change the state of the Jython interpreter that another script uses.


 

Hi sorry to reopen this discussion.

?

In jmri v 4.16 I had two ways I called a program ?execfile(self.cmdR) ?or globals()[self.cmdR](self.client_address,**self.args).

I use execfile when developing my code because I could change the self.cmdR program and the changes would be picked up without me having to restart jmri. ?I used global in production because it was muchmuch? faster than execfile. This file is called multiple times and therefore using globals() gave ?me a significant increase in performance.? With 4.18 which I have just installed, when using the globals approach none of the global ?jmri names (sensors, blocks etc) are recognised. This I fixed by defining them long hand (sensors????? = jmri.InstanceManager.getDefault(jmri.SensorManager etc.)

I am happy to do this but just want to reassure myself that by doing so I am not creating a massive problem for the future. ?

?

Thanks Jim