serielle Schnittstelle Daten lesen

Begonnen von privat58, 10 Februar 2016, 20:03:22

Vorheriges Thema - Nächstes Thema

privat58

Hallo,
vorab muss ich sagen, das ich von programmieren eigentlich keine Ahnung habe und vieles nur durch Probieren hinbekomme. Manches lerne ich mit der Zeit und bei Vielem fange ich jedes mal von vorn an.
Nun aber zu meinem Problem. Ich habe das Arduino-Programm uvr2web für meine Solarsteuerung ESR31 angepasst. Da gibt es eventuell noch Probleme mit den Minusgraden, ist aber nicht das Problem.
Auf der seriellen Schnittestelle kommen die Werte zeilenweise endlos raus:
Received .
DataFrameDamaged .
Receiving .
Received .
Sensor1 5.90
Sensor2 36.90
Sensor3 0.00
Leistung 0.00
kWh 361.20
MWh 8
Pumpe1 off
Drehzahlstufe1 0

Receiving .
Received .
Sensor1 5.90
Sensor2 36.90
Sensor3 0.00
Leistung 0.00
kWh 361.20
MWh 8
Pumpe1 off
Drehzahlstufe1 0

Receiving .
Received .
Sensor1 5.90
Sensor2 36.90
Sensor3 0.00
Leistung 0.00
kWh 361.20
MWh 8
Pumpe1 off
Drehzahlstufe1 0

Receiving .
Received .

usw..

Auf dem seriellen Monitor der arduino-Software werden die Daten ohne Probleme ausgegeben. Es gibt keine Fehler etc.

Ich habe auch einen Batteriemonitor BMV600 der die Daten auch ähnlich ausgibt. (Auch dort gibt es das selbe Problem)
Das Modul des Batteriemonitors habe ich mit dem readingsBulkUpdate angepasst. Das Modul sieht so aus:
#########################################################################
# fhem Modul für Solarregelung ESR 31 von Technische Alternative
# Die Beschreibung und Kommentierung dieses Moduls ist in deutsch gehalten,
# um anderen das erstellen eigener Module zu erleichtern.
#########################################################################
#
# # Kommentarbereich
package main;

use strict;                         #
use warnings;                       #
use Time::HiRes qw(gettimeofday);   #

sub ESR31_Read($);                  #
sub ESR31_Ready($);                 #
sub ESR31_setbits($$);              #
sub ESR31_SetReading($$$$);         #

my $buf1 = "";                      # Hilfsvariable für auslesen des Buffers
my $Zeit = 0;                       # Hilfsvariable Zeit
my $Tmin = -30; # Temperaturgrenze minimum
my $Tmax = 150; # Temperaturgrenze maximum
my $Dmin = 0; # Drehzahlstufe minimum
my $Dmax = 31; # Drehzahlstufe maximum
my $Pmin = 0; # Momentanleistung minimum
my $Pmax = 4500; # Momentanleistung maximum


my %ESR31_sets = (    #

);


#########################################################################
sub ESR31_Initialize($)
{
my ($hash) = @_;

require "$attr{global}{modpath}/FHEM/DevIo.pm";

$hash->{ReadFn}  = "ESR31_Read";
$hash->{ReadyFn} = "ESR31_Ready";
$hash->{DefFn}   = "ESR31_Define";
$hash->{UndefFn} = "ESR31_Undef";
$hash->{SetFn}   = "ESR31_Set";
$hash->{AttrList} =
  "do_not_notify:1,0 loglevel:0,1,2,3,4,5,6 " . $readingFnAttributes;
}

######################################################################### #
sub ESR31_Define($$)
{
my ( $hash, $def ) = @_;
my @a = split( "[ \t][ \t]*", $def );

return "wrong syntax: define <name> ESR31 [devicename|none]"
  if ( @a != 3 );

DevIo_CloseDev($hash);
my $name = $a[0];
my $dev  = $a[2];

if ( $dev eq "none" )
{
Log3 undef, 1, "ESR31 device is none, commands will be echoed only";
return undef;
}

$hash->{DeviceName} = $dev;
my $ret = DevIo_OpenDev( $hash, 0, "ESR31_Poll" );
return $ret;
}

#########################################################################
sub                   #
  ESR31_Undef($$)    #
{                     #
my ( $hash, $arg ) = @_;       #
DevIo_CloseDev($hash);         #
RemoveInternalTimer($hash);    #
return undef;                  #
}    #

#########################################################################
sub ESR31_Set($@)
{
my ( $hash, @a ) = @_;
my $name = $hash->{NAME};
return "\"set ESR31\" needs at least an argument" if ( @a < 2 );

my $cmd = $ESR31_sets{ $a[1] };
return "Unknown argument $a[1], choose one of "
  . join( " ", sort keys %ESR31_sets )
  if ( !defined($cmd) );

Log3 $name, 3, "DevIo_SimpleWrite: $hash $cmd";
DevIo_SimpleWrite( $hash, $cmd, 1 );
return undef;
}

#########################################################################
sub ESR31_Read($)
{
my ($hash) = @_;
my $name = $hash->{NAME};
my ( $data, $crc );
my $buf = DevIo_SimpleRead($hash);
my $tn  = TimeNow();
my ( $key, $val ) = ( "key", "val" );
#my $Gesamtertrag = 0; 
 
###### Daten der seriellen Schnittstelle holen und an $buf1 anhaengen

return "" if ( !defined($buf) );
$buf1 .= $buf;

#Log3 $name, 5, "Current buffer content: "  $buf1;

        my $pos_cs0 = index($buf1,"\nReceiving"); #sucht nach neuer Zeile mit Receiving
        my $pos_cs1 = -1;
#if($pos_cs0 >= 0)
#{
#       $pos_cs1 = index($buf1,"\nReceiving",$pos_cs0+1);
#}
#if(($pos_cs0 >= 0) && ($pos_cs1 >= 0)) #wenn 2mal Receiving dann beginnt er das lesen
{
readingsBeginUpdate($hash);
              my @e = split("\n",$buf1); #Splittet die Daten bei einer neuen Zeile auf
my $V_first = index($e[1],"Receiving") >= 0; #schaut in die Schlaufe und fängt bei Receiving an
for my $i (0 .. $#e)
{

      my @e_ = split(" ",$e[$i]);
if($e_[0] eq "Received")
{
next;
}
      if($e_[0] eq "Receiving")
{
readingsBulkUpdate($hash,"Daten lesen",$e_[1]); # Daten lesen
}

      if($e_[0] eq "Received")
{
        readingsBulkUpdate($hash,"Daten empfangen",$e_[1]); # Daten empfangen
}
     
      if($e_[0] eq "Sensor1")
{
readingsBulkUpdate($hash,"Sensor1",sprintf("%.1f",$e_[1])); # Sensor1 Temperatur in *C
}
      if($e_[0] eq "Sensor2")

        readingsBulkUpdate($hash,"Sensor2",sprintf("%.1f",$e_[1])); # Sensor2 Temperatur in *C
}
      if($e_[0] eq "Sensor3")
{
        readingsBulkUpdate($hash,"Sensor3",sprintf("%.1f",$e_[1])); # Sensor3 Durchflussmenge in l/h
}
  if($e_[0] eq "Sensor4")
{
        readingsBulkUpdate($hash,"Sensor4",sprintf("%.1f",$e_[1])); # Sensor4
}
      if($e_[0] eq "Sensor5")
{
        readingsBulkUpdate($hash,"Sensor5",sprintf("%.1f",$e_[1])); # Sensor5
}
      if($e_[0] eq "Sensor6")
{
        readingsBulkUpdate($hash,"Sensor6",sprintf("%.1f",$e_[1])); # Sensor6
}
      if($e_[0] eq "Sensor7")
{
        readingsBulkUpdate($hash,"Sensor7",sprintf("%.1f",$e_[1])); # Sensor7
}
      if($e_[0] eq "Sensor8")
{
        readingsBulkUpdate($hash,"Sensor8",sprintf("%.1f",$e_[1])); # Sensor8
}
      if($e_[0] eq "Sensor9")
{
        readingsBulkUpdate($hash,"Sensor9",sprintf("%.1f",$e_[1])); # Sensor9
}
      if($e_[0] eq "DataFrameDamaged")
{
        readingsBulkUpdate($hash,"Datenrahmen defekt",$e_[1]); # Datenrahmen defekt und verworfen
}
      if($e_[0] eq "Pumpe1")
{
        readingsBulkUpdate($hash,"Pumpe",$e_[1]); # Pumpe ein / aus
}
      if($e_[0] eq "Drehzahlstufe1")
#{
#if(($e_[1]) > $Dmin && ($e_[1]) < $Dmax ) #nur Werte übernehmen die im gültigen bereich liegen
{
readingsBulkUpdate($hash,"Drehzahlstufe",$e_[1]); # Drehzahlstufe Pumpe
}
#}
      if($e_[0] eq "kWh")
{
        readingsBulkUpdate($hash,"kWh",$e_[1]); # Gesamt kWh
#$Gesamtertrag = $e_[1] /1000 ;  #für Gesamtertrag als Reading
}
      if($e_[0] eq "MWh")
{
        readingsBulkUpdate($hash,"MWh",$e_[1]); # Gesamt MWh
#$Gesamtertrag = $Gesamtertrag + ($e_[1]);           #für Gesamtertrag als Reading
}
      if($e_[0] eq "Leistung")
{
        readingsBulkUpdate($hash,"Leistung",sprintf("%.0f",$e_[1]*1000)); # Momentanleistung
}
     
    }
#readingsBulkUpdate($hash,"Gesamtertrag",$Gesamtertrag);
#readingsBulkUpdate($hash,"Gesamtertrag",sprintf("%.1f",$Gesamtertrag)); # errechneter Gesamtertrag aus kWh und MWh als Reading
#readingsBulkUpdate($hash,"Power",sprintf("%.2f",$Power));

readingsEndUpdate( $hash, 1 );
$buf1 = "";
}
}

#########################################################################
sub ESR31_Ready($)
{
my ($hash) = @_;

return DevIo_OpenDev( $hash, 1, undef )
  if ( $hash->{STATE} eq "disconnected" );

# This is relevant for windows/USB only
my $po = $hash->{USBDev};
my ( $BlockingFlags, $InBytes, $OutBytes, $ErrorFlags ) = $po->status;
return ( $InBytes > 0 );
}

#########################################################################
sub ESR31_Poll($)
{
my ($hash) = @_;
my $name = $hash->{NAME};
push @{ $hash->{SENDBUFFER} }, $ESR31_sets{"logmode"};
DevIo_SimpleWrite( $hash, "07F0009B01014A070F", 1 );
Log3 $name, 5, "RS232 Modus PC-Master";
return undef;
}

#########################################################################
sub ESR31_SetReading($$$$)
{
my ( $hash, $tn, $key, $val ) = @_;
my $name = $hash->{NAME};
Log3 $name, 4, "$name: $key $val";
$hash->{READINGS}{$key}{TIME} = $tn;
$hash->{READINGS}{$key}{VAL}  = $val;
DoTrigger( $name, "$key: $val" );
}


1;


Im großen und ganzen stimmen die Werte, die ankommen. Aber ab und zu wird etwas nicht richtig "gelesen" und es kommen total falsche Werte, die ncht stimmen. Damit stimmt natürlich kein Plot und auch ein "event on change reading" wird irreführend ausgelöst.

Eventuell hat jemand einen Tip für mich.
Steffen

privat58

Hochschieb ;)
Ich habe heute Vormittag den Arduino am Rechner gehabt und die Daten angeschaut. Aus der Schnittstelle kommen die Daten ohne Fehler raus.
Somit liegt das Problem an meinem Modul, wo sie dann fehlerhaft nachbereitet werden.

privat58

Leider komme ich nicht weiter und werde wohl mit den Aussetzern leben müssen, falls jemand eine Idee hat bin ich jederzeit offen.
Hatte angenommen, das noch andere einen Arduino seriell auslesen. Dem ist wahrscheinlich nicht so.
mfg

CoolTux

#3
Die Frage die sich mir stellt ist, sind Deine Reading Values fehlerhaft oder schon die Raw Daten. Immer hin formatierst Du ja Deine Values, eventuell kommen daher die Fehler zu stande. Am besten Du schneidest die erste Zeit Irgendwie Deine Rawdaten mit und legst sie zum Vergleichen in ein log ab. Wegen meiner auch zuschaltbar über das Attribut verbose.



Grüße
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

Icinger

Fürs auslesen der Seriellen gibts extra das ECMD-Device, mit dem geht das ganz easy.
Verwende deine Zeit nicht mit Erklärungen. Die Menschen hören (lesen) nur, was sie hören (lesen) wollen. (c) Paulo Coelho

privat58

Ups, gar nicht bitbekommen, das da Antworten waren. Sorry
@CoolTux
Die Rohdaten stimmen. Diese hatte ich schon mal stundenlag mitschreiben lassen (auch auf einem Win-PC). Was immer mal nicht stimmt sind die Reading Values (egal ob formatiert oder nicht). Dadurch nehme ich an, das ich einen Fehler im Modul habe, kann diesen aber nicht finden.
Das selbe Problem hatten wir auch bei dem Batteriemonitor https://forum.fhem.de/index.php/topic,48130.msg397993.html#msg397993
Hier hatte dann Askie eine Grenze der Werte nach unten und oben festgelegt und alles, was nicht dazwischen passt wird ignoriert.
@Icinger
ECMD nutze ich schon für die Holzvergaser-Steuerung. Da ich aber nun mittlerweile 4 Geräte habe, die seriell ausgelesen werden, wäre es mir lieber dies in einzelne Module auszulagern, da eventuell auch andere User die Geräte haben und es dann einzeln genutzt werden könnte.

Was mich halt absolut irritiert ist, das die Reading Values im großen und ganzen stimmen aber es ab und zu totale Ausreißer in alle Himmelsrichtungen gibt.