Xpl
De MicElectroLinGenMet.
Sommaire |
Protopole xPL
Source Wikipedia: http://en.wikipedia.org/wiki/XPL_Protocol
XPL (eXtremely Simple Protocole) est un protocole ouvert destiné à permettre le contrôle et la surveillance des appareils de domotique. Les principaux buts du protocol XPL est de fournir un ensemble riche de fonctionnalités, tout en maintenant une structure de message simple. Le protocole permet une auto-découverte et une auto-configuration des capacités des dispositifs se qui le rend "plug-n-play".
Site du projet xPL, en anglais, http://wiki.xplproject.org.uk/
xPL Linux C library
Lien: http://www.xpl4java.org/xPL4Linux/
Voir le programme C Xpl-vmc.c comme exemple (à améliorer) d'utilisation de la xPLLib C ainsi que de la lib OWfs.
xPL Perl API
Lien: https://github.com/beanz/xpl-perl/
Installation sous Debian, rajouter ce dépot dans /etc/apt/sources.list:
deb http://debian.temporalanomaly.com/ squeeze main
Programmes fournis avec l'API
xpl-bridge xpl-hub xpl-packet-trace xpl-sms-send xpl-clock xpl-hub.origine xpl-perl-setup xpl-tty-tcp xpl-ctx35 xpl-lcdproc xpl-prog.sh xpl-udin xpl-currentcost xpl-linux-cpu xpl-rfxcom xpl-viom xpl-dawndusk xpl-lirc xpl-rfxcom.origine xpl-w800 xpl-dg834 xpl-logger xpl-rfxcom-trans xpl-x10 xpl-dmx xpl-monitor xpl-rrd xpl-xosd xpl-hddtemp xpl-mpd xpl-rrd-graphs xpl-xvkbd xpl-heyu-helper xpl-owfs xpl-sender
Dans la version 0.09-1, un leger bug empêche le lancement des programmes xpl.
$ xpl-hub -i eth0 -v xPL::Hub->new: Unable to detect interface eth0 at /usr/share/perl5/xPL/Hub.pm line 87.
Le problème est du à la version française de Linux, la commande ifconfig utilisée par l'API xpl ne retrouve pas les paramètres voulus si la sortie est francisée.
La solution temporaire consiste à lancé un export LANG=C avant toute commande xpl-perl.
Le bug ne semble plus être présent dans la version SVN.
Exemples d'utilisation
- xpl-sender
/usr/bin/xpl-sender -c osd.basic command=write text="$(date)" row=1
Permet d'envoyer des messages xPL.
- xpl-lirc
/usr/bin/xpl-lirc -i eth0
Ce met à l'écoute du daemon Lirc et envoie un message xPL lors de la réception de la télécommande.
Messages xPL reçus avec xPL_Logger:
09/06/27 12:25:56 xpl-trig {bnz-lirc.vesta *} remote.basic { keys='ok' device='terratec_cinergy_1400' } 09/06/27 12:28:49 xpl-trig {bnz-lirc.vesta *} remote.basic { keys='left' device='terratec_cinergy_1400' } 09/06/27 12:28:50 xpl-trig {bnz-lirc.vesta *} remote.basic { keys='ok' device='terratec_cinergy_1400' }
- xpl-rrd
/usr/bin/xpl-rrd -i eth0 /home/xpl/rrd
Ce script est un client XPL qui 'log' les messages connus (température, humidité, x10 ...) dans une base RRD. Il sera possible de générer des graphes avec le script xpl-rrd-graphs par intervalles réguliers.
$ /usr/bin/xpl-rrd-graphs /home/xpl/rrd /home/xpl/rrd/graphs
- xpl-owfs
/usr/bin/xpl-owfs -i eth0 -v /mnt/owfs
Ce script est un client XPL qui s'interface avec le système de fichiers owfs du bus 1-wire. Il supporte l'utilisation de messages control.basic avec les valeurs 'high', 'low' or 'pulse' pour les circuits PIO. Il envoie également des messages sensor.basic pour les sondes température, humidité, ou compteurs A ou B.
- xpl-rfxcom
/usr/bin/xpl-rfxcom -v -i eth0 -B 4800 /dev/rfxcom
Le rfxcom connecté sur un port USB permet la réception de différent protocol RF sur la fréquence 433.92MHz tel que les sondes Oregon, X10-RF, HomeEasy ...
Messages xPL reçus avec xPL_Logger:
Réception messages sondes Oregon
09/06/27 15:40:18 xpl-trig {bnz-rfxcom.vesta *} sensor.basic { device='thgr228n.ab' type='temp' current='24' } 09/06/27 15:40:18 xpl-trig {bnz-rfxcom.vesta *} sensor.basic { device='thgr228n.ab' type='humidity' current='52' string='comfortable' } 09/06/27 15:40:18 xpl-trig {bnz-rfxcom.vesta *} sensor.basic { device='thgr228n.ab' type='battery' current='90' units='%' }
09/06/27 15:40:54 xpl-trig {bnz-rfxcom.vesta *} sensor.basic { device='thwr288a.de' type='temp' current='24.6' } 09/06/27 15:40:54 xpl-trig {bnz-rfxcom.vesta *} sensor.basic { device='thwr288a.de' type='battery' current='90' units='%' }
Réception messages X10 avec la sonnette IDK ML-8300
09/06/27 15:50:33 xpl-trig {bnz-rfxcom.vesta *} x10.basic { command='on' device='o8' } 09/06/27 15:50:33 xpl-trig {bnz-rfxcom.vesta *} x10.basic { command='off' device='o8' }
Réception messages X10 (par exemple avec le montage à micro-controleur AVR)
09/06/27 10:04:51 xpl-trig {bnz-rfxcom.vesta *} x10.basic { command='on' device='a3' } 09/06/27 10:20:03 xpl-trig {bnz-rfxcom.vesta *} x10.basic { command='on' device='a4' } 09/06/27 10:49:33 xpl-trig {bnz-rfxcom.vesta *} x10.basic { command='on' device='a4' } 09/06/27 11:19:03 xpl-trig {bnz-rfxcom.vesta *} x10.basic { command='on' device='a4' }
Messages de xpl-rfxcom en mode verbeux pour la télécommande ATI Remote qui n'est pas interprétée par le programme (pas de décodage de la trame ni message xPL)
Processed: 14dc17f0 <= ATI Remote (code touches 0 à 9) Processed: 14d20df0 Processed: 14d30ef0 Processed: 14d40ff0 Processed: 14d510f0 Processed: 14d611f0 Processed: 14d712f0 Processed: 14d813f0 Processed: 14d914f0 Processed: 14da15f0
Module ATIRemote.pm
En prenant exemple sur le module X10.pm fourni avec la lib xpl-perl, j'en ai écrit un pour décoder les touches de la télécommande ATI Remote.
Il suffira de le copier dans le répertoire /usr/share/perl5/xPL/RF pour Debian et de relancer le programme xpl-rfxcom.
Le source est fourni "brut de fonderie" car je ne suis pas expert en Perl mais le module fonctionne pour moi.
Messages xPL reçus avec xPL_Logger:
09/06/27 11:16:50 xpl-trig {bnz-rfxcom.vesta *} remote.basic { keys='5' device='ATI_Remote' } 09/06/27 11:16:53 xpl-trig {bnz-rfxcom.vesta *} remote.basic { keys='6' device='ATI_Remote' } 09/06/27 11:16:55 xpl-trig {bnz-rfxcom.vesta *} remote.basic { keys='8' device='ATI_Remote' } 09/06/27 11:16:56 xpl-trig {bnz-rfxcom.vesta *} remote.basic { keys='9' device='ATI_Remote' } 09/06/27 11:16:57 xpl-trig {bnz-rfxcom.vesta *} remote.basic { keys='0' device='ATI_Remote' } 09/06/27 11:16:58 xpl-trig {bnz-rfxcom.vesta *} remote.basic { keys='check' device='ATI_Remote' } 09/06/27 11:16:59 xpl-trig {bnz-rfxcom.vesta *} remote.basic { keys='menu' device='ATI_Remote' } 09/06/27 11:17:00 xpl-trig {bnz-rfxcom.vesta *} remote.basic { keys='ok' device='ATI_Remote' } 09/06/27 11:17:09 xpl-trig {bnz-rfxcom.vesta *} remote.basic { keys='clic_right_on' device='ATI_Remote' } 09/06/27 11:17:09 xpl-trig {bnz-rfxcom.vesta *} remote.basic { keys='clic_right_off' device='ATI_Remote' } 09/06/27 11:17:11 xpl-trig {bnz-rfxcom.vesta *} remote.basic { keys='clic_left_on' device='ATI_Remote' } 09/06/27 11:17:11 xpl-trig {bnz-rfxcom.vesta *} remote.basic { keys='clic_left_off' device='ATI_Remote' } 09/06/27 11:17:13 xpl-trig {bnz-rfxcom.vesta *} remote.basic { keys='hand' device='ATI_Remote' } 09/06/27 11:17:14 xpl-trig {bnz-rfxcom.vesta *} remote.basic { keys='book' device='ATI_Remote' } 09/06/27 11:17:15 xpl-trig {bnz-rfxcom.vesta *} remote.basic { keys='web' device='ATI_Remote' } 09/06/27 11:17:16 xpl-trig {bnz-rfxcom.vesta *} remote.basic { keys='dvd' device='ATI_Remote' } 09/06/27 11:17:17 xpl-trig {bnz-rfxcom.vesta *} remote.basic { keys='tv' device='ATI_Remote' } 09/06/27 11:17:20 xpl-trig {bnz-rfxcom.vesta *} remote.basic { keys='power' device='ATI_Remote' }
Source du module
package xPL::RF::ATIRemote; # $Id$ # Dan, /usr/share/perl5/xPL/RF/ATIRemote.pm =head1 NAME xPL::RF::ATIRemote - Perl extension for decoding ATIRemote device RF messages =head1 SYNOPSIS use xPL::RF::ATIRemote; =head1 DESCRIPTION This is a module for decoding RF messages from ATIRemote devices. =head1 METHODS =cut use 5.006; use strict; use warnings; use English qw/-no_match_vars/; use xPL::Message; use Exporter; #use AutoLoader qw(AUTOLOAD); our @ISA = qw(Exporter); our %EXPORT_TAGS = ( 'all' => [ qw() ] ); our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); our @EXPORT = qw(); our $VERSION = '0.01'; our $SVNVERSION = qw/$Revision: 519 $/[1]; my $SPACE = q{ }; my %code_to_key = ( 'dc17' => '0', 'd20d' => '1', 'd30e' => '2', 'd40f' => '3', 'd510' => '4', 'd611' => '5', 'd712' => '6', 'd813' => '7', 'd914' => '8', 'da15' => '9', '3d78' => 'clic_left_on', '3e79' => 'clic_left_off', '417c' => 'clic_right_on', '427d' => 'clic_right_off', 'c803' => 'tv', 'c904' => 'dvd', 'ca05' => 'web', 'cb06' => 'book', 'cc07' => 'hand', 'c500' => 'A', 'c601' => 'B', 'c702' => 'power', '3772' => 'mouse_up', '3873' => 'mouse_down', '3671' => 'mouse_right', '3570' => 'mouse_left', '3974' => 'mouse_right_up', '3671' => 'mouse_left_up', '3b76' => 'mouse_right_down', '3c77' => 'mouse_left_down', 'ce09' => 'vol-', 'cd08' => 'vol+', 'cf0a' => 'mute', 'd10c' => 'ch-', 'd00b' => 'ch+', 'db16' => 'menu', 'dd18' => 'check', 'de19' => 'C', 'e01b' => 'D', 'df1a' => 'up', 'e722' => 'down', 'e41f' => 'right', 'e21d' => 'left', 'e31e' => 'ok', 'e621' => 'E', 'e823' => 'F', 'e11c' => 'timer', 'e520' => 'max', 'ea25' => 'play', 'ed28' => 'stop', 'e924' => 'rew', 'eb26' => 'fwd', 'ee29' => 'pause', 'ec27' => 'rec', ); =head2 C<parse( $parent, $message, $bytes, $bits )> This method attempts to recognize and parse RF messages corresponding to ATI messages. If messages are identified a reference to a list of xPL::Message objects is returned. If the message is not recognized, undef is returned. 29/05/2009 23:25:28= 14D20DF0 ATI[15]C Remote type= ATI Remote Wonder Channel= 15 Command= 1 bits=20 29/05/2009 23:25:43= 14D30EF0 ATI[15]C Remote type= ATI Remote Wonder Channel= 15 Command= 2 bits=20 29/05/2009 23:25:45= 14D40FF0 ATI[15]C Remote type= ATI Remote Wonder Channel= 15 Command= 3 bits=20 29/05/2009 23:25:48= 14D510F0 ATI[15]C Remote type= ATI Remote Wonder Channel= 15 Command= 4 bits=20 29/05/2009 23:25:48= 14D611F0 ATI[15]C Remote type= ATI Remote Wonder Channel= 15 Command= 5 bits=20 29/05/2009 23:25:49= 14D712F0 ATI[15]C Remote type= ATI Remote Wonder Channel= 15 Command= 6 bits=20 29/05/2009 23:25:51= 14D813F0 ATI[15]C Remote type= ATI Remote Wonder Channel= 15 Command= 7 bits=20 29/05/2009 23:25:52= 14D914F0 ATI[15]C Remote type= ATI Remote Wonder Channel= 15 Command= 8 bits=20 29/05/2009 23:25:52= 14DA15F0 ATI[15]C Remote type= ATI Remote Wonder Channel= 15 Command= 9 bits=20 29/05/2009 23:25:55= 14DC17F0 ATI[15]C Remote type= ATI Remote Wonder Channel= 15 Command= 0 bits=20 XPL-TRIG Structure remote.basic { keys=<button names or keycodes> - comma seperated values [device=<name or devicecode of device>] [zone=<ir zone>] } =cut sub parse { my $self = shift; my $parent = shift; my $message = shift; my $bytes = shift; my $bits = shift; $bits == 20 or return ; # 20 bits pour ATI Remote ! # printf("ATI bits %d, codes: %02x %02x %02x\n", $bits, $bytes->[0], $bytes->[1], $bytes->[2]) ; my $key = sprintf("%02x%02x", $bytes->[0], $bytes->[1]) ; # print "ATI Key: ", $key, " => ", $code_to_key{$key}, "\n" ; my %body = ( device => "ATI_Remote", keys => $code_to_key{$key}, ); return [xPL::Message->new( message_type => 'xpl-trig', class => 'remote.basic', head => { source => $parent->source, }, body => \%body, )]; } 1; __END__ =head1 EXPORT None by default. =head1 SEE ALSO Project website: http://www.xpl-perl.org.uk/ =head1 AUTHOR Domos, E<lt>domos78 at free point frE<gt> =head1 COPYRIGHT Copyright (C) 2009 by Domos This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.7 or, at your option, any later version of Perl 5 you may have available. =cut
xpl et lcdproc
- Autre programme personnel utilisant la librairie xpl-perl.
Affichage de températures remontées par xPL sur afficheur LCD comme celui-ci avec lcdproc.
Deux sondes Oregon remontent les températures salon/extérieure et une sonde DS18B20 1-wire est lu par le Wrt54gl.
- source programme perl: xpl-lcdsensors.pl
#!/usr/bin/perl -w =head1 NAME xpl-lcdsensors - Perl script for display temp. sensors en lcd with lcdproc =head1 SYNOPSIS xpl-lcdsensors [flags] [options] [filter...] where valid flags are: -h - show this help text -head - dump the head of all xPL messages -body - dump the body of all xPL messages -v - verbose client mode and valid options are (default shown in brackets): -i if0 - the interface for xPL messages (first non-loopback or loopback) =head1 DESCRIPTION Display temp. sensors on lcd with lcdproc. =cut #use strict; use warnings; use Fcntl; use Getopt::Long; use Pod::Usage; use POSIX qw/strftime/; use Time::Local; use IO::Socket; use xPL::Client; $|=1; # autoflush helps debugging my %args = ( vendor_id => 'domos', device_id => 'lcdtemp', ); my %opt = (); my $verbose; my $interface; my $help; my $man; my $verbose_head; my $verbose_body; # Paramètres lcdproc my $lcdhost = "localhost"; my $lcdport = "13666"; # Paramètres application my $lastsalontemp = 0 ; my $lastexttemp = 0 ; my $lastcongtemp = 0 ; my $minsalontemp = 99 ; my $maxsalontemp = 99 ; my $minexttemp = 99 ; my $maxexttemp = 99 ; my $mincongtemp = 99 ; my $maxcongtemp = 99 ; GetOptions('verbose+' => \$verbose, 'interface=s' => \$interface, 'define=s' => \%opt, 'help|?|h' => \$help, 'man' => \$man, 'head' => \$verbose_head, 'body' => \$verbose_body, ) or pod2usage(2); pod2usage(1) if ($help); pod2usage(-exitstatus => 0, -verbose => 2) if ($man); $args{'interface'} = $interface if ($interface); $args{'verbose'} = $verbose if ($verbose); # Connect to the lcdproc server ----------------------------------------------- my $lcd = IO::Socket::INET->new( Proto => "tcp", PeerAddr => $lcdhost, PeerPort => $lcdport, ) || die "Cannot connect to LCDproc port\n"; # Make sure our messages get there right away $lcd->autoflush(1); sleep 1; # Give server plenty of time to notice us... print $lcd "hello\n"; my $lcdresponse = <$lcd>; # Turn off blocking mode... fcntl($lcd, F_SETFL, O_NONBLOCK); # Set up some screen widgets... print $lcd "client_set name {sensors}\n"; $lcdresponse = <$lcd>; print $lcd "screen_add sensors\n"; $lcdresponse = <$lcd>; print $lcd "widget_add sensors title title\n"; $lcdresponse = <$lcd>; print $lcd "widget_set sensors title {Senseurs temp.}\n"; $lcdresponse = <$lcd>; print $lcd "widget_add sensors l1 string\n"; $lcdresponse = <$lcd>; print $lcd "widget_add sensors l2 string\n"; $lcdresponse = <$lcd>; print $lcd "widget_add sensors l3 string\n"; $lcdresponse = <$lcd>; print $lcd "backlight on\n"; $lcdresponse = <$lcd>; #print $lcd "screen_set sensors priority foreground\n"; # S'affiche devant les autres clients lcdproc. #$lcdresponse = <$lcd>; # Create an xPL Client object ------------------------------------------------ my $xpl = xPL::Client->new(%args, %opt) or die "Failed to create xPL::Client\n"; # Add a callback to receive filtered incoming xPL messages $xpl->add_xpl_callback(id => 'sensorsmsg', self_skip => 0, targetted => 0, callback => \&sensorsmsg, filter => { message_type => 'xpl-trig', class => 'sensor', class_type => 'basic', } ); # Add a timer 180s to the xPL Client event loop ... $xpl->add_timer(id => 'testtimer', timeout => 50, callback => \&tick, arguments => [$xpl]); $SIG{INT} = \&end; $SIG{TERM} = \&end; $SIG{QUIT} = \&end; # Run the main loop $xpl->main_loop(); # Traite message xPL sensor.basic. sub sensorsmsg { my %p = @_; my $msg = $p{message}; # 10/03/03 12:22:43 xpl-trig sensor.basic device='thn132n.54' type='temp' current='21' # 10/03/03 10:30:16 xpl-trig sensor.basic device='thwr288a.de' type='temp' current='6.2' # 10/03/03 12:29:55 xpl-trig sensor.basic device='28.FC1D80010000' type='temp' current='-18.4' if ($msg->device eq "thn132n.54" && $msg->type eq "temp") { $lastsalontemp = time() ; my $temp = sprintf("%.1f", $msg->current) ; if ( $temp < $minsalontemp || $minsalontemp==99) { $minsalontemp = $temp } ; if ( $temp > $maxsalontemp || $maxsalontemp==99) { $maxsalontemp = $temp } ; print $lcd "widget_set sensors l1 1 2 {S: ${temp}° $minsalontemp/$maxsalontemp }\n"; $lcdresponse = <$lcd>; } if ($msg->device eq "thwr288a.de" && $msg->type eq "temp") { $lastexttemp = time() ; my $temp = sprintf("%.1f", $msg->current) ; if ( $temp < $minexttemp || $minexttemp==99) { $minexttemp = $temp } ; if ( $temp > $maxexttemp || $maxexttemp==99) { $maxexttemp = $temp } ; print $lcd "widget_set sensors l2 1 3 {X: ${temp}° $minexttemp/$maxexttemp }\n"; $lcdresponse = <$lcd>; } if ($msg->device eq "28.FC1D80010000" && $msg->type eq "temp") { $lastcongtemp = time() ; my $temp = sprintf("%.1f", $msg->current) ; if ( $temp < $mincongtemp || $mincongtemp==99) { $mincongtemp = $temp } ; if ( $temp > $maxcongtemp || $maxcongtemp==99) { $maxcongtemp = $temp } ; print $lcd "widget_set sensors l3 1 4 {C:${temp}° $mincongtemp/$maxcongtemp }\n"; $lcdresponse = <$lcd>; } return 1; } # The callback to send the "clock.update" messages sub tick { my %p = @_; my $timetick = time() ; my $heure = strftime "%H:%M", localtime ; # Si minuit, réinit. valeur min/max. if ($heure eq '00:00') { $minsalontemp = 99 ; $maxsalontemp = 99 ; $minexttemp = 99 ; $maxexttemp = 99 ; $mincongtemp = 99 ; $maxcongtemp = 99 ; } if ( ($timetick - $lastsalontemp) > 300 ) { # Si dernière info. temp. salon > 5mn affiche message. print $lcd "widget_set sensors l1 1 2 { S: Plus à jour ! }\n"; $lcdresponse = <$lcd>; } if ( ($timetick - $lastexttemp) > 300 ) { # Si dernière info. temp. salon > 5mn affiche message. print $lcd "widget_set sensors l2 1 3 { X: Plus à jour ! }\n"; $lcdresponse = <$lcd>; } if ( ($timetick - $lastcongtemp) > 300 ) { # Si dernière info. temp. salon > 5mn affiche message. print $lcd "widget_set sensors l3 1 4 { C: Plus à jour ! }\n"; $lcdresponse = <$lcd>; } return 1; }; # send a "hbeat.end" message on exit sub end { defined $xpl && $xpl->send_hbeat_end() ; close($lcd); exit; } =head1 SEE ALSO xPL::Client(3), xPL::Listener(3) Project website: http://www.xpl-perl.org.uk/ =head1 AUTHOR Domos, E<lt>domos78@free.frE<gt> =head1 COPYRIGHT Copyright (C) 2005, 2008 by Mark Hindess This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.7 or, at your option, any later version of Perl 5 you may have available. =cut
26/6/2009