Neues Modul: I2C_ADS1x1x für TI Analog/Digitalwandler (z.B. ADS1115)

Begonnen von Adimarantis, 29 September 2020, 17:51:34

Vorheriges Thema - Nächstes Thema

Adimarantis

Hallo,

Nachdem ich bisher das Modul von @schlawiano aus diesem Thread : https://forum.fhem.de/index.php/topic,54044.0.html verwendet hatte, habe ich mich jetzt doch mal hingesetzt und einen vereinfachten re-write gewagt.
Auf Basis des PCF8574 und unter Verwendung von Fragmenten aus dem I2C_ADS1115 Moduls ist ein Modul entstanden, dass einiges des Feedbacks aus dem anderen Thread mit aufgreift:

  • Nur noch ein Modul für alle Channels (statt dem zweistufigen Ansatz)
  • Generisch für alle Texas Instruments A/D Wandler

Zusätzlich habe ich meine Standard Use Cases gleich mit implementiert. Ich verwende den ADS1115 um Widerstände zu messen - insbesondere von PT1000 Platintemperatursensoren und NTC Thermistoren.
Die entsprechenden Widerstands bzw. Temperaturumrechung ist gleich mit eingebaut. Im Default werden aber einfach nur eingehende Spannungen gemessen und in readings geschrieben.

Einschränkungen:


  • Einige der Chips haben Comparatoren eingebaut bzw. können aufgrund von Thresholds Interrupts (über einen eigenen PIN) auslösen. Diese Features sind im Modul nicht implementiert, da ich dafür aktuell keine Verwendung sehe. Das meiste lässt sich auch in Software (FHEM) lösen und ist IMHO eher dafür den Chip direkt in eine Schaltung zu integrieren. Wenn jemand aber einen Use Case hat, dann können wir uns gerne ansehen, wie man das sinnvoll integriert.
  • Die Implementierung der anderen Chips außer ADS1115 ist nicht getestet, da ich nur diesen einen Typ zur Verfügung habe.
  • Ich habe nicht viel Perl Erfahrung. Viel in diesem Modul ist einfach Copy&Paste und Abschreiben. Daher ist möglicherweise nicht alles so geschrieben wie es sollte - bitte um Feedback.

Getting started:
define myDevice I2C_ADS1x1x <I2C Adresse>

Die Adresse findet man mit
i2cdetect -y 1
raus.

Über das Attribut "device" ggf. noch den Chip definieren (Default: ADS1115). Je nach Chip wird dann nur 1 Channel statt 4 abgefragt und die Berechnung des Wertes verwendet andere Faktoren bei 12bit als bei 16bit. Sonst gibt es keine Unterschiede.

Dann noch das Attribut "IODev" mit dem Namen des I2C Devices (getested nur mit "RPII2C") welches zuvor definiert sein muss.

Natürlich muss der Chip noch korrekt an den I2C Bus angeschlossen sein und entsprechende Inputs, ggf. mit Spannungsteilern an die analogen Eingänge.

Für weitere Dokumentation siehe inline Doku im Modul.

Nochmal, bitte um Feedback ob das Modul den Ansprüchen entspricht, so das man es potentiell nach weiterem Tuning als Standard aufnehmen könnte.

Danke & Gruß,
Jörg

Update 26.10.20: Habe jetzt eine 12-Bit (ADS1015) getestet und den Code dafür gefixt. Außerdem ein 8ms usleep eingebaut um dem Chip genug Zeit zu geben das Ergebnis zu liefern.
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL + 2xRaspberry 1
Module: 50_Signalbot, 52_I2C_ADS1x1x , 58_RPI_1Wire, (50_SPI_MAX31865)

Adimarantis

Hallo,

ich bräuchte noch Feedback zu dem Modul um es ggf. als Standardmodul veröffentlichen zu können.
Es haben ja scheinbar ein paar Leute runtergeladen. Wäre dankbar über eine Rückmeldung.

Danke,
Jörg
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL + 2xRaspberry 1
Module: 50_Signalbot, 52_I2C_ADS1x1x , 58_RPI_1Wire, (50_SPI_MAX31865)

kpl

Hallo Jörg,

erstmal danke für das neue Modul.
Es funktioniert bei mir gut und macht die Konfiguration deutlich übersichtlicher.
Ich benötige jetzt nur noch ein anstatt sechs devices. Ich hatte bisher noch ein dummy device um die Werte zusammenzufassen. Ich benutze allerdings nur RAW Werte und keine der internen Umrechnungen, hierzu kann ich nichts sagen.
Um Unklarheiten zu vermeiden würde ich bei den gain Attributen den exakten Wert angeben und nicht nur die gerundeten Spannungen.
Wenn ich den operation_mode auf Continuously stelle bekomme ich immer wieder falsche Messwerte, dies war aber auch beim alten Modul so, bei SingleShot gibt es keine Ausreißer.  Ich verwende einen relativ hohe poll_interval von 0.02

Gruß,
Peter



Adimarantis

Hallo Peter,

Soweit ich das verstehe, kannst du den Continuous Mode eigentlich nur sinnvoll nutzen, wenn du nur einen Channel verwendest. Dann wird die Config einmal gesetzt und du kannst ständig lesen. Eigentlich sollte man da noch auf einen Interrupt vom RDY pin warten - das würde jetzt richtig kompliziert werden (da bräuchte man z.B. beim Pi noch eine GPIO).
Bei einem Kanalwechsel (und das mache ich ja ständig um alle 4 Kanäle zu lesen) sollte man dann anscheinend den ersten Wert möglichst verwerfen, da er ggf. gar nicht vom aktuellen Kanal kommt. Ein ständiger Wechsel führt den Modus aber ad absurdum.

Fazit: Man könnte den Modus nur implementieren, wenn in dem Fall auf einen Kanal begrenzt wird und ich dann die Config nur einmal schreibe und danach nur noch auslese. Das ist aber wohl eher was für extrem schnelles Timing und IMHO unter FHEM nicht sinnvoll. Ich hatte mir das noch gar nicht komplett durchdacht, aber es macht wohl Sinn den Modus komplett zu entfernen, da er hier nicht sinnvoll nutzbar ist.

Mein Ansatz beim Gain war es einfach aber sprechend zu halten. Im Vorläufermodul war das mit 1x,2x ... benannt - da finde ich die gerundeten Volt aussagekräftiger und 6.144V etc. fand ich zu lang. Aber da nehme ich gerne weiteres Feedback entgegen.

Bin bei der Durchsicht des Codes wegen dem Continuos aber noch auf ein paar Kleinigkeiten gestoßen, die ich noch fixen werde. Ist aber nichts, dass die Kernfunktionalität beeinträchtig.

Gruß,
Jörg
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL + 2xRaspberry 1
Module: 50_Signalbot, 52_I2C_ADS1x1x , 58_RPI_1Wire, (50_SPI_MAX31865)

Adimarantis

#4
Nach einigen Anregungen von noansi (Danke!), habe ich das Modul jetzt etwas umgebaut, so dass es die Conversions über Timer ansteuert und FHEM weniger blockiert.
Ich poste das neue Modul hier mal zum Testen (und lasse die "stabile" Version noch im ersten Beitrag stehen). Läuft bei mir schon ein paar Tage produktiv, sollten also keine groben Schnitzer drin sein. Wäre super wenn es noch jemand testen könnte.
Hier ist der Continious Mode auch deaktiviert, da wie gesagt IMHO nicht wirklich sinnvoll bei FHEM. Durch die asynchrone Abfrage lassen sich jetzt die 4 Channels zeitlich verteilen indem man das Attribut "polling_interleave" (in Sekunden) auf einen höheren Wert setzt. D.h. man kann bei einer Abfrage einmal pro Minute (polling_interval=1) mit polling_interleave=10 die 4 Abfragen eingermassen gleichmässig über die Zeit verteilen und damit die Last auf FHEM verteilen.

Jörg

Edit: Kleinere Anpassungen und Optimierungen
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL + 2xRaspberry 1
Module: 50_Signalbot, 52_I2C_ADS1x1x , 58_RPI_1Wire, (50_SPI_MAX31865)

noansi

Hallo Jörg,

danke für das engagierte Umschreiben.
Das Modul passt jetzt wesentlich besser zur FHEM Architektur durch den Verzicht auf busy-waiting beim I2C IO.  :)
Wer einen der unterstützten Chips für Spannungsmessungen, Widerstandsmessungen oder Temperaturmessungen an einem RasPi nutzen will, kann damit sicherlich gut was anfangen.

Gruß, Ansgar.

Adimarantis

Hallo,

das Modul ist seit heute offiziell im FHEM standard und kann jetzt über die "update" Funktion installiert/aktualisiert werden.
Nutzer von älteren Versionen sollten eigentlich keine Probleme haben, bitte aber tzotzdem nochmal prüfen ob alles wie gewohnt funktioniert.

Weitere Anregungen, Hilfestellung und Bug Reports bitte in diesem Thread posten.

Danke,
Jörg
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL + 2xRaspberry 1
Module: 50_Signalbot, 52_I2C_ADS1x1x , 58_RPI_1Wire, (50_SPI_MAX31865)

osid-timo

Hallo Adimarantis,
dein neues Modul habe ich heute entdeckt und bin leider gescheidert und bekomme keine Werte.
Bei mir tauchen folgende Meldungen im Log auf:

2021.02.01 16:48:14 5: myADS1115 => Processing state 0 timer 0.008 channels: 4 newstate:1
2021.02.01 16:48:14 4: myADS1115 =>  CONFIG adr: Sensor 0 Byte0:195 Byte1:132
2021.02.01 16:48:14 0: Strange call for nonexistent <undefined>: I2CWrtFn
2021.02.01 16:48:14 5: myADS1115 => Processing state 1 timer 1.0 channels: 4 newstate:2
2021.02.01 16:48:14 5: myADS1115 =>  READ adr: Sensor 0 Gain 4V
2021.02.01 16:48:14 0: Strange call for nonexistent <undefined>: I2CWrtFn
2021.02.01 16:48:15 5: myADS1115 => Processing state 2 timer 0.008 channels: 4 newstate:3
2021.02.01 16:48:15 4: myADS1115 =>  CONFIG adr: Sensor 1 Byte0:211 Byte1:132
2021.02.01 16:48:15 0: Strange call for nonexistent <undefined>: I2CWrtFn
2021.02.01 16:48:15 5: myADS1115 => Processing state 3 timer 1.0 channels: 4 newstate:4
2021.02.01 16:48:15 5: myADS1115 =>  READ adr: Sensor 1 Gain 4V
2021.02.01 16:48:15 0: Strange call for nonexistent <undefined>: I2CWrtFn
2021.02.01 16:48:16 5: myADS1115 => Processing state 4 timer 0.008 channels: 4 newstate:5
2021.02.01 16:48:16 4: myADS1115 =>  CONFIG adr: Sensor 2 Byte0:227 Byte1:132
2021.02.01 16:48:16 0: Strange call for nonexistent <undefined>: I2CWrtFn
2021.02.01 16:48:16 5: myADS1115 => Processing state 5 timer 1.0 channels: 4 newstate:6
2021.02.01 16:48:16 5: myADS1115 =>  READ adr: Sensor 2 Gain 4V
2021.02.01 16:48:16 0: Strange call for nonexistent <undefined>: I2CWrtFn
2021.02.01 16:48:16 1: HMUARTLGW myHmUART did not respond for the 3. time, resending
2021.02.01 16:48:17 5: myADS1115 => Processing state 6 timer 0.008 channels: 4 newstate:7
2021.02.01 16:48:17 4: myADS1115 =>  CONFIG adr: Sensor 3 Byte0:243 Byte1:132
2021.02.01 16:48:17 0: Strange call for nonexistent <undefined>: I2CWrtFn
2021.02.01 16:48:17 5: myADS1115 => Processing state 7 timer 55.968 channels: 4 newstate:0
2021.02.01 16:48:17 5: myADS1115 =>  READ adr: Sensor 3 Gain 4V
2021.02.01 16:48:17 0: Strange call for nonexistent <undefined>: I2CWrtFn


mein Config ist:
CFGFN      FHEM/fhemBase.cfg
   DEF        0x48
   FUUID      60180b8e-f33f-0a01-11ca-e1caeebe3148a08c
   IODevName  RPII2C
   NAME       myADS1115
   NR         260
   STATE      ???
   TYPE       I2C_ADS1x1x
   READINGS:
     2021-02-01 16:43:28   state           0
   helper:
     channels   4
     configword 33156
     state      0
     bm:
       I2C_ADS1x1x_Attr:
         cnt        3
         dmx        -1000
         dtot       0
         dtotcnt    0
         mTS        01.02. 16:47:38
         max        0.000339031219482422
         tot        0.000982761383056641
         mAr:
           set
           myADS1115
           a0_gain
           4V
       I2C_ADS1x1x_Get:
         cnt        14
         dmx        -1000
         dtot       0
         dtotcnt    0
         mTS        01.02. 16:48:13
         max        3.69548797607422e-05
         tot        0.000221967697143555
         mAr:
           HASH(0x34fd1e8)
           myADS1115
           ?
       I2C_ADS1x1x_Set:
         cnt        42
         dmx        -1000
         dtot       0
         dtotcnt    0
         mTS        01.02. 16:48:13
         max        0.000896930694580078
         tot        0.00321769714355469
         mAr:
           HASH(0x34fd1e8)
           myADS1115
           Update
Attributes:
   IODev      RPII2C
   a0_gain    4V
   a0_mode    RES
   a1_mode    RAW
   a2_mode    RAW
   a3_mode    RAW
   data_rate  1x
   decimals   3
   device     ADS1115
   mux        SINGLE
   poll_interleave 1.0
   poll_interval 1
   room       Test
   showtime   1
   sys_voltage 3.3
   verbose    5


über einen Tipp würde ich mich freuen

Gruß osid-timo
FHEM Pi3: 1* CUL, 30* Homematic, 10* EnOcean
FHEM Pi3: IR-Lesekopf, BT->SMA
FHEM Pi3: ZHK, 1-wire, 1* VBus   Resol DeltaSol BS

Adimarantis

als IODev hast du RPII2C was mir eher nach dem Modultype als dem Devicenamen aussieht.

Du solltest ja irgendwas der Art
define myI2CDev RPII2C 1
definiert haben.

In IODev gehört dann myI2CDev und nicht RPII2C.

Ich schau mir mal an ob ich das in Zukunft besser abfangen kann.

Gruß,
Jörg
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL + 2xRaspberry 1
Module: 50_Signalbot, 52_I2C_ADS1x1x , 58_RPI_1Wire, (50_SPI_MAX31865)

osid-timo

Hallo Adimarantis,
Asche auf mein Haupt, mit dem richtigen Namen klappt das natürlich.
Danke für den Tipp und das Modul

Gruß Osid-timo
FHEM Pi3: 1* CUL, 30* Homematic, 10* EnOcean
FHEM Pi3: IR-Lesekopf, BT->SMA
FHEM Pi3: ZHK, 1-wire, 1* VBus   Resol DeltaSol BS

Adimarantis

Der Maintainer von RPII2C (Danke Klaus!) hat mein Modul jetzt freundlicherweise in die Liste der bekannten Clients aufgenommen, sodass die IODevice in Zukunft normalerweise automatisch gesetzt wird.

Jörg
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL + 2xRaspberry 1
Module: 50_Signalbot, 52_I2C_ADS1x1x , 58_RPI_1Wire, (50_SPI_MAX31865)

Forstling

Hallo Danke für das Modul

Das habe ich vor 1-2 Jahren als ich meine PT1000 Sensoren von der Heizung einbinden wollte. Und nicht das richtige Modul für FHEM gefunden habe.

Bin jetzt zufällig darüber gestolpert als ich die command rev nach PT100 durchsucht habe.
Habe mir dann gleich 5 ADS1115 gekauft. die sind gestern angekommen und ich kann heute sagen das ganze macht einen recht guten ersten Eindruck.

Ich habe einen PT1000 mal über Nacht messen lassen (Pollintervall = 0,01666 (1s)), der Messwert schwankt um 0.1° (das scheint das Grundrauschen des AD-Wandlers zu sein) Mit meinen jetzigen Ausleseverfahren bin ich bei 0,05°)

Das Modul und der Wandler scheint genau das zu sein was ich damals gesucht habe.
Ich werde mir mal die Langzeitstabilität anschauen und dann mein Python-Skript und meine MAX31865 dafür in Rente schicken. 

Zu den Verbesserungsvorschlägen:
1. Ein Offset für die Temperaturwerte wäre nicht schlecht (Leitunglänge und Produktionsschwankungen der Sensoren)
2. ich hätte gern ein Komastelle mehr bei der Temperatur (nur informativ um zu sehen was der Wandler kann)

Adimarantis

Danke für das Feedback.

Das mit der 0.1 Auflösung habe ich so eingebaut, da ich bereits beim Betrachten der Widerstandswerte festgestellt hatte, das da eigentlich immer Sprünge drin sind durch die eine feinere Auflösung mir nicht als sinnvoll erschien.
Wenn du aber einfach mal testen willst was da rauskommt, dann ersetze doch in Zeile 436
$temperature=sprintf( '%.1f', I2C_ADS1x1x_RTD($resistance,$sensor,AttrVal($name,"a".$sensor."_r0",1000.0)));
durch
$temperature=sprintf( '%.2f', I2C_ADS1x1x_RTD($resistance,$sensor,AttrVal($name,"a".$sensor."_r0",1000.0)));
(danach ein reload 52_I2C_ADS1x1x) - dann solltest du zwei Dezimalstellen haben.
Das mit dem Offset mache ich über den Widerstandswert des Spannungsteilers (a0_res). Allerdings wird der Wert multipliziert ist also strenggenommen kein Offset sondern ein linearer Faktor.
Wenn dir ein additives Offset sinnvoller erscheint, dann kann ich das bei Gelegenheit hinzufügen.

Zum Thema MAX31865 - da habe ich auch ein Modul gebaut - allerdings inoffiziell (nicht über FHEM update) da es da nicht wirklich viel Nachfrage gab:
https://forum.fhem.de/index.php/topic,117964.0.html

Gruß.
Jörg


Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL + 2xRaspberry 1
Module: 50_Signalbot, 52_I2C_ADS1x1x , 58_RPI_1Wire, (50_SPI_MAX31865)

Forstling

DAnke für den Tipp das Modul war zu neu für mich ist aber recht interesannt.

Ich lass die 2 Sensoren mal am meiner Testmaschine gegeneinander antreten. sieht aber aktuell so aus als würde der MAX31865 deutlich bésser abschneiden.

Wie hast du die Spannungsversorgung der AD-Wandler gelöst nimmst du die Spannung direkt vom Raspberry oder hast du eine eine spezielle Quelle.

Was denkst du könnte man so evtl. etwas Stabilität rausholen?

Adimarantis

Ich habe mit dem ADS angefangen und dann eben aus dem Präzisionsgrund auch die MAX ausprobiert.
Die Spannung nehme ich vom Raspberry (3.3V) mit einem 1K Spannungsteiler.
Nachdem ich irgendwann das Kabelwirrwarr meiner Heizungssteuerung satt hatte, habe ich alle relevanten Sachen auf eine Platine "designed". Siehe Anhang.

Bin jetzt nicht wirklich der Elektroniker, vielleicht gibt es da auch noch bessere Methoden den ADS anzuschließen. Richtig zufrieden war ich damit nicht, aber letztendlich kommen es bei Heizung/Solar auf eine halbes Grad hin oder her nicht wirklich an.

Gruß,
Jörg
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL + 2xRaspberry 1
Module: 50_Signalbot, 52_I2C_ADS1x1x , 58_RPI_1Wire, (50_SPI_MAX31865)