Pluviometre X10-RF

De MicElectroLinGenMet.

Sommaire

Description

Comme dans l'article Sondes i2c X10-RF où le protocole X10-RF est utilisé pour envoyer des données autres que des commandes X10, cet article décrit l'utilisation d'un Microcontroleurs Atmel AVR comme compteur sans fils de pluviomètrie. Utilisé avec le récepteur RF 433.92MHz: le rfxcom.


Mise en oeuvre

Un pluviomètre mécanique à augets comme celui-ci ou celui de la station météo Lacross technology Ws2300 déclenche un ILS à chaque bascule ce qui générera une impulsion sur une entrée du micro-controleur AVR ATtiny13.
Celui-ci incrémentera un compteur 24Bits et émettera une trame X10 contenant la valeur de ce compteur.

Aprés chaque impulsion, le microcontroleurs retournera en veille pour économiser les piles.


L'avantage d'émettre la valeur d'un compteur de déclenchement du pluviomètre au lieu d'une information de déclenchement évite de perdre des données si la réception n'a pu se faire.




Détails du codage

  • Codage personnel de la trame X10 (6 octets)
1 entête    = 0x5A:    (Octet de valeur quelconque figé servant d'entête.)
2 idcarte   = 0x62:    (Octet correspondant à un ID donné à la carte émettrice pour la différencier d'une autre.)
3 adrsensor = 0x41:    (Adr. du composant lu.)
4 data1:               (Compteur sur 3 octects.)
5 data2:
6 data3:


Le programme xpl-rfxcom-rx de la lib xpl-perl pilotant un récepteur RF 433.92MHz le rfxcom recevra une trame de type:

Processed: 305a62410000F9



Un module xpl-perl dédié (X10Sensors.pm) interprétera ces données est génèrera un message xPL sensor.basic sur le réseau.

10/09/26 14:31:08 xpl-trig {bnz-rfxcomrx.alix *} sensor.basic { device='avr_6241' type='count' current='715' }
10/09/26 14:31:13 xpl-trig {bnz-rfxcomrx.alix *} sensor.basic { device='avr_6241' type='count' current='716' }
10/09/26 14:31:18 xpl-trig {bnz-rfxcomrx.alix *} sensor.basic { device='avr_6241' type='count' current='717' }
10/09/26 14:31:24 xpl-trig {bnz-rfxcomrx.alix *} sensor.basic { device='avr_6241' type='count' current='718' }


Shéma électronique

La led s'allume à chaque émission. Elle pourra être enlevé pour économiser les piles.




Photos du montage en test

Pluviometre et montage
Vue du montage sur plaquette



Programmes sources



/*  Emetteur x10_RF_Tx_Data */
/* Par domos78 at free point fr */
 
/*
 Envoi valeur compteur sur 24bits incrémenté par interruption sur INT0
 Testé avec pluviomètre, à tester sur compteur d'eau.
 
 Ajout. script PERL /usr/share/perl5/xPL/RF/X10Sensors.pm pour décoder trame
 en message xPL
*/
 
 
/* 
====================================================================================
 Copyright (C) Domos, domos78 at free point fr
 Ce programme est libre, vous pouvez le redistribuer et/ou le modifier selon	
 les termes de la Licence Publique Générale GNU publiée par la Free Software
 Foundation (version 2 ou bien toute autre version ultérieure choisie par vous).
 
 Ce programme est distribué car potentiellement utile, mais SANS AUCUNE
 GARANTIE, ni explicite ni implicite, y compris les garanties de
 commercialisation ou d'adaptation dans un but spécifique. Reportez-vous à la
 Licence Publique Générale GNU pour plus de détails.
 
 Vous devez avoir reçu une copie de la Licence Publique Générale GNU en même
 temps que ce programme. Si ce n'est pas le cas, écrivez à la Free Softwar
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, États-Unis
====================================================================================
*/ 
 
 
/* 15/09/2010	  								
1 entête:	(Octet de valeur quelconque figé servant d'entête.)
2 idcarte:	(Octet correspondant à un ID donné à la carte émettrice pour la différencier d'une autre.)
3 adrsensor:	(Adr. (i2c ou autre) du composant lu.)
4 data1:	(Donnée lu sur le composant limité à 3 octets.)
5 data2:
6 data3:
 
Réception avec xpl-rfxcom-rx:
Processed: 305a62410000F9
 
Log xPL:
10/09/25 23:21:03 xpl-trig {bnz-rfxcomrx.alix *} sensor.basic { device='avr_6241' type='count' current='249' }
10/09/25 23:21:05 xpl-trig {bnz-rfxcomrx.alix *} sensor.basic { device='avr_6241' type='count' current='250' }
10/09/25 23:21:07 xpl-trig {bnz-rfxcomrx.alix *} sensor.basic { device='avr_6241' type='count' current='251' }
*/
 
 
/* ============================================================================== */
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
 
// ATTiny13's internal oscillator defaults to 9.6 MHz. Prescaler set to divide by 8 (9.6/8=1.2MHz).
#define F_CPU 1200000UL
#include <util/delay.h>
 
// Attention PORTB pour l'écriture et PINB pour la lecture.
#define INT0PIN PB1		// Bit du port INT0.
#define INT0PORT PINB		// Port de l'entrée INT0.
#define X10PIN PB3		// Bit du port sur lequel est connectée la pin x10.
#define X10PORT PORTB		// Port de la sortie X10.
#define LEDPIN PB4		// Bit du port sur lequel est connectée la LED.
#define LEDPORT PORTB		// Port de la sortie LED.
 
#define NBTRAMES 0x06
 
#define ENTETE 0x5A
#define IDCARTE 0x62
#define ADR 0x41
 
// Macros
#define setbit(PORT, BIT)	{ PORT |= _BV(BIT); }
#define clrbit(PORT, BIT)	{ PORT &= ~_BV(BIT); }
#define togbit(PORT, BIT)	{ PORT ^= _BV(BIT);  }
 
#define Led_Off()		{ setbit(LEDPORT, LEDPIN); }
#define Led_On()		{ clrbit(LEDPORT, LEDPIN); }
 
// --------------------------------------------------------------------------------------
// Compteur 24 bits
uint8_t compteur1 = 0 ;
uint8_t compteur2 = 0 ;
uint8_t compteur3 = 0 ;
unsigned char data[4] ;
 
// -------------------------------------- Fonctions X10 ---------------------------------
// Envoi entête:
void x10_sendpreamble(void)
{
	clrbit(X10PORT, X10PIN) ;		// X10PIN à 0.
	_delay_ms(40) ;
	setbit(X10PORT, X10PIN) ;		// X10PIN à 1.
	_delay_ms (9) ;
	clrbit(X10PORT, X10PIN) ;		// X10PIN à 0.
	_delay_ms(4) ;
	_delay_us(500) ;
}
 
// --------------------------------------------------------------------------------------
// Envoi bit:
void x10_sendbit(void)
{
	setbit(X10PORT, X10PIN) ;		// X10PIN à 1.
	_delay_us(560) ;
	clrbit(X10PORT, X10PIN) ;		// X10PIN à 0.
	_delay_us(560) ;
}
 
 
// --------------------------------------------------------------------------------------
// Envoi d'un octet X10 RF
void x10_sendbyte(unsigned char X10octet)
{
	unsigned char nobit, valbit;
	for (nobit=0; nobit<=7; nobit++)
	{
		valbit=X10octet & 0x80;
		X10octet=(X10octet << 1);
 
		x10_sendbit();				// On envoi un bit
		if ( valbit )				// Si bit à 1 pause + longue.
		{
			_delay_us(600) ;
			_delay_us(600) ;
		}
	}
}
 
// --------------------------------------------------------------------------------------
// Envoie trame X10, data
void x10_senddata(unsigned char adr, unsigned char *buff)
{
	unsigned char bcle ;
 
	// Envoie data X10 .
	for (bcle = 0; bcle < NBTRAMES; bcle++)			// Envoie la trame NBTRAMES X.
	{
		x10_sendpreamble() ;
		x10_sendbyte(ENTETE) ;		// entete
		x10_sendbyte(IDCARTE) ;		// idcarte
		x10_sendbyte(adr) ;		// adr
		x10_sendbyte(buff[2]) ;		// data3
		x10_sendbyte(buff[1]) ;		// data2
		x10_sendbyte(buff[0]) ;		// data1
		x10_sendbit() ;
	}
}
 
// --------------------------------------------------------------------------------------
// Pause de n secondes
void delay_s(unsigned short sec)
{
	sec*=10 ;
	while(sec > 0)
	{
		_delay_ms(100) ;		// _delay_ms pas précise pour valeur trop grande.
		--sec ;
	}
}
 
// ----------------------------- Interruption INT0 --------------------------------------
ISR(INT0_vect)						// Fonction interruption
{
	sleep_disable() ;				// Clear the SE (sleep enable) bit. 
	_delay_ms(200) ;				// Pause pour debouncing
 
	compteur1++ ;
	if ( ! compteur1 )				// Incrémente compteurs suivants si débordement.
	{
		compteur2++ ;
		if ( ! compteur2 ) compteur3++ ;
	}
	do ;
	while ( bit_is_clear(INT0PORT, INT0PIN) ) ;	// Attends que ILS passe à l'état OFF 
							// (peut poser problème avec un compteur d'eau si ILS bloqué 'ON' car uC ne se met pas en veille.)
}
 
// --------------------------------------------------------------------------------------
// -------------------------------------- Main ------------------------------------------
int main(void) 
{
	// Init. PORT
	setbit(DDRB, X10PIN) ;			// X10PIN en sortie.
	setbit(DDRB, LEDPIN) ;			// LEDPIN en sortie.
 
	clrbit(X10PORT, X10PIN) ;		// X10PIN à 0.
 
	// Init. INT0 (Réveille aprés "power-down" uniquement en mode low level de INT0)
	MCUCR &=  ~( _BV(ISC01) | _BV(ISC00) ) ;	// The low level of INT0 generates an interrupt request. (ISC00=0, ISC01=0)
	GIMSK |= _BV(INT0) ; 						// Active INTO in global interrup mask
 
	// Configure "sleep mode"
	set_sleep_mode(SLEEP_MODE_PWR_DOWN) ;		// Conso. 0.001mA ou 0.010 (suivant ouverture/fermeture ILS) au lieu 1.4mA au repos, > 5mA en émission. 
 
	Led_On() ;						// Led ON au "boot".
	delay_s(1) ;
	Led_Off() ;						// Led OFF.
 
	sei(); 							// Autorise interruption.
 
	while (1) 
	{
		sleep_mode() ;				// Mise en veille. 
		Led_On() ;					// Led ON.
		data[0] = compteur1 ;		// INT0 révaille le uC, execute fonction INT0 et passe ici.
		data[1] = compteur2 ;
		data[2] = compteur3 ;
		x10_senddata(ADR, data) ;	// Envoie trames X10 perso (donnée compteur).
		Led_Off() ;					// Led OFF.
	}
}




  • Module X10Sensors.pm (xpl-perl) permettant d'interpréter la trame reçue par le programme xpl-rfxcom-rx


package xPL::RF::X10Sensors;
 
# $Id$
# Dan, /usr/share/perl5/xPL/RF/X10Sensors.pm
# Remplace I2CSensors.pm
 
=head1 NAME
 
xPL::RF::X10Sensors - Perl extension for decoding X10Sensors device RF messages
 
=head1 SYNOPSIS
 
  use xPL::RF::X10Sensors;
 
=head1 DESCRIPTION
 
This is a module for decoding RF messages from X10Sensors 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{ };
 
 
=head2 C<parse( $parent, $message, $bytes, $bits )>
 
This method attempts to recognize and parse RF messages corresponding
to personnal X10 RF sensors.  If messages are identified a reference to a list of
xPL::Message objects is returned.  If the message is not recognized,
undef is returned.
 
- 89C2051 sensors
Processed: 305a619e180210 	=> nb_bits-entete/idcarte/adri2c/data1/data2/data3
xpl-trig/sensor.basic: bnz-rfxcomrx.vesta -> * - ds1621_2051_619e[temp]=24.6
10/02/12 22:53:12 xpl-trig {bnz-rfxcomrx.vesta *} sensor.basic { device='ds1621_2051_619e' type='temp' current='24.6' }
 
- AVR 24 bits counter
Processed: 305a6241000007       => nb_bits-entete/idcarte/adrsensor/data1/data2/data3
xpl-trig/sensor.basic: bnz-rfxcomrx.alix -> * - avr_6241[count]=7
 
=cut
 
sub parse
{
  my $self = shift;
  my $parent = shift;
  my $message = shift;
  my $bytes = shift;
  my $bits = shift;
 
  $bits == 48 or return ;			# 48 (0x30) bits (6 octets) !
  $bytes->[0] == 0x5A or return ;		# 5A = entete !
 
  my %body ;
  my $idcard = $bytes->[1] ;
 
  if ( $idcard == 0x61 )                        # Concerne la carte senseurs i2c.
  {
	my $i2cadr = $bytes->[2] ;
 
	# Si adri2c du ds1621
	if ( $i2cadr == 0x9E )
	{
		my $device =  sprintf("ds1621_2051_%02x%02x", $idcard, $i2cadr) ; 
		my $temp = $bytes->[3] ;
		my $count = $bytes->[4] ;
		my $slope = $bytes->[5] ;
		my $valtemp = $temp  * 100 ;
		if ($slope)
		{
			$valtemp = $temp * 100 - 25 + ( 100 * ($slope - $count) ) / $slope ;
		}
		$valtemp = sprintf("%2.1f" , $valtemp / 100) ;
		%body = (
			current => $valtemp,
			type => "temp",
			device => $device,
       		      );
     	}
  	# Si adri2c du pcf8591
  	elsif ( $i2cadr == 0x90 )
  	{
		my $canal = $bytes->[4] ;
		my $ain = $bytes->[5] ;
		my $val = sprintf( "%.2f", $ain * (5/255) ) ;
		my $device =  sprintf("pcf8591_2051_%02x%02x_%02x", $idcard, $i2cadr, $canal) ; 
		%body = (
			current => $val ,
			type => "voltage",
			device => $device,
	             );
  	}
  	else { return } ;
  }
  elsif ( $idcard == 0x62 )                        # Concerne la carte compteur.
  {
	my $sensoradr = $bytes->[2] ;
 
	# Si sensoradr = compteur avr
	if ( $sensoradr == 0x41 )
	{
		my $device =  sprintf("avr_%02x%02x", $idcard, $sensoradr) ; 
		my $compteur = $bytes->[3] * 65536 + $bytes->[4] * 256 + $bytes->[5];
		%body = (
			current => $compteur ,
			type => "count",
			device => $device,
		);
	}
	else { return } ;
  }
  else { return } ;
 
  return [xPL::Message->new(
                            message_type => 'xpl-trig',
                            class => 'sensor.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



26/9/2010