Ankündigung

Einklappen
Keine Ankündigung bisher.

Zählerabfrage als Wiregate Plugin

Einklappen
Dieses Thema ist geschlossen.
X
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • NetFritz
    antwortet
    Hallo
    Habe nach langen suchen was gefunden.
    Code:
    sub hexstr_to_signed32int {
        my ($hexstr) = @_;
        die "Invalid hex string: $hexstr"
            if $hexstr !~ /^[0-9A-Fa-f]{1,8}$/;
     
        my $num = hex($hexstr);
        return $num >> 31 ? $num - 2 ** 32 : $num;
    }
    Ich lese die Zählerwerte mit Perl aus.
    Das Perl-Script wird über ein Start-Stop Script in der init.d gestartet.
    Es liest alle 2sek. die Werte aus.
    Die Augenblickliche Leistung wird alle 2sek. in die rrd und die SQLite DB geschrieben.
    Aus der SQLite DB hole ich dann die Werte auf den KNX-BUS.
    Gruß NetFritz

    Einen Kommentar schreiben:


  • NetFritz
    antwortet
    Hallo
    Ich bin auch dabei meinen Easymeter Q3C mit Perl auszulesen.
    Nur mit den Umrechnen der Augenblicklichen Leistung in Abgabe brauche ich mal Hilfe.
    Die Umrechnung in Bezug bekomme ich hin.
    Der Zähler liefert 32 Bit (4 Byte)
    Hex C4653601 bis 3B9AC9FF
    das entspricht dann
    Dec - 9999999.99 bis + 9999999.99 kW

    Der Zähler zeigt mir z.b. zur Zeit als Abgabe "FFFF93B8" an.
    Wie bekomme ich da den negativen Wert für Abgabe raus.
    Die positiven Werte wandele ich mit hex(3B9AC9FF) zu 999999999 .
    Gruß NetFritz

    Einen Kommentar schreiben:


  • gtdpower2
    antwortet
    Hallo zusammen,

    Ich bin gerade auch fleißig am rumexperimentieren mit SML. Hab dabei das Problem, dass ich keine negativen Wirkleistungen erkennen kann. Wenn ich mir den Code des SML-Servers anschaue, dann wird dort auch der integer-Wert einfach auf ein uint8 gelegt, oder?

    Einen Kommentar schreiben:


  • lio123
    antwortet
    ...mal wieder langweilig gewesen???

    Einen Kommentar schreiben:


  • makki
    antwortet
    Schon, Min/Max-Werte/Zeitraum Thread, Plugin

    Makki

    Einen Kommentar schreiben:


  • ctr
    antwortet
    Ja wie gesagt ich lasse das im Moment auch per cron in ein rrd schreiben. Gab es nicht schon ein WG Plugin um Daten aus einem RRD wieder auszulesen?

    Einen Kommentar schreiben:


  • makki
    antwortet
    Der Stand ist: nachdenken und sich was überlegen, im Mittel 2s (0-4) im Plugin warten ist jedenfalls keine brauchbare Option

    Als Quickhack würde ich den sml_server per crontab aufrufen mit "sml_server | nc .." auf einen lokalen UDP-Port senden lassen und dort ein Plugin horchen.. oder so ähnlich, aber das bekomm ich halt keinem in 10 minuten erklärt, also muss ich mir was besseres ausdenken wenn mir mal wieder langweilig ist

    Makki

    Einen Kommentar schreiben:


  • lio123
    antwortet
    Hi Makki,

    um ich weis, um die Zeit bist' noch nicht wach-wollte mal nach dem Stand fragen?!?

    Einen Kommentar schreiben:


  • lio123
    antwortet
    Zitat von makki Beitrag anzeigen
    Zusammenpacken heisst hier: ein gepflegtes Debian-Paket machen, damit das jeder Freakfrei aufm WG benutzen kann ohne zu wissen was C, gcc, automake oder .. bedeutet

    Das hört sich gut an!

    Bei mir vorhanden:
    -nackiches WG
    -VZ-OKK
    -EMH "Null Brain"-Zähler(vzgl EnBW NB)

    So ein ähnliches Projekt hätte ich für einen DELTASOL Solarregler, aber das steht ganz unten auf der Liste. DELTASOL wird unter vielen anderen Namen vertrieben und könnte damit auch einen großen Interessentenkreis haben.

    Grüße,
    Lio

    Einen Kommentar schreiben:


  • ctr
    antwortet
    Ein Zähler sendet etwa alle 3-4 Sekunden eine SML Nachricht, solange ist dann geblocked (pro abzufragendem Zähler).

    Ich kann Dich gern per WartungsVPN auf mein WG rauflassen, die Zähler (3 Stück) sind alle lokal angebunden (per pl2303 auf Optokopf) und alles zum Bauen (make, gcc, libsml und die modifizierte sml_server.c) sind auch schon drauf.

    Einen Kommentar schreiben:


  • makki
    antwortet
    Zusammenpacken heisst hier: ein gepflegtes Debian-Paket machen, damit das jeder Freakfrei aufm WG benutzen kann ohne zu wissen was C, gcc, automake oder .. bedeutet
    1sek wäre Ok, 4 sek zuviel, dann überlege ich mir was anderes..

    Testen würde ich halt gerne, obs denn auch wirklich final funzt (eines unserer ElabNET-Motto's: "was nicht getestet ist, funktioniert auch nicht!")
    Das Thema ansich wiegesagt finde ich sehr interessant, weil 100% der Haushalte sowas kraft Gesetz bekommen

    Makki

    Einen Kommentar schreiben:


  • lio123
    antwortet
    was heisst zusammenpacken?

    der sendet ca 1-4 sekunden-angeblich lastabhängig

    Was willst denn per vpn testen?

    Lio

    Einen Kommentar schreiben:


  • makki
    antwortet
    sieht ja übersichtlich aus, ich würde das die Tage mal zusammenpacken, letzte Frage: wie oft sendet der Zähler freiwillig, ergo wie lange blocked das read(fd .. maximal (im Normalbetrieb) ?
    Und wer lässt mich in 1-52 Wochen mit seinem Zähler per VPN testen ?

    Makki

    Einen Kommentar schreiben:


  • ctr
    antwortet
    Ok, hier meine sml_server.c:
    Code:
    // Copyright 2011 Juri Glass, Mathias Runge, Nadim El Sayed
    // DAI-Labor, TU-Berlin
    //
    // This is derived from the sample sml_server.c in libSML
    //
    // libSML is free software: you can redistribute it and/or modify
    // it under the terms of the GNU General Public License as published by
    // the Free Software Foundation, either version 3 of the License, or
    // (at your option) any later version.
    //
    // libSML is distributed in the hope that it will be useful,
    // but WITHOUT ANY WARRANTY; without even the implied warranty of
    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    // GNU General Public License for more details.
    //
    // You should have received a copy of the GNU General Public License
    // along with libSML.  If not, see <http://www.gnu.org/licenses/>.
    
    #include <stdio.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <errno.h>
    #include <termios.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/ioctl.h>
    #include <sys/time.h>
    
    #include <math.h>
    
    #include <netdb.h>
    #include <sys/socket.h>
    
    #include <signal.h>
    
    #include <sml/sml_file.h>
    #include <sml/sml_transport.h>
    
    
    #include "unit.h"
    
    int i;
    
    int serial_port_open(const char* device) {
            int bits;
            struct termios config;
            memset(&config, 0, sizeof(config));
    
            int fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY);
            if (fd < 0) {
                    printf("error: open(%s): %s\n", device, strerror(errno));
                    return -1;
            }
    
            // set RTS
            ioctl(fd, TIOCMGET, &bits);
            bits |= TIOCM_RTS;
            ioctl(fd, TIOCMSET, &bits);
    
            tcgetattr( fd, &config ) ;
    
            // set 8-N-1
            config.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
            config.c_oflag &= ~OPOST;
            config.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
            config.c_cflag &= ~(CSIZE | PARENB | PARODD | CSTOPB);
            config.c_cflag |= CS8;
    
            // set speed to 9600 baud
            cfsetispeed( &config, B9600);
            cfsetospeed( &config, B9600);
    
            tcsetattr(fd, TCSANOW, &config);
            return fd;
    }
    
    void transport_receiver(unsigned char *buffer, size_t buffer_len) {
            // the buffer contains the whole message, with transport escape sequences.
            // these escape sequences are stripped here.
            sml_file *file = sml_file_parse(buffer + 8, buffer_len - 16);
            // the sml file is parsed now
    
            for (i = 0; i < file->messages_len; i++) {
                    sml_message *message = file->messages[i];
    
                    if (*message->message_body->tag == SML_MESSAGE_GET_LIST_RESPONSE) {
                            sml_list *entry;
                            sml_get_list_response *body;
    
                            body = (sml_get_list_response *) message->message_body->data;
    
                            for (entry = body->val_list; entry != NULL; entry = entry->next) { /* linked list */
    
                                    int unit = (entry->unit) ? *entry->unit : 0;
                                    double value;
    
                                    switch (entry->value->type) {
                                            case 0x51: value = *entry->value->data.int8; break;
                                            case 0x52: value = *entry->value->data.int16; break;
                                            case 0x54: value = *entry->value->data.int32; break;
                                            case 0x58: value = *entry->value->data.int64; break;
                                            case 0x61: value = *entry->value->data.uint8; break;
                                            case 0x62: value = *entry->value->data.uint16; break;
                                            case 0x64: value = *entry->value->data.uint32; break;
                                            case 0x68: value = *entry->value->data.uint64; break;
    
                                            default:
                                                    // fprintf(stderr, "Unknown value type: %x", entry->value->type);
                                                    value = 0;
                                    }
    
                                    /* apply scaler */
                                    //value *= pow(10, scaler); requires additional includes from obis library that has unmet dependencies
                                    value *= 0.0001; // using fixed scalar for now, works with Hager eHZ
    
                                    if (value) {
                                            printf("%.2f %s\n", value, dlms_get_unit(unit));
                                    }
                            }
                    exit(0); // processed first message - exit
                    }
            }
    
            // free the malloc'd memory
            sml_file_free(file);
    }
    
    int main(int argc, char **argv) {
            // this example assumes that a EDL21 meter sending SML messages via a
            // serial device. Use serial device name as input parameter, i.e. /dev/ttyUSB1
            char *device = argv[1];
            int fd = serial_port_open(device);
    
            if (fd > 0) {
                    // listen on the serial device, this call is blocking.
                    sml_transport_listen(fd, &transport_receiver);
                    close(fd);
            }
    
            return 0;
    }
    Die benötigt noch (für die Einheiten) eine unit.h im gleichen Verzeichnis, die habe ich aus dem vzlogger Projekt genommen:

    Code:
    /**
     * DLMS Units as specified in ISO EN 62056-62 and used by SML
     *
     * @package vzlogger
     * @copyright Copyright (c) 2011, The volkszaehler.org project
     * @license http://www.gnu.org/licenses/gpl.txt GNU Public License
     * @author Steffen Vogel <info@steffenvogel.de>
     */
    /*
     * This file is part of volkzaehler.org
     *
     * volkzaehler.org is free software: you can redistribute it and/or modify
     * it under the terms of the GNU General Public License as published by
     * the Free Software Foundation, either version 3 of the License, or
     * any later version.
     *
     * volkzaehler.org is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with volkszaehler.org. If not, see <http://www.gnu.org/licenses/>.
     */
    
    typedef struct {
        char code;
        char *unit;
    } dlms_unit_t;
    
    /**
     * Static lookup table
     */
    dlms_unit_t dlms_units[] = {
    // code, unit        // Quantity            Unit name        SI definition (comment)
    //=====================================================================================================
    {1, "a"},        // time                year            52*7*24*60*60 s
    {2, "mo"},        // time                month            31*24*60*60 s
    {3, "wk"},        // time                week            7*24*60*60 s
    {4, "d"},        // time                day            24*60*60 s
    {5, "h"},        // time                hour            60*60 s
    {6, "min."},        // time                min            60 s
    {7, "s"},        // time (t)            second            s
    {8, "°"},        // (phase) angle        degree            rad*180/π
    {9, "°C"},        // temperature (T)        degree celsius        K-273.15
    {10, "currency"},    // (local) currency
    {11, "m"},        // length (l)            metre            m
    {12, "m/s"},        // speed (v)            metre per second    m/s
    {13, "m³"},        // volume (V)            cubic metre        m³
    {14, "m³"},        // corrected volume        cubic metre        m³
    {15, "m³/h"},        // volume flux            cubic metre per hour     m³/(60*60s)
    {16, "m³/h"},        // corrected volume flux    cubic metre per hour     m³/(60*60s)
    {17, "m³/d"},        // volume flux                        m³/(24*60*60s)
    {18, "m³/d"},        // corrected volume flux                m³/(24*60*60s)
    {19, "l"},        // volume            litre            10-3 m³
    {20, "kg"},        // mass (m)            kilogram
    {21, "N"},        // force (F)            newton
    {22, "Nm"},        // energy            newtonmeter        J = Nm = Ws
    {23, "Pa"},        // pressure (p)            pascal            N/m²
    {24, "bar"},        // pressure (p)            bar            10⁵ N/m²
    {25, "J"},        // energy            joule            J = Nm = Ws
    {26, "J/h"},        // thermal power        joule per hour        J/(60*60s)
    {27, "W"},        // active power (P)        watt            W = J/s
    {28, "VA"},        // apparent power (S)        volt-ampere
    {29, "var"},        // reactive power (Q)        var
    {30, "Wh"},        // active energy        watt-hour        W*(60*60s)
    {31, "VAh"},        // apparent energy        volt-ampere-hour    VA*(60*60s)
    {32, "varh"},        // reactive energy        var-hour        var*(60*60s)
    {33, "A"},        // current (I)            ampere            A
    {34, "C"},        // electrical charge (Q)    coulomb            C = As
    {35, "V"},        // voltage (U)            volt            V
    {36, "V/m"},        // electr. field strength (E)    volt per metre
    {37, "F"},        // capacitance (C)        farad            C/V = As/V
    {38, "Ω"},        // resistance (R)        ohm            Ω = V/A
    {39, "Ωm²/m"},        // resistivity (ρ)        Ωm
    {40, "Wb"},        // magnetic flux (Φ)        weber            Wb = Vs
    {41, "T"},        // magnetic flux density (B)    tesla            Wb/m2
    {42, "A/m"},        // magnetic field strength (H)    ampere per metre    A/m
    {43, "H"},        // inductance (L)        henry            H = Wb/A
    {44, "Hz"},        // frequency (f, ω)        hertz            1/s
    {45, "1/(Wh)"},        // R_W                            (Active energy meter constant or pulse value)
    {46, "1/(varh)"},    // R_B                            (reactive energy meter constant or pulse value)
    {47, "1/(VAh)"},    // R_S                            (apparent energy meter constant or pulse value)
    {48, "V²h"},        // volt-squared hour        volt-squaredhours    V²(60*60s)
    {49, "A²h"},        // ampere-squared hour        ampere-squaredhours    A²(60*60s)
    {50, "kg/s"},        // mass flux            kilogram per second    kg/s
    {51, "S, mho"},        // conductance siemens                    1/Ω
    {52, "K"},        // temperature (T)        kelvin
    {53, "1/(V²h)"},    // R_U²h                        (Volt-squared hour meter constant or pulse value)
    {54, "1/(A²h)"},    // R_I²h                        (Ampere-squared hour meter constant or pulse value)
    {55, "1/m³"},        // R_V, meter constant or pulse value (volume)
    {56, "%"},        // percentage            %
    {57, "Ah"},        // ampere-hours            ampere-hour
    {60, "Wh/m³"},        // energy per volume                    3,6*103 J/m³
    {61, "J/m³"},        // calorific value, wobbe
    {62, "Mol %"},        // molar fraction of        mole percent        (Basic gas composition unit)
                // gas composition  
    {63, "g/m³"},        // mass density, quantity of material            (Gas analysis, accompanying elements)
    {64, "Pa s"},        // dynamic viscosity pascal second            (Characteristic of gas stream)
    {253, "(reserved)"},    // reserved
    {254, "(other)"},    // other unit
    {255, "(unitless)"},    // no unit, unitless, count
    {}            // stop condition for iterator
    };
        
    char * dlms_get_unit(unsigned char code) {
        dlms_unit_t *it = dlms_units;
        do { /* linear search */
            if (it->code == code) {
                return it->unit;
            }
        } while ((++it)->code);
        
        return NULL; /* not found */
    }
    Das kompiliert dann mit dem Makefile der libsml/example

    liefert dann bei mir folgendes bei Aufruf:
    Code:
    root@wiregate467:/usr/local/src/libsml/examples# /usr/local/bin/sml_server /dev/ttyUSB-1-4.7
    12771.70 Wh
    611.28 W
    root@wiregate467:/usr/local/src/libsml/examples# /usr/local/bin/sml_server /dev/ttyUSB-1-4.5
    6772.06 Wh
    35.37 W
    root@wiregate467:/usr/local/src/libsml/examples# /usr/local/bin/sml_server /dev/ttyUSB-1-4.6
    1587.30 Wh
    4.35 W
    erste Zeile ist der abolsute Zählerstand und die zweite Zeile ist die Durchschnittslast der letzten (10/15?) Minuten. Es kann sein dass einige Zähler noch mehr ausspucken, dann werden es mehr als 2 Zeilen.

    Einen Kommentar schreiben:


  • lio123
    antwortet
    Die Werte brauch auch ich momentan nicht auf dem Bus
    RRD-solange wie möglich reicht mir aus.
    Es sollte nachher nur auf dem WG weiterlaufen

    Ein sei bemerkt: Zähler ist nicht gleich Zähler und NEtzbetreiber nicht gleich Netzbetrieber. Es verhält sich so, wie die Anzahl der nicht gewollten von Uhren in der Küche:Null Brain

    Empfehlung: Beim NB nachfragen, ob's eine Zählerauswahl gibt und dann auf HAGER setzen. Denn die sind offen und bieten Doku online an, und aus der Hardware kommt gleich was brauchbares raus.

    Einen Kommentar schreiben:

Lädt...
X