Hallo,
leider ist "Fehlermeldungen" ja geschlossen, daher hoffe ich, dass jemand den kleinen Bugfix einschecken kann:
2014.10.31 09:43:44 1: ReadingsBulkUpdate: value: 0.0336111111111111 name: Ku_Deckenlampe reading: power-hourly - value or rd->val not defined
2014.10.31 09:43:44 1: PERL WARNING: Use of uninitialized value in string ne at fhem.pl line 3678.
Das tritt immer dann auf, wenn das reading keinen Wert hat oder noch nicht existiert:
fhem.pl:
Log(1,"ReadingsBulkUpdate: value: $value name: $hash->{NAME} reading: $reading - value or rd->val not defined") if(!defined($value) || !defined($readings->{VAL}));
$changed= !($attreocr || $attreour)
|| $eour
|| ($eocr && ($value ne $readings->{VAL}) && $threshold_reached);
($value ne $readings->{VAL})
müste ersetzt werden durch:
defined($readings->{VAL) && ($value ne $readings->{VAL})
Gruß
Elektrolurch
Deine Aenderung wuerde die Meldung in der Tat vermeiden, allerdings bin ich noch nicht sicher, ob das sinnvoll ist. Readings ohne VAL finde ich nicht in Ordnung, und sollte mAn gefixt werden. Oder mir erklaert jemand, warum man hier eine Ausnahme machen sollte.
Ich muss es noch Mal gegenchecken, aber ich glaube, die Meldung kommt auch, wenn das reading nicht existiert und nicht nur der val.
Zitat von: rudolfkoenig am 01 November 2014, 00:21:57
Readings ohne VAL finde ich nicht in Ordnung, und sollte mAn gefixt werden. Oder mir erklaert jemand, warum man hier eine Ausnahme machen sollte.
Hm... ich kann Dir schon erklären, wie es zu Readings ohne VAL kommen kann:
Wenn man ein Modul hat, das eine bestimmte "Liste" von
möglicherweise vorhandenen Readings füllen möchte und dazu diese Liste abarbeitet, ohne im Vorfeld zu wissen, ob es für das jeweilige Reading überhaupt einen Wert geben kann.
Als Beispiel passiert sowas beispielsweise in meinem GDS Modul, in dem ein Array von Hashes sämtlicher eventuell vorhandener Wetterdaten in einer Schleife abgearbeitet wird, und an ReadingsBulkUpdate jeweils ein ReadingName und ein ReadingValue übergeben wird, unabhängig davon, ob ein ReadingValue existiert.
Je nach verwendeter Wetterstation sind nämlich nicht immer alle möglichen Wetterwerte vorhanden, sondern nur eine Teilmenge davon.
Bisher habe ich mich immer auf die bestehende und sehr zuverlässige "Logik" gestützt, dass BulkUpdate einfach keine Readings ohne Wert anlegt.
Es wäre natürlich nicht schwer, dies in meinem Modul abzufangen. Aber man würde damit auf ein Stück liebgewonnener Logik in Deiner fhem.pl verzichten müssen. Bin mir auch nicht ganz sicher, ob ich der einzige bin, der sich bisher in seinem Modul auf diese schöne Logik verläßt.
Zitatich kann Dir schon erklären, wie es zu Readings ohne VAL kommen kann:
Dann musst du das so machen, dass ich es verstehe, am besten mit Code. Ich will nicht mit Raten anfangen.
Das hab ich doch lang und breit erklärt? Welchen Teil hast Du nicht verstanden, sodass Du raten musst?
Moin Rudi,
siehe z.B. hier:
http://forum.fhem.de/index.php/topic,28047.0.html
In Antwort 3 habe ich für OWMULTI den Ablauf beschrieben.
Da ist das Problen deshalb aufgetaucht, weil der "Container" für $hash->{READINGS} angelegt wird für weitere Informationen, bevor das erste Reading existiert.
Gruß Joachim
Hier sammle ich die (möglicherweise vorhandenen) Daten aus dem XML File nach %readings
my (%readings, @dummy, $i, $k, $n, $v, $t);
# topLevel informations
@dummy = split(/\./, $alertsXml->{identifier});
$readings{a_identifier} = $alertsXml->{identifier} if($_gdsAll || $_gdsDebug);
$readings{a_idPublisher} = $dummy[5] if($_gdsAll);
$readings{a_idSysten} = $dummy[6] if($_gdsAll);
$readings{a_idTimeStamp} = $dummy[7] if($_gdsAll);
$readings{a_idIndex} = $dummy[8] if($_gdsAll);
$readings{a_sent} = $alertsXml->{sent};
$readings{a_status} = $alertsXml->{status};
$readings{a_msgType} = $alertsXml->{msgType};
# infoSet informations
$readings{a_language} = $alertsXml->{info}[$info]{language} if($_gdsAll);
$readings{a_category} = $alertsXml->{info}[$info]{category};
$readings{a_event} = $alertsXml->{info}[$info]{event};
$readings{a_responseType} = $alertsXml->{info}[$info]{responseType};
$readings{a_urgency} = $alertsXml->{info}[$info]{urgency} if($_gdsAll);
$readings{a_severity} = $alertsXml->{info}[$info]{severity} if($_gdsAll);
$readings{a_certainty} = $alertsXml->{info}[$info]{certainty} if($_gdsAll);
# eventCode informations
# loop through array
$i = 0;
while(1){
($n, $v) = (undef, undef);
$n = $alertsXml->{info}[$info]{eventCode}[$i]{valueName};
if(!$n) {last;}
$n = "a_eventCode_".$n;
$v = $alertsXml->{info}[$info]{eventCode}[$i]{value};
$readings{$n} .= $v." " if($v);
$i++;
}
# time/validity informations
$readings{a_effective} = $alertsXml->{info}[$info]{effective} if($_gdsAll);
$readings{a_onset} = $alertsXml->{info}[$info]{onset};
$readings{a_expires} = $alertsXml->{info}[$info]{expires};
$readings{a_valid} = checkCAPValid($readings{a_expires});
$readings{a_onset_local} = capTrans($readings{a_onset});
$readings{a_expires_local} = capTrans($readings{a_expires});
$readings{a_sent_local} = capTrans($readings{a_sent});
# text informations
$readings{a_headline} = $alertsXml->{info}[$info]{headline};
$readings{a_description} = $alertsXml->{info}[$info]{description} if($_gdsAll || $_gdsLong);
$readings{a_instruction} = $alertsXml->{info}[$info]{instruction} if($readings{a_responseType} eq "Prepare"
&& ($_gdsAll || $_gdsLong));
# area informations
$readings{a_areaDesc} = $alertsXml->{info}[$info]{area}[$area]{areaDesc};
$readings{a_areaPolygon} = $alertsXml->{info}[$info]{area}[$area]{polygon} if($_gdsAll || $_gdsPolygon);
# area geocode informations
# loop through array
$i = 0;
while(1){
($n, $v) = (undef, undef);
$n = $alertsXml->{info}[$info]{area}[$area]{geocode}[$i]{valueName};
if(!$n) {last;}
$n = "a_geoCode_".$n;
$v = $alertsXml->{info}[$info]{area}[$area]{geocode}[$i]{value};
$readings{$n} .= $v." " if($v);
$i++;
}
$readings{a_altitude} = $alertsXml->{info}[$info]{area}[$area]{altitude} if($_gdsAll);
$readings{a_ceiling} = $alertsXml->{info}[$info]{area}[$area]{ceiling} if($_gdsAll);
Hier gehe ich in einer Schleife über %readings und übergebe Namen und Werte an readingsBulkUpdate.
Zu diesem Zeitpunkt existiert noch KEINES der möglichen Readings.
readingsBeginUpdate($hash);
while(($k, $v) = each %readings){
readingsBulkUpdate($hash, $k, $v); }
readingsEndUpdate($hash, 1);
@Joachim: $hash->{READINGS} ist nicht das Problem, sondern dass jemand $hash->{READINGS}{"power-hourly"} angelegt hat, ohne $hash->{READINGS}{"power-hourly "}{VAL} zu fuellen.
@betateilchen: in deinem Fall sollte es auch kein Problem geben, da am Anfang $hash->{READINGS}{$v} nicht angelegt ist.
Entweder gibts ein Reading nicht, oder es ist richtig angelegt. Ich wehre mich nur gegen halb-angelegte Readings.
Hallo Rudi,
siehe oben, das reading existierte in meinem Beispiel nicht mehr, da mit delete gelöscht.
Außerdem kann val auch ein "undef" enthalten, warum auch immer.
Was ist der Sinn der Abfrage in der fhem.pl / readingsBulkUpdate?
Das Update soll nur dann u.a. erfolgen, wenn der Wert nicht gleich dem neuen Wert ist.
Das heißt doch umgekehrt: Wenn das reading und/oder der Wert nicht existiert, dann update machen.
Gruß
Elektrolurch
@ Rudi,
In OWMULTI ist es ja jetzt auch gelöst, das "Problem" entsteht dann, wenn man bei der Initialisierung des Moduls, z.B. Einheiten oder variable weitere Bezeichnungen erzeugt.
Bei OWMULTI z.B.:
$hash->{READINGS}{$owg_channel}{TYPE} = $cnama[1];
$hash->{READINGS}{$owg_channel}{UNIT} = $unarr[0];
$hash->{READINGS}{$owg_channel}{UNITABBR} = $unarr[1];
Dann existiert Der "Container" $hash->{READINGS}{"power-hourly"} schon für TYPE, UNIT, UNITABBR aber noch nicht für VAL, da das erst beim readingsBulkUpdate angelegt wird.
Abfangen kann man das entweder im Modul bei der Initialisierung, oder in der fhem.pl.
Was nun der "saubere" Weg ist, weiß ich nicht.
Gruß Joachim
@Joachim:
solche Eintraege (TYPE/UNIT/etc) werden nicht unterstuetzt, z.Bsp. nicht gespeichert.
Wenn du sie unbedingt haben willst, dann bitte sicherstellen, dass die notwendigen Werte VAL und TIME gesetzt werden, z.Bsp. readingsBulkUpdate vorher aufrufen.
Falls man unsicher ist, sollte man $hash->{READINGS} nicht direkt anfassen, sondern nur ueber die angebotenen Routinen.
@Elektrolurch:
VAL kann kein undef enthalten, wenn es ueber readingsBulkUpdate gesetzt wird.
Falls man ein reading entfernt, dann sollte man es komplett entfernen.
-> Ich finde die Fehlermeldung immer noch ok.
Zitatsolche Eintraege (TYPE/UNIT/etc) werden nicht unterstuetzt, z.Bsp. nicht gespeichert.
Wenn du sie unbedingt haben willst,
War mir klar, und OWMULTI ist nicht meins, fand das nur als Beispiel recht gut.
Gruß Joachim
Zitat von: rudolfkoenig am 02 November 2014, 11:33:37
@betateilchen: in deinem Fall sollte es auch kein Problem geben, da am Anfang $hash->{READINGS}{$v} nicht angelegt ist.
Dann bin ich ja beruhigt. Nichtsdestotrotz werde ich das GDS bei Gelegenheit dahingehend ändern, dass readingsBulkUpdate nur dann aufgerufen wird, wenn es überhaupt einen Wert für das Reading gibt.
delete($hash->{READINGS}{'min-Laststellung'});
ist doch sauber entfernt?
Und auch dann kommt die Warnung aus readingsBulkUpdate,
aber das hatte ich ja schon oben geschrieben....
Ich würde - aus einem reinen Bauchgefühl heraus - an solch einer Stelle immer mit undef arbeiten anstatt mit delete.
@Elektrolurch: das ist mAn perfekt geloescht, und es sollte danach auch nicht zum Problem kommen, es sei denn, dass nach dem Loeschen jemand $hash->{READINGS}{'min-Laststellung'} wieder anlegt, z.Bsp indem man $hash->{READINGS}{'min-Laststellung'}{VAL} prueft.
Falls du meinst, dass das nicht der Fall ist, und mir einen Beispiel ohne speziellen Hardware (dummy/FS20) zusammenstellst, werde ich es pruefen.
@betateilchen: Zitat "perldoc -f undef":
ZitatSaying "undef $hash{$key}" will probably not do what you expect on most predefined variables or DBM list values, so don't do that; see "delete".
Zitat von: rudolfkoenig am 03 November 2014, 23:45:14
@betateilchen: Zitat "perldoc -f undef":
lustig, bei "delete" steht, dass undef sogar perfomanter sei :)
Klar, je weniger man tut, desto schneller ist es :)
Okay:
Zitat:
es sei denn, dass nach dem Loeschen jemand $hash->{READINGS}{'min-Laststellung'} wieder anlegt, z.Bsp indem man $hash->{READINGS}{'min-Laststellung'}{VAL} prüft...
ist das wirklich so?
defined($hash->{READINGS}{'min-Laststellung'}{VAL}) und
exists($hash->{READINGS}{'min-Laststellung'}{VAL})
legen wieder das gelöschte reading an?
Ich dachte immer, das die Abrage an dem Punkt endet, an dem der erste Teil nicht mehr definiert/existiert und wenn also 'min-Laststellung' nicht existiert, perl dann dort aufhört und nicht das reading anlegt, um dann festzustellen, das {VAL} nicht deffiniert ist.
Sollte das also tatsächlich in perl so sein, dann muss ich meinen Code mal prüfen...
Gruß
Elektrolurch
P.S.: Den Unterschied zwischen defined und exists kenne ich.
Ja, das ist wirklich so, hat mich oft gebissen.
Sonst koennte man ReadingsVal auch einfacher bauen:
sub
ReadingsVal($$$)
{
my ($d,$n,$default) = @_;
if(defined($defs{$d}) &&
defined($defs{$d}{READINGS}) &&
defined($defs{$d}{READINGS}{$n}) &&
defined($defs{$d}{READINGS}{$n}{VAL})) {
return $defs{$d}{READINGS}{$n}{VAL};
}
return $default;
}