Export vers Bdd

Bonjour,
je suis nouveau sur ce forum, et je debute aussi en PERL.

Pour les besoins d'un projet , je dois exporter des valeurs depuis un compteur electrique et les inscrire dans une base de donneés sous un serveur. Le problème, c'est que je ne vois pas trop par quel bout y aller. J'ai deja commence à code un script qui va lire les données dans le compteur et maintenant, je m'attaque à la partie SQL/PERL. J'ai lu ici et ailleurs, qu'il fallait utiliser le module DBI, mais apres cela . . . c'est le trou noir.

Si quelqu'un peut me donner un coup de main (ou un bout de code ^^)

Je deposerais mon travail, tel qu'il est aujourd'hui.

Je vous remercie tous!

ju

6 réponses

  1. Voila deja, le script qui va lire les datas dans le compteurs :

    #!/usr/bin/perl

    use strict;
    use warnings;
    use Socket;

    # Paramètres ModBus/TCP
    my $MODBUS_PORT = 502;

    # Codes des fonctions lecture, ecriture, ...
    my $READ_COILS = 0x01;
    my $READ_DISCRETE_INPUTS = 0x02;
    my $READ_HOLDING_REGISTERS = 0x03;
    my $READ_INPUT_REGISTERS = 0x04;
    my $WRITE_SINGLE_COIL = 0x05;
    my $WRITE_SINGLE_REGISTER = 0x06;

    # Codes des exceptions erreurs, ...
    my $EXP_ILLEGAL_FUNCTION = 0x01;
    my $EXP_DATA_ADDRESS = 0x02;
    my $EXP_DATA_VALUE = 0x03;
    my $EXP_SLAVE_DEVICE_FAILURE = 0x04;
    my $EXP_ACKNOWLEDGE = 0x05;
    my $EXP_SLAVE_DEVICE_BUSY = 0x06;
    my $EXP_MEMORY_PARITY_ERROR = 0x08;
    my $EXP_GATEWAY_PATH_UNAVAILABLE = 0x0A;
    my $EXP_GATEWAY_TARGET_DEVICE_FAILED_TO_RESPOND = 0x0B;

    # Valeurs par défaut
    my $opt_server = 'localhost';
    my $opt_server_port = $MODBUS_PORT; #502
    my $opt_timeout = 1; # temps max de 1 s
    my $opt_unit_id = 1;
    my $opt_mb_ad;
    my $opt_mb_fc = $READ_HOLDING_REGISTERS;
    my $opt_mb_nb = 1;
    my $opt_bit_value = 0;
    my $opt_word_value = 0;

    $opt_server = '192.168.1.253'; # @ IP du serveur TCP
    my $server_ip = inet_aton($opt_server); # on donne l'@ IP à la variable
    unless ($server_ip) {
    print STDERR 'unable to resolve "'.$opt_server.'"'."\n"; # et la,
    exit 1;
    }

    my $status = query_info();
    until ($status) {
    sleep(1); # toutes les 1s, a adapter à ses besoins
    $status = query_info();
    }
    # boucle infinie, a stopper avec un kill

    sub query_info {

    # Gestion du dialogue reseau
    # Ouverture de la session TCP

    socket(SERVER, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
    unless (connect(SERVER, sockaddr_in($MODBUS_PORT, $server_ip))) {
    print STDERR 'connexion au serveur "'.$server_ip.':'.$MODBUS_PORT.'" impossible'."\n";
    return 2;
    }

    my @adresses = qw(267 305 15); #Liste des adresses à interroger puissance P, Q et I
    my %result;

    foreach (@adresses) {
    $opt_mb_ad = $_;
    # Création de la requête
    my $tx_hd_tr_id = int(rand 65535);
    my $tx_hd_length = 6;
    my $tx_hd_pr_id = 0;
    my $tx_buffer = pack("nnnCCnn", $tx_hd_tr_id, $tx_hd_pr_id , $tx_hd_length, $opt_unit_id, $opt_mb_fc, $opt_mb_ad, $opt_mb_nb);

    # Emission de la requête vers le serveur
    send(SERVER, $tx_buffer, 0);

    # Attente d'une réponse
    unless (can_read('SERVER', $opt_timeout)) {
    close SERVER;
    print STDERR 'receive timeout'."\n"; # erreur si depassement du temps d'attente
    return 1;
    }

    # Réception de l'entête depuis le serveur
    my ($rx_frame, $rx_buffer);
    recv(SERVER, $rx_buffer, 7, 0);
    $rx_frame = $rx_buffer;

    # Décodage de l'entête
    my ($rx_hd_tr_id, $rx_hd_pr_id, $rx_hd_length, $rx_hd_unit_id) = unpack "nnnC", $rx_buffer;

    # Vérifie la cohérence de l'entête
    unless (($rx_hd_tr_id == $tx_hd_tr_id) &&
    ($rx_hd_pr_id == 0) &&
    ($rx_hd_length < 256) &&
    ($rx_hd_unit_id == 1)) {
    close SERVER;
    print STDERR 'error in receive frame'."\n";
    return 1;
    }

    # Réception du corps du message
    recv(SERVER, $rx_buffer, $rx_hd_length-1, 0);
    $rx_frame .= $rx_buffer;

    # Décodage du corps du message
    my ($rx_bd_fc, $rx_body) = unpack "Ca*", $rx_buffer;

    # Vérification du statut d'exception
    if ($rx_bd_fc > 0x80) {

    # Affichage du code exception
    my ($rx_except_code) = unpack "C", $rx_body;
    print 'exception (code '.$rx_except_code.')'."\n";
    }

    else {

    ## Lecture de mot
    my ($rx_bd_bc, $rx_read_word_data) = unpack "Ca*", $rx_body;

    # Lecture d'entier de 16 bits
    # un seul registre a lire d'ou le 'n'
    $result{$opt_mb_ad} = unpack 'n', $rx_read_word_data;
    }
    }
    close SERVER;
    # fin de la boucle foreach
    # impression en console

    foreach (sort {$a <=> $b} (keys %result)) {
    print "<$_> : $result{$_};" # On utilise un hash pour passer les valeurs et avoir plusieurs valeurs par retour
    #disp_data(%result);
    }
    print "\n";

    #attente $timeout
    sub can_read{
    my ($sock_handle, $timeout) = @_;
    my $hdl_select="";
    vec($hdl_select, fileno($sock_handle),1)=1;
    return (select($hdl_select, undef, undef, $timeout)==1);
    }

    #utilisation du timestamp pour avoir l'heure réseau
    my $time = time;
    my @months = ("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");
    my ($sec, $min, $hour, $day,$month,$year) = (localtime($time))[0,1,2,3,4,5];

    print "Unix time ".$time." converts to ".$months[$month]." ".$day.", ".($year+1900);print " ".$hour.":".$min.":".$sec."\n";

    }

    J'ai aussi utilisé pour les besoins du programme, la variable timestamp pour avoir le temps et l'heure des extractions.
    0
    1. Et le script qui créé la BDD, mais il ne marche pas :
      erreur suivantes :

      Malformed UTF-8 line 149,19,24,24,27.

      #!/usr/bin/perl
      use warnings;
      use strict;
      use Encode;
      use utf8;
      use DBI; # Charger le module DBI
      use vars qw/ $VERSION /; # version script

      ActiverAccents();

      # Paramètres de connection à la base de données
      my $bd = 'energie';
      my $serveur = 'localhost'; # @ IP
      my $identifiant = 'root'; # identifiant
      my $motdepasse = 'admin';
      my $port = ''; #Si vous ne savez pas, ne rien mettre

      # Connection à la base de données mysql
      print "Connexion à la base de données $bd\n";
      my $dbh = DBI->connect( "DBI:mysql:database=$bd;host=$serveur;port=$port",
      $identifiant, $motdepasse, {
      RaiseError => 1,
      }
      ) or die "Connection impossible à la base de données $bd !\n $! \n $@\n$DBI::errstr";

      # Création des tables
      print "Création de la table energie\n";
      my $sql_creation_table_energie = <<"SQL";
      CREATE TABLE Regions (
      id_compteur VARCHAR (10) NOT NULL ,
      puissance_p INT NOT NULL ,
      puissance_q INT NOT NULL ,
      courant_In INT NOT NULL ,
      PRIMARY KEY ( id_compteur )
      ) COMMENT = 'base compteur';
      SQL

      $dbh->do('DROP TABLE IF EXISTS energie;') or die "Impossible de supprimer la table energie\n\n";
      $dbh->do($sql_creation_table_energie) or die "Impossible de créer la table energie\n\n";

      print "Création de la table releves\n";
      my $sql_creation_table_releves = <<"SQL";
      CREATE TABLE releves(
      id_compteur VARCHAR (10) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT 'Elle sera générée automatiquement.',
      time TIMESTAMP NOT NULL,
      ) COMMENT = 'Releves';
      SQL

      $dbh->do('DROP TABLE IF EXISTS releves;') or die "Impossible de supprimer la table releves\n\n";
      $dbh->do($sql_creation_table_releves) or die "Impossible de créer la table releves\n\n";

      # Lecture des fichiers et insertion des données
      #my $fichier_compteur = 'c:/reg2013.txt';
      #my $fichier_releves = 'c:/releves.txt';

      # Fichier Region
      print "Insertion des données dans la table releves\n";
      open my $fh_releves, '<:encoding(UTF-8)', $fichier_releves or die "Impossible de lire le fichier $fichier_regions\n";
      my $entete_fichier_releves = <$fh_releves>;

      ################# a mettre en forme####################
      # Insertion des données
      my $requete_sql_releves = <<"SQL";
      INSERT INTO regions ( id_compteur, puissance_p, puissance_q, courant_in, time)
      VALUES ( ?, ?, ?, ?, ? ); #
      SQL

      my $sth_releves = $dbh->prepare($requete_sql_releves);

      while ( my $ligne = <$fh_releves> ) {
      chomp $ligne;
      my ( $id_compteur, puissance_p, puissance_q, courant_in, time) ) = split /\t/, $ligne;
      $sth_releves->execute( $id_compteur, puissance_p, puissance_q, courant_in, time)
      or die "Echec Requête $requete_sql_releves : $DBI::errstr";
      }
      close $fh_releves;

      # Déconnection de la base de données
      $dbh->disconnect();

      sub ActiverAccents {
      my $encodage;
      # Windows
      if ( lc($^O ) eq 'mswin32') {
      eval {
      my ($codepage) = ( 'chcp' =~ m/:\s+(\d+)/ );
      $encodage = "cp$codepage";
      foreach my $h ( \*STDOUT, \*STDERR, \*STDIN, ) {
      binmode $h, ":encoding($encodage)";
      }
      };
      }
      else {
      $encodage = 'locale charmap';
      eval {
      foreach my $h ( \*STDOUT, \*STDERR, \*STDIN, ) {
      binmode $h, ":encoding($encodage)";
      }
      };
      }
      return $encodage;
      }

      Si quelqu'un passe par mon post,

      Merci

      ju
      0
      1. Bonjours moi c'est ange cristelle je suis nouvelle sur le site mais je contre bien vous aide
        0
        1. C'est sympa,
          Je chrche en même temps et je posterais mon nouveau code, si j'avance de mon coté ^^

          Merci
          0
          1. Nouveau code après modif,
            j'ai encore des erreurs :

            - malformed UTF-8 0x20 at line 19 19 24 24 27,
            - cant find string terminator.

            #!/usr/bin/perl
            use warnings;
            use strict;
            use Encode;
            use utf8;
            use DBI; # Charger le module DBI

            ActiverAccents();

            # Paramètres de connection à la base de données
            my $bd = 'Energie';
            my $serveur = 'localhost'; # @ IP IP
            my $identifiant = 'root'; # identifiant
            my $motdepasse = 'admin';
            my $port = ''; #Si vous ne savez pas, ne rien mettre

            # Connection à la base de données mysql
            print "Connexion à la base de données $bd\n";
            my $dbh = DBI->connect( "DBI:mysql:database=$bd;host=$serveur;port=$port",
            $identifiant, $motdepasse, {
            RaiseError => 1,
            }
            ) or die "Connection impossible à la base de données $bd !\n $! \n $@\n$DBI::errstr";

            # Création des tables
            print "Création de la table COMPTEUR\n";
            my $sql_creation_table_compteur = <<"SQL";
            id_compteur INT NOT NULL ,
            emplacement VARCHAR( 10 ) NOT NULL ,
            batiment VARCHAR( 10 ) NOT NULL ,
            niveau VARCHAR( 10 ) NOT NULL ,
            PRIMARY KEY ( id_compteur )
            ) COMMENT = 'COMPTEUR';
            SQL

            $dbh->do('DROP TABLE IF EXISTS compteur;') or die "Impossible de supprimer la table compteur\n\n";
            $dbh->do($sql_creation_table_compteur) or die "Impossible de créer la table compteur\n\n";

            print "Création de la table Releves\n";
            my $sql_creation_table_releves = <<"SQL";
            CREATE TABLE releves (
            id_compteur INT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT 'Elle sera générée automatiquement.',
            puissance_p INT NOT NULL ,
            puissance_q INT NOT NULL ,
            courant_I INT NOT NULL ,
            ) COMMENT = 'COMPTEUR';
            SQL

            $dbh->do('DROP TABLE IF EXISTS releves;') or die "Impossible de supprimer la table releves\n\n";
            $dbh->do($sql_creation_table_releves) or die "Impossible de créer la table releves\n\n";

            # Insertion des données
            my $requete_sql_compteur = <<"SQL";
            INSERT INTO rcompteur ( id_compteur, emplacement, batiment, niveau)
            VALUES ( 1, TDD1, D, 1);
            SQL

            close $fh_regions;

            # Déconnection de la base de données
            $dbh->disconnect();

            sub ActiverAccents {
            my $encodage;
            # Windows
            if ( lc($^O ) eq 'mswin32') {
            eval {
            my ($codepage) = ( 'chcp' =~ m/:\s+(\d+)/ );
            $encodage = "cp$codepage";
            foreach my $h ( \*STDOUT, \*STDERR, \*STDIN, ) {
            binmode $h, ":encoding($encodage)";
            }
            };
            }
            else {
            $encodage = 'locale charmap';
            eval {
            foreach my $h ( \*STDOUT, \*STDERR, \*STDIN, ) {
            binmode $h, ":encoding($encodage)";
            }
            };
            }
            return $encodage;
            }

            Si quelqu'u n peut m'aider un peu . . . ^^

            Merci

            @+
            0
            1. Contributeur
              Salut clubber43,

              Tu fais un
              use utf8;
              indiquant à Perl que ton script contient des caractères écrits en utf8, mais il semble que cela ne soit pas le cas si tu as en ligne 19 un message "malformed UTF-8 0x20" et que tu aies à cet endroit un caractère qui n'est pas légalement encodé en utf8.

              Si ton texte n'est pas en utf8, convertis le en utf8 (ou retire cette directive, si elle ne reflète pas la réalité et que ton script n'est pas en utf8).

              Une remarque, stp, cela ne sert à rien de poster un code de 88 lignes alors que le message d'erreur te permet de cerner les lignes problématiques et de diagnostiquer ton problème en le réduisant à une poignée de lignes. En faisant cela, tu avances toi même aussi dans la résolution du problème, tu incites d'avantage les contributeurs du forum à t'aider, et tu te montres plus respectueux à leur égard en limitant autant que tu le peux le temps nécessaire à la compréhension de ton problème.

              De plus, pour la lisibilité de ton code, s'il te plaît utilises les balises "code", comme cela

              <code perl>
                print "Hello world!\n";
              </code>

              Dal
              0
            2. Ok, c'est sympa, je ne savais pas comment faire, du coup pour la prochaine fois, je ferais ça.

              Merci pour le coup de main
              0
            3. Contributeur
              De rien :-)

              Le bouton "code" qui permet d'insérer les balises selon le langage est dans l'éditeur du forum, mais il est vrai qu'il est peu explicite. Il faut cliquer sur le triangle avec la pointe vers le bas, à droite de l'icône <> et sélectionner le langage pour lequel tu postes.

              Dal
              0