JMRI: Scripting FAQ

# JMRI: FAQ Scripts

Foire aux questions sur les scripts JMRI avec Jython

## Où puis-je en apprendre davantage sur le langage Jython?

Voir la page

Python & JMRI pour plus d'informations, y compris sur les pointeurs vers des articles, etc Voir aussi les liens de navigation à gauche.

## En quoi Jython et Python diffèrent-ils?

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 . </ div>

## Où puis-je trouver des exemples de scripts JMRI?

Voir la page exemples . En outre, la page introduction montre quelques-unes des commandes de base. </ div>

## Qu'est-ce que des mots comme " `import` ", " `"classe` ", etc, dans les fichiers d'exemple veulent dire?

Ils font partie du langage utilisé pour les scripts jython.

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.

## Y at-il besoin de conventions de dénomination?

Dans de nombreux fichiers d'exemple, les aiguillages sont visés par des noms comme "to 12", les signaux par des noms comme "si21", et les capteurs par des noms comme "bo45". Ces conventions sont nées de la façon de coder héritée de certains vieux code, et ils peuvent rendre le code plus clair. Mais ils ne sont en aucun cas nécessaire; le programme ne se soucie pas ce que vous appelez les variables.

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.

## Un Script Peut-il accéder à une application fenêtres de JMRI ?

Vos scripts peuvent modifier les propriétés de tous les fenêtres principales JMRI. Elles sont toutes des objets jmri.util.JmriJFrame, elles ont donc toutes les différentes méthodes d'une JFrame Swing. Par exemple, cet extrait de code

`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 ()` .

## Quelle est la différence entre les classes "Siglet" et "AbstractAutomaton" ?

(Peut-être pas une question fréquemment demandée, mais elle a besoin d'être posée quelque part)

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:

defineIO
  qui définit les différents capteurs, les aiguillages et signale que le signal de sortie dépend de tant d'entrée lorsqu'il faut calculer l'apparence de ce signal.
setOutout
  qui recalcule l'apparence du signal avec les entrées définies.

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:

  Init qui est appelé une seule fois pour accomplir un temps de configuration dont vous avez besoin
  handle
qui est appelé à plusieurs reprises, encore et encore jusqu'à ce qu'il retourne FALSE.

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")

## Comment puis-je limiter la priorité d'un script?

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.

## Comment puis je invoquer un autre fichier script depuis un script?

    execfile("filename.py");

## Comment puis je charger un fichier de panneau de partir d'un script?

     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.

## Comment puis-je trouver un fichier dans le répertoire des préférences?

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".

## Puis je communiquer entre les scripts?

Tous les scripts partagent un espace d'adressage unique, ce qui signifie qu'une variable comme le "x" se réfère au même endroit dans tous les scripts. Cela vous permet de définir un procédure, par exemple, dans un script, et l'utiliser ailleurs. Par exemple, si un fichier "definitions.py" contient:

     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.
Vous pouvez également partager des variables, ce qui permet à deux routines de partager l'information. Dans l'exemple ci-dessus, les variables `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.

## Un script peut-il attendre plus d'une chose à changer?

Si votre script est basé sur une classe Siglet ou AbstractAutomaton (par exemple si vous écrivez une "poignée" de routine ", il y a une routine général" waitChange" qui attend que plusieurs capteurs aient changer avant de revenir vers vous. Notez que plusieurs peuvent changer dans le même temps, de sorte que vous pouvez supposer seulement qu'il y a une seule valeur différente! Et vous aurez alors à vérifier si elles sont devenues des états particuliers. Il est écrit que:

     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é)

## Un script peut il entendre plus d'un aiguillage?

Les Objets JMRI (aiguillages, capteurs, etc) peuvent avoir des "Auditeurs" qui leur sont attachés. Ces derniers sont ensuite avertis lorsque le statut de l'objet change. Si vous utilisez les classes ou les Siglet Automat, vous n'avez pas besoin d'utiliser cette possibilité, et les classes gèrent toutes les créations et enregistrements des auditeurs. Mais si vous voulez faire quelque chose de spécial, vous devrez peut-être utiliser cette possibilité

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.userName

Lorsque 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).

## Comment puis-je obtenir un script pour jouer un son?

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.

a

Vous 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 ()