Sp@r0 Posté(e) le 12 juillet 2012 Partager Posté(e) le 12 juillet 2012 (modifié) Bonjour, Je crée ce topic pour vous présenter ma nouvelle configuration domotique basé sur le fameux framework xPL-PERL, jusqu'à présent j'utilisais des scripts maisons en python => 1 - Pourquoi changer ? Pour plusieurs raisons : - assez lourd à maintenir - difficile de rajouter des nouveaux équipements - très éparpillé (plein de logiciel différents avec des méthodes différentes ...) 2 - Le matériel Je dispose du matériel de domotique suivant : - un récepteur RFXCOM USB (dispo chez domadoo.fr ou directement chez le fabricant) - un émetteur RFXCOM USB (dispo chez domadoo.fr ou directement chez le fabricant) - un émetteur/récepteur infrarouge USBUIRT (pilote la TV, le décodeur SAT, le homecinema LG) - 2 sonde de température/hydrométrie Oregon - 1 sonde de température/hydrométrie/barométrie oregon - une sonde de consomation d'electricité OWL CM113 - 6 interrupteurs télécommandés Chacoon - surement d'autres capteurs / actionneurs !!!! 3 - Le projet J'ai donc décidé de passé du coté de xPL PERL (que plusieurs personnes du forum utilisent déjà) car ce fameux protocole xPL offre pleins d'avantages : - compatible avec à peu prés tout - permet des communications en réseaux (un cluster de domotique !!!) - très polyvalent (xPL permet de loger n'importe koi même des activité processeurs, des bandes passantes ....) Je dispose d'une RaspberryPI (un pc à 27€ !!!) qui ce chargera de : - émetteur RFXCOM - récepteur RFXCOM - émetteur/récepteur USBUIRT - les actions reflex (ordre IR => allumage lampe le tous en xPL) Je dispose d'un DS110j qui ce chargera : - sauvegarde des données dans une base RRD - génération de graphiques - serveur web de suivi 4 - Installation de xPL PERL Rien de spécial j'ai suivi les tutos du forums et de Patrick'H (que je remercie au passage pour son excellent tuto), si juste de 2 remarques qui peuvent servir à d'autres pour la compilation de certains modules PERL ipkg install gcc make optware-devel aide bien, attention il manque un lien symbolique dans le paquet optware-devel : /opt/bin/arm-none-linux-gnueabi-ld -> /opt/arm-none-linux-gnueabi/bin/ld[/code] J'utilise les modules suivants : [b]xpl-hub :[/b] Le serveur xPL [b]xpl-rfxcom-rx :[/b] Récupération des trames radios [b]xpl-rfxcom-rx :[/b] Emiission des trames radios [b]xpl-rrd :[/b] Sauvegarde des valeurs en base rrd [b]xpl-rrd-graph :[/b] Génération des graphiques [b]xpl-lirc :[/b] Emission/reception Infra rouge => [b]VOIR 5[/b] [b]xpl-reflex :[/b] les actions reflex (ordre IR => allumage lampe le tous en xPL) => [b]VOIR 6[/b] [b]xpl-domo : [/b]serveur web domotique => [b]VOIR 7[/b] [size=5][b]5 - XPL-LIRC[/b][/size] Déjà il faut installé LIRC !!! il vaut mieux le compilé à partir des sources car il faut le module usb_uirt_raw qui n'est pas sélectionné dans ipkg Alors xpl-lirc est inclus dans xPL-PERL, mais il ne permet que de recevoir et pas d'émettre !!! Alors j'ai un peut modifier le fichier LIRC.pm de xpl-perl pour que cela marche dans les 2 sens : [code] package xPL::Dock::LIRC; =head1 NAME xPL::Dock::LIRC - xPL::Dock plugin for an LIRC client =head1 SYNOPSIS use xPL::Dock qw/LIRC/; my $xpl = xPL::Dock->new(); $xpl->main_loop(); =head1 DESCRIPTION This L<xPL::Dock> plugin adds an LIRC client. =head1 METHODS =cut use 5.006; use strict; use warnings; use English qw/-no_match_vars/; use xPL::IOHandler; use xPL::Dock::Plug; our @ISA = qw(xPL::Dock::Plug); our %EXPORT_TAGS = ( 'all' => [ qw() ] ); our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); our @EXPORT = qw(); our $VERSION = qw/$Revision$/[1]; __PACKAGE__->make_readonly_accessor($_) foreach (qw/server/); =head2 C<getopts( )> This method returns the L<Getopt::Long> option definition for the plugin. =cut sub getopts { my $self = shift; $self->{_server} = '/dev/lircd'; return ( 'lirc-verbose+' => \$self->{_verbose}, 'lirc-server=s' => \$self->{_server}, ); } =head2 C<init(%params)> =cut sub init { my $self = shift; my $xpl = shift; $self->SUPER::init($xpl, @_); $self->{_io} = xPL::IOHandler->new(xpl => $self->{_xpl}, verbose => $self->verbose, device => $self->{_server}, port => 8765, input_record_type => 'xPL::IORecord::LFLine', output_record_type => 'xPL::IORecord::LFLine', reader_callback => sub { $self->lirc_reader(@_) }); # Add a callback to receive incoming xPL messages (Sp@r0 edit) $xpl->add_xpl_callback(id => 'xpl-remote', callback => \&xpl_remote, arguments => $self, filter => { message_type => 'xpl-cmnd', schema => 'remote.basic', }); return $self; } =head2 C<lirc_reader( )> This callback reads data from the LIRC server. =cut sub lirc_reader { my ($self, $msg) = @_[0,2]; $self->info($msg,"\n"); if ($msg->raw =~ m!^\S+ \S{2} (\S+) (\S+)!) { my $device = lc($2); my $key = lc($1); my %args = ( message_type => 'xpl-trig', schema => 'remote.basic', body => [ device => $device, 'keys' => $key ], ); $self->info("Sending $device $key\n"); return $self->xpl->send(%args); } return 0; } # LIRC IR code SEND_ONCE code (Sp@r0 edit) sub xpl_remote { my %p = @_; my $msg = $p{message}; my $self = $p{arguments}; #$self->info("Détection d'une commande IR\n"); #$self->info("Device : ",$msg->field('device') ,"\n"); #$self->info("Keys : ",$msg->field('keys') ,"\n"); $self->{_io}->write("SEND_ONCE ".$msg->field('device')." ".$msg->field('keys')); $self->{_io}->write_next(); } 1; __END__ =head1 EXPORT None by default. =head1 SEE ALSO xPL::Dock(3), lircd( Project website: http://www.xpl-perl.org.uk/ LIRC website: http://www.lirc.org/ =head1 AUTHOR Mark Hindess, E<lt>soft-xpl-perl@temporalanomaly.comE<gt> =head1 COPYRIGHT Copyright (C) 2008, 2009 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 [/code] [size=5][b]6 - XPL-REFLEX[/b][/size] Récupération de messages xPL pour générer des commandes xPL, accessoirement il génere une sonde de puissance à partir de ma sonde de courant [code] use strict; use warnings; use Getopt::Long; use Pod::Usage; use xPL::Client; $|=1; # autoflush helps debugging my %args = ( vendor_id => 'bnz', device_id => 'listener', ); my %opt = (); my $verbose; my $interface; my $help; my $man; my $verbose_head; my $verbose_body; 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); # 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 all incoming xPL messages $xpl->add_xpl_callback(id => "reflex", self_skip => 0, targeted => 0, callback => \&reflex, filter => "@ARGV"); # Run the main loop print "===== DEBUT du programme =====\n"; $xpl->main_loop(); # The callback to log the incoming messages sub reflex { my %p = @_; my $msg = $p{message}; my $schema = $msg->schema; # GESTION DE LA TOUCHE ROUGE EN MODE TV if ($schema eq 'remote.basic' && $msg->field('device') eq 'samsungshd85' && $msg->field('keys') eq 'key_red') { print "Détection touche Rouge mode TV\n"; $xpl->send_from_string("-m xpl-cmnd -c homeeasy.basic address=0x3ec312 unit=0 command=on"); } # GESTION DE LA TOUCHE VERTE EN MODE TV if ($schema eq 'remote.basic' && $msg->field('device') eq 'samsungshd85' && $msg->field('keys') eq 'key_green') { print "Détection touche Verte mode TV\n"; $xpl->send_from_string("-m xpl-cmnd -c homeeasy.basic address=0x3ec312 unit=0 command=off"); } # GESTION DE LA TOUCHE JAUNE EN MODE TV if ($schema eq 'remote.basic' && $msg->field('device') eq 'samsungshd85' && $msg->field('keys') eq 'key_yellow') { print "Détection touche Jaune mode TV\n"; $xpl->send_from_string("-m xpl-cmnd -c homeeasy.basic address=0x3ec312 unit=0 command=off"); $xpl->send_from_string("-m xpl-cmnd -c homeeasy.basic address=0x3ec312 unit=2 command=off"); } # GESTION DE LA TOUCHE POWER EN MODE TV if ($schema eq 'remote.basic' && $msg->field('device') eq 'samsungshd85' && $msg->field('keys') eq 'key_power') { print "Détection touche Power mode TV\n"; $xpl->send_from_string("-m xpl-cmnd -c homeeasy.basic address=0x3ec312 unit=2 command=on"); } # GESTION DE LA TOUCHE RECORD EN MODE TV if ($schema eq 'remote.basic' && $msg->field('device') eq 'samsungshd85' && $msg->field('keys') eq 'key_record') { print "Détection touche Record mode TV\n"; $xpl->send_from_string("-m xpl-cmnd -c homeeasy.basic address=0x3ec312 unit=1 command=off"); } # GESTION DE LA PUISSANCE EDF if ($schema eq 'sensor.basic' && $msg->field('device') eq 'electrisave.06' && $msg->field('type') eq 'current') { print "Détection infos de courant\n"; #print "Courant : ".$msg->field('current')."\n"; #print "Puissance : ".($msg->field('current')*240)."\n"; $xpl->send_from_string("-m xpl-trig -c sensor.basic device=owlcm113 type=energy current=".($msg->field('current')*240)." units=W"); } return 1; }; # send a "hbeat.end" message on exit END { defined $xpl && $xpl->send_hbeat_end(); } [/code] [size=5][b]7 - XPL-DOMO[/b][/size] Un premier jet de serveur qui gère 3 fonctions: http://localhost:8080/xplPOST => affiche un formulaire pouvant émettre tt ordre du schéma remote.basic et homeeasy.basic http://localhost:8080/xplTX => affiche une page html qui reçoit des ordres par des requêtes POST http://localhost:8080/www => un serveur de page static pour les images et autres [code] use strict; use warnings; # Create an xPL Client object my $xpl = xPL::Client->new( 'vendor_id' => 'sparo', 'device_id' => 'sender', 'interface' => 'eth0', ) or die "Failed to create xPL::Client\n"; # Tableau d'arguments pour le schema remote.basic my %xpl_msg_remote = ( '-m' => '', '-c' => '', 'device' => '', 'keys' => '', ); # Tableau d'arguments pour le schema homeeasy.basic my %xpl_msg_homeeasy = ( '-m' => '', '-c' => '', 'address' => '', 'unit' => '', 'command' => '', ); # Catch du signal de terminaison pour arrêter le serveur enfant my $pid = 0; use sigtrap 'handler' => \&cleanAndExit, 'INT', 'ABRT', 'QUIT', 'TERM'; # # SUB Class gérant le serveur WEB en perl # { package MyWebServer; use HTTP::Server::Simple::Static; use base qw(HTTP::Server::Simple::CGI); use xPL::Client; my %dispatch = ( '/xplTX' => \&resp_xplTX, '/xplRX' => \&resp_xplRX, '/xplPOST' => \&resp_xplPOST, ); # # SUB qui recupere la requete # sub handle_request { my $self = shift; my $cgi = shift; my $path = $cgi->path_info(); my $handler = $dispatch{$path}; # Cherche si c'est du static if ($path =~ m{^/xPLrrdgraph/} or $path =~ m{^/www/} or $path eq '/style.css') { return $self->serve_static($cgi, "/volume1/DevZ/DomoZ/xpl-domo" ); } else { # Cherche si c'est une page cgi if (ref($handler) eq "CODE") { print "HTTP/1.0 200 OK\r\n"; $handler->($cgi); } else { # Ni l'un ni l'autre !!! print "HTTP/1.0 404 Not found\r\n"; print $cgi->header, $cgi->start_html('Not found'), $cgi->h1('Not found'), $cgi->end_html; } } } # # SUB qui gére le serveur d'envoi # sub resp_xplTX { my $cgi = shift; # CGI.pm object my $record; return if !ref $cgi; # Demarrage de la page print $cgi->header, $cgi->start_html('Envoi de commande xPL'); # Lecture du template HTML open (MYFILE, "xPLTX.xhtml") or die "cannot open < xPLTX.xhtml: $!";; while ($record = <MYFILE>) { print $record; } close(MYFILE); # Gestion de le requete POST if ($cgi->param()) { if ($cgi->param('schema') eq "homeeasy.basic") { print "<b>Commande xPL :</b> -m xpl-cmnd -c ".$cgi->param('schema')." address=".$cgi->param('address')." unit=".$cgi->param('unit')." command=".$cgi->param('command'); $xpl_msg_homeeasy{'-m'} = 'xpl-cmnd'; $xpl_msg_homeeasy{'-c'} = $cgi->param('schema'); $xpl_msg_homeeasy{'address'} = $cgi->param('address'); $xpl_msg_homeeasy{'unit'} = $cgi->param('unit'); $xpl_msg_homeeasy{'command'} = $cgi->param('command'); $xpl->send_from_arg_list(%xpl_msg_homeeasy); } if ($cgi->param('schema') eq "remote.basic") { print "<b>Commande xPL :</b> -m xpl-cmnd -c ".$cgi->param('schema')." device=".$cgi->param('device')." keys=".$cgi->param('keys'); $xpl_msg_remote{'-m'} = 'xpl-cmnd'; $xpl_msg_remote{'-c'} = $cgi->param('schema'); $xpl_msg_remote{'device'} = $cgi->param('device'); $xpl_msg_remote{'keys'} = $cgi->param('keys'); $xpl->send_from_arg_list(%xpl_msg_remote); } print $cgi->end_html; } } # # SUB qui gére le serveur de reception # sub resp_xplPOST { my $cgi = shift; # CGI.pm object return if !ref $cgi; print $cgi->header, $cgi->start_html('Envoi de commande xPL'), $cgi->h1("Envoi de commande xPL"), $cgi->start_form; print "<b>Type de schema (remote.basic, homeeasy.basic) :</b>", $cgi->textfield('schema'); print "<b><br>Device (remote.basic) :</b>", $cgi->textfield('device'); print "<b><br>Keys (remote.basic) :</b>", $cgi->textfield('keys'); print "<b><br>Address (homeeasy.basic) :</b>", $cgi->textfield('address'); print "<b><br>Unit (homeeasy.basic) :</b>", $cgi->textfield('unit'); print "<b><br>Command (homeeasy.basic) :</b>", $cgi->checkbox_group(-name=>'command', -values=>['on','off'], -defaults=>['']); print "<br><br>", $cgi->submit, $cgi->end_form; if ($cgi->param()) { if ($cgi->param('schema') eq "homeeasy.basic") { print "<b>Commande xPL :</b> -m xpl-cmnd -c ".$cgi->param('schema')." address=".$cgi->param('address')." unit=".$cgi->param('unit')." command=".$cgi->param('command'); $xpl_msg_homeeasy{'-m'} = 'xpl-cmnd'; $xpl_msg_homeeasy{'-c'} = $cgi->param('schema'); $xpl_msg_homeeasy{'address'} = $cgi->param('address'); $xpl_msg_homeeasy{'unit'} = $cgi->param('unit'); $xpl_msg_homeeasy{'command'} = $cgi->param('command'); $xpl->send_from_arg_list(%xpl_msg_homeeasy); } if ($cgi->param('schema') eq "remote.basic") { print "<b>Commande xPL :</b> -m xpl-cmnd -c ".$cgi->param('schema')." device=".$cgi->param('device')." keys=".$cgi->param('keys'); $xpl_msg_remote{'-m'} = 'xpl-cmnd'; $xpl_msg_remote{'-c'} = $cgi->param('schema'); $xpl_msg_remote{'device'} = $cgi->param('device'); $xpl_msg_remote{'keys'} = $cgi->param('keys'); $xpl->send_from_arg_list(%xpl_msg_remote); } print $cgi->end_html; } } } # Interception du kill et ctrl-c sub cleanAndExit(){ print "Caught a kill signal, cleaning up and exiting\n"; kill(9, $pid); exit(1); } # start the server on port 8080 $pid = MyWebServer->new(8080)->background; print "Serveur HTTP : START pid $pid\n"; # Run xPL main loop print "Serveur xPL : START\n"; $xpl->main_loop(); [/code] CONCLUSION Premièrement désolé pour ce topic fleuve !!! mais je me suis dit que cela aiderais peut être quelqu'un un jour ou l'autre :) J'aurais bien aimé avoir ce genre d'exemple car le PERL c'est bien mais pas beaucoup de documentation et d'exemple disponible sur le WEB ..... Voilà je vais essayer de créer qq chose de relativement propre pour être facilement réutilisable et modifiable :) Modifié le 12 juillet 2012 par Sp@r0 0 Citer Lien vers le commentaire Partager sur d’autres sites More sharing options...
PatrickH Posté(e) le 13 juillet 2012 Partager Posté(e) le 13 juillet 2012 Un grand BRAVO pour cette réalisation et comme d'habitude c'est clair net et précis...et merci pour le partage de ces informations Patrick 0 Citer Lien vers le commentaire Partager sur d’autres sites More sharing options...
totovaauski Posté(e) le 13 juillet 2012 Partager Posté(e) le 13 juillet 2012 bonsoir si "fleuve" veut dire "partage", M.Sp@ro est digne de l'Amazone, je me ralie a PatrickH pour te feliciter et te remercier. cordialement 0 Citer Lien vers le commentaire Partager sur d’autres sites More sharing options...
Messages recommandés
Rejoindre la conversation
Vous pouvez publier maintenant et vous inscrire plus tard. Si vous avez un compte, connectez-vous maintenant pour publier avec votre compte.