FHEM Forum

FHEM - Hausautomations-Systeme => 1Wire => Thema gestartet von: justme1968 am 06 April 2013, 23:04:49

Titel: workaround um OWserver asynchron zu machen
Beitrag von: justme1968 am 06 April 2013, 23:04:49
hier eine idee um die abfragen die von OWServer/OWDevice an owfs gehen zumindest zum teil asynchron zu machen.

anlass hierfür ist das meine fhem installation mit jedem zusätzlichen 1Wire sensor träger geworden ist. für jeden temperatursensor wird etwas über eine sekunde zum auslesen benötigt. bei 10 oder 20 sensoren die minütlich ausgelesen werden ist das insgesamt schon im bereich von 20-50% die nur mit dem auslesen der sensoren verbraucht wird. in meiner installation hängt der 1Wire bus an einem raspberry pi der zur zeit nur hierfür genutzt wird. fhem selber läuft auf einer synology diskstation. die prozessorlast die ich auf dem pi sehe ist aber klein genug das es auch funktionieren sollte wenn fhem mit auf dem gleichen raspberry pi läuft.

das ganze basiert darauf den ofsw internen cache zu nutzen und dafür zu sorgen das er immer gefüllt bzw. aktuell ist um die anfragen von fhem direkt zu beantworten und fhem nicht warten zu lassen wenn erst die tatsächlichen werte aus der hardware gelesen werden müßen. zum füllen des cache wird ein einfaches shellscript verwendet das den 1Wire bus per owfs filesystem ausliest. konkret schaut das so aus:
sudo mkdir /1wire
  • 1Wire filesystem mounten:sudo owfs -s localhost:4304 --allow_other -m /1wire
  • den cache per shellscipt im hintergrund immer wieder füllen:nohup sh -c "while true; do nice find /1wire/uncached/[0-9]* -maxdepth 1 \( -name temperature -or -name "latch.[A-C]" -or -name "counters.[A-C]" \) -exec cat {} \; >/dev/null  ; done" &welche attribute genau ausgelesen werden muß eventual an die in fhem abgefragten were angepasst werden. z.b. die anderen temperatur auflösungen. [/list]
    das mounten und starten des hintergrund jobs sollte am besten in ein start script verpackt werden.

    punkt 1. und 2. sind auf dem raspberry pi in der default owfs installation nicht nötig. hier wird owfs beim starten unter /mnt/1wire gemountet. der pfad für das find ist dann entsprechend anzupassen.

    weiter optimieren läßt sich das noch in dem man den cache timeout im owserver etwas erhöht und das script nicht stur in einer schleife laufen läßt sondern nach jedem durchgang etwas warten läßt so das es etwa zwei mal pro cache timeout komplett durch läuft.

    das ganze ist nur ein workaround und sicher kein ersatzt für eine echte lösung die z.b das auslesen direkt in fhem im hintergrund macht. es funktioniert aber bei mir seit ein paar tagen ohne probleme und viele hänger in fhem sind seit dem nicht mehr da. der effekt ist um so mehr bemerkbar je mehr temperatursensoren am bus hängen. vielleicht hilft es ja noch jemandem.

    gruss
      andre
  • Titel: Aw: workaround um OWserver asynchron zu machen
    Beitrag von: Dr. Boris Neubert am 07 April 2013, 10:29:58
    Zitat von: justme1968 schrieb am Sa, 06 April 2013 23:04hier eine idee um die abfragen die von OWServer/OWDevice an owfs gehen zumindest zum teil asynchron zu machen.

    Das Attribut nonblocking ist Dir keine Hilfe?

    Grüße
    Boris
    Titel: Aw: workaround um OWserver asynchron zu machen
    Beitrag von: justme1968 am 07 April 2013, 10:57:26
    das hilft noch viel besser.

    das attribut habe ich komplett verschlafen.

    danke und gruss
      andre
    Titel: Aw: workaround um OWserver asynchron zu machen
    Beitrag von: justme1968 am 15 September 2013, 23:19:06
    die kurze version: nonblocking ist nutzlos und verhindert bei mehr als ein 2-3 devices nicht das blockieren von fhem. zum einen ist es völlig wirkungslos was den 1-2 sekunden delay beim auslesen eines DS18B20 angeht. d.h. 10 DS18B20 abzufragen kostet auch mit nonblocking über 10 sekunden blockierte zeit je durchlauf in fhem. darauf hatte die idee oben eigentlich abgezielt. mit dem workaround oben gibt es diese blockierte zeit nicht mehr. zum anderen hilft es aber auch leider nicht wenn das owfs tatsächlicht nicht mehr erreichbar ist weil fhem trozdem blockiert.

    die lange version: ich habe mir gerade nonblocking noch mal angeschaut und wollte es auf BlockingCall umbauen weil ich eigentlich das abziehen und wieder anstecken von usbdevices auch mit nonblocking zum laufen bekommen wollte (siehe: Link (http://forum.fhem.de/index.php?topic=13156.msg80625#msg80625)) und in einem zweiten schritt auf einen einzigen fork mit einem child der permanent im hintergrund für das holen der werte zustündig ist.

    ein weitere grund ist dieser thread hier: Link (http://forum.fhem.de/index.php?topic=14397.0). mein fhem bleibt reproduzierbar hängen wenn owserver auf einem meiner raspberry pi nicht erreichbar ist. unabhängig von nonblocking.

    dabei ist mir aufgefallen das die augenblickliche nonblocking implementierung für das  der fhem vordergrund prozess blockiert mit nonblocking ganz genau so wie ohne. ausser der last durch die zusätzlichen fork ändert sich nichts:

    - ohne nonblocking: der parent liest direkt und blockiert so lange bis OWServer die daten übers netz von owfs gelesen hat.

    - mit nonblocking: der parent forkt, im child wird auf die gleiche art wie oben blockierend gelesen, während dessen wartet der parent aber leider auch weil er blockierend vom child liest um die antwort zu bekommen.

    hier die debug ausgaben für einen künstlich um 10 sekunden verzögertes lesen:2013.09.15 22:16:13 3: parent before read
    2013.09.15 22:16:13 3: child before read
    2013.09.15 22:16:23 3: child got         25.5
    2013.09.15 22:16:23 3: parent got 25.5
    wärend dieser 10 sekunden ist der parent blockiert und nicht ansprechbar.

    d.h. nonblocking behebt nicht das regelmässige blockieren auf grund der reinen abfrage zeit der sensoren und auch nicht das blockieren auf grund von kurzfristigen netzwerkproblemen. sondern es erzeugt durch das forken bei jeder einzelnen sensor abfrage sogar noch zusätzlichen overhead.

    nonblocking soll eigentlich verhindern das fhem durch ein nicht erreichbares owfs dauerhaft blockiert wird weil der child prozess nach 20 sekunden ohne antwort gekillt wird. leider funktioniert aber das killen nicht da der parent genau durch das lesen des child blockiert ist. aber selbst wenn gekillt würde würde das  bei mehr als 2-3 werte die alle 60 sekunden gepollt werden auch nicht mehr funktionieren da der parent für jede anfrage ja immer noch blockiert und sich die anfragen der weiteren devices in dieser zeit aufstauen. d.h. nach dem kill ist direkt der nächste versuch einen wert zu lesen da und das blockieren beginnt von vorne.

    wie wäre es das nonblocking attribut so zu ändern das OWNet socket bzw. eine pipe zu einem ein einziges mal geforkten child über die selectlist in die fhem event loop einzuhängen. dann wären die antworten tasächlich asynchron auswertbar. owserver device müsste sich alle abgesetzten anfragen per fifo merken und könnte sogar bei einem bestimmten füllstand alte anfragen verwerfen bzw. das pollen der abhängigen OWDevices so lange aussetzen. ganz nebenbei wäre auch der overhead durchs unnötige forken mit allen nebeneffekten vermieden. OWDevice bräuchte eine parseFn um die asynchronen readings zu empfangen.

    gruss
      andre
    Titel: vorschlag um OWserver asynchron zu machen
    Beitrag von: justme1968 am 20 November 2013, 01:48:17
    ich habe (fast) eine beta version einer wirklich nicht blockierenden d.h. wirklich asynchronen OWServer version.

    gibt es interesse daran (vor allem der original autoren) dann würde ich gerne ein paar design fragen diskutieren bevor ich das ganze zu einem fertigen patch zusammen baue.

    das prinzipielle vorgehen dabei ist das nach dem forken im parent nicht mehr blockierend auf die rückgabe des child gewartet wird sondern das lese ende der pipe in die selectlist eingeängt wird und erst dann gelesen wird wenn der wert vom child auch wirklich da ist.

    noch klären würde ich gerne:
    - nicht mehr bei jedem read forken sondern nur noch ein mal und umstellen auf BlockingCall.
    - verwenden der neuen addToWritebuffer funktion um vom parent zum child zu kommunizieren.
    - soll das ganze 'sauber' mit dispatch und ParseFn in OWDevice realisiert werden oder 'reicht' es die readings direkt aus OWServer zu aktualisieren.
    - test mit möglichst vielen systemen und vor allem randbedingungen.

    gruss
      andre
    Titel: Antw:workaround um OWserver asynchron zu machen
    Beitrag von: ntruchsess am 20 November 2013, 10:45:45
    schau Dir mal an, was ich hier vor ein paar Tagen angefangen habe um sowas generisch zu lösen: AsyncDevice.pm (https://github.com/ntruchsess/fhem-mirror/blob/async_device/fhem/FHEM/AsyncDevice.pm)
    Die Idee ist, dass man (ähnlich wie im blocking.pm) einen Serversocket aufmacht, forked und den Childprozess mit dem Parent über diesen Socket dauerhaft verbindet (könnte natürlich auch eine Pipe oder auf Systemen, die Threads unterstützen ein neuer Thread statt Fork in Verbindung mit einer Queue sein). Weitere Details der Kommunikation sind noch nicht implementiert, ich stelle mir aber vor, dass man das verwendete Protokoll der Remote-aufrufe durch marshalling/unmarshalling in z.B. JSON-Format fast komplett abstrahieren könnte.

    - Norbert
    Titel: Antw:workaround um OWserver asynchron zu machen
    Beitrag von: justme1968 am 20 November 2013, 11:18:30
    hallo norbert,

    das ist genau der verallgemeinerte (und sehr viel ausgearbeitetere) fall von dem was ich mit der owserver änderung gemacht habe.

    die haupt herausforderung bei OWServer/OWDevice ist leider das dispatch und nicht die eigentliche parent/child kommunikation.

    deine generische lösung hat auf jeden fall den vorteil das alles was an infrastruktur aufgaben nötig ist ein mal zentral gemacht wird.

    was ich aus dem stehgreif nicht abschätzen kann ist wie groß der overhead einer allgemeinen lösung durch die eine zusätzliche indirekten ist und vor allem wenn man json noch mit rein bringt. die 500ms sollen ja nicht wieder aufgefressen werden.

    ich probiere es einfach mal :)

    gruss
      andre
    Titel: Antw:workaround um OWserver asynchron zu machen
    Beitrag von: ntruchsess am 20 November 2013, 12:40:16
    beziehst Dich auf das Dipatchen der asynchronen Antworten? Schick einfach eine Referenz auf den Aufrufer mit dem Request mit (das muss keine Perl-referenz sein, jedem Aufruf eine correlationid zu verpassen um die Antwort dem Aufrufer zuordnen zu können reicht schon). Bei 1-Wire (darum geht's ja) ginge alternativ natürlich auch die 1-Wire Geräteid.

    - Norbert
    Titel: Antw:workaround um OWserver asynchron zu machen
    Beitrag von: Joachim am 04 Januar 2014, 13:35:07
    Moin @ all,
    gibt es hier eigentlich schon was neues, oder was zum testen?
    Wäre zum Testen mit einem Pi und ds2482-800  1-Wire-9 Board dabei.
    Darf auch gene alpha sein.

    Gruß Joachim
    Titel: Antw:workaround um OWserver asynchron zu machen
    Beitrag von: justme1968 am 04 Januar 2014, 13:43:57
    es gibt inzwischen den patch aus diesem thread: http://forum.fhem.de/index.php/topic,16945.0.html (http://forum.fhem.de/index.php/topic,16945.0.html). der ist inzwischen eingecheckt und ganz normal teil von fhem. damit wird ein blockieren in fast allen fällen zuverlässig erkannt und verhindert.

    was damit noch nicht verhindert wird ist das (kurze) blockieren für die daher der eigentlichen temperatur messung. das kann man etwas optimieren in dem man die genauigkeit auf 9 bit setzt. das sollte für den Hausgebrauch immer noch locker reichen.

    den ansatz mit dem dispatch habe ich noch nicht weiter verfolgt weil OWServer und OWDevice an ein paar stellen abfagen machen und mehr oder weniger auf eine direkte antwort angewiesen sind und deshalb noch ein paar andere dinge zum teil aufwändig geändert werden müssten. eventuell ist es einfacher die beiden module komplett in einen eigenen prozess zu kapseln so wie es hier: http://forum.fhem.de/index.php/topic,18275.0.html (http://forum.fhem.de/index.php/topic,18275.0.html) beschrieben ist.

    aktuell läuft es mit den änderungen die das komplette einfrieren verhindern so weit zuverlässig das ich gerne erst ein paar andere dinge fertig machen möchte bevor ich das wieder angehe.

    gruss
      andre
    Titel: Antw:workaround um OWserver asynchron zu machen
    Beitrag von: Joachim am 04 Januar 2014, 14:08:50
    Moin Andre,
    Das Blockieren von FHEM, wenn OWFS nicht erreichbar ist meinte ich nicht, das hatte ich alles verfolgt und erfreut zu Kenntniss genommen, das es gelöst ist.
    Mir geht es um das Blockieren während des Auslesens. Die Variante, die Auflösung herunterzusetzen gefällt mir nicht wirklich, ich glaube, ich muss mir mal Deinen Würgaround:
    Zitatnohup sh -c "while true; do nice find /1wire/uncached/[0-9]* -maxdepth 1 \( -name temperature -or -name "latch.[A-C]" -or -name "counters.[A-C]" \) -exec cat {} \; >/dev/null  ; done" &
    genauer ansehen.
    Insgesamt hast Du recht mit dem was in diesem
    http://forum.fhem.de/index.php/topic,16945.0.html
    Tread steht, das wäre der sauberste Ansatz, da es diverse Module gibt, die auf ein genaues Timing angewiesen sind, und ein Blockieren von 1 sec. durch ein Modul einfach indikutabel ist.
    Bei mir sind aktuell ca. 20 1-Wire Bausteine angeschlossen, in Verbindung mit HM und Max ergibt das alles, aber kein stabiles System.

    Gruß Joachim