188 lines
7.9 KiB
Python
188 lines
7.9 KiB
Python
# Author: Lionel Jeanson copyright 2017
|
|
#
|
|
# Inspired from ThrottleBridge.py
|
|
# Author: Paul Bender, copyright 2004,2010
|
|
#
|
|
# Part of the JMRI distribution
|
|
#
|
|
# Listen for a given (3 as a default) DCC throttle commands
|
|
# and forward them to the curently selected one in throttle window
|
|
# or call advanced function if any defined for curently selected roster entry
|
|
#
|
|
# See JMRI output or log in case of issue.
|
|
#
|
|
# Customize at will.
|
|
|
|
listenToDCCThrottle = 3
|
|
|
|
import jmri
|
|
import jmri.ThrottleListener as ThrottleListener
|
|
import jmri.jmrit.jython.Jynstrument as Jynstrument
|
|
import java.beans.PropertyChangeListener as PropertyChangeListener
|
|
import javax.swing.JButton as JButton
|
|
import javax.swing.ImageIcon as ImageIcon
|
|
import time
|
|
|
|
class DCCThrottle(Jynstrument, ThrottleListener, PropertyChangeListener):
|
|
#Jynstrument main and mandatory methods
|
|
def getExpectedContextClassName(self):
|
|
return "jmri.jmrit.throttle.ThrottleWindow"
|
|
|
|
def init(self):
|
|
self.label = JButton(ImageIcon(self.getFolder() + "/DCCThrottle.png","DCCThrottle")) #label
|
|
self.label.addMouseListener(self.getMouseListeners()[0]) # In order to get the popupmenu on the button too
|
|
self.add(self.label)
|
|
# create a dcc throttle and request one from the ThrottleManager
|
|
self.masterThrottle = None
|
|
if ( jmri.InstanceManager.throttleManagerInstance().requestThrottle(listenToDCCThrottle, self) == False):
|
|
print "Couldn't request a throttle for "+locoAddress
|
|
# Advanced functions
|
|
self.advFunctions = AdvFunctions()
|
|
|
|
def quit(self):
|
|
if (self.masterThrottle != None):
|
|
self.masterThrottle.removePropertyChangeListener(self)
|
|
self.masterThrottle = None
|
|
self.advFunctions = None
|
|
|
|
#Property listener part
|
|
def propertyChange(self, event):
|
|
panelThrottle = None
|
|
if (self.getContext().getCurentThrottleController() != None) :
|
|
panelThrottle = self.getContext().getCurentThrottleController().getThrottle()
|
|
roster = self.getContext().getCurentThrottleController().getRosterEntry()
|
|
if(panelThrottle == None):
|
|
return
|
|
if(event.propertyName == "IsForward"):
|
|
panelThrottle.setIsForward(event.newValue)
|
|
return
|
|
if(event.propertyName == "SpeedSetting"):
|
|
panelThrottle.setSpeedSetting(event.newValue)
|
|
return
|
|
if(event.propertyName == "F0"):
|
|
if (roster != None) and (self.advFunctions.call(roster, "0", event.newValue, panelThrottle) != None):
|
|
return
|
|
panelThrottle.setFunction(0,event.newValue)
|
|
return
|
|
if(event.propertyName == "F1"):
|
|
if (roster != None) and (self.advFunctions.call(roster, "1", event.newValue, panelThrottle) != None):
|
|
return
|
|
panelThrottle.setFunction(1,event.newValue)
|
|
return
|
|
if(event.propertyName == "F2"):
|
|
if (roster != None) and (self.advFunctions.call(roster, "2", event.newValue, panelThrottle) != None):
|
|
return
|
|
panelThrottle.setFunction(2,event.newValue)
|
|
return
|
|
if(event.propertyName == "F3"):
|
|
if (roster != None) and (self.advFunctions.call(roster, "3", event.newValue, panelThrottle) != None):
|
|
return
|
|
panelThrottle.setFunction(3,event.newValue)
|
|
return
|
|
if(event.propertyName == "F4"):
|
|
if (roster != None) and (self.advFunctions.call(roster, "4", event.newValue, panelThrottle) != None):
|
|
return
|
|
panelThrottle.setFunction(4,event.newValue)
|
|
return
|
|
if(event.propertyName == "F5"):
|
|
if (roster != None) and (self.advFunctions.call(roster, "5", event.newValue, panelThrottle) != None):
|
|
return
|
|
panelThrottle.setFunction(5,event.newValue)
|
|
return
|
|
if(event.propertyName == "F6"):
|
|
if (roster != None) and (self.advFunctions.call(roster, "6", event.newValue, panelThrottle) != None):
|
|
return
|
|
panelThrottle.setFunction(6,event.newValue)
|
|
return
|
|
if(event.propertyName == "F7"):
|
|
if (roster != None) and (self.advFunctions.call(roster, "7", event.newValue, panelThrottle) != None):
|
|
return
|
|
panelThrottle.setFunction(7,event.newValue)
|
|
return
|
|
if(event.propertyName == "F8"):
|
|
if (roster != None) and (self.advFunctions.call(roster, "8", event.newValue, panelThrottle) != None):
|
|
return
|
|
panelThrottle.setFunction(8,event.newValue)
|
|
return
|
|
if(event.propertyName == "F9"):
|
|
if (roster != None) and (self.advFunctions.call(roster, "9", event.newValue, panelThrottle) != None):
|
|
return
|
|
panelThrottle.setFunction(9,event.newValue)
|
|
return
|
|
|
|
#ThrottleListener part (real dccThrottle)
|
|
def notifyThrottleFound(self, dccThrottle):
|
|
self.masterThrottle = dccThrottle
|
|
self.masterThrottle.addPropertyChangeListener(self)
|
|
|
|
def notifyFailedThrottleRequest(self, locoAddress, reason):
|
|
self.masterThrottle = None
|
|
# Sleep a bit and try again
|
|
try:
|
|
time.sleep(1)
|
|
except BaseException:
|
|
pass
|
|
if ( jmri.InstanceManager.throttleManagerInstance().requestThrottle(listenToDCCThrottle, self) == False):
|
|
print "Couldn't request a throttle for "+locoAddress
|
|
|
|
def notifyDecisionRequired(LocoAddress, decision):
|
|
pass # Throttle steal / share decisions are delegated to the ThrottleManager
|
|
|
|
class AdvFunctions():
|
|
def call(self, rosterEntry, advFn, status, throttle):
|
|
assert (rosterEntry!=None), "rosterEntry is null"
|
|
assert (advFn!=None), "advFn is null"
|
|
assert (status!=None), "status is null"
|
|
assert (throttle!=None), "throttle is null"
|
|
todoStr = rosterEntry.getAttribute("advF"+advFn)
|
|
if (todoStr == None):
|
|
return None
|
|
# poor man parser, should unserialize a json object instead
|
|
todo = todoStr.split(";")
|
|
for task in todo:
|
|
task = task.lstrip()
|
|
# Actual function call
|
|
if (task.startswith("F")):
|
|
task = task.rstrip()
|
|
setter = None
|
|
getter = None
|
|
ok = False
|
|
for fct in throttle.getClass().getMethods():
|
|
fctName = fct.getName()
|
|
if (fctName == "set"+task):
|
|
setter=fct
|
|
if (fctName == "get"+task):
|
|
getter=fct
|
|
if (setter != None and getter != None):
|
|
ok = True
|
|
break
|
|
if (ok):
|
|
if (not rosterEntry.getFunctionLockable(int(task[1:]))):
|
|
setter.invoke(throttle, status)
|
|
else:
|
|
state = getter.invoke(throttle)
|
|
setter.invoke(throttle, not state)
|
|
continue
|
|
# Play sound
|
|
if (task.startswith("P") and status):
|
|
path = task[1:]
|
|
self.play(path, throttle)
|
|
continue
|
|
return True
|
|
|
|
def play(self, sndPath, throttle):
|
|
assert (sndPath!=None), "sndPath is null"
|
|
sourceName="IAS"+sndPath+"-"+str(throttle.getLocoAddress())
|
|
bufferName="IAB"+sndPath
|
|
source = audio.getAudio(sourceName)
|
|
if (source == None):
|
|
buffer = audio.getAudio(bufferName)
|
|
if (buffer == None):
|
|
buffer = audio.provideAudio(bufferName)
|
|
buffer.setURL(sndPath)
|
|
source = audio.provideAudio(sourceName)
|
|
source.setAssignedBuffer(bufferName)
|
|
# would need to update location here
|
|
source.play()
|
|
|