Wenn dies dein erster Besuch hier ist, lies bitte zuerst die Hilfe - Häufig gestellte Fragen durch. Du musst dich vermutlich registrieren, bevor du Beiträge verfassen kannst. Klicke oben auf 'Registrieren', um den Registrierungsprozess zu starten. Du kannst auch jetzt schon Beiträge lesen. Suche dir einfach das Forum aus, das dich am meisten interessiert.
So, inzwischen zeichnen auch die rrds auf. Da war noch ein Fehler im Skript.
Jetzt habe ich allerdings ein Problem die Daten richtig darzustellen (weiß nicht, ob das hierhin gehört oder in die CometVisu Abteilung).
Im Anhang ist ein Screenshot von Verbrauch und Leistung der letzten 6h.
Der rote Graph (Leistung) sieht auch gut aus: 6:40 Haare gefönt passt
Der grüne Graph passt aber meiner Meinung nach nicht. Als Source nehme ich den counter mit 60 Minuten. Die zeitliche Zuordnung sieht aber komisch aus (1h versetzt) und die Werte sind dann doch etwas hoch.
Die Funktion ist aus dem original SML Skript von jumi.
Code:
sub rrd_counter
{
if ($debug==1){print ("COUNTER","\n")};
foreach (@countermodes)
{
my $obisname = $_[0];
if ($debug==1){print $obisname." obisname \n";}
my $value = $_[1];
if ($debug==1){print $value." value \n";}
my $rrdname = $obisname."_".$_."_c\.rrd";
if ($debug==1){print ($rrdname,"\n")};
my $rrdfile = $rrdpath."\/".$rrdname;
unless (-e $rrdfile)
{
RRDs::create ($rrdfile,"DS:value:COUNTER:".(($_*60)+600).":0:10000000000",
"RRA:AVERAGE:0.5:1:366",
"RRA:AVERAGE:0.5:7:1308",
"-s ".($_*60)); # step
}
my $countervalue = int($value*$_*60);
if ($debug==1){print $countervalue." countervalue \n";}
RRDs::update("$rrdfile", "N:$countervalue");
}
}
Bei der Ausführung erhalte ich folgende Ausgabe (nicht passend zum Screenshot)
Code:
OBIS ID: 1.8.0
OBIS search: 77070100010800FF
found: 650000018201621E52FF590000000000723D5101
check sml status: [386]
check sml value time: [empty]
check sml unit: [30]
check sml scaler: [-1]
check sml value: [7486801]
check sml value signature: [empty]
Unit config: [Wh][cg]
Final value: [748680.1 Wh]
COUNTER
zaehler_verbrauch obisname
748680.1 value
zaehler_verbrauch_5_c.rrd
224604030 countervalue
zaehler_verbrauch obisname
748680.1 value
zaehler_verbrauch_15_c.rrd
673812090 countervalue
zaehler_verbrauch obisname
748680.1 value
zaehler_verbrauch_60_c.rrd
2695248360 countervalue
zaehler_verbrauch obisname
748680.1 value
zaehler_verbrauch_1440_c.rrd
64685960640 countervalue
GAUGE
zaehler_verbrauch obisname
748680.1 value
zaehler_verbrauch_g.rrd
GA:9/0/0 value:748680.1 DPT:14
Die meisten Linux-Dateisysteme sind case-sensitive
D.h. "smlwp.pl" ist nicht das Gleiche wie "smlWP.pl"
Im Screenshot heißt es smlWP.pl aber mit killall und manuellem Aufruf hatten Du smlwp.pl probiert (und die korrekte Fehlermeldung bekommen, dass es die Datei nicht gibt)
Wenn Du es richtig schreibst, passierst sicher auch etwas...
Hallo
Ich auch immer wieder Probleme mit dem Zähler-Script hatte, das mehre liefen.
Jetzt starte ich mit Cron ein Bash-Schript, das überprüft ob das Script noch läuft, wenn ja wird es mit Kill beendet.
Code:
# sml_zaehler.pl starten
if [ "$(pidof sml_zaehler.pl)" ]
then
echo "sml_zaehler.pl laeuft noch"
pkill -9 sml_zaehler.pl
echo "sml_zaehler.pl gekillt"
fi
/var/www/myhouse/cron/sml_zaehler.pl
ach habe gerade gesehn, dass ich das Problem mit dem vorherigen skript auch mal im Post 331 hatte.
also, ich hab nun auch Kill all smlWP.pl gemacht, da er mir sagte, dass das Plugin noch sonstwo läuft.
Antwort war, dass da kein Prozess abgebrochen wurde.
Danach habe ich Cronjob deaktiviert und versucht nochmals über Kommandozeile das Plugin zu starten.
Danach sagt er mir, dass es noch woanderst läuft????
habe nun endlich mal das Jumi normalo Plugin für meinen Haushaltszähler nun endlich mal für den Wärmepumpen-Zähler mit 2 Tarifen aufgepimpt.
Hilfestellungen gab mir Jumi damals schon.
Wie kann ich prüfen, ob das Plugin läuft. Crontab habe ich analog eingerichtet. Ich sehe aber im Diagrammgenerator die neuen rrds nicht.
Kann ich irgendwo in einem Log Laufzeitfehler oder dergleichen erkennen?
Hier mal das Plugin:
Code:
#!/usr/bin/perl
use warnings;
use strict;
use Device::SerialPort;
use feature "switch";
use EIBConnection;
use RRDs;
use Fcntl qw(:DEFAULT :flock);
#0701000F0700FF = 7.0 FIXME !!! [0F]0700
#070100010801FF = 1.8.1
#070100010800FF = 1.8.1
# Lock setzen damit Skript nur einmal startet
open *{0}
or die "What!? $0:$!";
flock *{0}, LOCK_EX|LOCK_NB
or die "$0 is already running somewhere!\n";
my $eib_url = "local:/tmp/eib"; #for local eibd "local:/tmp/eib" for eibd in LAN: "ip:192.168.2.220:6720"
my $device = "/dev/usbserial-FTFUDSF1";
my $repeat = 20; # Wiederholung alle x Sekunden
my $rrdpath = "/var/www/rrd";
my $debug = 1;
my @obis;
push @obis,{obis=>"1.8.0", fact=>10000, ga =>"14/7/53", dpt => 14, rrd_name => "WP_Zaehler_Verbrauch", rrd => "c" }; #rrd: c=counter ; g=gauge
push @obis,{obis=>"7.0", fact=>10, ga =>"14/7/52", dpt => 9 , rrd_name => "WP_Zaehler_Leistung_Ges", rrd => "g" };
push @obis,{obis=>"1.8.1", fact=>10, ga =>"14/7/54", dpt => 14 , rrd_name => "WP_Zaehler_Leistung_Tarif1", rrd => "c" };
push @obis,{obis=>"1.8.2", fact=>10, ga =>"14/8/55", dpt => 14 , rrd_name => "WP_Zaehler_Leistung_Tarif2", rrd => "c" };
my @countermodes = (5,15,60,1440); #Aufloesungen fuer COUNTER RRDs in Minuten (1440 = Tagesverbrauch)
my $port = Device::SerialPort->new($device) || die $!;
$port->databits(8) || die "failed setting databits";
$port->baudrate(9600) || die "failed setting baudrate";
$port->parity("none") || die "failed setting parity";
$port->stopbits(1);
$port->handshake("none");
$port->dtr_active(0);
$port->purge_all();
$port->read_char_time(0); # don't wait for each character
$port->read_const_time(4000); # 1 second per unfulfilled "read" call
$port->write_settings || die "cannot write settings";
# Loop zum Datenempfang
my $error=0;
while ($error != 1)
{
my ($x,$data) = 0 ;
my $sml = 0;
my $start = 0;
my $value = 0;
my $dec_value = 0;
my $count = 0;
my $saw = 0;
if ($debug == 1) {print "Step 1 - Daten holen \n";}
while ($start < 2) # wait for second 1B1B1B1B01010101
{
($count,$saw)=$port->read(512); # will read 512 chars
if ($count == 512) # wurden 512 chars gelesen ?
{
$x = uc(unpack('H*',$saw)); # nach hex wandeln
$data .= $x;
if ($data =~ /1B1B1B1B01010101/) {$start ++};
} # if
} # while
if ($debug==1) {print "Step 2 - Reg Exp 1 Datensatz zusammensetzen \n";}
$data =~ m/1B1B1B1B01010101(.*?)B1B1B1/;
$sml = $1;
print "Zaehler Haushalt: \n";
if ($debug==1) {print "Step 3 - Datensatz auswerten \n";}
foreach my $obiscnt (@obis)
{
# Umwandeln OBIS in HEx
my $hc ="";
foreach my $c (split(/\./,$obiscnt->{obis})) {
$hc .= sprintf("%02X", $c);
}
my $obissearch = $hc;
# FF fuer Suche an Hex-Wert anhaegne
$obissearch .="FF";
if ($debug==1) { print $obissearch." Obis\n";}
$sml =~ m/$obissearch(.*?)0177/;
#$sml =~ m/$obiscnt->{obis}(.*?)0177/;
my $sml_val = $1;
if ($debug==1) { print $1." contains hex \n";}
#extract value
$sml_val =~ s/^.*52FF//;
$sml_val = substr($sml_val,2);
if ($debug == 1) { print $sml_val." hex \n";}
$value = $sml_val;
$dec_value = sprintf("%d", hex($value));
$dec_value /= $obiscnt->{fact};
print $dec_value."<<<<---- Wert\n";
# RRD-Graphen erstellen - bei Bedarf wieder aktiv setzen
#if ($obis->{rrd} eq "c")
# {
# &rrd_counter ($obis->{rrd_name},$dec_value)
# }
#if ($obis->{rrd} eq "g")
# {
# &rrd_gauge ($obis->{rrd_name},$dec_value)
# }
&knx_write ($obiscnt->{ga},$dec_value,$obiscnt->{dpt});
if ($debug == 1) {print "GA:".$obiscnt->{ga}." Wert:".$dec_value." DPT:".$obiscnt->{dpt}."\n";}
} # foreach
sleep $repeat;
} # while
$port->close() || warn "Serial port did not close proper!\n";
undef $port;
### SUBS ###
sub rrd_counter
{
if ($debug==1){print ("COUNTER","\n")};
foreach (@countermodes)
{
my $obisname = $_[0];
if ($debug==1){print $obisname." obisname \n";}
my $value = $_[1];
if ($debug==1){print $value." value \n";}
my $rrdname = $obisname."_".$_."\.rrd";
if ($debug==1){print ($rrdname,"\n")};
my $rrdfile = $rrdpath."\/".$rrdname;
unless (-e $rrdfile)
{
RRDs::create ($rrdfile,"DS:value:COUNTER:".(($_*60)+600).":0:10000000000","RRA:AVERAGE:0.5:1:365","RRA:AVERAGE:0.5:7:300","-s ".($_*60));
}
my $countervalue = int($value*$_*60);
RRDs::update("$rrdfile", "N:$countervalue");
}
}
sub rrd_gauge
{
if ($debug==1){print ("GAUGE","\n")};
my $obisname = $_[0];
if ($debug==1){print $obisname." obisname \n";}
my $value = $_[1];
if ($debug==1){print $value." value \n";}
my $rrdname = $obisname."\.rrd";
if ($debug==1){print ($rrdname,"\n")};
my $rrdfile = $rrdpath."\/".$rrdname;
unless (-e $rrdfile)
{
RRDs::create ($rrdfile,"DS:value:GAUGE:900:0:10000000000","RRA:AVERAGE:0.5:1:2160","RRA:AVERAGE:0.5:5:2016","RRA:AVERAGE:0.5:15:2880","RRA:AVERAGE:0.5:60:8760");
}
RRDs::update("$rrdfile", "N:$value");
}
sub knx_write {
my ($dst,$value,$dpt,$response,$dbgmsg) = @_;
my $bytes;
my $apci = ($response) ? 0x40 : 0x80; # 0x40=response, 0x80=write
# DPT 1 (1 bit) = EIS 1/7 (move=DPT 1.8, step=DPT 1.7)
# DPT 2 (1 bit controlled) = EIS 8
# DPT 3 (3 bit controlled) = EIS 2
# DPT 4 (Character) = EIS 13
# DPT 5 (8 bit unsigned value) = EIS 6 (DPT 5.1) oder EIS 14.001 (DPT 5.10)
# DPT 6 (8 bit signed value) = EIS 14.000
# DPT 7 (2 byte unsigned value) = EIS 10.000
# DPT 8 (2 byte signed value) = EIS 10.001
# DPT 9 (2 byte float value) = EIS 5
# DPT 10 (Time) = EIS 3
# DPT 11 (Date) = EIS 4
# DPT 12 (4 byte unsigned value) = EIS 11.000
# DPT 13 (4 byte signed value) = EIS 11.001
# DPT 14 (4 byte float value) = EIS 9
# DPT 15 (Entrance access) = EIS 12
# DPT 16 (Character string) = EIS 15
# $dpt = $eibgaconf{$dst}{'DPTSubId'} unless $dpt; # read dpt from eibgaconf if existing
given ($dpt) {
when (/^12/) { $bytes = pack ("CCL>", 0, $apci, $value); } #EIS11.000/DPT12 (4 byte unsigned)
when (/^13/) { $bytes = pack ("CCl>", 0, $apci, $value); }
when (/^14/) { $bytes = pack ("CCf>", 0, $apci, $value); }
when (/^16/) { $bytes = pack ("CCa14", 0, $apci, $value); }
when (/^17/) { $bytes = pack ("CCC", 0, $apci, $value & 0x3F); }
when (/^20/) { $bytes = pack ("CCC", 0, $apci, $value); }
when (/^\d\d/) { return; } # other DPT XX 15 are unhandled
when (/^[1,2,3]/) { $bytes = pack ("CC", 0, $apci | ($value & 0x3f)); } #send 6bit small
when (/^4/) { $bytes = pack ("CCc", 0, $apci, ord($value)); }
when ([5,5.001]) { $bytes = pack ("CCC", 0, $apci, encode_dpt5($value)); } #EIS 6/DPT5.001 1byte
when ([5.004,5.005,5.010]) { $bytes = pack ("CCC", 0, $apci, $value); }
when (/^5/) { $bytes = pack ("CCC", 0, $apci, $value); }
when (/^6/) { $bytes = pack ("CCc", 0, $apci, $value); }
when (/^7/) { $bytes = pack ("CCS>", 0, $apci, $value); }
when (/^8/) { $bytes = pack ("CCs>", 0, $apci, $value); }
when (/^9/) { $bytes = pack ("CCCC", 0, $apci, encode_dpt9($value)); } #EIS5/DPT9 2byte float
default { LOGGER('WARN',"None or unsupported DPT: $dpt sent to $dst value $value"); return; }
}
my $leibcon = EIBConnection->EIBSocketURL($eib_url) or return("Error opening con: $!");
if ($leibcon->EIBOpenT_Group(str2addr($dst),1) == -1) { return("Error opening group: $!"); }
my $res=$leibcon->EIBSendAPDU($bytes);
$leibcon->EIBClose();
return $res;
# str2addr: Convert an EIB address string in the form "1/2/3" or "1.2.3" to an integer
sub str2addr {
my $str = $_[0];
if ($str =~ /(\d+)\/(\d+)\/(\d+)/) { # logical address
return ($1 << 11) | ($2 << 8) | $3;
} elsif ($str =~ /(\d+)\.(\d+)\.(\d+)/) { # physical address
return ($1 << 12) | ($2 << 8) | $3;
} else {
#bad
return;
}
}
}
sub encode_dpt9
{
# 2byte signed float
my $state = shift;
my $data;
my $sign = ($state <0 ? 0x8000 : 0);
my $exp = 0;
my $mant = 0;
$mant = int($state * 100.0);
while (abs($mant) > 2047)
{
$mant /= 2;
$exp++;
}
$data = $sign | ($exp << 11) | ($mant & 0x07ff);
return $data >> 8, $data & 0xff;
}
Das ganze ist kein Plugin im eigentlichen Sinne sondern sollte per cron aufgerufen werden, funktioniert so also auch auf jedem anderen Linux-System und ist nicht WireGate abhängig, eben wegen der Timing Probleme.
Man kann das natürlich so umbauen dass es als Plugin läuft, macht m.M.n. aber wenige Sinn.
Zu den RRDs, versuche erstmal die Gauge-RRDs anzuzeigen, das sollte klappen. Aber dazu muss eben mindestens alle 5 Minuten das script laufen -> crontab.
Die Counter RRDs zeigen erst was nach 2x$countermodes Minuten an. Also die Tagesverbräuche sieht man erst nach 48 Stunden, Stundenverbrauch erst nach 2 Stunden usw..
Ich dachte ich hätte mal was gelesen, dass es nicht "so geschickt" ist, wenn PlugIns "warten".
Kannst du mir das mit der rrd Geschichte noch was erklären. Ich probier nämlich gerade die Geschichte in der Cometvisu anzuzeigen, aber es wird kein Graph angezeigt.
So. Feierabend für heute.
Ich habe das sml_meter Skript soweit angepasst, dass die Daten automatisch interpretiert werden.
Bei mir getestet und für gut befunden
Es wäre super, wenn das sonst wer mit nem SML eHz auch noch testen könnte.
Was ich noch nicht getestet habe sind die rrd Dateien. Das habe ich aber 1 zu 1 vom Original so übernommen.
Wenn ich in den nächsten Tagen noch Zeit habe, werde ich mich mal mit socat befassen...
Code:
use warnings;
use strict;
use Device::SerialPort;
use feature "switch";
use EIBConnection;
use RRDs;
use Switch;
use Scalar::Util qw(looks_like_number);
#####################################################################
# define everything here
my $eib_url = "local:/tmp/eib"; #for local eibd "local:/tmp/eib" for eibd in LAN: "ip:192.168.2.220:6720"
my $device = "/dev/ttyUSB0";
my $rrdpath = "/var/www/rrd";
my @obis;
push @obis,{obis=>"1.8.0", fact=>"0.001", ga =>"9/0/0", dpt => 9, rrd_name => "zaehler_verbrauch", rrd => "c" }; #rrd: c=counter ; g=gauge
push @obis,{obis=>"16.7.0", fact=>"", ga =>"9/0/1", dpt => 9, rrd_name => "zaehler_leistung", rrd => "g" };
push @obis,{obis=>"36.7.0", fact=>"", ga =>"9/0/2", dpt => 9, rrd_name => "zaehler_leistung_L1", rrd => "g" };
push @obis,{obis=>"56.7.0", fact=>"", ga =>"9/0/3", dpt => 9, rrd_name => "zaehler_leistung_L2", rrd => "g" };
push @obis,{obis=>"76.7.0", fact=>"", ga =>"9/0/4", dpt => 9, rrd_name => "zaehler_leistung_L3", rrd => "g" };
my @countermodes = (5,15,60,1440); #Aufloesungen fuer COUNTER RRDs in Minuten (1440 = Tagesverbrauch)
my $debug = "1";
my $port = Device::SerialPort->new($device) || die $!;
$port->databits(8);
$port->baudrate(9600);
$port->parity("none");
$port->stopbits(1);
$port->handshake("none");
$port->write_settings;
$port->dtr_active(1);
$port->purge_all();
$port->read_char_time(0); # don't wait for each character
$port->read_const_time(2000); # 1 second per unfulfilled "read" call
#####################################################################
# app starting here
my ($x,$rawdata) = 0 ;
my $count = 0;
my $saw = 0;
my $start = 0;
if ($debug == 1) {print "Step 1 - Collect data \n";}
while ($start < 2) { # wait for second 1B1B1B1B01010101
($count,$saw)=$port->read(512); # will read 512 chars
if ($count == 512) { # 512 chars read?
$x = uc(unpack('H*',$saw)); # nach hex wandeln
$rawdata .= $x;
if ($rawdata =~ /1B1B1B1B01010101/) {$start ++};
} # if
} # while
if ($debug==1) {print "Step 2 - Reg Exp 1 build dataset \n";}
$rawdata =~ m/1B1B1B1B01010101(.*?)B1B1B1/;
#$ra = $1;
#print $sml."\n";
if ($debug==1) {print "Step 3 - Analyze data \n";}
# find OBIS values in raw data
foreach my $obiscnt (@obis) {
if ( $debug == 1 ) {print "\n";}
my $obissearch = &obis2search($obiscnt->{obis});
$rawdata =~ m/$obissearch(.*?)017707/;
my $obisdata = $1."01";
print "found: ".$obisdata."\n";
my $smlStatus = "";
my $smlValTime = "";
my $smlUnit = "";
my $smlScaler = "";
my $smlValue = "";
my $smlValueS = "";
## check status
if ( $debug == 1 ) {print "check sml status: ";}
$smlStatus = &parseOBIS(\$obisdata);
## check value time
if ( $debug == 1 ) {print "check sml value time: ";}
$smlValTime = &parseOBIS(\$obisdata);
## check unit
if ( $debug == 1 ) {print "check sml unit: ";}
$smlUnit = &parseOBIS(\$obisdata);
## check scaler
if ( $debug == 1 ) {print "check sml scaler: ";}
$smlScaler = &parseOBIS(\$obisdata);
## check value
if ( $debug == 1 ) {print "check sml value: ";}
$smlValue = &parseOBIS(\$obisdata);
## check value signature
if ( $debug == 1 ) {print "check sml value signature: ";}
$smlValueS = &parseOBIS(\$obisdata);
#print "done: ".$obisdata."\n";
#print $smlStatus;
# Calculate value
if ( $smlValue ne "" ) {
my $calcvalue = ($smlValue * (10**$smlScaler));
my $smlUnitStr = &getSMLUnitStr($smlUnit);
if ( $debug == 1 ) {print "Calculated value: [".$calcvalue." ".$smlUnitStr."]\n";}
my $dec_value = $calcvalue;
# scale value
if ( looks_like_number($obiscnt->{fact}) ) {
$dec_value = ($calcvalue * $obiscnt->{fact});
if ( $debug == 1 ) {print "Final value: [".$dec_value."]\n";}
}
# write rrd
if ($obiscnt->{rrd} eq "c") {
&rrd_counter ($obiscnt->{rrd_name},$dec_value)
}
if ($obiscnt->{rrd} eq "g") {
&rrd_gauge ($obiscnt->{rrd_name},$dec_value)
}
# send value to bus
&knx_write ($obiscnt->{ga},$dec_value,$obiscnt->{dpt});
if ($debug == 1) {print "GA:".$obiscnt->{ga}." value:".$dec_value." DPT:".$obiscnt->{dpt}."\n";}
}
}
$port->close() || warn "Serial port did not close proper!\n";
undef $port;
## subs ##
#####################################################################
# convert OBIS to search parameter
sub obis2search {
my ($obisid) = @_;
my $res = "77070100";
if ($debug==1) { print "OBIS ID: ".$obisid."\n";}
foreach my $c ( split(/\./,$obisid) ) {
$res .= sprintf("%02X",$c);
}
$res .= "FF";
if ($debug==1) { print "OBIS search: ".$res."\n";}
return $res;
}
#####################################################################
# parse OBIS data
sub parseOBIS {
#my ($obisdata) = @_;
my $r_obisdata = shift;
my $res = "";
if ( length($$r_obisdata) < 2 ) {
print "error --> data too short\n";
return $res;
}
my $smlDataTypeID = substr($$r_obisdata,0,2);
if ( $smlDataTypeID == "01" ) {
## no data
if ( $debug == 1 ) {print "[empty]\n";}
$$r_obisdata =~ s/^..//; # remove first 2 characters
return $res;
}
else {
#if ( $debug == 1 ) {print "found something ";}
my $smlDataType = substr($smlDataTypeID,0,1);
my $smlIntBitCode = substr($smlDataTypeID,1,1);
# only signed and unsigned int possible
if ( $smlDataType != "5" && $smlDataType != "6") {
if ( $debug == 1 ) {print "Invalid datatype [".$smlDataType."]\n"; };
return $res;
}
$$r_obisdata =~ s/^..//; # remove first 2 characters
my $smlIntBitCnt = 0;
switch ( $smlIntBitCode ) {
case 2 { $smlIntBitCnt = 8 }
case 3 { $smlIntBitCnt = 16 }
case 5 { $smlIntBitCnt = 32 }
case 9 { $smlIntBitCnt = 64 }
else { if ( $debug == 1 ) {print "Invalid integer bit count [".$smlIntBitCode."]\n"; };
return $res;
}
}
my $smlIntCharCnt = ($smlIntBitCnt/4);
# check that the rest of the string is long enought for the bit count
if ( (length($$r_obisdata)) < $smlIntCharCnt ) {
if ( $debug == 1 ) {print "String not long enough for for detected bit count [".$smlIntCharCnt."]\n"; };
return $res;
}
# get the hex values
my $hexval = substr($$r_obisdata,0,$smlIntCharCnt);
$$r_obisdata = substr($$r_obisdata,$smlIntCharCnt);
# if signed, get 2' complement
if ( $smlDataType == 5 ) {
my $hexbin = sprintf("%0${smlIntBitCnt}b",hex($hexval));
if ( substr($hexbin,0,1) == 1 ) {
#if ( $debug == 1 ) { print "2's complement \n"; }
my $hexinv = sprintf("%08x",~hex($hexval));
$res = (substr($hexinv,6,2)+1)*(-1);
}
else {
$res = hex($hexval);
}
}
else {
$res = hex($hexval);
}
if ( $debug == 1 ) { print "[".$res."]\n";}
return $res;
}
return $res;
}
#####################################################################
# get SML unit string depending on value
sub getSMLUnitStr {
my ($smlUnit) = @_;
my $res = "";
switch ($smlUnit) {
case 30 { $res = "Wh" }
case 27 { $res = "W" }
}
return $res;
}
#####################################################################
sub knx_write {
my ($dst,$value,$dpt,$response,$dbgmsg) = @_;
my $bytes;
my $apci = ($response) ? 0x40 : 0x80; # 0x40=response, 0x80=write
# DPT 1 (1 bit) = EIS 1/7 (move=DPT 1.8, step=DPT 1.7)
# DPT 2 (1 bit controlled) = EIS 8
# DPT 3 (3 bit controlled) = EIS 2
# DPT 4 (Character) = EIS 13
# DPT 5 (8 bit unsigned value) = EIS 6 (DPT 5.1) oder EIS 14.001 (DPT 5.10)
# DPT 6 (8 bit signed value) = EIS 14.000
# DPT 7 (2 byte unsigned value) = EIS 10.000
# DPT 8 (2 byte signed value) = EIS 10.001
# DPT 9 (2 byte float value) = EIS 5
# DPT 10 (Time) = EIS 3
# DPT 11 (Date) = EIS 4
# DPT 12 (4 byte unsigned value) = EIS 11.000
# DPT 13 (4 byte signed value) = EIS 11.001
# DPT 14 (4 byte float value) = EIS 9
# DPT 15 (Entrance access) = EIS 12
# DPT 16 (Character string) = EIS 15
# $dpt = $eibgaconf{$dst}{'DPTSubId'} unless $dpt; # read dpt from eibgaconf if existing
given ($dpt) {
when (/^12/) { $bytes = pack ("CCL>", 0, $apci, $value); } #EIS11.000/DPT12 (4 byte unsigned)
when (/^13/) { $bytes = pack ("CCl>", 0, $apci, $value); }
when (/^14/) { $bytes = pack ("CCf>", 0, $apci, $value); }
when (/^16/) { $bytes = pack ("CCa14", 0, $apci, $value); }
when (/^17/) { $bytes = pack ("CCC", 0, $apci, $value & 0x3F); }
when (/^20/) { $bytes = pack ("CCC", 0, $apci, $value); }
when (/^\d\d/) { return; } # other DPT XX 15 are unhandled
when (/^[1,2,3]/) { $bytes = pack ("CC", 0, $apci | ($value & 0x3f)); } #send 6bit small
when (/^4/) { $bytes = pack ("CCc", 0, $apci, ord($value)); }
when ([5,5.001]) { $bytes = pack ("CCC", 0, $apci, encode_dpt5($value)); } #EIS 6/DPT5.001 1byte
when ([5.004,5.005,5.010]) { $bytes = pack ("CCC", 0, $apci, $value); }
when (/^5/) { $bytes = pack ("CCC", 0, $apci, $value); }
when (/^6/) { $bytes = pack ("CCc", 0, $apci, $value); }
when (/^7/) { $bytes = pack ("CCS>", 0, $apci, $value); }
when (/^8/) { $bytes = pack ("CCs>", 0, $apci, $value); }
when (/^9/) { $bytes = pack ("CCCC", 0, $apci, encode_dpt9($value)); } #EIS5/DPT9 2byte float
default { LOGGER('WARN',"None or unsupported DPT: $dpt sent to $dst value $value"); return; }
}
my $leibcon = EIBConnection->EIBSocketURL($eib_url) or return("Error opening con: $!");
if ($leibcon->EIBOpenT_Group(str2addr($dst),1) == -1) { return("Error opening group: $!"); }
my $res=$leibcon->EIBSendAPDU($bytes);
$leibcon->EIBClose();
return $res;
# str2addr: Convert an EIB address string in the form "1/2/3" or "1.2.3" to an integer
sub str2addr {
my $str = $_[0];
if ($str =~ /(\d+)\/(\d+)\/(\d+)/) { # logical address
return ($1 << 11) | ($2 << 8) | $3;
} elsif ($str =~ /(\d+)\.(\d+)\.(\d+)/) { # physical address
return ($1 << 12) | ($2 << 8) | $3;
} else {
#bad
return;
}
}
}
#####################################################################
sub encode_dpt9
{
# 2byte signed float
my $state = shift;
my $data;
my $sign = ($state <0 ? 0x8000 : 0);
my $exp = 0;
my $mant = 0;
$mant = int($state * 100.0);
while (abs($mant) > 2047)
{
$mant /= 2;
$exp++;
}
$data = $sign | ($exp << 11) | ($mant & 0x07ff);
return $data >> 8, $data & 0xff;
}
#####################################################################
sub rrd_counter
{
if ($debug==1){print ("COUNTER","\n")};
foreach (@countermodes)
{
my $obisname = $_[0];
if ($debug==1){print $obisname." obisname \n";}
my $value = $_[1];
if ($debug==1){print $value." value \n";}
my $rrdname = $obisname."_".$_."\.rrd";
if ($debug==1){print ($rrdname,"\n")};
my $rrdfile = $rrdpath."\/".$rrdname;
unless (-e $rrdfile)
{
RRDs::create ($rrdfile,"DS:value:COUNTER:".(($_*60)+600).":0:10000000000","RRA:AVERAGE:0.5:1:365","RRA:AVERAGE:0.5:7:300","-s ".($_*60));
}
my $countervalue = int($value*$_*60);
RRDs::update("$rrdfile", "N:$countervalue");
}
}
#####################################################################
sub rrd_gauge
{
if ($debug==1){print ("GAUGE","\n")};
my $obisname = $_[0];
if ($debug==1){print $obisname." obisname \n";}
my $value = $_[1];
if ($debug==1){print $value." value \n";}
my $rrdname = $obisname."\.rrd";
if ($debug==1){print ($rrdname,"\n")};
my $rrdfile = $rrdpath."\/".$rrdname;
unless (-e $rrdfile)
{
RRDs::create ($rrdfile,"DS:value:GAUGE:900:0:10000000000","RRA:AVERAGE:0.5:1:2160","RRA:AVERAGE:0.5:5:2016","RRA:AVERAGE:0.5:15:2880","RRA:AVERAGE:0.5:60:8760");
}
RRDs::update("$rrdfile", "N:$value");
}
Ich hab ja selbst keinen SML-Zähler, daher ist es besser wenn es jemand macht der das vor Ort testen kann.
Bitte auch das Ergebnis posten oder am besten gleich im SVN updaten.
Ich bin gerade dabei, dass Skript so anzupassen, dass die OBIS Daten automatisch geparst werden.
Dafür habe ich mir mal die SML Definition angeschaut (VDE)
Die Values kann ich schon umrechnen.
Dann kann man sich auch den Faktor sparen.
Die Aufteilung eines OBIS Strings ist folgendermaßen:
Code:
LSOBIS UNIT/SCALER/? VALUE TRENNER
77 List start mit 7 nodes
07 01 00 01 08 01 FF OBIS ID 1-0:1.8.1
01 status (leer)
01 valtime (leer)
62 1E unit (1E => Wh)
52 FF scaler (-1)
59 00 00 00 00 00 6E B7 D6 value (7256022 => 725,6022 kWh)
01
77 ....
010802FF 0101621E52FF59 0000000000000000 0177
100700FF 0101621B520055 000000EE 0177
240700FF 0101621B520055 00000030 0177
380700FF 0101621B520055 0000007A 0177
4C0700FF 0101621B520055 00000043 0177
Wir verarbeiten personenbezogene Daten über die Nutzer unserer Website mithilfe von Cookies und anderen Technologien, um unsere Dienste bereitzustellen. Weitere Informationen findest Du in unserer Datenschutzerklärung.
Indem Du unten auf "ICH stimme zu" klickst, stimmst Du unserer Datenschutzerklärung und unseren persönlichen Datenverarbeitungs- und Cookie-Praktiken zu, wie darin beschrieben. Du erkennst außerdem an, dass dieses Forum möglicherweise außerhalb Deines Landes gehostet wird und bist damit einverstanden, dass Deine Daten in dem Land, in dem dieses Forum gehostet wird, gesammelt, gespeichert und verarbeitet werden.
Einen Kommentar schreiben: