Raspberry, Firmata und I2C

Begonnen von doesel, 20 Mai 2015, 11:46:41

Vorheriges Thema - Nächstes Thema

doesel

Hallo,
ich hatte mein Problem schon vor ein paar Tagen bei "Anfängerfragen" geschildert, bekam aber leider keine Antwort von einem Wissenden...
Deshalb nun hier ein neuer Versuch.

Ich versuche den Feuchtigkeitssensor SHT21 über einen an den Raspberry angeschlossenen Arduino (Configurable Firmata) in Betrieb zu nehmen, jedoch verstehe ich nicht das Zusammenspiel von FRM_I2C und I2C_SHT21.
Hat das jemand schon realisiert? Übrigens: Auch mit dem BMP180 ist mir das nicht gelungen, direkt am Raspberry läuft dieser jedoch.

Nachdem ich die Suchfunktion im Forum und Google erfolglos bemüht habe, erhoffe ich mir hier den entscheidenden Hinweis.
(FHEM auf Cubietruck mit Igor-Image, 64GB SSD), seit März 19 FHEM auf NUC im Proxmox-Container, 240GB SSD, div. Homematic, Max Fensterkontakte, Onewire über Firmata und FHEM2FHEM auf Raspberrys, MySensors, Jeelink-Clone mit GSD-Modul, CUL, SDM220Modbus, Logo!8, WS980WiFi

thymjan

Wenn ich mir die Command Reference durchschaue, bin ich der Meinung die Definitionen von FRM und I2C_SHT21 sollten genügen. Das Modul FRM_I2C ist für das allgemeinere Schreiben auf dem I2C-Bus gedacht, oder?
Bin aber leider ein schlechter Berater, da I2C_SHT21 bei mir zwar den Status "initialized" hat, aber leider auch keine Werte liefert. Mit einem Testprogramm und dem Seriellen Monitor der Arduino-IDE funktioniert das auslesen über I2C allerdings tadellos.

Hat jemand eine Kombi FRM + I2C_xxxxx am Laufen, der uns helfen kann?

klausw

Zitat von: thymjan am 17 August 2015, 07:01:39
Wenn ich mir die Command Reference durchschaue, bin ich der Meinung die Definitionen von FRM und I2C_SHT21 sollten genügen. Das Modul FRM_I2C ist für das allgemeinere Schreiben auf dem I2C-Bus gedacht, oder?
exakt, das FRM Modul sollte das IODev für I2C_SHT21 sein. Steht auch so in der Commandref drin.

Da ich kein FRM nutze kann ich nur mutmaßen...
Das Modul I2C_SHT21 ist nicht im @clients von 10_FRM.pm aufgeführt, daher reagiert 10_FRM.pm auch nicht auf Anfragen dieses Moduls.
Bitte mal testweise in der 10_FRM.pm in das clients Array (z.B. nach der Zeile I2C_BMP180) eine neue Zeile mit I2C_SHT21 einfügen. Speichern und danach FHEM neu starten.
Jetzt sollte es laufen.
Der BMP180 sollte ohne Modifikation funktionieren.

...und bitte Rückmeldung, damit Norbert es noch ins Modul einpflegen kann
RasPi B v2 mit FHEM 18B20 über 1Wire, LED PWM Treiber über I2C, Luchtdruck-, Feuchtesensor und ein paar Schalter/LED\'s zum testen
Module: RPI_GPIO, RPII2C, I2C_EEPROM, I2C_MCP23008, I2C_MCP23017, I2C_MCP342x, I2C_PCA9532, I2C_PCF8574, I2C_SHT21, I2C_BME280

thymjan

#3
ZitatBitte mal testweise in der 10_FRM.pm in das clients Array (z.B. nach der Zeile I2C_BMP180) eine neue Zeile mit I2C_SHT21 einfügen. Speichern und danach FHEM neu starten.
Jetzt sollte es laufen.
Hab ich gemacht. Leider ohne Erfolg: STATE von meinem I2C_SHT21 Sensor bleibt auf "Initialized"
Im Log steht nach wie vor (direkt nach den Meldungen von shutdown restart) einmal "received String_data: I2C: Too few bytes received" und dann passiert nix mehr.
________________________________________________
FRM Readings:
error   I2C: Too few bytes received    2015-08-17 22:44:46
state   opened                                 2015-08-17 22:44:42
________________________________________________

So habe ich FRM und I2C_SHT21 definiert:

define FRM_1 FRM /dev/ttyUSB0@57600
define AdaSensor I2C_SHT21 64
attr AdaSensor IODev FRM_1
attr AdaSensor poll_interval 5


Ist das Modul I2C_SHT21 über FRM angeschlossen akzeptiert es als I2C Adresse nur Dezimalzahlen. Bei direktem Anschluss am Raspberry mit RPII2C als IODev geht es im Hex-Format 0x40.

Edit 1.9.15: mit verbose 5 gibt es bei der Angabe der Adresse im hex-Format auch bei RPII2C eine Fehlermeldung und es wird der default-Wert 64 verwendet.

klausw

Zitat von: thymjan am 17 August 2015, 22:50:36
Im Log steht nach wie vor (direkt nach den Meldungen von shutdown restart) einmal "received String_data: I2C: Too few bytes received" und dann passiert nix mehr.
________________________________________________
FRM Readings:
error   I2C: Too few bytes received    2015-08-17 22:44:46
state   opened                                 2015-08-17 22:44:42
________________________________________________
Klingt für mich als würde nix vom FRM Modul kommen...leider recht ungenau

Zitat von: thymjan am 17 August 2015, 22:50:36
So habe ich FRM und I2C_SHT21 definiert:

define FRM_1 FRM /dev/ttyUSB0@57600
define AdaSensor I2C_SHT21 64
attr AdaSensor IODev FRM_1
attr AdaSensor poll_interval 5

FRM hat ein Attribut i2c-config. Vielleicht muss dieses noch genutzt werden.

Alternativ kannst du über FRM_I2C einmal versuchen den SHT21 händisch anzusteuern. So lässt sich herausfinden, ob die Kommunikation funktioniert.

Zitat von: thymjan am 17 August 2015, 22:50:36
Ist das Modul I2C_SHT21 über FRM angeschlossen akzeptiert es als I2C Adresse nur Dezimalzahlen. Bei direktem Anschluss am Raspberry mit RPII2C als IODev geht es im Hex-Format 0x40.

dein FHEM ist aktuell? (update ausgeführt)
Die I2C Adresse wird im I2C_SHT21 Modul verarbeitet.
Das hat nichts mit dem IODev zu tun. Sie sollte in beiden Fällen als Dezimalwert im Internal I2C_Address stehen.
RasPi B v2 mit FHEM 18B20 über 1Wire, LED PWM Treiber über I2C, Luchtdruck-, Feuchtesensor und ein paar Schalter/LED\'s zum testen
Module: RPI_GPIO, RPII2C, I2C_EEPROM, I2C_MCP23008, I2C_MCP23017, I2C_MCP342x, I2C_PCA9532, I2C_PCF8574, I2C_SHT21, I2C_BME280

thymjan

#5
Die Module habe ich jetzt so konfiguriert für die händische Ansteuerung von SHT21:
define FRM_1 FRM /dev/ttyUSB0@57600
attr FRM_1 i2c-config 1
attr FRM_1 model nano
attr FRM_1 sampling-interval 3000

define AdaTest FRM_I2C 64 229 3
attr AdaTest IODev FRM_1


Die Funktion von i2c-config ist mir nicht 100%ig klar:
Zitat
i2c-config
Configure the arduino for ic2 communication. This will enable i2c on the i2c_pins received by the capability-query issued during initialization of FRM.
As of Firmata 2.3 you can set a delay-time (in microseconds) that will be inserted into i2c protocol when switching from write to read.
See: Firmata Protocol details about I2C
Einerseits steht hier das die i2c-Pins am Arduino beim Initialisieren von FRM aktiviert werden, andererseits kann auch noch eine Wartezeit zwischen Lese- und Schreib-Befehlen angegeben werden?
Und hier steige ich völlig aus:

/* I2C config
* -------------------------------
* 0  START_SYSEX (0xF0) (MIDI System Exclusive)
* 1  I2C_CONFIG (0x78)
* 2  Delay in microseconds (LSB)
* 3  Delay in microseconds (MSB)
* ... user defined for special cases, etc
* n  END_SYSEX (0xF7)
*/


Mit obiger Konfiguration von
FRM_I2C
  - IC2-Adresse von SHT21: 0x40/64;
  - Command Trigger Humidity Measurement 0xE5/227;
  - 3 Bytes sollen gelesen werden [Data (MSB), Data (LSB), Checksum]


erhalte ich Zahlenkolonnen folgender Art:
120 82 16 120 70 151 120 66 83 120 54 111 120 50 171 120 50 171 120 50 171 120 42 81 ... bzw.
120 82 16
120 70 151
120 66 83
120 54 111
120 50 171
120 50 171
120 50 171
120 42 81
Scheint so als würde der Sensor was erzählen. Zeitgleich läuft im Log nach wie vor auf:
[...]
2015.08.18 21:02:07 3: received String_data: I2C: Too few bytes received
2015.08.18 21:02:07 3: received String_data: I2C: Too few bytes received
2015.08.18 21:02:37 3: received String_data: I2C: Too few bytes received
2015.08.18 21:02:37 3: received String_data: I2C: Too few bytes received
2015.08.18 21:02:38 3: received String_data: I2C: Too few bytes received
[...]

State von FRM_1 ist jetzt "opened"
State von AdaTest ist "active"

thymjan

Habe jetzt den Arduino nano mit configurable firmata per Ethernet angeschlossen.
Jetzt erscheint im logfile alle 5 Minuten (polling-Intervall) folgendes:
2015.08.28 18:13:18 5: FRM:>f07640007301f7
2015.08.28 18:13:18 5: FRM:>f07640080200f7
2015.08.28 18:13:18 5: FRM:>f07640007501f7
2015.08.28 18:13:18 5: FRM:>f07640080200f7
2015.08.28 18:13:18 5: FRM:<f077400000006b002001f7
2015.08.28 18:13:18 5: onI2CMessage address: '64', register: '0' data: [107,160]
2015.08.28 18:13:18 5: FRM:<f0774000000074001200f7
2015.08.28 18:13:18 5: onI2CMessage address: '64', register: '0' data: [116,18]
2015.08.28 18:18:18 5: FRM:>f07640007301f7
2015.08.28 18:18:18 5: FRM:>f07640080200f7
2015.08.28 18:18:18 5: FRM:>f07640007501f7
2015.08.28 18:18:18 5: FRM:>f07640080200f7
2015.08.28 18:18:18 5: FRM:<f077400000006b002401f7
2015.08.28 18:18:18 5: onI2CMessage address: '64', register: '0' data: [107,164]
2015.08.28 18:18:18 5: FRM:<f0774000000074002a00f7
2015.08.28 18:18:18 5: onI2CMessage address: '64', register: '0' data: [116,42]
2015.08.28 18:18:44 5: FRM:>e37f01
2015.08.28 18:18:48 5: FRM:>900400
2015.08.28 18:23:18 5: FRM:>f07640007301f7
2015.08.28 18:23:18 5: FRM:>f07640080200f7
2015.08.28 18:23:18 5: FRM:>f07640007501f7
2015.08.28 18:23:19 5: FRM:>f07640080200f7
2015.08.28 18:23:19 5: FRM:<f077400000006b002801f7
2015.08.28 18:23:19 5: onI2CMessage address: '64', register: '0' data: [107,168]
2015.08.28 18:23:19 5: FRM:<f0774000000074004600f7
2015.08.28 18:23:19 5: onI2CMessage address: '64', register: '0' data: [116,70]
2015.08.28 18:28:19 5: FRM:>f07640007301f7
2015.08.28 18:28:19 5: FRM:>f07640080200f7
2015.08.28 18:28:19 5: FRM:>f07640007501f7
2015.08.28 18:28:19 5: FRM:>f07640080200f7
2015.08.28 18:28:19 5: FRM:<f077400000006b002801f7
2015.08.28 18:28:19 5: onI2CMessage address: '64', register: '0' data: [107,168]
2015.08.28 18:28:19 5: FRM:<f0774000000074004600f7
2015.08.28 18:28:19 5: onI2CMessage address: '64', register: '0' data: [116,70]

Das sieht ja schon vielversprechender aus. Allerdings kommt im I2C_SHT21-Modul nix davon an. Das steht nach wie vor im Modus initialized.
Hat irgendjemand das I2C_SHT21-Modul über Firmata am Laufen und kann mir helfen?

klausw

steht dein Loglevel generell auf 5?
Mich wundert es, das keine Einträge vom SHT21 vorhanden sind.
RasPi B v2 mit FHEM 18B20 über 1Wire, LED PWM Treiber über I2C, Luchtdruck-, Feuchtesensor und ein paar Schalter/LED\'s zum testen
Module: RPI_GPIO, RPII2C, I2C_EEPROM, I2C_MCP23008, I2C_MCP23017, I2C_MCP342x, I2C_PCA9532, I2C_PCF8574, I2C_SHT21, I2C_BME280

thymjan

Habe bisher nur in den Modulen I2C_SHT21 und FRM verbose auf 5 gesetzt. Mache das jetzt mal in global.

thymjan

#9
Internals:
   DEF        64
   FRM_1_SENDSTAT Ok
   I2C_Address 64
   IODev      FRM_1
   NAME       AdaSensor
   NR         25
   STATE      Initialized
   TYPE       I2C_SHT21
Attributes:
   IODev      FRM_1
   poll_interval 5
   roundHumidityDecimal 0
   roundTemperatureDecimal 2
   verbose    5

FHEM ist aktuell. Habe eben nochmal geupdated.
Auch mit "attr global verbose 5" bleibt I2C_SHT21 über FRM stumm: Keine Einträge im logfile.

Bei I2C_SHT21 über RPII2C gibt es im logfile Einträge:
2015.08.31 21:43:29 5: empfangen: 110 84
2015.08.31 21:43:29 5: empfangen: 94 18


Ich vermute, dass FRM die Daten gar nicht an I2C_SHT21 weitergibt, sonst hätte ich ja auch Readings in I2C_SHT21, oder?
Die Kommunikation von I2C_SHT21 in Richtung FRM und Arduino zu I2C scheint zu funktionieren. Verkleinere ich beispielsweise das polling-Intervall, werden die Werte auch dementsprechend häufiger abgefragt. Die abgefragten Werte sind im Logfile (FRM) zu sehen, scheinen dann aber im FRM-Modul stecken zu bleiben. Der Eintrag von "I2C_SHT21" in die clients-list in der Datei "10_FRM.pm" scheint nicht auszureichen.

klausw

Es wird weitergegeben,
im Logfile steht ja empfangen

ersetze bitte testweise
Log3 $hash, 5, "empfangen: $clientmsg->{received}";
durch
my $ankommen = "$name: vom client empfangen";
foreach my $av (keys %{$clientmsg}) { $ankommen .= "|" . $av . ": " . $clientmsg->{$av}; }
Log3 $hash, 0, $ankommen;

und schicke mir das log
Ich vermute, da fehlt eine Variable im Hash


RasPi B v2 mit FHEM 18B20 über 1Wire, LED PWM Treiber über I2C, Luchtdruck-, Feuchtesensor und ein paar Schalter/LED\'s zum testen
Module: RPI_GPIO, RPII2C, I2C_EEPROM, I2C_MCP23008, I2C_MCP23017, I2C_MCP342x, I2C_PCA9532, I2C_PCF8574, I2C_SHT21, I2C_BME280

thymjan

#11
Habe die erweiterte Ausgabe ins Logfile in 52_I2C_SHT21.pm in der Subroutine I2C_SHT21_I2CRec eingebaut.

Auf dem RasPi an dem der Sensor direkt am I2C-Bus angeschlossen ist, spuckt das logfile folgendes aus:
2015.09.01 19:39:48 0: Sensor: vom client empfangen|PimoroniI2C_SENDSTAT: Ok|direction: i2cread|nbyte: 2|type: temp|i2caddress: 64|received: 108 36
2015.09.01 19:39:48 0: Sensor: vom client empfangen|PimoroniI2C_SENDSTAT: Ok|direction: i2cread|nbyte: 2|type: hum|i2caddress: 64|received: 115 46


Auf dem RasPi der die Messwerte vom über Ethernet angeschlossenen Arduino nano mit ConfigurableFirmata empfängt bleibt das Modul I2C_SHT21 nach wie vor stumm.
Lediglich der Datenverkehr zwischen FRM und Arduino wird geloggt:
2015.09.01 19:51:39 5: FRM:>f07640007301f7
2015.09.01 19:51:39 5: FRM:>f07640080200f7
2015.09.01 19:51:39 5: FRM:>f07640007501f7
2015.09.01 19:51:39 5: FRM:>f07640080200f7
2015.09.01 19:51:39 5: FRM:<f0774000000067006c01f7f0774000000004016e00f7
2015.09.01 19:51:39 5: onI2CMessage address: '64', register: '0' data: [103,236]
2015.09.01 19:51:39 5: onI2CMessage address: '64', register: '0' data: [132,110]

thymjan

#12
Habe testweise zusätzlich einen BMP180 Sensor an den Arduino Nano angeschlossen. Von diesem kommen die Messwerte im Modul I2C_BMP180 an.
define BMP180 I2C_BMP180
attr BMP180 IODev FRM_1
attr BMP180 model BMP180
attr BMP180 oversampling_settings 3
attr BMP180 poll_interval 5
attr BMP180 roundPressureDecimal 2
attr BMP180 roundTemperatureDecimal 2


Ein Auslesevorgang sieht im logfile so aus:
2015.09.02 20:27:14 5: FRM:>f076770074012e00f7
2015.09.02 20:27:14 5: FRM:>f076770876010200f7
2015.09.02 20:27:14 5: FRM:>f076770074017401f7
2015.09.02 20:27:14 5: FRM:>f076770876010300f7
2015.09.02 20:27:14 5: FRM:<f0777700760156000f01f7f0777700760124010d000001f7
2015.09.02 20:27:14 5: onI2CMessage address: '119', register: '246' data: [86,143]
2015.09.02 20:27:14 5: BMP180 empfangen: 86 143
2015.09.02 20:27:14 5: onI2CMessage address: '119', register: '246' data: [164,13,128]
2015.09.02 20:27:14 5: BMP180 empfangen: 164 13 128


list BMP180:
Internals:
   CFGFN
   FRM_1_SENDSTAT Ok
   I2C_Address 119
   IODev      FRM_1
   NAME       BMP180
   NR         123
   STATE      T: 24.19 P: 980.49 P-NN: 1015.20
   TYPE       I2C_BMP180
   Readings:
     2015-09-02 21:18:55   pressure        980.49
     2015-09-02 21:18:55   pressure-nn     1015.20
     2015-09-02 21:18:55   state           T: 24.19 P: 980.49 P-NN: 1015.20
     2015-09-02 21:18:55   temperature     24.19
   Calibrationdata:
     ac1        8245
     ac2        -1107
     ac3        -14864
     ac4        34269
     ac5        25328
     ac6        13848
     b1         6515
     b2         41
     b5         3862.94178706027
     mb         -32768
     mc         -11786
     md         2620
Attributes:
   IODev      FRM_1
   model      BMP180
   oversampling_settings 3
   poll_interval 5
   roundPressureDecimal 2
   roundTemperatureDecimal 2
   verbose    5

thymjan

Jetzt habe ich das Problem gefunden:

Der Client I2C_SHT21 ruft die CallFn im Master FRM auf und schickt im %sendpackage den key {type} mit, die FRM noch nicht erwartet/versteht.
Und {type} wird dann von FRM auch nicht mehr zurück an I2C_SHT21 geschickt.

Müssen wir FRM so umschreiben, dass der key {type} nicht verloren geht?

thymjan

#14
Und hier meine Lösung:

Habe ins Datenblatt vom SHT21 geschaut. Pro Messung (Temp. bzw. Luftfeuchte) werden ja jeweils zwei Datenbytes (MSB und LSB) übermittelt.
Die maximale Auflösung des Sensors sind 14 bit. Sind also zwei Bits übrig. Eins wird für die Information genutzt, ob der Messwert den Temperaturwert ('0') oder den Luftfeuchtewert ('1') enthält. Deshalb habe ich statt des keys {type: temp, hum} eine Bitmaske benutzt, die identifiziert ob es sich beim empfangenen Wert um den Temperatur- oder Luftfeuchtewert handelt. Das war dann einfacher umzusetzen als erwartet.

Damit man den Sensor SHT21 über einen Arduino mit ConfigurableFirmata mit IODev FRM benutzen kann sind folgende Schritte notwendig:


  • Im Modul 10_FRM.pm in die Liste der potentiellen clients I2C_SHT21 eintragen.
  • Im Modul 52_FRM_SHT21.pm muss die Subroutine I2C_SHT21_I2CRec manipuliert werden:

    sub I2C_SHT21_I2CRec ($$) {
        my ($hash, $clientmsg) = @_;
        my $name = $hash->{NAME};
        my $phash = $hash->{IODev};
        my $pname = $phash->{NAME};
        while ( my ( $k, $v ) = each %$clientmsg ) {  #erzeugen von Internals fuer alle Keys in $clientmsg die mit dem physical Namen beginnen
            $hash->{$k} = $v if $k =~ /^$pname/ ;
        }
        #if ($clientmsg->{direction} && $clientmsg->{type} && $clientmsg->{$pname . "_SENDSTAT"} eq "Ok") {
        if ($clientmsg->{direction} && $clientmsg->{$pname . "_SENDSTAT"} eq "Ok") {
            if ( $clientmsg->{direction} eq "i2cread" && defined($clientmsg->{received}) ) {
                Log3 $hash, 5, "empfangen: $clientmsg->{received}";
                #I2C_SHT21_GetTemp  ($hash, $clientmsg->{received}) if $clientmsg->{type} eq "temp" && $clientmsg->{nbyte} == 2;
                #I2C_SHT21_GetHum ($hash, $clientmsg->{received}) if $clientmsg->{type} eq "hum" && $clientmsg->{nbyte} == 2;
                my @raw = split(" ",$clientmsg->{received});
                I2C_SHT21_GetTemp ($hash, $clientmsg->{received}) if !($raw[1] & 2) && $clientmsg->{nbyte} == 2;
                I2C_SHT21_GetHum ($hash, $clientmsg->{received}) if ($raw[1] & 2) && $clientmsg->{nbyte} == 2;
            }
        }
    }
So funktioniert I2C_SHT21 auch immer noch mit RPII2C.

@klausw: Denkst Du es entstehen bei dieser Vorgehensweise Nachteile gegenüber der Verwendung des keys {type}?

hier nochmal der code zum kopieren:
sub I2C_SHT21_I2CRec ($$) {
    my ($hash, $clientmsg) = @_;
    my $name = $hash->{NAME};
    my $phash = $hash->{IODev};
    my $pname = $phash->{NAME};
    while ( my ( $k, $v ) = each %$clientmsg ) {  #erzeugen von Internals fuer alle Keys in $clientmsg die mit dem physical Namen beginnen
        $hash->{$k} = $v if $k =~ /^$pname/ ;
    }
    if ($clientmsg->{direction} && $clientmsg->{$pname . "_SENDSTAT"} eq "Ok") {
        if ( $clientmsg->{direction} eq "i2cread" && defined($clientmsg->{received}) ) {
            Log3 $hash, 5, "empfangen: $clientmsg->{received}";
            my @raw = split(" ",$clientmsg->{received});
            I2C_SHT21_GetTemp ($hash, $clientmsg->{received}) if !($raw[1] & 2) && $clientmsg->{nbyte} == 2;
            I2C_SHT21_GetHum ($hash, $clientmsg->{received}) if ($raw[1] & 2) && $clientmsg->{nbyte} == 2;
        }
    }
}