Immer drei Codes vorhalten

Begonnen von TomLee, 25 Juni 2023, 13:10:57

Vorheriges Thema - Nächstes Thema

TomLee

Der Titel hat noch wenig mit meiner ersten Frage zu tun, wenn mir jemand bitte hilft, ergibt sich das aber noch im weiteren Verlauf.

Gegeben sind zum testen:

defmod du_reed dummy
attr du_reed setList on off

setstate du_reed on
setstate du_reed 2023-06-25 02:34:11 codes 1234 5678 9101
setstate du_reed 2023-06-25 12:50:21 state on

Und der dummy (wird erst später gebraucht):
defmod du_doorpen dummy

setstate du_doorpen 1234
setstate du_doorpen 2023-06-24 17:15:11 state 1234

Macht wenig Sinn die Elemente von einem Array in das andere zu stupsen, ist nur beispielhaft, es soll aber mein Unverständnis verdeutlichen.
Das hier funzt:

defmod not_du_reed notify du_reed:on {\
my @codes = split(' ',ReadingsVal('du_reed','codes',0));;\
my @a;;\
for (@codes){\
push (@a,$_) }\
return join q( ), @a;;\
}

Warum klappt das dann nicht genauso mit der Schleife wenn ich die Elemente des Array in einem Hash als Key haben möchte, @codes gibt doch genauso die Anzahl zurück ?
(Ich erwähns gleich, die Elemente als Key deswegen, weil später beim auslösen des notify das Schlüssel->Wert-Paar aus dem Hash gelöscht werden soll, das zu dem Wert in dem du_doorpen dummy passt)

defmod not_du_reed notify du_reed:on {\
my @codes = split(' ',ReadingsVal('du_reed','codes',0));;\
my %hcodes=();;\
my @a = keys(%hcodes);;\
\
for (@codes){\
$hcodes{"$codes[$_]"}=$_};;\
print Dumper \%hcodes;;\
}

Ergibt:
2023.06.25 12:50:21 1: PERL WARNING: Use of uninitialized value within @codes in string at (eval 3369) line 7.
2023.06.25 12:50:21 3: eval: my $EVENT=   $evalSpecials->{'%EVENT'};my $EVTPART0=   $evalSpecials->{'%EVTPART0'};my $NAME=   $evalSpecials->{'%NAME'};my $SELF=   $evalSpecials->{'%SELF'};my $TYPE=   $evalSpecials->{'%TYPE'};{
my @codes = split(' ',ReadingsVal('du_reed','codes',0));
my %hcodes=();
my @a = keys(%hcodes);

for (@codes){
$hcodes{"$codes[$_]"}=$_};
print Dumper \%hcodes;
}
$VAR1 = {
          '' => 9101
        };
2023.06.25 12:50:21 3: not_du_reed return value: 1

Ich bekomms nur mit Hilfe des Bereichsoperator hin:

defmod not_du_reed notify du_reed:on {\
my @codes = split(' ',ReadingsVal('du_reed','codes',0));;\
my %hcodes=();;\
\
for (0..@codes-1){\
$hcodes{"$codes[$_]"}=$_};;\
print Dumper \%hcodes;;\
}

TomLee

ZitatMal wieder von hinten durch die Brust ins Auge?

Ich mein nicht das die Verwendung von Each mich hier weiter bringt. Du bist aber immer schon 5 Schritte voraus, wo ich gerade mal beim zweiten bin, vlt. dann nicht ganz auszuschliessen.

Wenn du_reed auslöst wird, soll das Schlüsselpaar das zu dem Wert in du_doorpen passt aus dem Hash gelöscht werden (Code verbraucht).

Das klappt auch, so:

defmod not_du_reed notify du_reed:on {\
my @codes = split(' ',ReadingsVal('du_reed','codes',0));;\
my %hcodes=();;\
\
for (1..@codes-1){\
$hcodes{"$codes[$_]"}=$_};;\
if (exists $hcodes{ReadingsVal('du_doorpen','state',0)}) {\
delete($hcodes{ReadingsVal('du_doorpen','state',0)});;\
};;\
print Dumper \%hcodes;;\
}

Aber dann komm ich nicht weiter, es soll der verbrauchte Code ersetzt werden durch einen neuen -> immer drei Codes vorgehalten werden:

du_reed:on {
my @codes = split(' ',ReadingsVal('du_reed','codes',0));
my %hcodes=();
my @a = keys(%hcodes);

for (1..@codes-1){
$hcodes{"$codes[$_]"}=$_};
if (exists $hcodes{ReadingsVal('du_doorpen','state',0)}) {
delete($hcodes{ReadingsVal('du_doorpen','state',0)});
push (@a,int(rand(9999)));
my $v = join q( ), @a;
fhem("setreading du_reed codes $v");
};
#print Dumper \%hcodes;
}

Warum wird alles was nach dem delete steht nicht ausgeführt ?

betateilchen

#2
Zitat von: TomLee am 25 Juni 2023, 14:20:05Ich mein nicht das die Verwendung von Each mich hier weiter bringt. Du bist aber immer schon 5 Schritte voraus, wo ich gerade mal beim zweiten bin, vlt. dann nicht ganz auszuschliessen.

Meinen Vorschlag mit Each() hatte ich wieder gelöscht, weil ich trotz mehrmaligem Lesen Deines Beitrags immer noch nicht verstanden hatte, was Du als Ergebnis haben möchtest, bzw. was die grundsätzliche Aufgabenstellung ist.

Beispielsweise verstehe ich das hier schon nicht:

my %hcodes=();
my @a = keys(%hcodes);

Was soll denn in @a landen, wenn in %hcodes überhaupt noch nichts drinsteht, weil es erst in der Zeile davor leer instanziert wird?

Und warum willst Du eigentlich krampfhaft mit einem hash arbeiten, wenn die Werte doch schon in einem array stehen, das Du entsprechend verwenden kannst?
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

betateilchen

Die Aufgabe besteht darin, durch ein notify eine Liste mit 3 zufälligen 4-stelligen (!) Werten zu befüllen, indem jeweils ein "verbrauchter" Wert durch einen anderen ersetzt wird - korrekt?

-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

TomLee

ZitatUnd warum willst Du eigentlich krampfhaft mit einem hash arbeiten, wenn die Werte doch schon in einem array stehen, das Du entsprechend verwenden kannst?

Ist es verständlicher nach meinem letzten Beitrag ?

TomLee

Zitat von: betateilchen am 25 Juni 2023, 14:32:24Die Aufgabe besteht darin, durch ein notify eine Liste mit 3 zufälligen 4-stelligen (!) Werten zu befüllen, indem jeweils ein "verbrauchter" Wert durch einen anderen ersetzt wird - korrekt?

Genau, mit qrencode, will ich noch entsprechende QR-Codes erzeugen und den jewiligen verbrauchten löschen und eunen neuen ergänzen.
Damit hab ich mich bisher aber noch nicht beschäftigt wie ich das umsetze  ::)

betateilchen

#6
Zitat von: TomLee am 25 Juni 2023, 14:32:44Ist es verständlicher nach meinem letzten Beitrag ?

Nein, es erklärt nicht, warum Du den hash brauchst.

Zitat von: betateilchen am 25 Juni 2023, 14:32:24Die Aufgabe besteht darin, durch ein notify eine Liste mit 3 zufälligen 4-stelligen (!) Werten zu befüllen, indem jeweils ein "verbrauchter" Wert durch einen anderen ersetzt wird - korrekt?

sub du_test {
  my $checkVal = shift // "0000";
  my @codes = split(' ',ReadingsVal('du_reed','codes',"0 0 0"),3);
  my $newCode = sprintf("%04d",rand(9999));
  @codes = map { $_ eq $checkVal ? $newCode : $_ } @codes;
  return join(" ",@codes);
}

Die Funktion wird vom notify aus mit dem Wert aus du_doorpen aufgerufen.

du_reed:on {du_test(ReadingsVal('du_doorpen','state','0000'))}

Das setreading ist in der Funktion noch nicht enthalten.

Ansonsten tut die Funktion genau das was Du möchtest:
Sie ersetzt einen vorhandenen Wert, der als Parameter übergeben wird, durch einen neuen, wenn der übergebene Wert im Array gefunden wurde.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

betateilchen

#7
Hier noch die Variante mit eingebautem setreading:

sub du_test {
  my $checkVal = shift // "0000";
  my @codes = split(' ',ReadingsVal('du_reed','codes',"0 0 0"),3);
  my $newCode = sprintf("%04d",rand(9999));
  @codes = map { $_ eq $checkVal ? $newCode : $_ } @codes;
  CommandSetReading(undef,"du_reed codes ".join(" ",@codes));
}

Zitat von: TomLee am 25 Juni 2023, 14:36:47mit qrencode will ich noch entsprechende QR-Codes erzeugen

Das lässt sich problemlos in die Funktion einbauen.

Dass es für die Erzeugung von QR-Codes in FHEM ein eigenes Modul gibt, weißt Du hoffentlich.
Vielleicht lässt sich das sogar hier einbinden.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

TomLee

ZitatNein, es erklärt nicht, warum Du den hash brauchst.

Ich war der Meinung man kann in einem Array ein bestimmtes Element nicht ersetzen, nur anfügen, darum dann der Gedanke das über den Schlüssel eines Hash zu machen.

Auf den Vergleich und ersetzen in der Schleife wär/bin ich nicht gekommen, das ist sehr cool, vielen Dank dafür.

Warum du in split den Parameter LIMIT extra angegeben hast und den Ersatzwert mit Komma getrennt, versteh ich noch nicht, aber ich merk mir das und werd mich mit beschäftigen.

Das Beispiel mit dem setreading wär nicht nötig gewesen soviel hab ich bis jetzt schon verstanden das selbst umzusetzen, trotzdem aber auch danke dafür. Ich werd aber bei setreading bleiben und nicht CommandSetReading verwenden.

Ich bin nicht der schnellste aber ich werd das mit qrencode auch hinbekommen, die Frage die sich mir halt als erstes stellt, ist es ein Problem immer alle Dateien zu ersetzen oder soll man es so umsetzen das nur die ersetzt wird deren Code verbraucht wurde.

Ich hab mich bisher schon mit dem Modul beschäftigt und mit qrencode, das Modul nutzt einen externen Service und ich frag mich ob das sein muss wenn es auch einfach mit qrencode geht.

betateilchen

#9
Zitat von: TomLee am 25 Juni 2023, 16:09:09Warum du in split den Parameter LIMIT extra angegeben hast

Weil ich nicht mehr als 3 Werte zurückbekommen möchte.
Um den Code an dieser Stelle in diesem Punkt auch in 2 Jahren noch nachvollziehbar zu machen, gebe ich den Parameter explizit an.

Zitat von: TomLee am 25 Juni 2023, 16:09:09und den Ersatzwert mit Komma getrennt, versteh ich noch nicht,

Weil Du deinen Code immer auch mindestens einmal mit den "default" Werten aus ReadingsVal() oder ReadingsNum() durchspielen solltest, um zu prüfen, ob er auch dann noch fehlerfrei funktioniert. Wenn Du bei ReadingsVal() einen numerischen Wert als default zurückgibst, kannst Du den nicht mit split() als String aufteilen.

Zitat von: TomLee am 25 Juni 2023, 16:09:09die Frage die sich mir halt als erstes stellt, ist es ein Problem immer alle Dateien zu ersetzen oder soll man es so umsetzen das nur die ersetzt wird deren Code verbraucht wurde.

Das verstehe ich nicht.

Zitat von: TomLee am 25 Juni 2023, 16:09:09das Modul nutzt einen externen Service und ich frag mich ob das sein muss wenn es auch einfach mit qrencode geht.

qrencode ist nicht "einfach".
Man kann sich fragen, ob man einen externen Service verwenden möchte oder nicht, ok.
Aber man muss auch nicht permanent versuchen, das Rad neu zu erfinden.
Wenn sich jemand schon soweit Gedanken gemacht hat, dass man an eine URL nur einen Wert anhängen muss, um einen QR-Code zu bekommen, kann und soll man diese Vorarbeit ruhig nutzen.

sub du_test {
  my $checkVal = shift // "0000";
  my $oldSet   = ReadingsVal('du_reed','codes',"0 0 0");
  my @codes    = split(' ',$oldSet,3);
  my $newCode  = sprintf("%04d",rand(9999));
  @codes = map { $_ eq $checkVal ? $newCode : $_ } @codes;
  my $newSet   = join(" ",@codes);
  return if ($oldSet eq $newSet);
  CommandSetReading(undef,"du_reed codes $newSet");
  return "<html><img src=\"http://qrcode.tec-it.com/API/QRCode?data=$newCode\" /></html>";
}

Testen kannst Du das in der FHEM Befehlszeile mit {du_test "<gültiger CODE>"}, Du bekommst dann automatisch den QR-Code für den neuen Code angezeigt.



Zitat von: TomLee am 25 Juni 2023, 16:09:09Ich war der Meinung man kann

Meinung != Wissen
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

betateilchen

Zitat von: TomLee am 25 Juni 2023, 16:09:09den Ersatzwert mit Komma getrennt, versteh ich noch nicht,

Stimmt, an dieser Stelle wären Leerzeichen richtig gewesen, habs korrigiert.
War gedanklich beim Schreiben an einer anderen Stelle.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

TomLee

Lass mir mal etwas Zeit (kann auch bis morgen dauern) das alles zu verarbeiten/Gedanken über eine Umsetzung mit qrencode zu machen.

Ich brauch am Ende die Dateien, die Anzeige des QR-Code in FHEMWEB bringt mir nix, kann aber auch hier wieder sein das ich nicht sehe was du aufzeigen möchtest.


TomLee

Ah, schon beim abschicken kam mir was du zeigen wolltest, ich brauch nur die URL, die Anzeige in FHEMWEB ist nur ein Beispiel.

Trotzdem, ich würd das gerne erstmal alles selbst verarbeiten und selbst Gedanken machen und nicht alles vorgeworfen bekommen, auch wenn das nett gemeint ist.

betateilchen

Zitat von: TomLee am 25 Juni 2023, 16:48:36Trotzdem, ich würd das gerne erstmal alles selbst verarbeiten und selbst Gedanken machen und nicht alles vorgeworfen bekommen, auch wenn das nett gemeint ist.

Du stehst Dir halt oft selbst im Weg und machst Dir unnötig das Leben schwer, weil Du in den allermeisten Fällen viel zu kompliziert denkst.

Fang doch mal damit an, einfaches und logisches Denken zu lernen.

Zum Beispiel die eigentliche Aufgabenstellung, die Du lösen möchtest, in einem Satz zu beschreiben anstatt in drei nicht funktionierenden CODE-Schnipseln.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

TomLee

Zitat von: betateilchen am 25 Juni 2023, 16:23:22Das verstehe ich nicht.

Nochmal anders.
Obs OK ist wenn ein neuer Code ergänzt wird, die alte Datei (der verbrauchte QR-Code) zu löschen und die verbleibenden zwei einfach zu überschreiben?

sub du_test {
  my $checkVal = shift // "0000";
  my $oldSet   = ReadingsVal('du_reed','codes',"0 0 0");
  my @codes    = split(' ',$oldSet,3);
  my $newCode  = sprintf("%04d",rand(9999));
  @codes = map { $_ eq $checkVal ? $newCode : $_ } @codes;
  my $newSet   = join(" ",@codes);
  return if ($oldSet eq $newSet);
  fhem("setreading du_reed codes $newSet");
  system("rm www/scripts/tmp/$checkVal.png &");
  for (@codes) {
  system("qrencode -o www/scripts/tmp/$_.png $_ &")};
}