- Informatique
- Arduino
- Projets
- Mécanique
CollectdPacket est une librairie pour Arduino permettant de créer des paquets UDP pour collectd.
Beaucoup de tutoriels Arduino montrent des fonctionnement où des données sont captées puis inscrites dans des fichiers ou bien envoyées vers des serveurs en PHP pour les afficher… L'idée de cette librairie est de pouvoir exploiter des données sur un système de métrologie centralisé.
Dès lors que votre carte Arduino possède une interface réseau (filaire ou wifi), il vous sera possible
d'envoyer vos données vers un serveur collectd
Tout le fonctionnement de cette classe est basé sur la documentation du protocole binaire de collectd.
Voici quelques explications sur les différentes méthodes publiques de la classe.
Les notions de 'plugin', 'instances', 'types' etc… sont directement reprises du format utilisé par le protocole binaire de collectd.
Ne pas hésitez à s'y référer pour plus d'explications sur leur signification.
Les explications/exemples donnés ici sont uniquement destinées à faciliter la compréhension de la classe CollectPacket mais ne sont en aucun cas une référence sur le fonctionnement de Collectd.
class CollectdPacket { public: CollectdPacket( const char *hostname, unsigned long interval ); void addPlugin( const char *plugin ); void addPluginInstance( const char *instance ); void addType( const char *type ); void addTypeInstance( const char *instance ); void addTimestamp( unsigned long timestamp ); void addTimestampHR( unsigned long timestamp ); void addValue( byte type, float value ); word getPacketSize( void ); byte *getPacketBuffer( void ); void resetPacket( void ); }
Nom du plugin auquel seront affectées les données.
void addPlugin( const char *plugin );
addPlugin( "temperature" );
Nom de l'instance du plugin auquel seront affectées les données dans le cas ou il y a plusieurs mesures pour un même plugin (plusieurs capteurs différents).
void addPluginInstance( const char *instance );
addPlugin( "temperature" ); addPluginInstance( "sensor1" ); // code to get data from sensor 1 addPluginInstance( "sensor2" ); // code to get data from sensor 2
Type de données de la mesure. Cette méthode peu être utilisée quand une sonde permet de renvoyer plusieurs type différents de données.
void addType( const char *type );
addPlugin( "THN132N" ); // Oregon scientifics humidity and temp sensor addType( "temperature" ); // code to get the temperature from sensor addType( "humidity" ); // Code to get humidity from sensor
Instance utilisée par le 'type' de données de la mesure. Cette méthode peu être utilisée quand une sonde permet de renvoyer plusieurs sous types de données.
void addTypeInstance( const char *instance );
addPlugin( "Sensor" ); addType( "power" ); // Example sensor that mesures electrical power addTypeInstance( "watts" ); // code that get the power in watts from sensor addTypeInstance( "amperes" ); // code that get the power in amperes from sensor
Permet d'horodater le paquet. La date est exprimée en secondes depuis le 1er janvier 1900.
void addTimestamp( unsigned long timestamp );
Depuis les versions récentes de Collectd (version 5) cette fonction n'est plus utilisée et est remplacée par la version 'HR' (high resolution).
→ Voir la fonction addTimestampHR
Permet d'horodater le paquet. La date est exprimée en secondes depuis le 1er janvier 1900. Cette date peu être récupérée via un serveur NTP par exemple.
void addTimestampHR( unsigned long timestamp );
Cette méthode permet d'ajouter les valeurs collectées au paquet. Elle prend deux arguments, le type de donnée et la donnée elle même.
Les types sont des constantes définies comme suit :
Ces types sont directement issus des types de données supportées par RRDTool (format de stockage de Collectd).
void addValue( byte type, float value );
addPlugin( "temperature" ); addPluginInstance( "sensor1" ); // code to get data from sensor 1 addValue( VALUE_TYPE_GAUGE, sensor1_temp ); addPluginInstance( "sensor2" ); // code to get data from sensor 2 addValue( VALUE_TYPE_GAUGE, sensor2_temp );
Renvoie la taille du paquet Collectd généré (exprimé en octets).
word getPacketSize( void );
Renvoi le contenu du paquet Collectd. C'est ce contenu qui doit être envoyé au serveur.
byte *getPacketBuffer( void );
ré-initialise le paquet Collectd afin de recommencer un cycle. Cette méthode est utile lorsque vous utilisez la même instance d'un paquet dans une boucle. Cette méthode vide le contenu du paquet en conservant les paramètres utilisés lors de sa création (client name et interval).
void resetPacket( void );
L'exemple ci-dessous met en oeuvre un capteur de température Dallas 1-wire DS18S20 pour effectuer des relevés et les envoyer vers un serveur Collectd. Le capteur de température est relié à la broche 8 de l'Arduino qui est équipé d'un ethernet shield pour la communication réseau.
#include <Ethernet.h> #include <EthernetUdp.h> #include <OneWire.h> #include <SPI.h> #include <CollectdPacket.h> #include "ntp_client.h" # Another personal library ;-) // The device id of a DS18S20 is 0x10 #define DS18S20 0x10 CollectdPacket packet( "Arduino", 30 ); // Init 'CollectdPacket' class with : // client name = Arduino // interval = 30s OneWire ds18s20( 8 ); // Init the OneWire on pin 8 static byte mac[] = { 0x00, 0x04, 0x25 , 0x15, 0x48, 0x12 }; static byte ip[] = { 10, 1, 1, 40 }; static byte collectd_ip[] = { 10, 1, 1, 100 }; static byte ntp_ip[] = { 10, 1, 1, 254 }; // Init the UDP instance EthernetUDP udp_handler; void setup() { Serial.begin( 9600 ); Serial.println( "Initialized a packet for 'Arduino' with interval 30" ); Ethernet.begin( mac, ip ); udp_handler.begin( 8888 ); // Start an UDP instance listening on port 8888 } void loop() { float temperature; byte ds_addr[8]; byte ds_buffer[12]; char ds_idstr[17]; // 16 chars + \0 // Search for the Dallas sensor until found while ( ! ds18s20.search( ds_addr ) ) { ds18s20.reset_search(); delay( 250 ); } // Not so beautiful but just for DEBUGING purpose... 8-) sprintf( ds_idstr, "%02x%02x%02x%02x%02x%02x%02x%02x", ds_addr[0], ds_addr[1], ds_addr[2], ds_addr[3], ds_addr[4], ds_addr[5], ds_addr[6], ds_addr[7] ); Serial.print( "Found sensor id : " ); Serial.println( ds_idstr ); if ( ds_addr[0] != DS18S20 ) { Serial.println( "Found sensor is not a DS18S20, skipping" ); return; } if ( OneWire::crc8( ds_addr, 7 ) != ds_addr[7] ) { Serial.println("CRC is not valid, skipping..."); return; } // Send a mesure command to the sensor ds18s20.reset(); ds18s20.select( ds_addr ); ds18s20.write( 0x44, 1 ); // Wait for conversion to finish (~750ms) // There is no reason to wait it, but as this program is an example // we can proceed that way. delay( 800 ); // Retrieve mesured data ds18s20.reset(); ds18s20.select( ds_addr ); ds18s20.write( 0xBE ); // Read the scratchpad ds18s20.read_bytes( ds_buffer, 9 ); unsigned int raw = ( ds_buffer[1] << 8 ) | ds_buffer[0]; raw = raw << 3; // 9 bit resolution default if ( ds_buffer[7] == 0x10 ) { // count remain gives full 12 bit resolution raw = ( raw & 0xFFF0 ) + 12 - ds_buffer[6]; } temperature = (float) raw / 16.0; Serial.print( "Sensor temperature : " ); Serial.println( temperature ); Serial.println( "Resetting packet..." ); packet.resetPacket(); packet.addTimestampHR( GetTimeFromNTPServer( ntp_ip, 5 ) ); packet.addPlugin( "sensors" ); packet.addPluginInstance( "ds18s20" ); // Could be 'ds_idstr' if you want... packet.addType( "temperature" ); packet.addValue( VALUE_TYPE_GAUGE, temperature ); Serial.print( "Generated a packet of " ); Serial.print( packet.getPacketSize() ); Serial.println( " bytes" ); Serial.print( "Sending packet to 10.1.1." ); Serial.println( collectd_ip[3] ); udp_handler.beginPacket( collectd_ip, 25826 ); udp_handler.write( packet.getPacketBuffer(), packet.getPacketSize() ); udp_handler.endPacket(); delay( 29 * 1000 ); // Sleep 29 seconds (30s - 800ms... ;)) }
Cet exemple, permet de faire de jolis graphiques tels que celui-ci :