Fhem Heizungssteuerung mit PiXtend V1.3

Begonnen von auge, 28 August 2020, 09:13:36

Vorheriges Thema - Nächstes Thema

auge

Hallo,

möchte eine Heizungssteuerung mit PiXtend V1.3 bauen.
Habe das PiXtend Modul inzwischen erfolgreich in Fhem eingebunden.
Allerdings sehe ich mich mit einer Schwierigkeit konfrontiert für die ich einen Rat brauche.

Ich habe in Pixtend 8 digitale Eingänge.
Ich habe nun z.B. das Magnetventil über Optokoppler auf einen Eingang gelegt.
Mit einem GET Befehl "get PiXtend DigitalIn1" kann ich in Fhem ich zwar den Zustand abfragen , um aber zu erkennen wann das Ventil aktiv ist müsste ich den Eingang ständig pollen.
(Erst PiXtend V2 bietet wohl eine Anschaltung an Fhem mit Interruptsteuerung an, was neue Hardware bedeuten würde.)

Macht es Sinn die Eingänge in Fhem mit "at" Kommand im Sekundenrhythmus abzufragen oder gibt hierfür eine bessere Lösung. (z.B. über Perl Modul?)
Was bedeutet es für das Log wenn ich alle Sekunde so eine Abfrage mache?
Beschäftige ich Fhem durch solche Abfragen über Gebühr? (Es gibt 8 Eingänge die ich im schlimmsten Fall so einzeln abfragen müsste.)

Ich könnte PiXtend natürlich durch einen MCP 23017 ersetzen, würde aber wenn möglich bei dem PiXtend V1.3 Modul bleiben wenn es mit vertretbarem Aufwand lösbar ist.
Gibt es vielleicht ein alternatives Board für den Raspberry das folgende Schnittstelle schon besitzt?
1. RTC
2. 8 digitale Eingänge (5V)
3. 1-Wire Bus mit Bus Controller
4. über SPI oder besser I2C gekoppelt.
Sonst müsste ich mir wirklich noch selbst was bauen.

Viele Grüße
Auge

 

auge

Wie bekomme ich eigentlich den Rückgabewert aus einem GET Kommando in ein Reading.
Aktuell kann ich mit GET den Status des Eingangs abfragen, es gibt in dem Gerät aber kein bereits angelegtes Reading.
Ich hätte jetzt versucht ein Userreading anzulegen aber dazu muss ich den Rückgabewert irgendwie speichern.
Das gelingt mir auch nicht.
Ist bestimmt ganz einfach wenn die Syntax versteht.

Beta-User

(ohne die Hardware oder das Modul zu kennen oder irgendwie die Verwendung von PI-GPIO gutheißen zu wollen (darum scheint es ja irgendwie auch zu gehen) als Verweis auf allgemeine Optionen):

(U.a.) mit setreading solltest du ggf. einfach ein neues Reading erstellen können; da kannst du dann ggf. auch vorher checken, ob sich was geändert hat; weitere Info dazu findest du in der commandref, v.a. https://fhem.de/commandref_modular_DE.html#setreading.
(Falls du mehr Hilfe benötigst, solltest du mehr Input liefern; ggf. ist es auch sinnvoller, die Hardware irgendwie anders "durchzureichen", keine Ahnung...).
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

auge

Danke für die Rückmeldung.
Nun kann ich mit "setreading PiXtend DigitalIn0 on" ein entsprechendes Reading setzten.
Ein Event, das ich weiterverarbeiten (Trigger) kann, sehe ich im Event Monitor allerdings noch nicht.

Wie bekomme ich denn den Rückgabewert aus dem aus der GET Funktion in das setreading?
Ich vermute ich kann irgendeine Variable befüllen und die dann in das setreading übergeben werden kann.
Ein Hinweis auf die entsprechende Command Ref. wäre hilfreich.

Grundsätzlich funktioniert PiXtend folgendermaßen.
Es wird in dem Modul  97_PiXtend.pm ein externes C-Programm (pixtendtool) aufgerufen was den Microcontroller auf dem externen Board über eine SPI-Schnittstelle ausliest.
Über das 97_PiXtend.pm kann nun der GET-Befehl aufgerufen werden.
Es wird bei GET-Abfrage der Eingänge aber kein Reading oder Event erzeugt.
Es erfolgt nur ein Rückgabewert als Anzeige in der Fhem Weboberfläche.
Es ist nichts im Log oder Event Monitor zu sehen.
Ein Reading kann ich nun mit "setreading PiXtend DigitalIn0 on/off" erzeugen.
Mir fehlt jetzt noch den Rückgabewert des Get-Befehls in das Reading (mit einer Variable?) zu übergeben und einen Event am Besten nur bei einer Änderung zu erzeugen.
Idee: event on change reading

Wenn ich diese Befehlssequenz habe, würde ich versuchen das in ein Script oder dergleichen auszulagern um alle 8 Eingänge auszulesen.
Ob das dann im Sekundenrhythmus funktioniert wird man sehen.
Als Anfänger überfordert es mich ein wenig selbst ein Modul oder einen Gerätetreiber zu schreiben.
Wie werden denn Sensorenwerte z.B. DS18B20 zyklisch abgerufen?
Das macht doch das entsprechende Modul.
Sowas müsste ich dann in ähnlicher Weise auch hier realisierbar sein.
Ist es in Fhem sinnvoll das im Sekundentakt zu machen?
Falls das Unsinn ist, sollte ich gleich die Hardware gegen einen MCP23017 tauschen.
Hier gibt es die Möglichkeit im Modul einen Interrupt bei einer Änderungen der Eingänge zu verwenden.
Schön wäre es jedoch die bestehende Plattform nutzen zu können.
Ich vermute mir fehlt hier die Erfahrung.


Viele Grüße
Auge




Beta-User

Also:

Wie stark das ganze den Server belastet, kann ich nicht sagen, kommt vermutlich auch darauf an, wie schnell der Microcontroller antwortet. Meine Lösung wäre eine ganz andere, nämlich einen Arduino einzusetzen und den pushen zu lassen. Bidirektional wäre das z.B. mit MySensors möglich, mit etwas mehr Systemlast (?) auch mit Firmata; beides würde direkt mit den passenden Modulen Readings erzeugen, dementsprechend besteht mMn. "Verbesserungspotential" an dem hier angepinnten Modul (ich hab's nicht im Detail angesehen, kann auch sein, du übersiehst was).

Wenn du bei dem at+get-Konzept bleiben willst, kannst du mal nach https://forum.fhem.de/index.php/topic,85759.msg836582.html#msg836582 sehen. Da wird auch ein "get" abgesetzt und dann die Rückmeldung weiterverarbeitet (dort allerdings als file weggeschrieben).
Tendenziell dürfte diese Aufgabe als Einstieg zu schwer sein, da sind zu viele Bausteinchen unbekannt (Schleife abarbeiten für alle inputs und dann vor dem Aktualisieren der Readings (!) prüfen, ob eine Änderung vorliegt). Ich würde empfehlen, den Hersteller zu kontaktieren, mMn. ist das ganze ohne durch Anfänger halbwegs handhabbaren Code schlicht und ergreifend Murks...

(Wenn es sein muß, coache ich dich auch dabei, die Lücke zu schließen. Aber wenn, dann mußt du das "auf die harte Tour wollen"... Erste Aufgabe wäre, nach CommandGet im WeekdayTimer-Code suchen, die Code-Elemente aus den beiden genannten Quellen soweit du kannst erst mal selbst zusammenbasteln, das ganze dort, wo du noch keinen Code selbst erstellt hast mit Worten beschreiben und direkt mit readings.*update-Funktionen arbeiten (development module intro im Wiki würde weiterhelfen)...)
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

auge

#5
Ist ein .PM File in Pearl geschrieben?

Idee das Setreading gleich bei der Abfrage im .PM File zusetzten.
Mir ist klar, dass die rot eingefügten Befehle so direkt so nicht gehen werden. Nur als Idee, wenn ich die Sprache des Scripts kenne.

Auszug aus dem 97_PiXtend.pm-File.
=============================

elsif(index($opt, "digitalin") != -1)
{
$opt =~ s/digitalin//;
my ($val) = qx($pixcmd -di) =~ /\[(\w+)\]/;
if($val & (1<<$opt))
{
[color=red]setreading PiXtend $opt 1[/color]
return "Digital Input $opt is HIGH";
}
else
{
[color=red]setreading PiXtend $opt 0[/color]
return "Digital Input $opt is LOW";
}
}

      

auge

#6
Folgendes funktioniert.
Ist aber unsauber programmiert da das Gerät PiXtend hart codiert ist.

$opt =~ s/digitalin//;
                        my ($val) = qx($pixcmd -di) =~ /\[(\w+)\]/;
                        if($val & (1<<$opt))
                        {
                               [color=red] {fhem "setreading PiXtend DigitalIn$opt'  1"};[/color]
                              #  return "Digital Input $opt is HIGH";
                        }
                        else
                        {
                               [color=red] {fhem "setreading PiXtend DigitalIn$opt 0"};[/color]
                               # return "Digital Input $opt is LOW";


Jetzt bekomme ich bei jedem get auch ein entsprechendes Reading.
Kann man das so machen??

Beta-User

Sehr cool, du bist recht weit gekommen, Chapeau!

Also: Prinzipiell kann man das so machen (und es ist ein Versäumnis des Moudulators, die Funktionalität des Reading-Updates da nicht gleich eingebaut zu haben.

Im Detail würde ich allerdings nicht den "wrapper" "fhem" verwenden, denn diese Funktion ruft eigentlich auch nur intern andere Funktionen auf (siehe die Kette beginnend mit https://svn.fhem.de/trac/browser/trunk/fhem/fhem.pl#L3852), das ganze ist eine Art Zwiebel, und eigentlich brauchst du nur den innersten Bereich, nämlich readingsSingleUpdate bzw. Teile aus ReadingsBulkUpdate/readingsBulkUpdateIfChanged (Startpunkt: https://svn.fhem.de/trac/browser/trunk/fhem/fhem.pl#L4983).
Diese Funktion(en) sind im Wiki beschrieben, siehe z.B. https://wiki.fhem.de/wiki/DevelopmentModuleAPI#readingsBulkUpdateIfChanged.

Damit bekommt man auch den hartcodierten Namen raus aus dem Code, weil Referenzpunkt damit dann der Device-hash wird, was eine Art zentraler Startpunkt für jedes FHEM-Device darstellt.

Damit wäre das "get" fertig; was allerdings weiter unschön bleibt: Man muß das pollen aktiv anschubsen. Eigentlich wäre es besser, wenn man im Device selbst angeben könnte, ob Inputs vorhanden sind und in welcher Frequnez die abzufragen sind. Die Details zu sowas hängen aber stark von der Hardware ab, im Moment scheint es recht nah an dem zu sein, was z.B. mit periodicCmd im MQTT2_DEVICE passiert. Dazu wäre in etwa das zu machen, was in https://svn.fhem.de/trac/changeset/21566/ steht...
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

auge

#8
Super!!
Das mit dem Update funktioniert schon mal.

elsif(index($opt, "digitalin") != -1)
                {
                        my ($val) = qx($pixcmd -di) =~ /\[(\w+)\]/;
                        readingsBeginUpdate($hash);
                        for(my $i=0; $i < 8; $i++)
                        {
                        if($val & (1<<$i)) { readingsBulkUpdateIfChanged($hash, "DigitalIn$i", "on");}
                        else { readingsBulkUpdateIfChanged($hash, "DigitalIn$i", "off");}
                        }
                        readingsEndUpdate($hash, 1);
                }


Wie rufe ich nun die Funktion in regelmäßigen Zeitabständen auf.
Klar könnte ich ein "at" verwenden.
Gibt es eine Möglichkeit das auch im Module selbst effizienter zu machen?
Gibt es dazu ein sleep für eine Schleife oder eine Zeitfunktion in Fhem bzw. Perl?

Beta-User

InternalTimer wäre das Schlagwort, siehe auch meine letzte Antwort.Kurz&mobil
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

auge

#10
@ Beta-User: Vielen Dank für die Untersützung.
Es hat mir sehr geholfen.

Konnte es tatsächlich mit dem InternalTimer realisieren.
Hilfreich war auch, dass es in dem Modul schon eine ähnliche Routine für die analogen Inputs gab.
Hier die Routine die ich eingefügt habe.

sub PiXtend_GetDigitalIn($)
{
my ($hash) = @_;

my ($val) = qx($pixcmd -di) =~ /\[(\w+)\]/;
            readingsBeginUpdate($hash);
            for(my $i=0; $i < 8; $i++)
            {
if($val & (1<<$i))
{readingsBulkUpdateIfChanged($hash, "DigitalIn$i", "on");}
else
{readingsBulkUpdateIfChanged($hash, "DigitalIn$i", "off");}
            }
            readingsEndUpdate($hash, 1);


if(AttrVal($hash->{NAME}, "UseDigitalInputs", "no") eq "yes")
{
InternalTimer(gettimeofday()+1, "PiXtend_GetDigitalIn", $hash);
}
}

Mal sehen ob das mit einer Sekunde stabil läuft. Der Raspberry ist jedenfalls nur zu 3% ausgelastet.
Theoretisch hätte ich auch noch den Quellcode um den Mikrocontroller (Atmega32) auf dem Board anzupassen um noch auf eine interruptbasierende Lösung zu schwenken.
Aber das ist definitiv eine Hausnummer bei der ich noch weniger weiß was ich tue.

Viele Grüße
Auge




Beta-User

Sehr gut!

Vielleicht noch ein paar Anmerkungen:
- Code macht sich im Forum in passenden Tags besser (der #-Button)
- Gerne darfst du das im Zusammenhang dann nochmal posten bzw. ggf. auch an die Quelle zurückspiegeln
- Wenn da ein ATMega32 läuft, wäre ggf. eine serielle Lösung besser, die könnte pushen; schwierig ist das vermutlich nicht anzupassen, wenn man den Quellcode hat (Stichwort wäre keyValueProtocol) (mich wundert, dass das dann als 1-Wire-Busmaster arbeiten soll...?)
- Die ersten Zeilen würde ich zwischenzeitlich so schreiben:
sub PiXtend_GetDigitalIn {  my $hash = shift // return;
Details zu den Hintergründen wären in der Perl-Eckezu finden.

- Wenn du den InternalTimer automatisch startest, muß der auch gelöscht werden, wenn das Device gelöscht wird usw.. Will sagen: Da fehlen vermutlich ein paar Umfeldarbeiten...
- Es wäre zu empfehlen, das Intervall (per Attribut) konfigurierbar zu machen und dann in den Internals anzuzeigen, welches gerade gilt. "Material" wäre z.B. in MYSENSORS_DEVICE zu finden (z.B. timeoutAck).
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors