User Tools

Site Tools


Action disabled: index
digint:user-fr

Bibliothèques de Centrales Numériques Utilisateurs

UUDP

La bibliothèque UUDP dans Rocrail fournie une interface UDP pour les bibliothèques utilisateurs sur le port 21111.
Le protocole utilisé est RCP sans entêtes.
Initialement une ouverture de session doit être envoyée: <logon/>

Exemple Java

Cet exemple est un codage rapide pour montrer la communication UDP, et n'est pas une base pour le développement d'une bibliothèque de Centrale Numérique.

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
 
public class UUDP {
  static DatagramSocket ds = null;
  static InetAddress ip = null;
  static UUDPreader reader = null;
  static boolean running = true;
 
  public static void main(String[] args) {
    System.out.println("UUDP example");
 
    try {
      UUDP.ds = new DatagramSocket();
      UUDP.ip = InetAddress.getLocalHost();
      byte buf[] = null;
 
      buf = "<logon/>".getBytes();
      DatagramPacket DpSend = new DatagramPacket(buf, buf.length, UUDP.ip, 21111);
      UUDP.ds.send(DpSend);
 
      UUDP.reader = new UUDP.UUDPreader();
      Thread th = new Thread(UUDP.reader);
      th.start();
 
      boolean onoff = true;
      for (int i = 0; i < 4; i++) {
        buf = ("<fb addr=\"123\" state=\"" + (onoff ? "true" : "false") + "\"/>").getBytes();
        DpSend = new DatagramPacket(buf, buf.length, UUDP.ip, 21111);
        UUDP.ds.send(DpSend);
        Thread.sleep(1000);
        onoff = !onoff;
      }
 
      running = false;
      buf = "<logoff/>".getBytes();
      DpSend = new DatagramPacket(buf, buf.length, UUDP.ip, 21111);
      UUDP.ds.send(DpSend);
      th.interrupt();
    } catch (Exception e) {
    }
  }
 
  static class UUDPreader implements Runnable {
    public void run() {
      try {
        while (running) {
          byte[] receive = new byte[256];
          DatagramPacket DpReceive = new DatagramPacket(receive, receive.length);
          ds.receive(DpReceive);
          System.out.println("received: " + new String(receive));
        }
      } catch (Exception e) {
      }
    }
  }
 
}


MQTT

Une bibliothèque de Centrale Numérique utilisateur MQTT pour faire une connexion à un broker MQTT pour obtenir les commandes, et pour publier les évènements du terrain.
Avec cette méthode, la bibliothèque de Centrale Numérique est complètement indépendante des sources Rocrail, et peut également être utilisée avec un autre logiciel.
Le choix du langage de programmation est également indépendant, tant qu'il est possible de se connecter à un broker MQTT.

Python

Bibliothèques supplémentaires Python

Installer la bibliothèque supplémentaire Python:

pip install paho-mqtt
pip install pyserial

Dans le cas de Linux ou macOS les commandes doivent être exécutées dans le contexte de super utilisateur:

sudo pip install paho-mqtt
sudo pip install pyserial

Exemple

Cet exemple essaie de faire une connexion série avec la Centrale Numérique DCC++, et essaie de s'abonner au broker MQTT.

Sauvegarder le script sous le nom mqtt-cs.py.

import time
import os
import serial
import xml.etree.ElementTree as ET
 
#https://pypi.org/project/paho-mqtt/1.0/
import paho.mqtt.client as paho
 
 
# Open a serial connection with the DCC++ command station: 
ser = serial.Serial(
    port='/dev/tty.usbmodem14101',
    baudrate=115200,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_TWO,
    bytesize=8
)
if ser.isOpen():
  print "Serial connection established."
 
 
def sendDCCpp(msg):
  if ser.isOpen():
    rc = ser.write(msg);
    print "" + str(rc) + " bytes send to DCC++"
 
# Handle system commands/events: 
def onSys(node):
  if node.get('cmd') == "shutdown":
    print("SYSTEM SHUTDOWN... Clean up and exit...")
    #os._exit(0)
  if node.get('cmd') == "stop":
    sendDCCpp("<0>")
  if node.get('cmd') == "go":
    sendDCCpp("<1>")
 
# Handle output commands/events: 
def onOutput(node):
  print("set output " + node.get('addr') + ":" + node.get('port') + " to " + node.get('cmd') )
 
# Handle clock commands/events: 
def onClock(node):
  print(node.get('cmd') + " clock to " + node.get('hour') + ":" + node.get('minute') )
 
# MQTT callback function:
def on_message(client, userdata, message):
  #evaluate the Rocrail command
  print("broker message = " + str(message.payload.decode("utf-8")))
  node = ET.fromstring(str(message.payload.decode("utf-8")))
  if node.tag == "sys":
    onSys(node)
  if node.tag == "co":
    onOutput(node)
  if node.tag == "clock":
    onClock(node)
 
 
broker="nasRR" #this is the IP of the computer on which the MQTT broker is installed.
 
# Create client object 
client= paho.Client("client-001")
 
# Bind function to callback
client.on_message=on_message
 
print "connecting to broker " + broker
client.connect(broker)#connect
 
# Start loop to process received MQTT messages
client.loop_start()
 
# Subscribe: 
topic = "rocrail/service/command"
print "subscribe to " + topic
client.subscribe(topic)
 
 
# Evaluate and handle DCC++ messages:
def onDCCpp(serin):
  print "DCCpp: " + serin
 
  if serin == "<p0>":
    print "DCC++ reports power OFF"
    client.publish("rocrail/service/field","<state iid=\"python\" power=\"false\"/>")
  if serin == "<p1>":
    print "DCC++ reports power ON"
    client.publish("rocrail/service/field","<state iid=\"python\" power=\"true\"/>")
 
  #evaluate the field sensors and publish
  addr  = "4711"
  state = "true"
  client.publish("rocrail/service/field","<fb iid=\"python\" addr=\""+addr+"\" state=\""+state+"\"/>")
 
 
# Main loop for reading the serial connection: 
while ser.isOpen():
  serin = ""
  if ser.inWaiting() > 0:
    serin = ser.read(1)
    if serin == '<':
      serchar = ''
      while serchar != '>':
        serchar = ser.read(1)
        serin += serchar
 
  if serin != '':
    onDCCpp(serin)
 
  if ser.inWaiting() == 0:
    time.sleep(0.01)
 
 
# Clean up 
ser.close() 
client.disconnect()
client.loop_stop()

Il y a des modules Python qui peuvent être utilisés pour analyser les commandes Rocrail XML arrivant au Format RCP.
Les commandes sont structurées relativement simplement, et elles peuvent également être analysées avec les fonctions de texte standard.
Si l'attribut iid est réglé dans une commande, il doit être vérifié si la commande doit traitée par cette bibliothèque utilisateur.

Session

Python

Démarrer le script avec python mqtt-cs.py

MBA2019:digint robversluis$ python mqtt-cs.py
connecting to broker nasRR
subscribe to  rocrail/service/command
broker message = <sys cmd="shutdown" informall="true" val="0"/>

SYSTEM SHUTDOWN... Clean up and exit...
DCCpp: <iDCC++ BASE STATION FOR ARDUINO UNO / ARDUINO MOTOR SHIELD: V-1.2.1+ / Jun  6 2019 07:58:21>
DCCpp: <N0: SERIAL>
broker message = <fbinfo cmd="fbmods">
  <fbmods bus="0" modules="0,1,2"/>
</fbinfo>

broker message = <boosterlist/>

broker message = <clock divider="1" hour="8" minute="39" wday="4" mday="6" month="6" year="2019" time="1559803151" temp="20" bri="255" cmd="set"/>

set clock to 8:39

Rocrail

20190421.104604.509 r9999I clocktic OClntCon 0606 mqtt publish to [rocrail/service/command]:[<clock divider="1" hour="10" minute="46"]

20190421.104828.200 r9999I mqttread OClntCon 0799 broker published [rocrail/service/field]:[<fb iid="python" addr="4711" state="true"/>]
20190421.104828.201 r9999a mqttread OModel   5124 trying to match sensor event: [python] 0:4711 uidname=[] state=1 code=
20190421.104828.201 r9999a mqttread OModel   5160 sensor key: 0_4711_python_
20190421.104828.201 r9999a mqttread OModel   5180 unregistered sensor event: [python] 0:4711 uidname=[]


Configuration des bibliothèques Utilisateur

La configuration des bibliothèques utilisateur n'est pas supportée par Rocrail et doit être faite à l'extérieur. Par exemple avec un fichier texte .conf.

digint/user-fr.txt · Last modified: 2021/07/20 16:19 by phil45