Openhab - Configurazione del binding serial

Serial Binding

Esempio 1: comandare i relè RS485 KMTronics

Aggiungere la porta da usare (in questo caso /dev/ttyUSB2) in

/etc/defaults/openhab2

EXTRA_JAVA_OPTS="-Dgnu.io.rxtx.SerialPorts=/dev/ttyUSB0:/dev/ttyUSB2:/dev/ttyS0:/dev/ttyS2:/dev/ttyACM0:/dev/ttyAMA0"

Aggiungere

serial.items

Switch kmt "KMTronic" (light) {serial="/dev/ttyUSB2@9600"}
String toSerial "To Serial [%s]"   {serial="/dev/ttyUSB2@9600"}

Switch serve per creare il pulsante e ricevere i dati dalla seriale. String serve per trasmettere i dati sulla seriale

Il dispositivo RS485 relay controller si comanda inviando delle stringhe di 3 caratteri ASCII

Relay commands:
OFF command : FF xx 00 (HEX) or 255 xx 0 (DEC)
ON command : FF xx 01 (HEX) or 255 xx 1 (DEC)

da configurare secondo questa tabella

KMTronic commands

java usa i caratteri unicode. L'uscita deve essere quindi formattata con \u a 16 bit.

aggiungere

serial.rules

rule "kmt1_ON"
    when 
        Item kmt1 received command ON
    then
        toSerial.sendCommand("\u00FF\u0001\u0001")
end

rule "kmt1_OFF"
    when 
        Item kmt1 received command OFF
    then        
        toSerial.sendCommand("\u00FF\u0001\u0000")       
end

Il set di caratteri di default con l'installazione openhabian non gestisce i caratteri oltre 0x3F. Bisogna quindi cambiare locale in en_US ISO-8859-1. L'operazione si può fare tramite il menu di openhabian-config, ma non funziona immediatamente. Bisogna prima cancellare il file /etc/default/locale e poi usare il menu

 30 | System Settings
    32 | Set System Locale 

Esempio 2: controllare un Arduino tramite porta seriale

Sono stati collegati ad una scheda Arduino alcuni dispositivi molto comuni per verificare come si possono gestire diversi tipi di item e come passare le informazioni da una piattaforma all'altra in entrambi i versi.

In particolare:

  • NeoPixel Ring. Questo dispositivo molto comune usa un tipo di protocollo che richiede delle precise temporizzazioni. E' facilmente pilotabile tramite la libreria Fastled disponibile nell'ambiente Arduino. Viene comandato da OpenHAB tramite un item Colorwheel in RGB con valori da 0 a 255 più il numero di LED accesi da 1 a 16 (0 = tutti spenti)
  • Mini servo pilotabile tramite la libreria Servo, anche questa molto comune. Riceve da OpenHAB il comando di posizione da 0 a 180°
  • Fotoresistenza al CdS (Light Dependant Resistor). Trasmette a OpenHAB il valore di luminosità ambiente letto tramite un ADC di Arduino.

Vediamo il software dal lato Arduino. Questo rimane in ascolto sulla porta seriale (da configurare secondo il tipo di scheda Arduino utilizzata). Quando sono disponibili dati li analizza in sequenza come dati BCD separati da virgola. La stringa termina con il carriage return.

void ReadCommand(void)
{
    /*Read a command string from the serial port
    the string must follow this format:
    LedNum,red,green,blue,servo1Pos\r
    where:
    LedNum is the number of LEDs ON on the LED ring (clockwise), 0 (all OFF) to 16 (all ON)
    red, green blue are the RGB values for all the LEDs, 0 to 255
    Servo1Pos is the position of the servo, 0 to 180°
    all the values are in BCD no leading zeroes, i.e.:
    value = 128 means
    ASCII 49
    ASCII 50
    ASCII 56
    value = 64 means
    ASCII 54
    ASCII 52
    all the values are comma separated
    all values must be always sent, even if no change
    carriage return terminates the string
    */
    
    while (Serial1.available() > 0) 
    {
      digitalWrite(led,1);
      pixel = Serial1.parseInt();
      red = Serial1.parseInt();
      green = Serial1.parseInt();
      blue = Serial1.parseInt();
      servo1Pos = Serial1.parseInt();
      
      if (Serial1.read() == '\r') 
      {
        digitalWrite(led,0);
        pixel = constrain(pixel, 0, 16);
        red = constrain(red, 0, 255);
        green = constrain(green, 0, 255);
        blue = constrain(blue, 0, 255);
        servo1Pos = constrain(servo1Pos, 9, 180);
        
        gear(pixel, red, green, blue);
        
        servo1.write(servo1Pos);
      }
    }
}

Il LED ring e il servo sono pilotati con i valori acquisiti

void gear(int Pos, byte red, byte green, byte blue)
{
  if (Pos>NUM_LEDS[0])
  {
    Pos=NUM_LEDS[0];
  }
  
  for(int i=1; i<=NUM_LEDS[0]; i++)
  {
    int j=NUM_LEDS[0]-i;
    if(i<=Pos)
    {
      setPixel(j,red,green,blue);
    }
    else
    {
      setPixel(j,0,0,0);
    }
  }
  FastLED.show();
}

Sul lato OpenHAB occorre configurare la porta seriale utilizzata come descritto nel precedente esempio. Poi configurare gli item necessari:

String Arduino "Light [%s]"  (arduino) {serial="/dev/ttyUSB3@9600"}

Dimmer LedRingPos "LED Ring"  (arduino)
Color LedRingColor "Color [%s]"  (arduino) 

Dimmer Servo1 "Servo"  (arduino)

String toSerialTTL "LED Ring [%s]"   {serial="/dev/ttyUSB3@9600"}
  • L'item 'Arduino' serve per ricevere i dati in formato stringa dalla scheda esterna relativi alla luce ambiente.
  • L'item 'LedRingPos' serve per trasmette il numero di LED che devono essere accesi nell'anello.
  • L'item 'LedRingColor' è di tipo Color, specifico per gestire i valori di colore in HSB.
  • L'item 'Servo1' è ancora di tipo dimmer per regolare la posizione del servo.
  • L'item 'toSerialTTL' non sarà visualizzato, serve solo per inviare la stringa di comandi ad Arduino sulla seriale.

Per formattare i dati da e per la scheda esterna occorre usare alcune regole

Quando si cambia il colore tramite la colorwheel lo stato dell'item LedRingColor acquisisce i valori in una variabile di tipo hsb. Dal momento che al LED ring interessano i valori in RGB da 0 a 255, devono essere presi i metodi red, green, blue (in percentuale) e moltiplicati per 2.55. Poi formattati come stringa BCD comma delimited ed inviati sulla seriale.

var HSBType hsb
var RingPos = 0.0
var red = 0
var green = 0
var blue = 0
var Servo1Pos = 0.0

rule "HSBtoRGB"
    when
        Item LedRingColor changed
    then
        hsb = LedRingColor.state as HSBType
        red   = (hsb.red * 2.55).intValue
        green = (hsb.green * 2.55).intValue
        blue  = (hsb.blue * 2.55).intValue
        
        toSerialTTL.sendCommand(RingPos+","+red+","+green+","+blue+","+Servo1Pos+"\r")
end

Per regolare il numero di led accesi sull'anello di usa un item di tipo dimmer, che genera un valore da 0 a 100. Dividendolo per 6.25 si ottiene un range da 0 a 16.

rule "Led Ring Pos"
    when
        Item LedRingPos changed
    then
        RingPos = ((LedRingPos.state as DecimalType) / 6.25).intValue
        toSerialTTL.sendCommand(RingPos+","+red+","+green+","+blue+","+Servo1Pos+"\r")
end

In modo simile il valore del dimmer Servo1 viene moltiplicato per 1.8 per ottenere un range da 0 a 180.

rule "Servo1 Pos"
    when
        Item Servo1 changed
    then
        Servo1Pos = ((Servo1.state as DecimalType) * 1.8).intValue
        toSerialTTL.sendCommand(RingPos+","+red+","+green+","+blue+","+Servo1Pos+"\r")
end

Il valore ricevuto dall'Arduino, corrispondente alla luminosità, deve essere convertito in variabile numerica per essere utilizzato. Per fare questo occorre prima convertire lo stato dell'item in stringa, poi convertire il valore BCD della stringa in integer. A questo punto si può usare come confronto per, ad esempio, accendere uno dei relè KMTronic descritti in precedenza quando la luce scende sotto una soglia stabilita.

rule "LDR"
    when 
        Item Arduino changed
    then
        var LightStr = Arduino.state.toString
        var Light = new java.math.BigDecimal(Integer::parseInt(LightStr))
        
        if (Light > 800)
        {
            toSerial.sendCommand("\u00FF\u0001\u0001")
        }
        else
        {
            toSerial.sendCommand("\u00FF\u0001\u0000")
        }
        
end

Per utilizzare questi oggetti occorre definirli nel nostro sitemap.

  • Text item=Arduino - mostra il valore letto dalla LDR (0-1024)
  • Slider item=LedRingPos - regola il numero di LED accesi sull'anello
  • Colorpicker item=LedRingColor - regola il colore e la luminositò dell'anello di LED
  • Slider item=Servo1 - regola la posizione del servo
 Frame label="Serial"
    {
        Text label="Arduino" icon=sensor
        {
            Text item=Arduino
            Slider item=LedRingPos 
            Colorpicker item=LedRingColor
            Slider item=Servo1 
        }
    }

TIP

A volte succede che il valore di un item presentato sulla finestra non viene aggiornato al variare dello stesso. Quando succede questo si può notare nella karaf console di OpenHAB che il servizio PageChangeListener.get si è chiuso a causa di un errore indefinito di lettura del file sitemap, avvenuto durante il salvataggio del file stesso. Per ripristinare il normale funzionamento occorre riavviare OpenHAB:

sudo systemctl restart openhab2

Guido Ottaviani (Autore/Progettista elettronico-firmware-robotica)
Si occupa della progettazione elettronica e del firmware di sistemi embedded per la Robotica e applicazioni industriali e civili oltre che di divulgazione tecnica su internet.
http://www.guiott.com - https://github.com/guiott - guido@guiott.com



Le attività del TanzoLab si svolgono ogni mercoledi sera, salvo casi speciali, dalle ore 18:30 presso i locali della Acme Systems srl e consistono in:

  • Talk monotematici a cura di professionisti in vari settori tecnologici
  • Workshop pratici su elettronica embedded, produzione e informatica
  • Progettazione e realizzazione di nuovi prodotti embedded per l'IT

Le attività vengono coordinate tramite questo sito, in cui vengono pubblicati tutti i lavori svolti o in via di sviluppo, e tramite un gruppo Telegram con cui per interagire direttamente via chat con gli altri membri.