Export vers Bdd

clubber43 Messages postés 6 Statut Membre -  
[Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   -
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. clubber43 Messages postés 6 Statut Membre
     
    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
  2. clubber43 Messages postés 6 Statut Membre
     
    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
  3. clubber43 Messages postés 6 Statut Membre
     
    .
    0
  4. ange cristel Messages postés 2 Statut Membre
     
    Bonjours moi c'est ange cristelle je suis nouvelle sur le site mais je contre bien vous aide
    0
  5. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  6. clubber43 Messages postés 6 Statut Membre
     
    C'est sympa,
    Je chrche en même temps et je posterais mon nouveau code, si j'avance de mon coté ^^

    Merci
    0
  7. clubber43 Messages postés 6 Statut Membre
     
    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. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108
       
      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. clubber43
       
      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. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108
       
      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