Aller au contenu

Domotique V2.0


Sp@r0

Messages recommandés

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(8) 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é par Sp@r0
Lien vers le commentaire
Partager sur d’autres sites

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.

Invité
Répondre à ce sujet…

×   Collé en tant que texte enrichi.   Coller en tant que texte brut à la place

  Seulement 75 émoticônes maximum sont autorisées.

×   Votre lien a été automatiquement intégré.   Afficher plutôt comme un lien

×   Votre contenu précédent a été rétabli.   Vider l’éditeur

×   Vous ne pouvez pas directement coller des images. Envoyez-les depuis votre ordinateur ou insérez-les depuis une URL.

×
×
  • Créer...

Information importante

Nous avons placé des cookies sur votre appareil pour aider à améliorer ce site. Vous pouvez choisir d’ajuster vos paramètres de cookie, sinon nous supposerons que vous êtes d’accord pour continuer.