Foire aux questions sur les scripts JMRI avec Jython
Python & JMRI pour plus d'informations, y compris sur les pointeurs vers des articles, etc Voir aussi les liens de navigation à gauche.
Aux fins de la rédaction de scripts JMRI, ils ne diffèrent pas beaucoup. La plupart des différences impliquent ce qui se passe en cas d'erreur . Il y a aussi quelques restrictions sur ce que vous pouvez faire avec les informations de configuration de l'ordinateur , etc, en Jython, mais ce ne sont pas des choses qu'un script JMRI est susceptible d'avoir besoin.
Quelques informations supplémentaires sur les différences sont disponibles ici.
import
",
" "classe
", etc, dans les fichiers
d'exemple veulent dire?Les importations permettent de se référer à des choses par des noms plus courts, essentiellement raconter jython "rechercher Jarray, les paquets JMRI reconnaître tous les noms là-bas ". Pour quelqu'un essayant de comprendre ce script, vous pouvez simplement les traiter comme des "assurer que le programme peut trouver les pièces que nous voulons ".
"Classe" signifie "commencer la définition d'un groupe de choses qui vont ensemble "( A vous tous les autres experts, s'il vous plaît ne me sauter pas dessus au sujet de cela, je comprends à la fois le polymorphisme intrinsèque/extrinsèque, j'ai juste essayer d'obtenir l'idée générale).
Par exemple, dans le fichier SigletExample.py il y a une description d'une "Classe" appelée SigletExample, qui contient deux routines/fonctions/membres: Un sous-programme appelé "defineIO", et un appelé "setOutput"
Cette "classe" est associée à une autre classe appelé "Siglet" (en fait jmri.jmrit.automat.Siglet; c'est encore une chose avec une longue désignation), qui sait quand il faut appeler les routines par ces deux noms pour obtenir qu'elles fassent ce que vous voulez.
Essentiellement, vous définissez deux parties ("defineIO" & "setOutput") qui se branchent dans une structure pré-existante pour piloter les signaux. Cette structure pré-existante est très puissante, et vous permet de faire toutes sortes de choses, mais fournit également cette méthode pour essayer de le garder simple.
OK, à ce point les yeux de la plupart des gens sont entièrement retournés. Votre meilleur pari quand à commencer par ce truc est d'utiliser la copie et "modifier " l'approche du développement logiciel. Il est bon d'essayer de comprendre le contenu entier du fichier, mais ne vous inquiétez pas si vous ne le comprenez pas assez bien pour être capable de le recréer à partir de zéro. Au lieu de cela, il suffit de modifier de petits morceaux et jouer avec.
Par exemple, "self.to12" est juste le nom d'une variable. Vous pouvez appeler ça comme vous voulez, par exemple self.MyBigFatNameForTheLeftTurnout
Le "self" est une partie complètement locale; "self" se réfère à "un objet de la classe particulière j'ai bien défini dès maintenant ". Alternativement, vous pouvez définir une variable globale, mais ce n'est pas recommandé. Si vous avez plusieurs scripts qui fonctionnent (et vous pouvez en avoir autant que vous voulez comme nous vous recommandons de placer chaque tête de signal dans un script distinct), les variables peuvent se confondre si vous utilisez le même nom de variable pour dire des choses trop différentes. En utilisant le "self" comme celui-ci vous vous s'assurer que cela n'arrive pas.
Notez que les aiguillages, etc, ont des "Noms systèmes" qui ressemblent à "LT12". Vous verrez ceci occasionnellement, mais c'est quelque chose de différent de celui des noms de variables dans un fichier de script.
window =
jmri.util.JmriJFrame.getFrameList()[1]
window.setLocation(java.awt.Point(0,0))
localise la fenêtre principale de l'application, et définit sa situation dans le coin supérieur gauche de l'écran.
Le jmri.util.JmriJFrame.getFrameList( )
appelé dans la première ligne renvoie une
liste des fenêtres existantes.
L'élément [0] de cette liste est
l'écran original de démarrage et
l'élément [1] est la fenêtre
principale; après cela, ce sont les
différentes fenêtres dans l'ordre
où elles sont créées. Pour trouver
une en particulier, vous pouvez l'indexée
à travers la liste en vérifiant par
exemple Titre de la fenêtre avec le
getTitle ()
.
Certains exemples utilisent la classe AbstractAutomaton comme une base, tandis que d'autres utilisent la classe Siglet . C'est parce que ceux-ci sont destinés à des fins différentes .
"Siglet" est destinée à être utilisée pour piloter les signaux. Vous fournir deux morceaux de code:
La classe de base Siglet gère alors l'ensemble de l'écoute des changements, la mise en place pour l'exécution en parallèle, etc. Votre routine defineIO sera appelé une fois au début, et tout le temps après qu'une ou plusieurs des entrées seront modifiées, votre routine setOutput sera appelée à recalculer l'apparence du signal.
Bien sûr, vous pouvez utiliser cette classe pour calculer d'autres choses que les apparences de signaux. Mais l'élément clé est que le calcul est refait quand les entrées changent, et seulement lors du changement des entrées.
AbstractAutomaton est une classe plus générale qui vise à permettre des opérations plus puissantes (et Siglet en réalité utilise cette base plus puissante). Vous définissez deux fonctions:
Utiliser AbstractAutomoton vous fournit un certain nombre d' outils: vous pouvez attendre d'un capteur particulier qu'il soit actif, faire quelque chose, puis attendre qu'un autre capteur passe à inactif, etc. Cela vous permet beaucoup plus de liberté pour créer des séquences plus complexes& et puissantes que la classe Siglet, parce les Siglets sont limités à faire une seule chose (ils n'ont pas pour objectif de faire des séquences d'opérations).
Pour plus d'infos sur le changement de routines que fournit AbstractAutomaton pour vous aider, consultez les Javadocs pour la classe. (Faites défiler jusqu'à la section intitulée "Résumé de la méthode")
Si le script exécute une boucle qui est censée mettre à jour quelque chose, il ne peut pas être écrit pour fonctionner en continu ou bien il va juste utiliser du temps d'ordinateur autant qu'il peut. Il devrait plutôt attendre.
La meilleure chose à faire est d'attendre que quelque chose change. Pour Par exemple, si votre script observe certains capteurs pour décider quoi faire, attendre que l'un de ces capteurs change (voir les exemples de scripts pour les exemples)
Plus simple, mais pas aussi efficace, est d'attendre un peu de temps avant de vérifier à nouveau. Par exemple
waitMsec (1000)provoque un script automate ou Siglet pour attendre 1000 millisecondes (une seconde) avant de continuer.
Pour juste un simple script, ce qui n'use pas le les classes Automat ou Siglets , vous pouvez dormir en faisant
du sommeil à l'importation du temps le sommeil (10)La première ligne définit le "sommeil" de routine, et ne doit être fait qu'une fois. La deuxième ligne, puis dort pendant 10 secondes. Notez que la précision de cette méthode n'est pas aussi bonne que celle utilisant l'une des classes spéciales.
execfile("filename.py");
jmri.InstanceManager.getDefault(jmri.ConfigureManager).load(java.io.File("filename.xml "))
Cela ressemble à "filename.xml" dans le répertoire du programme JMRI, qui n'est pas un bon endroit pour conserver vos fichiers. (Ils ont tendance à être perdus ou endommagés quand JMRI est mis à jour). Voir la question suivante pour une solution à cela.
Vous pouvez toujours
spécifier le chemin complet vers un fichier, par
exemple C:\Documents and Files\
mine\JMRI\filename.xml
ou /Users
/mine/.jmri/filename.xml
. Ce n'est pas
très portable, d'ordinateur à ordinateur,
cependant, et peut devenir un handicap pour continuer
plus loin.
JMRI fournit des routines pour convertir les noms "portables" en des noms que votre ordinateur reconnaîtra:
fullname jmri.util.FileUtil.getExternalFilename = ("préférence: filename.xml")
Le ":préférence
"
signifie regarder quel fichier démarre dans le
répertoire préférences sur
l'ordinateur actuel. D'autres choix sont "le
programme:" et "home".
def printStatus (): print "x est", x print "y est", y print "z est", z retour a x = 0 y = 0 z = 0
Une fois que le fichier a été
exécuté,plus tard des script pourront invoquer la
routine printStatus ()
en cas de besoin.
x
, y
, et
z
sont disponibles pour n'importe qui.
Cela peut conduire à des bugs obscures, si
deux routines différentes utilisent une
variable du même nom, sans se rendre compte
qu'ils partagent les données avec les autres.
Mettre votre code en "classes" est un moyen
d'éviter cela.
self.waitChange ([self.sensorA, self.sensorB, self.sensorC])où vous avez précédemment défini chacun de ces "self.sensorA" et les choses via une ligne comme:
self.sensorA = sensors.provideSensor ("21")Vous pouvez ensuite vérifier pour diverses combinaisons comme:
si self.sensorA.knownState == ACTIF: print "L'avion! L'avion!" elif self.sensorB.knownState == INACTIF: print "Croiriez-vous à un oiseau très rapide?" d'autre print "Rien à voir ici, se déplacer le long ..."(Je n'ai pas vraiment saisi ce script et ni exécuter, alors il pourrait y avoir des fautes de frappe, désolé)
Une routine simple peut écouter plus d'un aiguillage, capteur, etc
Si vous conservez une référence de votre objet écouteur, vous pouvez le joindre à plusieurs objets:
m = MyListener () turnouts.provideTurnout ("12"). addPropertyChangeListener (m) turnouts.provideTurnout ("13"). addPropertyChangeListener (m) turnouts.provideTurnout ("14"). addPropertyChangeListener (m)
Mais comment l'auditeur sait ce qui a changé?
Une routine auditeur ressemble à ceci:
Paroles de classe MyListener (java.beans.PropertyChangeListener): def propertyChange (auto, événement): print "le changement", event.propertyName a print "à partir", event.oldValue, "à", event.newValue print "SystemName source", event.source.systemName a print "userName source", event.source.userNameLorsque l'écouteur est appelé, il donne un objet (appelé event ci-dessus) qui contient le nom de la propriété qui a changé, ainsi que les valeurs anciennes et nouvelles de cette propriété.
Vous pouvez également obtenir une référence de l'objet original qui a changé par "nom", et ensuite faire tout ce que vous voulez par là. Dans l'exemple ci-dessus, vous pouvez récupérer les SystemName, nom d'utilisateur (ou même d'autres types de statut).
Le fichier Jython/SampleSound.py montre comment jouer un son dans un script. En bref, vous charger un son dans une variable ("snd" dans ce cas), puis appelez "play ()" pour y jouer une fois, etc
Notez que si plus d'un son est joué à un moment, le programme les combine entre eux du mieux qu'il peut. Généralement, il fait un assez bon travail.
aVous pouvez combiner le jeu () avec une autre logique de jouer un son quand un capteur change, etc Ron McKinnon a fourni un exemple pour faire cela. Il joue une cloche passage à niveau lorsque le capteur devient actif.
# Il écoute les modifications apportées à un capteur, # Puis joue un fichier son quand le capteur est actif Importation Jarray Importation JMRI # Créer l'objet sonore en chargeant un fichier snd = jmri.jmrit.Sound ("ressources/sons/Crossing.wav") Classe SensndExample (jmri.jmrit.automat.Siglet): # Modifier ceci pour définir tous vos aiguillages, les capteurs et # têtes de Signal. def defineIO (auto): # Obtenir le capteur de self.Sen1Sensor = sensors.provideSensor ("473") # Enregistrer les entrées de sorte que setOutput sera appelé en cas de besoin. self.setInputs (jarray.array ([self.Sen1Sensor], jmri.NamedBean)) Retour # setOutput est appelée lorsque d'un changements des entrées, et est # responsable de l'établissement la sortie correcte # # Modifier cela pour faire votre calcul. def setOutput (auto): Si self.Sen1Sensor.knownState == ACTIVE: snd.play () Retour # Fin de définition de la classe # Lancer une de ceux ci-dessus SensndExample (). Start ()