Neues Modul für Brilix/Alsavo Pool-Wärmepumpe

Begonnen von Init, 02 Juni 2023, 19:18:54

Vorheriges Thema - Nächstes Thema

Init

Hallo zusammen,

da ich gerne meine Wärmepumpe über FHEM steuern möchte und es nichts in der Richtung gibt, habe ich endlich Zeit gefunden ein eigenes Mini-Modul anzufangen.

Da ich gerne die Dinge komplett verstehen würde, die ich hier mache, habe ich folgende Verständnisfrage:

Warum leitet folgendes "set" über FHEMWEB bei einem "on" immer auf eine leere Seite weiter, auf der dann "on" steht:
sub Alsavo_Set($@) {
.....
    if($cmd eq "off" || $cmd eq "on"){
        $hash->{STATE} = "$cmd";
        }
.....
}


Und warum bleibt folgende Version nach dem Ausführen des gleichen "set" auf der Seite und aktualisiert die Daten dort?
sub Alsavo_Set($@) {
.....
    if($cmd eq "off" || $cmd eq "on"){
        $hash->{STATE} = "$cmd";
        Log3 $name, 3, "$self #3 State: after: ". $hash->{STATE};
        }
.....
}


Letzte Variante hätte ich gerne, aber ich möchte keine überflüssigen Logausgaben einbauen.

Viele Grüße
Marc

Beta-User

Bitte nicht direkt ins Internal schreiben, sondern das Reading "state" aktualisieren (allerdings m.E. in Senderichtung mit einem Übergangswert).
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

Init

Danke für den Hinweis auf die richtige Implementierung.

Es sieht nun wie folgt aus:

sub Alsavo_Set($@) {
.....
    if($cmd eq "off" || $cmd eq "on"){
        readingsSingleUpdate($hash,'state',$cmd,1);
        }
.....
}

Aber leider lande ich nach dem Schalten auf on oder off wieder auf einer leeren Seite, wo das letzte $cmd ausgegeben wird. Also on oder off.

Was mache ich hier falsch?

Möchte weiterhin keine unnötige Logausgabe implementieren.

Viele Grüße
Marc


Beta-User

Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

Init

Das
Zitatreturn
fehlte.

Jetzt funktioniert es wie erwartet.

Vielen Dank!

Init

Hallo,

jetzt habe ich leider das nächste Problem  :(

Ich möchte die Daten aus der Wärmepumpe über qx abholen, aber dies soll FHEM nicht blockieren.

Daher rufe ich das Update wie folgt auf:
    BlockingCall("getUpdates", $hash, "", "", "", "");

In der Sub getUpdates rufe ich das Modul der Wärmepumpe auf um die Statuswerte als Reading zu speichern, aber die Readings im BlockingCall werden nicht an das Device übergeben. Hier mein sub:
sub getUpdates($){
    my ($hash) = @_;
    my $output=qx (./AlsavoCtrl -s xxx -l xxx -a 172.16.0.70 -p 1194 2>/dev/null);
my @lines = split /\n/, $output;
readingsSingleUpdate($hash,'marc','initB10r',1);
readingsBeginUpdate($hash);
foreach my $line( @lines ) {
    my $jsonraw = (split(/\=/,$line))[1];
    my $json = from_json($jsonraw);
    my $rowId = $json->{index};
    my $rowValue = $json->{value};
    my $rowReadingName = $Alsavo_params{$rowId};
readingsBulkUpdate($hash, $rowId, $rowValue );
    }
readingsEndUpdate($hash, 1);
    return;
    }

Auch das "readingsSingleUpdate" klappt nicht. Vor dem BlockingCall funktioniert ein "readingsSingleUpdate".

Ist das nicht möglich, was ich hier versuche?

Viele Grüße
Marc

Beta-User

Kann mir das leider grade nicht im Detail ansehen.

Vielleicht suchst du mal meine Version von TvHeadend. Die ist etwas anders strukturiert (gepackaged), aber sonst vermutlich ähnlich.
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

Init

Danke für deine Hilfe!

Habe mir die letzte Version von runtergeladen, aber leider verfährst du da anders als ich, da du alles über HTTP-Requests abfragen kannst.

Bei meiner Wärmepumpe muss ich ein qx auf ein python-Skript machen.

Hab aber nun auch das Problem entdeckt. Ich muss das Ergebnis im Hauptprozess verarbeiten. Im Wiki wird auch auf diese Einschränkung hingewiesen:
ZitatVeränderungen an internen Variablen von FHEM (Device Hashes, Timers, usw.) werden innerhalb eines BlockingCalls durchgeführt und sind dort auch sichtbar, haben aber keinerlei Einfluss auf den eigentlichen FHEM Hauptprozess und alle Definitionen. Solche Veränderungen müssen an die finishFn delegiert werden

Grüße
Marc

Init

Hallo zusammen,

ich bin heute endlich wieder dazu gekommen an dem Modul weiterzumachen :-)

Vorhin haben die Set Befehle noch funktioniert und auf einmal bekomme ich statt den Schaltwert "on" / "off" in der Perl Funktion zufällige Zahlenwerte. Statt "on" kommt 30,20 oder 31 :-(

Mir ist nicht bewusst, dass ich da irgendwas in der Richtung geändert habe. In der Oberfläche wird korrekt "on" / "off" bei der Option "Timer" angezeigt.

Nachdem ich nicht weitergekommen bin, habe ich an eine Stelle den Code zurückgerollt, wo es definitiv noch funktioniert hatte, aber leider erhalte ich weiter Werte wie 30 statt on :-(

Ich weiß echt nicht weiter.

Hier der relevante Code

my %Alsavo_sets = (
    off                => 'noArg',
    on                  => 'noArg',
    RunMode            => 'Auto,Heating,Cooling',
    PowerMode          => 'Silent,Smart,Powerful',
    TemperaturHeating  => 'slider,15,1,41',
    TemperaturCooling  => 'slider,6,1,35',
    TemperaturAutoMode  => 'slider,6,1,41',
    Timer              => 'on,off',
    TimerOnTime        => 'time',
    TimerOffTime        => 'time'
    );

sub Alsavo_Initialize($) {
    my ($hash) = @_;
    Alsavo_Log($hash, 3, "Hashinhalte von \"Alsavo_config_params\"". join( " ", map { "$_" . ( $Alsavo_config_params{$_} ? ":$Alsavo_config_params{$_}" : "" ) } keys %Alsavo_config_params ));

    $hash->{DefFn}  = 'Alsavo_Define';
    $hash->{UndefFn} = 'Alsavo_Undef';
    $hash->{DeleteFn}= 'Alsavo_Delete';
    $hash->{SetFn}  = 'Alsavo_Set';
    $hash->{GetFn}  = 'Alsavo_Get';
    $hash->{AttrFn}  = 'Alsavo_Attr';
    $hash->{ReadFn}  = 'Alsavo_Read';
    $hash->{AttrList} = "debuglevel:0,1,2 " . $readingFnAttributes;
    }

sub Alsavo_Set($@) {
    my ( $hash, $name, $cmd, @args ) = @_;
    Alsavo_Log($hash, 3, "#1 Cmd: $cmd - Args: ".join( " ", @args));
    if($cmd eq "on"){
        my $bitmask = $hash->{READINGS}{config_4_System_config_bitmask_1}{VAL};
        $bitmask |= 32; # Activating Bit 5
        return undef;
        }
    elsif($cmd eq "off"){
        my $bitmask = $hash->{READINGS}{config_4_System_config_bitmask_1}{VAL};
        $bitmask &= ~32; # Deactivating Bit 5
        return undef;
        }
    elsif($cmd eq "Timer"){
        my $mode = shift @args;
        if($mode eq "on"){
            my $bitmask = $hash->{READINGS}{config_4_System_config_bitmask_1}{VAL};
            $bitmask |= 4; # Activating Bit 2
            doBlockingCall($hash,"4 .$bitmask");
            return undef;
            }
        elsif($mode eq "off"){
            my $bitmask = $hash->{READINGS}{config_4_System_config_bitmask_1}{VAL};
            $bitmask &= ~4; # Deactivating Bit 2
            doBlockingCall($hash,"4 .$bitmask");
            return undef;
            }
        else {
            return "Unbekannter Timer-Modus: $mode";
            }
        }
    else { # Unbekannte Commands und für das Webfrontend mit dem cmd=?
        return "Unknown argument $cmd, choose one of " . join( " ", map { "$_" . ( $Alsavo_sets{$_} ? ":$Alsavo_sets{$_}" : "" ) } keys %Alsavo_sets );
        #return SetExtensions($hash, map { "$_" . ( $Alsavo_sets{$_} ? ":$Alsavo_sets{$_}" : "" ) } keys %Alsavo_sets ), $name, $cmd, @args);
    }



Und in der Methode Alsavo_Set erhalte ich in "join( " ", @args)" die Ausgabe wie 30,20 oder andere Zahlen.

Hat jemand eine Idee?

Viele Grüße
Marc

Beta-User

Es ist echt schwierig, auf Schnippsel was sinnvolles zu antworten...

Also: Wenn (!) das "entfernte Gerät" nicht via HTTP-requests gesteuert werden kann/soll, sind m.E. auch die HTTP-Werkzeuge aus dem FHEM-Baukasten nicht passend. Allerdings _glaube_ ich nicht, dass das Python-script was anderes macht, nur ist da halt der Code schon funktional. Ich würde versuchen, das nach Perl zu portieren und direkt ins Modul zu integrieren. Falls das script eine Art Web-Interface bietet, wäre es sonst ggf. einfacher, das via HTTPMOD oder JsonMod zu lösen, falls es MQTT kann, wäre MQTT2_DEVICE das Mittel der Wahl...

Vielleicht zeigst du, wo das script zu finden ist und fügst hier den kompletten Modul-Code mal an? (Verschieben nach Perl für FHEM-User wäre vermutlich auch eine Idee...).

Sonstiges:

- "return undef;" => Wenn du nicht weißt, für was du das undef brauchst, wirf es weg! "return;" macht dasselbe...

- Warum springst du in der setFn bei on/off raus, ohne was zu machen? Oder anders: Was willst du tun?

- Selbst beim Entwickeln sollte man m.E. nicht allzu "konkrete" Angaben im Code verstreuen - die IP-Adresse des Gerätes (aus dem qx) gehört ins define oder ein Attribut und sollte dann so auch verwendet werden.
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

Init

Hallo Beta-User,

vielen Dank für deine Antwort.

Mein Modul soll ein Python-Skript (AlsavoCtrl) aufrufen, um unsere Wärmepumpe des Pools zu steuern und auszuwerten.
Es gibt zwar mittlerweile eine Docker-Version, welche auch mqtt verwendet, aber ich würde gerne bei der Implementierung in meinem Modul bleiben.
Ein Umbau des Skript auf 100% Perl wäre die tollste Variante, aber dies ist definitiv eine Nummer zu groß für mich, da ich mit Perl nur im Bereich FHEM zu tun habe.

Ich habe mal das Modul angehängt.

Bin dort für jede konstruktive Kritik zu haben.

Log-Ausgaben verschwinden natürlich noch, da diese mir einfach geholfen haben herauszufinden, wann was aufgerufen wird.
Die Hilfe kommt am Schluss.

Erstellt wird das Gerät über:  define <name> Alsavo <ip> <port> <serialnumber> <password> [<interval> <AlsavoCtrl-Path>]

Wo ich das gerade schreiben, dass Passwort muss natürlich auch noch verschlüsselt werden und liegt derzeit in plain text ab.

Aktuell bekomme ich alle Daten der Wärmepumpe und im Bereich "Set" werden auch schon die richtigen Daten angezeigt.

Status passt auch, allerdings hätte ich hier gerne noch ein Icon + Text mit aktueller Temperatur als Status im Webinterface. Bislang bekomme ich nur die Temperatur über StateFormat = "   {sprintf("Wassertemperatur: %.1f °C", ReadingsVal($name,"status_16_Water_in_temp","-1"))}", aber nun habe ich kein Icon mehr :-(

Aber zurück zum eigentlichen Problem.
In Zeile 281 erhalte ich in "@args" aktuell eine Zahl statt on oder off, wenn ich über das WebInterface Set Device Timer on/off wähle und dann auf set klicke.

Zitat von: Beta-User am 01 September 2024, 06:36:26- "return undef;" => Wenn du nicht weißt, für was du das undef brauchst, wirf es weg! "return;" macht dasselbe...
Habe ich geändert

Zitat von: Beta-User am 01 September 2024, 06:36:26- Warum springst du in der setFn bei on/off raus, ohne was zu machen? Oder anders: Was willst du tun?
In beiden Varianten wird noch folgende Zeile eingefügt:
doBlockingCall($hash,"4 .$bitmask");

Zitat von: Beta-User am 01 September 2024, 06:36:26- Selbst beim Entwickeln sollte man m.E. nicht allzu "konkrete" Angaben im Code verstreuen - die IP-Adresse des Gerätes (aus dem qx) gehört ins define oder ein Attribut und sollte dann so auch verwendet werden.
Das habe ich leider nicht verstanden. Wo hatte ich die IP im Code? Oder beziehst du dich auf eine alte Nachricht von mir?

Wenn dieser Bereich im Forum nicht richtig ist, dann kannst den Thread gerne verschieben.

Viele Grüße
Marc

Beta-User

#11
Also: Es geht um das Script von strandborg von hier: https://github.com/strandborg/AlsavoCtrl? Das wäre wohl C++ und fragt einen externen Server ab... Damit wäre evtl. HTTPMOD wieder im Spiel...

Da ich das ohne Hardware/passende Zugangscodes etc. nicht testen kann, hatte ich vor der Abfrage, ob das script da ist ein return in den (geringfügig überarbeiteten) Code eingebaut.

Generell: Du arbeitest mit "generischen Funktionsnamen". Das ist super, wenn man es mit einem gepackagten Modul zu tun haben. Haben wir nur nicht => ändern (nach dem Vorbild der "firstInit")...
Zitat von: Init am 01 September 2024, 10:33:45Status passt auch, allerdings hätte ich hier gerne noch ein Icon + Text mit aktueller Temperatur als Status im Webinterface. Bislang bekomme ich nur die Temperatur über StateFormat = "  {sprintf("Wassertemperatur: %.1f °C", ReadingsVal($name,"status_16_Water_in_temp","-1"))}", aber nun habe ich kein Icon mehr :-(
Würde ich über devStateIcon-Code machen, schau mal in die attrTemplate-file zu MQTT2_DEVICE, da gibt es Legionen an Beispielen, wie das ginge.
Hier mal ein extremes Beispiel (Achtung: myUtils ist gepackaged! Icons sind (noch...) nicht klickbar...):
(OK, Bild will grade nicht...)
attr Heizung_neu devStateIcon {FHEM::Heizung_Utils::devStateIcon($name)} sub devStateIcon {
  my $devname = shift // return;
 
  return if !defined $defs{$devname};
 
  my $col = ReadingsVal($devname,'LWT','Offline') eq 'Online' ? 'green' : 'red';
  my $ret = FW_makeImage("lan_rs485\@$col",'file_unknown@grey');
  my $rval = ReadingsNum($devname,'DS01_Temperature',0);
  $col = substr(Color::pahColor(-15,0,40,$rval,0),0,6);
  $ret .= ' ';
  $ret .= FW_makeImage("temp_temperature\@$col",'file_unknown@grey');
  $ret .= ' ';
  $ret .= ReadingsNum($devname,'DS01_Temperature',0,1);
  $ret .= ' °C<br>';
 
  $ret .= ' ';
  $ret .= ReadingsNum($devname,'Solar_sens1',0,1);
  $ret .= ' °C ';
  $col = substr(Color::pahColor(-10,40,95,ReadingsNum($devname,'Solar_sens1',0),0),0,6);
  $ret .= FW_makeImage("sani_solar_temp\@$col",'file_unknown@grey');
  $ret .= ' ';
 
  $rval = ReadingsNum($devname,'Solar_pump1',0);
  if ($rval) {
      $col = substr(Color::pahColor(0,40,100,ReadingsNum($devname,'Solar_pump1',0),0),0,6);
      $ret .= FW_makeImage("sani_pump\@$col",'file_unknown@grey');
  } else {
      $ret .= FW_makeImage('sani_pump','file_unknown@grey');
  }
  $ret .= ' ';
  $ret .= ReadingsNum($devname,'Solar_pump1',0);
  $ret .= ' %<br>';

  $rval = ReadingsNum($devname,'DS03_Temperature',1);
  $col = substr(Color::pahColor(0,40,90,$rval,0),0,6);
  $ret .= $rval;
  $ret .= ' °C ';
  $ret .= FW_makeImage("sani_return_temp\@$col",'file_unknown@grey');
  $ret .= ' ';
  $rval = ReadingsNum($devname,'DS02_Temperature',1);
  $col = substr(Color::pahColor(0,40,90,$rval,0),0,6);
  $ret .= FW_makeImage("sani_supply_temp\@$col",'file_unknown@grey');
  $ret .= ' ';
  $ret .= $rval;
  $ret .= ' °C<br>';
  $rval = ReadingsNum($devname,'Solar_sens2',0,1);
  my $col1 = substr(Color::pahColor(0,40,90,$rval,0),0,6);
  $ret .= "$rval °C / ";
  $rval = ReadingsNum($devname,'Solar_sens3',0,1);
  my $col2 = substr(Color::pahColor(0,40,90,$rval,0),0,6);
  $ret .= "$rval °C / ";
  $rval = ReadingsNum($devname,'Solar_sens4',0,1);
  my $col3 = substr(Color::pahColor(0,40,90,$rval,0),0,6);
  $ret .= "$rval °C / ";
  $rval = ReadingsNum($devname,'Solar_sens5',0,1);
  $col = substr(Color::pahColor(0,40,90,$rval,0),0,6);
  $ret .= "$rval °C ";

  my $deftags = qq(<defs>
        <linearGradient id="lgrad1" x1="0" y1="1" x2="0" y2="0">
            <stop offset="0%" stop-color="#$col1" />
            <stop offset="25%" stop-color="#$col2" />
            <stop offset="50%" stop-color="#$col3" />
            <stop offset="75%" stop-color="#$col" />
        </linearGradient>
    </defs>);
  $ret .= special_makeImage("sani_buffer_temp_all\@url(#lgrad1)",$deftags);
   
  return qq(<div><p style="text-align:right">$ret</p></div>);
}
Zitat von: Init am 01 September 2024, 10:33:45Das habe ich leider nicht verstanden. Wo hatte ich die IP im Code? Oder beziehst du dich auf eine alte Nachricht von mir?
Das bezog sich auf einen deiner vorherigen Posts.

Verschieben kannst du selbst (Knopf unter dem ersten Beitrag), sonst bräuchten wir einen Admin oder Moderator...
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

Init

Tausend Dank für die Überarbeitung und das Beispiel vom devStateIcon!
Jetzt funktioniert es wieder, aber ich verstehe nicht warum!
Liegt es an der Umbenennen von "firstInit" oder der am auskommentieren von "Data::Dumper"?

Was ist ein "gepackagten Modul"? Werde alle übrigen Funktionen den Präfix "Alsavo_" voranstellen.

Zitat von: Beta-User am 01 September 2024, 12:03:03Verschieben kannst du selbst (Knopf unter dem ersten Beitrag), sonst bräuchten wir einen Admin oder Moderator...
Diese Funktion habe ich dort leider nicht, sonst wäre ich jetzt deinem Rat gefolgt und hätte es nach "Perl für FHEM-User" geschoben.

Beta-User

Zitat von: Init am 01 September 2024, 13:06:07Liegt es an der Umbenennen von "firstInit" oder der am auskommentieren von "Data::Dumper"?
Ziemlich sicher nicht an letzterem, und bei ersterer Funktion kommt es darauf an, ob "noch jemand" so eine generische Benennung (außerhalb seines eigenen Namespace) gemacht hat...

Details zu Packages: https://forum.fhem.de/index.php?topic=122708.0

Zitat von: Init am 01 September 2024, 13:06:07Diese Funktion habe ich dort leider nicht, sonst wäre ich jetzt deinem Rat gefolgt und hätte es nach "Perl für FHEM-User" geschoben.
Hmmm, ich habe die jedenfalls nicht (kein Mod), und ich bin ziemlich sicher, dass die Option für dich verfügbar ist. Ggf. mit einem anderen Browser, aktivierten scripts, upgedatetem cache, whatever...
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

Init

#14
Ich werde gerade irre :-(

Es hatte ja mit dem überarbeiteten Skript funktioniert. Jetzt habe ich angefangen die Funktionen umzubenennen und nun bekomme ich wieder Zahlen in  @args (Zeile 282+283) statt on/off.

Danach habe ich wieder das Original eingespielt und es funktioniert weiterhin nicht.
Auch das Löschen und eine Neuerstellung vom Device helfen nicht.

Was kann das nur sein. Habe echt keine Idee :-(

Im Anhang ein Screenshot von meinen Optionen unter dem ersten Post (Chrome und Edge). Habe nun den Moderator angeschrieben.