Le boîtier RFXCOM, en version LAN (connecté par prise RJ-45 et non par USB), modèle RFXCOM Récepteur LAN RF 433.92 + 310-Mhz, 1 interface COM que j’avais acheté en 2008 traînait depuis quelques temps dans un placard, n’étant pas compatible avec OpenHAB 1.x. La version 2.0.x a apporté une compatibilité partielle, actuellement cassée en version 2.1.x.

Afin de recabler ces sondes en y passant le moins de temps possible, il a donc été nécessaire de reconfigurer un hub xPL et d’ajouter un script PERL pour convertir les événements xPL en topics MQTT, auxquels OpenHAB sera abonné.

Installation

Construction du container :

  • on part d’une base ALPINE embarquant déjà une installation de PERL + CPAN
  • on installe et on compile le package xpl-perl et ses dépendances
  • la configuration provient de variables d’environnement (utilisées par le shell et le perl lancés au démarrage), et peuvent se surcharger au lancement du container via -e
  • le script de démarrage est chargé de lancer :

    • le hub xPL
    • le script xpl-perl-rx (réceptions d’événements RFXCOM et émission de ces derniers en tant que messages xPL)
    • un script PERL créé pour l’occasion, chargé de réceptionner ces événements xPL et de les forwarder en MQTT.

Plusieurs alternatives auraient pu être envisagées mais se sont révèlent toutes problématiques :

  • intégration directe du RFXCOM en version LAN dans OpenHAB : actuellement impossible (voir : )
  • intégration directe du hub xPL dans OpenHAB : le binding xPL n’a jamais été porté en version OpenHAB 2.x
  • création d’un script PERL qui lirait les événements RFXCOM et les forwarderait directement vers OpenHAB, sans passer par la couche xPL (la couche xPL n’apporte ici rien du tout !) : serait tout à fait possible, mais me semblait un peu plus de taf niveau écriture (pour la partie lecture des événements xPL / conversion des trames)

Le container se crée à l’aide du Dockerfile suivant :

FROM    scottw/alpine-perl 

ENV     XPL_HOSTNAME "xpl2mqtt" 
ENV     MQTT_INTERFACE eth0 
ENV     MQTT_HOSTNAME 192.168.8.4 
ENV     MQTT_PORT 1883 
ENV     RFXCOM_HOSTNAME 192.168.8.13 
ENV     RFXCOM_PORT 10001 

ADD     start.sh /opt/ 
ADD     xpl-to-mqtt.pl /opt/ 

CMD     /opt/start.sh 

RUN     apk update && apk add git curl tar bash make perl && \ 
        cd /opt && \ 
        git clone https://github.com/beanz/xpl-perl && \ 
        cd xpl-perl && cpan install YAML::Syck AnyEvent Date::Parse Module::Pluggable Sub::Name AnyEvent::RFXCOM::RX  AnyEvent::MQTT && \ 
        perl Makefile.PL && make && make install && \ 
        chmod a+x /opt/*.sh 

WORKDIR /opt/ 

Les commandes xpl pour 1) démarrer le hub, 2) éventuellement démarrer le logger (debug), 3) démarrer la connexion sur le RFXCOM sont :

xpl-hub       -i ${MQTT_INTERFACE} --define broadcast=0.0.0.0 -v &
# xpl-logger  -i ${MQTT_INTERFACE} --define broadcast=0.0.0.0 -v &
xpl-rfxcom-rx -i ${MQTT_INTERFACE} --define broadcast=255.255.255.255 -v --rfxcom-rx-verbose --rfxcom-rx-baud 9600 --rfxcom-rx-tty ${RFXCOM_HOSTNAME}:${RFXCOM_PORT}

Le container se lance classiquement via :

docker run -d --restart=always -v $(realpath /etc/localtime):/etc/localtime:ro -v /home/datas/docker-config/openhab2/etc/timezone:/etc/timezone:ro --name xpl-to-mqtt xpl-to-mqtt 

Script PERL

Ce script reçoit les événements XPL et les republie vers MQTT.

L’usage de Net::MQTT::Simple entraînait des disconnect continus côté broker (mosquitto) (peut-être lié à l’absence de keep-alive), même si la reconnexion se faisait proprement, le switch sur AnyEvent::MQTT semblait dès lors préférable.

#!/usr/bin/perl -w

print("xpl-to-mqtt starting ...\n");
use strict;
use warnings;
use diagnostics;
use Getopt::Long;
use Pod::Usage;
use xPL::Client;
use AnyEvent::MQTT;
my %args = ( vendor_id => 'bnz', device_id => 'listener', );
my %opt = ();
my $verbose;
my $interface;
my $help;

GetOptions('verbose+' => \$verbose, 'interface=s' => \$interface, 'define=s' => \%opt, 'help|?|h' => \$help, ) or pod2usage(2);
$args{'interface'} = $interface if ($interface);
$args{'verbose'} = $verbose if ($verbose);

# Create an xPL Client object
my $mqtt = AnyEvent::MQTT->new("host" => $ENV{'MQTT_HOSTNAME'}, "port" => $ENV{'MQTT_PORT'}); # keep-alive can be customized as an additional parameter, see documentation
my $xpl = xPL::Client->new(%args, %opt) or die "Failed to create xPL::Client\n";

# Add a callback to receive all incoming xPL messages
$xpl->add_xpl_callback(id => "logger", self_skip => 0, targetted => 0, callback => \&log, filter => "@ARGV");

# Run the main loop
$xpl->main_loop();

# The callback to log the incoming messages
sub log {
    my %p = @_;
    my $msg = $p{message};
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);

    # Ex. de trame : xpl-stat/sensor.basic: bnz-rfxcomrx.bd5520524470 -> * thgr228n.4d/temp/15.6
    my ($ligne) = $msg->summary;

    if ($ligne =~ m/hbeat/) {
      print "Skipping heartbeat \n";
    } else {
      print "About to process [$ligne]\n";
      $ligne =~ m/.*\> \* (.*)/;
      my $id;
      my $attribute;
      my $value;
      my $dummy;
      ($id, $attribute, $value, $dummy) = split /\//, $1, 4;
      # print "  id [$id]\n";
      # print "  att [$attribute]\n";
      # print "  value [$value]\n";
      # if (defined $dummy) {
      #   print "  misc [$dummy]\n";
      # }
      my $final_id = $id =~ s/\./\//r;
      my $topic = "metrics/rfxcom/$final_id/$attribute";
      print " => pushing on [$topic], value [$value]\n";
      # $mqtt->publish("$topic", "$value");
      my $cv = $mqtt->publish(message => $value, topic => $topic, qos => 1);
      $cv->recv; # sent
    }
}

Troubleshooting

Messages non correctement décodés

Essayer de procéder à un reset de la configuration du RFXLAN : telnet <hostname> 9999 (setup mode).

# telnet 192.168.8.13 9999
Trying 192.168.8.13...
Connected to 192.168.8.13.
Escape character is '^]'.

MAC address 00204A9768C6
Software version V6.5.0.4 (070531) 

Press Enter for Setup Mode 


*** basic parameters 
Hardware: Ethernet TPI
IP addr - 0.0.0.0/DHCP/BOOTP/AutoIP, no gateway set
DHCP device name : not set

*** Security
Telnet Setup is      enabled
TFTP Download is     enabled
Port 77FEh is        enabled
ECHO is              disabled
Enhanced Password is disabled
Port 77F0h is        enabled

*** Channel 1
Baudrate 4800, I/F Mode 4C, Flow 00
Port 10001
Connect Mode : C0
Send '+++' in Modem Mode enabled
Show IP addr after 'RING' enabled
Auto increment source port disabled
Remote IP Adr: --- none ---, Port 00000
Disconn Mode : 00
Flush   Mode : 00

*** Expert
TCP Keepalive    : 45s
ARP cache timeout: 600s
Monitor Mode @ bootup : enabled
MTU Size: 1400
Alternate MAC: disabled
Ethernet connection type: auto-negotiate

Change Setup:
  0 Server
  1 Channel 1
  5 Expert
  6 Security
  7 Defaults
  8 Exit without save
  9 Save and exit            Your choice ? 

Liens :