Raspberry, Firmata und I2C

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

Vorheriges Thema - Nächstes Thema

thymjan

#30
Hallo Klaus,

habe mich damals an die Anleitung von Norbert Truchsess gehalten.
Da gibts einen elend langen Threat den ich mühsam durchgearbeitet habe.
Das war die Kombi Nano-ENC28J60. Das ist ziemlich knapp mit dem Speicherplatz. Aber einmal konfiguriert läufts stabil bei mir.
Firmata-mäßig läuft da allerdings momentan einiges. Da habe ich den Überblick verloren.
Wenn Du Norberts Weg und seine Firmata verwenden willst, bin ich Dir gerne behilflich.
Muss die Infos nur nochmal zusammen kratzen.

Das nächste große Ding wäre ja auch Firmata mit WLAN oder Bluetooth. Habe ich hier auch zwei Module.
Spätestens da muss man sich mit den neuen Firmatas intensiv beschäftigen.

Hängen wir uns rein!

Grüße,
Stefan


thymjan

@Jürgen:
Wie versorgst Du den Arduino mit Strom? Bei mir hat ein gutes Netzteil die Stabilität erheblich verbessert.

Gruß,
Stefan

schami23

#32
Hallo Stefan,

Die Stomversorgung erfolgt über USB 5V 2A.

Hab jetzt alles neu gemacht, hat schwierigkeiten mit der Verbindung zum Arduino hab das Problem behoben die neue FHEM Version mag die Klammern beim global nicht.

Leider hab ich das Problem immer noch seltsammerweise kommt ab und zu eine Luftfeuchtikeit zurück aber keine Temperatur nie beides.
Wenn das SHT21 Modul abfragt kommt vom Arduino folgendes zurück.

2016.01.05 08:37:10 3: received String_data: I2C: Too few bytes received
2016.01.05 08:37:10 5: empfangen: 156 248
2016.01.05 08:37:10 3: received String_data: I2C: Too few bytes received
2016.01.05 08:37:10 5: empfangen: 156 248
2016.01.05 08:42:11 5: empfangen: 100 164
2016.01.05 08:42:11 3: received String_data: I2C: Too few bytes received
2016.01.05 08:42:11 5: empfangen: 100 164


Ich hab im FRM unter Readings
error                          I2C: Too few bytes received
stehen

Ich verwende diese Firmata auf beide Mega
/*
* Firmata is a generic protocol for communicating with microcontrollers
* from software on a host computer. It is intended to work with
* any host computer software package.
*
* To download a host software package, please click on the following link
* to open the download page in your default browser.
*
* http://firmata.org/wiki/Download
*/

/*
  Copyright (C) 2006-2008 Hans-Christoph Steiner.  All rights reserved.
  Copyright (C) 2010-2011 Paul Stoffregen.  All rights reserved.
  Copyright (C) 2009 Shigeru Kobayashi.  All rights reserved.
  Copyright (C) 2009-2013 Jeff Hoefs.  All rights reserved.
  Copyright (C) 2013 Norbert Truchsess. All rights reserved.
  Copyright (C) 2014 Nicolas Panel. All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  See file LICENSE.txt for further informations on licensing terms.

  formatted using the GNU C formatting and indenting
*/


#include <Firmata.h>

/*
* by default Firmata uses the Serial-port (over USB) of Arduino.
* ConfigurableFirmata may also comunicate over ethernet using tcp/ip.
* To configure this 'Network Firmata' to use the original WIZ5100-based
* ethernet-shield or Arduino Ethernet uncomment the includes of 'SPI.h' and 'Ethernet.h':
*/

#include <SPI.h>
#include <Ethernet.h>

/*
* To configure 'Network Firmata' to use an ENC28J60 based board include
* 'UIPEthernet.h' (no SPI.h required). The UIPEthernet-library can be downloaded
* from: https://github.com/ntruchsess/arduino_uip
*/

//#include <UIPEthernet.h>

/*
* To execute Network Firmata on Yun uncomment Bridge.h and YunClient.h.
* Do not include Ethernet.h or SPI.h in this case.
* On Yun there's no need to configure local_ip and mac in the sketch
* as this is configured on the linux-side of Yun.
*/

//#include <Bridge.h>
//#include <YunClient.h>

#if defined ethernet_h || defined UIPETHERNET_H || defined _YUN_CLIENT_H_
/*==============================================================================
* Network configuration for Network Firmata
*============================================================================*/
#define NETWORK_FIRMATA
//replace with ip of server you want to connect to, comment out if using 'remote_host'
#define remote_ip IPAddress(192,168,56,104)
//replace with hostname of server you want to connect to, comment out if using 'remote_ip'
//#define remote_host " "
//replace with the port that your server is listening on
#define remote_port 3031
//replace with arduinos ip-address. Comment out if Ethernet-startup should use dhcp. Is ignored on Yun
//#define local_ip IPAddress(192,168,56,140)
//replace with ethernet shield mac. It's mandatory every device is assigned a unique mac. Is ignored on Yun
const byte mac[] = {0x90, 0xA2, 0xDA, 0x0D, 0x07, 0x01};
#endif

// To configure, save this file to your working directory so you can edit it
// then comment out the include and declaration for any features that you do
// not need below.

// Also note that the current compile size for an Arduino Uno with all of the
// following features enabled is about 22.4k. If you are using an older Arduino
// or other microcontroller with less memory you will not be able to include
// all of the following feature classes.

#include <utility/DigitalInputFirmata.h>
DigitalInputFirmata digitalInput;

#include <utility/DigitalOutputFirmata.h>
DigitalOutputFirmata digitalOutput;

#include <utility/AnalogInputFirmata.h>
AnalogInputFirmata analogInput;

#include <utility/AnalogOutputFirmata.h>
AnalogOutputFirmata analogOutput;

#include <Servo.h> //wouldn't load from ServoFirmata.h in Arduino1.0.3
#include <utility/ServoFirmata.h>
ServoFirmata servo;

#include <Wire.h> //wouldn't load from I2CFirmata.h in Arduino1.0.3
#include <utility/I2CFirmata.h>
I2CFirmata i2c;

#include <utility/OneWireFirmata.h>
OneWireFirmata oneWire;

#include <utility/FirmataStepper.h>
FirmataStepper stepper;

#include <utility/FirmataExt.h>
FirmataExt firmataExt;

#include <utility/FirmataScheduler.h>
FirmataScheduler scheduler;

#include <utility/EncoderFirmata.h>
EncoderFirmata encoder;


// dependencies. Do not comment out the following lines
#if defined AnalogOutputFirmata_h || defined ServoFirmata_h
#include <utility/AnalogWrite.h>
#endif

#if defined AnalogInputFirmata_h || defined I2CFirmata_h || defined EncoderFirmata_h
#include <utility/FirmataReporting.h>
FirmataReporting reporting;
#endif

// dependencies for Network Firmata. Do not comment out.
#ifdef NETWORK_FIRMATA
#if defined remote_ip && defined remote_host
#error "cannot define both remote_ip and remote_host at the same time!"
#endif
#include <utility/EthernetClientStream.h>
#ifdef _YUN_CLIENT_H_
YunClient client;
#else
EthernetClient client;
#endif
#if defined remote_ip && !defined remote_host
#ifdef local_ip
EthernetClientStream stream(client, local_ip, remote_ip, NULL, remote_port);
#else
EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), remote_ip, NULL, remote_port);
#endif
#endif
#if !defined remote_ip && defined remote_host
#ifdef local_ip
EthernetClientStream stream(client, local_ip, IPAddress(0, 0, 0, 0), remote_host, remote_port);
#else
EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), IPAddress(0, 0, 0, 0), remote_host, remote_port);
#endif
#endif
#endif

/*==============================================================================
* FUNCTIONS
*============================================================================*/

void systemResetCallback()
{
  // initialize a defalt state

  // pins with analog capability default to analog input
  // otherwise, pins default to digital output
  for (byte i = 0; i < TOTAL_PINS; i++) {
    if (IS_PIN_ANALOG(i)) {
#ifdef AnalogInputFirmata_h
      // turns off pullup, configures everything
      Firmata.setPinMode(i, ANALOG);
#endif
    } else if (IS_PIN_DIGITAL(i)) {
#ifdef DigitalOutputFirmata_h
      // sets the output to 0, configures portConfigInputs
      Firmata.setPinMode(i, OUTPUT);
     
#endif
    }
  }

#ifdef FirmataExt_h
  firmataExt.reset();
#endif
}

/*==============================================================================
* SETUP()
*============================================================================*/

void setup()
{
 
 
#ifdef NETWORK_FIRMATA
#ifdef _YUN_CLIENT_H_
  Bridge.begin();
#else
#ifdef local_ip
  Ethernet.begin((uint8_t *)mac, local_ip); //start ethernet
#else
  Ethernet.begin((uint8_t *)mac); //start ethernet using dhcp
#endif
#endif
  delay(1000);
#endif
  Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION);

#if defined AnalogOutputFirmata_h || defined ServoFirmata_h
  /* analogWriteCallback is declared in AnalogWrite.h */
  Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
#endif

#ifdef FirmataExt_h
#ifdef DigitalInputFirmata_h
  firmataExt.addFeature(digitalInput);
#endif
#ifdef DigitalOutputFirmata_h
  firmataExt.addFeature(digitalOutput);
#endif
#ifdef AnalogInputFirmata_h
  firmataExt.addFeature(analogInput);
#endif
#ifdef AnalogOutputFirmata_h
  firmataExt.addFeature(analogOutput);
#endif
#ifdef ServoFirmata_h
  firmataExt.addFeature(servo);
#endif
#ifdef I2CFirmata_h
  firmataExt.addFeature(i2c);
#endif
#ifdef OneWireFirmata_h
  firmataExt.addFeature(oneWire);
#endif
#ifdef StepperFirmata_h
  firmataExt.addFeature(stepper);
#endif
#ifdef FirmataReporting_h
  firmataExt.addFeature(reporting);
#endif
#ifdef FirmataScheduler_h
  firmataExt.addFeature(scheduler);
#endif
#ifdef EncoderFirmata_h
  firmataExt.addFeature(encoder);
#endif
#endif
  /* systemResetCallback is declared here (in ConfigurableFirmata.ino) */
  Firmata.attach(SYSTEM_RESET, systemResetCallback);

  // Network Firmata communicates with Ethernet-shields over SPI. Therefor all
  // SPI-pins must be set to IGNORE. Otherwise Firmata would break SPI-communication.
  // add Pin 10 and configure pin 53 as output if using a MEGA with Ethernetshield.
  // No need to ignore pin 10 on MEGA with ENC28J60, as here pin 53 should be connected to SS:
#ifdef NETWORK_FIRMATA
  // ignore SPI and pin 4 that is SS for SD-Card on Ethernet-shield
  for (byte i = 0; i < TOTAL_PINS; i++) {
if (IS_PIN_SPI(i)
|| 4 == i
|| 10 == i //explicitly ignore pin 10 on MEGA as 53 is hardware-SS but Ethernet-shield uses pin 10 for SS
) {
Firmata.setPinMode(i, IGNORE);
}
}
pinMode(PIN_TO_DIGITAL(53), OUTPUT); //configure hardware-SS as output on MEGA
pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD-card bypassing Firmata
digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low;

// start up Network Firmata:
Firmata.begin(stream);
#else
// start up the default Firmata using Serial interface:
Firmata.begin(57600);
#endif
systemResetCallback(); // reset to default config
}

/*==============================================================================
* LOOP()
*============================================================================*/
void loop()
{
#ifdef DigitalInputFirmata_h
  /* DIGITALREAD - as fast as possible, check for changes and output them to the
   * stream buffer using Firmata.write()  */
  digitalInput.report();
#endif

  /* STREAMREAD - processing incoming messagse as soon as possible, while still
   * checking digital inputs.  */
  while (Firmata.available()) {
    Firmata.processInput();
#ifdef FirmataScheduler_h
    if (!Firmata.isParsingMessage()) {
      goto runtasks;
    }
  }
  if (!Firmata.isParsingMessage()) {
runtasks: scheduler.runTasks();
#endif
  }

  /* SEND STREAM WRITE BUFFER - TO DO: make sure that the stream buffer doesn't go over
   * 60 bytes. use a timer to sending an event character every 4 ms to
   * trigger the buffer to dump. */

#ifdef FirmataReporting_h
  if (reporting.elapsed()) {
#ifdef AnalogInputFirmata_h
    /* ANALOGREAD - do all analogReads() at the configured sampling interval */
    analogInput.report();
#endif
#ifdef I2CFirmata_h
    // report i2c data for all device with read continuous mode enabled
    i2c.report();
#endif
#ifdef EncoderFirmata_h
    // report encoders positions if reporting enabled.
    encoder.report();
#endif
  }
#endif
#ifdef StepperFirmata_h
  stepper.update();
#endif
#if defined NETWORK_FIRMATA && !defined local_ip &&!defined _YUN_CLIENT_H_
  if (Ethernet.maintain())
  {
    stream.maintain(Ethernet.localIP());
  }
#endif
}


Welche Firmata verwendest du?



Grüße Jürgen
FHEM auf Debian Stretch, HM-CFG-LAN, HM Thermostat und Rauchmelder, ESPEasy, viel selbst gebasteltes mit MQTT, Snips

schami23

Ich hab das Problem GELÖST.

Nach der Durchsicht der der HTU21DF Librarie und des I2C_SHT21 Moduls ist mir aufgefallen das eine andere Abfrageadresse zum lese für den  HTU21DF verwendet werden muss.


#define HTU21DF_I2CADDR       0x40
#define HTU21DF_READTEMP      0xE3
#define HTU21DF_READHUM       0xE5
#define HTU21DF_WRITEREG       0xE6
#define HTU21DF_READREG       0xE7
#define HTU21DF_RESET       0xFE


Ich hab im I2C_SHT21 fölgende änderung vorgenohmen und jetzt läuft es.

sub I2C_SHT21_readTemperature($) {
my ($hash) = @_;
  my $name = $hash->{NAME};
  return "$name: no IO device defined" unless ($hash->{IODev});
  my $phash = $hash->{IODev};
    my $pname = $phash->{NAME};
 
# Write 0xF3 to device. This requests a temperature reading
my $i2creq = { i2caddress => $hash->{I2C_Address}, direction => "i2cwrite" };

       #$i2creq->{data} = hex("F3");

        # E3 für HTU21DF
        $i2creq->{data} = hex("E3");

CallFn($pname, "I2CWrtFn", $phash, $i2creq);
usleep(85000); #fuer 14bit

# Read the two byte result from device
my $i2cread = { i2caddress => $hash->{I2C_Address}, direction => "i2cread" };
        $i2cread->{nbyte} = 2;
$i2cread->{type} = "temp";
CallFn($pname, "I2CWrtFn", $phash, $i2cread);

return;
}

sub I2C_SHT21_readHumidity($) {
my ($hash) = @_;
my $name = $hash->{NAME};
return "$name: no IO device defined" unless ($hash->{IODev});
my $phash = $hash->{IODev};
my $pname = $phash->{NAME};

# Write 0xF5 to device. This requests a humidity reading
my $i2creq = { i2caddress => $hash->{I2C_Address}, direction => "i2cwrite" };

       # $i2creq->{data} = hex("F5");

       # E5 für HTU21DF
        $i2creq->{data} = hex("E5");

CallFn($pname, "I2CWrtFn", $phash, $i2creq);
usleep(39000); #fuer 12bit

# Read the two byte result from device
my $i2cread = { i2caddress => $hash->{I2C_Address}, direction => "i2cread" };
        $i2cread->{nbyte} = 2;
$i2cread->{type} = "hum";
CallFn($pname, "I2CWrtFn", $phash, $i2cread);

return; # $retVal;
}


Danke

Grüße Jürgen
FHEM auf Debian Stretch, HM-CFG-LAN, HM Thermostat und Rauchmelder, ESPEasy, viel selbst gebasteltes mit MQTT, Snips

klausw

Zitat von: thymjan am 04 Januar 2016, 16:10:54
Hallo Klaus,
...
Hängen wir uns rein!

Grüße,
Stefan
Ich werde mich mal einlesen und dich bei Fragen löchern :)
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

schami23

#35
Ich hab das I2C_SHT21 Modul adaptiert für ein I2C_HTU21DF Modul.
Hab halt nur SHT21 durch HTU21DF ersetzt und die Adresse geändert.
Ich hab es bei mir so am laufen.

package main;

use strict;
use warnings;

use Time::HiRes qw(usleep);
use Scalar::Util qw(looks_like_number);
#use Error qw(:try);

use constant {
HTU21DF_I2C_ADDRESS => '0x40',
};

##################################################
# Forward declarations
#
sub I2C_HTU21DF_Initialize($);
sub I2C_HTU21DF_Define($$);
sub I2C_HTU21DF_Attr(@);
sub I2C_HTU21DF_Poll($);
sub I2C_HTU21DF_Set($@);
sub I2C_HTU21DF_Undef($$);
sub I2C_HTU21DF_DbLog_splitFn($);

my %sets = (
'readValues' => 1,
);

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

$hash->{DefFn}    = 'I2C_HTU21DF_Define';
$hash->{InitFn}   = 'I2C_HTU21DF_Init';
$hash->{AttrFn}   = 'I2C_HTU21DF_Attr';
$hash->{SetFn}    = 'I2C_HTU21DF_Set';
$hash->{UndefFn}  = 'I2C_HTU21DF_Undef';
  $hash->{I2CRecFn} = 'I2C_HTU21DF_I2CRec';
$hash->{AttrList} = 'IODev do_not_notify:0,1 showtime:0,1 poll_interval:1,2,5,10,20,30 ' .
'roundHumidityDecimal:0,1,2 roundTemperatureDecimal:0,1,2 ' .
$readingFnAttributes;
  $hash->{DbLog_splitFn} = "I2C_HTU21DF_DbLog_splitFn";
}

sub I2C_HTU21DF_Define($$) {
my ($hash, $def) = @_;
my @a = split('[ \t][ \t]*', $def);

  $hash->{STATE} = "defined";

  if ($main::init_done) {
    eval { I2C_HTU21DF_Init( $hash, [ @a[ 2 .. scalar(@a) - 1 ] ] ); };
    return I2C_HTU21DF_Catch($@) if $@;
  }
  return undef;
}

sub I2C_HTU21DF_Init($$) {
my ( $hash, $args ) = @_;

my $name = $hash->{NAME};

if (defined $args && int(@$args) > 1)
{
  return "Define: Wrong syntax. Usage:\n" .
          "define <name> I2C_HTU21DF [<i2caddress>]";
}

if (defined (my $address = shift @$args)) {
    $hash->{I2C_Address} = $address =~ /^0.*$/ ? oct($address) : $address;
    return "$name I2C Address not valid" unless ($address < 128 && $address > 3);
} else {
$hash->{I2C_Address} = hex(HTU21DF_I2C_ADDRESS);
}


my $msg = '';
# create default attributes
if (AttrVal($name, 'poll_interval', '?') eq '?') { 
    $msg = CommandAttr(undef, $name . ' poll_interval 5');
    if ($msg) {
      Log3 ($hash, 1, $msg);
      return $msg;
    }
  }
AssignIoPort($hash);
$hash->{STATE} = 'Initialized';

# my %sendpackage = ( i2caddress => $hash->{I2C_Address}, direction => "i2cread" );
# $sendpackage{reg} = hex("AA");
# $sendpackage{nbyte} = 22;
# return "$name: no IO device defined" unless ($hash->{IODev});
# my $phash = $hash->{IODev};
# my $pname = $phash->{NAME};
# CallFn($pname, "I2CWrtFn", $phash, \%sendpackage);

return undef;
}

sub I2C_HTU21DF_Catch($) {
  my $exception = shift;
  if ($exception) {
    $exception =~ /^(.*)( at.*FHEM.*)$/;
    return $1;
  }
  return undef;
}


sub I2C_HTU21DF_Attr (@) {# hier noch Werteueberpruefung einfuegen
my ($command, $name, $attr, $val) =  @_;
my $hash = $defs{$name};
my $msg = '';
if ($command && $command eq "set" && $attr && $attr eq "IODev") {
if ($main::init_done and (!defined ($hash->{IODev}) or $hash->{IODev}->{NAME} ne $val)) {
main::AssignIoPort($hash,$val);
my @def = split (' ',$hash->{DEF});
I2C_HTU21DF_Init($hash,\@def) if (defined ($hash->{IODev}));
}
}
if ($attr eq 'poll_interval') {
#my $pollInterval = (defined($val) && looks_like_number($val) && $val > 0) ? $val : 0;

if ($val > 0) {
RemoveInternalTimer($hash);
InternalTimer(1, 'I2C_HTU21DF_Poll', $hash, 0);
} else {
$msg = 'Wrong poll intervall defined. poll_interval must be a number > 0';
}
} elsif ($attr eq 'roundHumidityDecimal') {
$msg = 'Wrong $attr defined. Use one of 0, 1, 2' if defined($val) && $val <= 0 && $val >= 2 ;
} elsif ($attr eq 'roundTemperatureDecimal') {
$msg = 'Wrong $attr defined. Use one of 0, 1, 2' if defined($val) && $val <= 0 && $val >= 2 ;
}
return ($msg) ? $msg : undef;
}

sub I2C_HTU21DF_Poll($) {
my ($hash) =  @_;
my $name = $hash->{NAME};

# Read values
I2C_HTU21DF_Set($hash, ($name, 'readValues'));

my $pollInterval = AttrVal($hash->{NAME}, 'poll_interval', 0);
if ($pollInterval > 0) {
InternalTimer(gettimeofday() + ($pollInterval * 60), 'I2C_HTU21DF_Poll', $hash, 0);
}
}

sub I2C_HTU21DF_Set($@) {
my ($hash, @a) = @_;
my $name = $a[0];
my $cmd =  $a[1];

if(!defined($sets{$cmd})) {
return 'Unknown argument ' . $cmd . ', choose one of ' . join(' ', keys %sets)
}

if ($cmd eq 'readValues') {
I2C_HTU21DF_readTemperature($hash);
I2C_HTU21DF_readHumidity($hash);
}
}

sub I2C_HTU21DF_Undef($$) {
my ($hash, $arg) = @_;

RemoveInternalTimer($hash);
return undef;
}

sub I2C_HTU21DF_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/ ;
  }
#alte Variante zur Temp Hum Unterscheidung
    #if ( $clientmsg->{direction} && $clientmsg->{type} && $clientmsg->{$pname . "_SENDSTAT"} && $clientmsg->{$pname . "_SENDSTAT"} eq "Ok" ) {
# if ( $clientmsg->{direction} eq "i2cread" && defined($clientmsg->{received}) ) {
# Log3 $hash, 5, "empfangen: $clientmsg->{received}";
# I2C_HTU21DF_GetTemp  ($hash, $clientmsg->{received}) if $clientmsg->{type} eq "temp" && $clientmsg->{nbyte} == 2;
# I2C_HTU21DF_GetHum ($hash, $clientmsg->{received}) if $clientmsg->{type} eq "hum" && $clientmsg->{nbyte} == 2;
# }
#}
   
    # Bit 1 of the two LSBs indicates the measurement type (‘0’: temperature, ‘1’ humidity)
    if ( $clientmsg->{direction} && $clientmsg->{$pname . "_SENDSTAT"} && $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_HTU21DF_GetTemp ($hash, $clientmsg->{received}) if !($raw[1] & 2) && $clientmsg->{nbyte} == 2;
        I2C_HTU21DF_GetHum  ($hash, $clientmsg->{received}) if  ($raw[1] & 2) && $clientmsg->{nbyte} == 2;
        }
    }
}

sub I2C_HTU21DF_GetTemp ($$) {
my ($hash, $rawdata) = @_;
  my @raw = split(" ",$rawdata);
  my $temperature = $raw[0] << 8 | $raw[1];
$temperature = ( 175.72 * $temperature / 2**16 ) - 46.85;
$temperature = sprintf(
'%.' . AttrVal($hash->{NAME}, 'roundTemperatureDecimal', 1) . 'f',
$temperature
);
readingsSingleUpdate($hash,"temperature", $temperature, 1);
}

sub I2C_HTU21DF_GetHum ($$) {
my ($hash, $rawdata) = @_;
  my @raw = split(" ",$rawdata);
my $name = $hash->{NAME};
my $temperature = ReadingsVal($name,"temperature","0");

my $humidity = $raw[0] << 8 | $raw[1];
$humidity = ( 125 * $humidity / 2**16 ) - 6;
$humidity = sprintf(
'%.' . AttrVal($hash->{NAME}, 'roundHumidityDecimal', 1) . 'f',
$humidity
);
readingsBeginUpdate($hash);
readingsBulkUpdate(
$hash,
'state',
'T: ' . $temperature . ' H: ' . $humidity
);
#readingsBulkUpdate($hash, 'temperature', $temperature);
readingsBulkUpdate($hash, 'humidity', $humidity);
readingsEndUpdate($hash, 1);
}


sub I2C_HTU21DF_readTemperature($) {
my ($hash) = @_;
  my $name = $hash->{NAME};
  return "$name: no IO device defined" unless ($hash->{IODev});
  my $phash = $hash->{IODev};
    my $pname = $phash->{NAME};
 
# Write 0xF3 to device. This requests a temperature reading
my $i2creq = { i2caddress => $hash->{I2C_Address}, direction => "i2cwrite" };
  $i2creq->{data} = hex("E3");
CallFn($pname, "I2CWrtFn", $phash, $i2creq);
usleep(85000); #fuer 14bit

# Read the two byte result from device
my $i2cread = { i2caddress => $hash->{I2C_Address}, direction => "i2cread" };
  $i2cread->{nbyte} = 2;
$i2cread->{type} = "temp";
CallFn($pname, "I2CWrtFn", $phash, $i2cread);

return;
}

sub I2C_HTU21DF_readHumidity($) {
my ($hash) = @_;
my $name = $hash->{NAME};
return "$name: no IO device defined" unless ($hash->{IODev});
my $phash = $hash->{IODev};
my $pname = $phash->{NAME};

# Write 0xF5 to device. This requests a humidity reading
my $i2creq = { i2caddress => $hash->{I2C_Address}, direction => "i2cwrite" };
  $i2creq->{data} = hex("E5");
CallFn($pname, "I2CWrtFn", $phash, $i2creq);
usleep(39000); #fuer 12bit

# Read the two byte result from device
my $i2cread = { i2caddress => $hash->{I2C_Address}, direction => "i2cread" };
  $i2cread->{nbyte} = 2;
$i2cread->{type} = "hum";
CallFn($pname, "I2CWrtFn", $phash, $i2cread);

return; # $retVal;
}

sub I2C_HTU21DF_DbLog_splitFn($) {
    my ($event) = @_;
    Log3 undef, 5, "in DbLog_splitFn empfangen: $event";
    my ($reading, $value, $unit) = "";
    my @parts = split(/ /,$event);
    $reading = shift @parts;
    $reading =~ tr/://d;
    $value = $parts[0];
    $unit = "\xB0C" if(lc($reading) =~ m/temp/);
    $unit = "%" if(lc($reading) =~ m/humi/);
    return ($reading, $value, $unit);
}

1;

=pod
=begin html

<a name="I2C_HTU21DF"></a>
<h3>I2C_HTU21DF</h3>
(en | <a href="commandref_DE.html#I2C_HTU21DF">de</a>)
<ul>
<a name="I2C_HTU21DF"></a>
Provides an interface to the HTU21DF I2C Humidity sensor from <a href="www.sensirion.com">Sensirion</a>.
The I2C messages are send through an I2C interface module like <a href="#RPII2C">RPII2C</a>, <a href="#FRM">FRM</a>
or <a href="#NetzerI2C">NetzerI2C</a> so this device must be defined first.<br>
<b>attribute IODev must be set</b><br>
<a name="I2C_HTU21DFDefine"></a><br>
<b>Define</b>
<ul>
<code>define &lt;name&gt; I2C_HTU21DF [&lt;I2C Address&gt;]</code><br>
where <code>&lt;I2C Address&gt;</code> is an 2 digit hexadecimal value<br>
</ul>
<a name="I2C_HTU21DFSet"></a>
<b>Set</b>
<ul>
<code>set &lt;name&gt; readValues</code><br>
Reads the current temperature and humidity values from sensor.<br><br>
</ul>
<a name="I2C_HTU21DFAttr"></a>
<b>Attributes</b>
<ul>
<li>poll_interval<br>
Set the polling interval in minutes to query data from sensor<br>
Default: 5, valid values: 1,2,5,10,20,30<br><br>
</li>
<li>roundHumidityDecimal<br>
Number of decimal places for humidity value<br>
Default: 1, valid values: 0 1 2<br><br>
</li>
<li>roundTemperatureDecimal<br>
Number of decimal places for temperature value<br>
Default: 1, valid values: 0,1,2<br><br>
</li>
<li><a href="#IODev">IODev</a></li>
<li><a href="#do_not_notify">do_not_notify</a></li>
<li><a href="#showtime">showtime</a></li>
</ul><br>
</ul>

=end html

=begin html_DE

<a name="I2C_HTU21DF"></a>
<h3>I2C_HTU21DF</h3>
(<a href="commandref.html#I2C_HTU21DF">en</a> | de)
<ul>
<a name="I2C_HTU21DF"></a>
Erm&ouml;glicht die Verwendung eines HTU21DF I2C Feuchtesensors von <a href="www.sensirion.com">Sensirion</a>.
I2C-Botschaften werden &uuml;ber ein I2C Interface Modul wie beispielsweise das <a href="#RPII2C">RPII2C</a>, <a href="#FRM">FRM</a>
oder <a href="#NetzerI2C">NetzerI2C</a> gesendet. Daher muss dieses vorher definiert werden.<br>
<b>Das Attribut IODev muss definiert sein.</b><br>
<a name="I2C_HTU21DFDefine"></a><br>
<b>Define</b>
<ul>
<code>define &lt;name&gt; I2C_HTU21DF [&lt;I2C Address&gt;]</code><br>
Der Wert <code>&lt;I2C Address&gt;</code> ist ein zweistelliger Hex-Wert<br>
</ul>
<a name="I2C_HTU21DFSet"></a>
<b>Set</b>
<ul>
<code>set &lt;name&gt; readValues</code><br>
Aktuelle Temperatur und Feuchte Werte vom Sensor lesen.<br><br>
</ul>
<a name="I2C_HTU21DFAttr"></a>
<b>Attribute</b>
<ul>
<li>poll_interval<br>
Aktualisierungsintervall aller Werte in Minuten.<br>
Standard: 5, g&uuml;ltige Werte: 1,2,5,10,20,30<br><br>
</li>
<li>roundHumidityDecimal<br>
Anzahl Dezimalstellen f&uuml;r den Feuchtewert<br>
Standard: 1, g&uuml;ltige Werte: 0 1 2<br><br>
</li>
<li>roundTemperatureDecimal<br>
Anzahl Dezimalstellen f&uuml;r den Temperaturwert<br>
Standard: 1, g&uuml;ltige Werte: 0,1,2<br><br>
</li>
<li><a href="#IODev">IODev</a></li>
<li><a href="#do_not_notify">do_not_notify</a></li>
<li><a href="#showtime">showtime</a></li>
</ul><br>
</ul>

=end html_DE

=cut


Grüße Jürgen
FHEM auf Debian Stretch, HM-CFG-LAN, HM Thermostat und Rauchmelder, ESPEasy, viel selbst gebasteltes mit MQTT, Snips

klausw

Zitat von: schami23 am 05 Januar 2016, 11:09:06
Ich hätte das I2C_SHT21 Modul adabtiert für ein I2C_HTU21DF Modul.

Nee lass mal lieber, sind schon ohnehin inzwischen sehr viel Module :)

Was ich seltsam finde, das hier im Forum bereits berichtet wurde (weiss leider nicht mehr von wem) das beide Sensoren kompatibel sind.
Ich könnte ein Attribut in das Modul einbauen, das sich der Sensortyp auswählen lässt. Das wäre meiner Meinung nach die beste Lösung.
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

schami23

Okay, Super Idee.

Ihr seit die Profis ich bin noch blutiger Anfänger.

Danke

Jürgen
FHEM auf Debian Stretch, HM-CFG-LAN, HM Thermostat und Rauchmelder, ESPEasy, viel selbst gebasteltes mit MQTT, Snips

thymjan

Hallo Ihr beiden,

ich hatte behauptet, dass der HTU21 mit dem SHT21-Modul funktioniert. Hab das auch hier mit Firmata-USB und direkt am Raspi am Laufen. Wundert mich jetzt mit den zwei Adressen...

Muss ich mir nochmal anschauen.

Gruß,
Stefan

klausw

Zitat von: schami23 am 05 Januar 2016, 11:25:06
Okay, Super Idee.

Ihr seit die Profis ich bin noch blutiger Anfänger.

Danke

Jürgen
Ich habe nochmal geschaut. Beide Sensoren sind von den Registern her identisch.
Das einzige was du machst, ist den Transaktionsmodus von No Hold master auf Hold master umzustellen.
Das ist ein anderes Problem. beim "Hold master" blockiert der Sensor den Bus solange, bis die Sensorwerte abgerufen werden können.
Beim "No Hold master" wir der Konvertierungsvorgang angeschubst und nach einer gewissen Zeit werden sie Sensorwerte abgefragt.
Hold master funktioniert beim Raspberry nicht (war glaube ich nen silicon bug im Chip).
Vermutlich sind die Wartezeiten zwischen Anfordern und auslesen einfach zu kurz, weil es bei FRM ja auch noch zu Laufzeiten kommt.

Folgendes bitte testen:

Gehe bitte wieder auf F3 und F5
und ändere die Wartezeiten:
usleep(39000);
usleep(85000);
auf die 10fachen Werte (also ne 0 anfügen)

dann sollte es laufen

Ist der Firmata per Lan angeschlossen?
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

klausw

Zitat von: thymjan am 05 Januar 2016, 11:49:35
Hallo Ihr beiden,

ich hatte behauptet, dass der HTU21 mit dem SHT21-Modul funktioniert. Hab das auch hier mit Firmata-USB und direkt am Raspi am Laufen. Wundert mich jetzt mit den zwei Adressen...

Muss ich mir nochmal anschauen.

Gruß,
Stefan
Dich hatte ich auch in Verdacht  8)
Ich vermute, das es am Timing liegt.
FRM über USB hat kleine Latenzzeiten, aber über das Netzwerk kann es schon sein das der Abstand zwischen beiden Botschaften zu kurz ist.
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

schami23

ZitatIch habe nochmal geschaut. Beide Sensoren sind von den Registern her identisch.
Das einzige was du machst, ist den Transaktionsmodus von No Hold master auf Hold master umzustellen.
Das ist ein anderes Problem. beim "Hold master" blockiert der Sensor den Bus solange, bis die Sensorwerte abgerufen werden können.
Beim "No Hold master" wir der Konvertierungsvorgang angeschubst und nach einer gewissen Zeit werden sie Sensorwerte abgefragt.
Hold master funktioniert beim Raspberry nicht (war glaube ich nen silicon bug im Chip).
Vermutlich sind die Wartezeiten zwischen Anfordern und auslesen einfach zu kurz, weil es bei FRM ja auch noch zu Laufzeiten kommt.

Folgendes bitte testen:

Gehe bitte wieder auf F3 und F5
und ändere die Wartezeiten:
usleep(39000);
usleep(85000);
auf die 10fachen Werte (also ne 0 anfügen)

dann sollte es laufen

Ist der Firmata per Lan angeschlossen?

Ja stimmt, hab es gerade getestet jetzt lauft es.

Mein FRM ist via Lan angeschlossen
FHEM auf Debian Stretch, HM-CFG-LAN, HM Thermostat und Rauchmelder, ESPEasy, viel selbst gebasteltes mit MQTT, Snips

klausw

Zitat von: schami23 am 05 Januar 2016, 12:38:24
Ja stimmt, hab es gerade getestet jetzt lauft es.
Super Sache
Kannst du bitte Testen, bis zu welchem Zeitwert es funktioniert?

Den Wert für die Temperatur kannst du ja eigentlich lassen, wenn der schon vorher ging.
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

schami23

#43
Hab folgende Zeitwerte erfolgreich getestet:


Für die Temperatur          usleep(85000);
Für die Luftfeuchtigkeit    usleep(135000);


2016-01-05_14:02:24 AdaSensor temperature: 21.8
2016-01-05_14:02:24 AdaSensor humidity: 35.9
2016-01-05_14:02:26 AdaSensor temperature: 21.8
2016-01-05_14:02:26 AdaSensor humidity: 35.9
2016-01-05_14:02:28 AdaSensor temperature: 21.8
2016-01-05_14:02:28 AdaSensor humidity: 35.8
2016-01-05_14:02:30 AdaSensor temperature: 21.8
2016-01-05_14:02:30 AdaSensor humidity: 35.8
2016-01-05_14:02:32 AdaSensor temperature: 21.8
2016-01-05_14:02:32 AdaSensor humidity: 35.8
2016-01-05_14:02:34 AdaSensor temperature: 21.8
2016-01-05_14:02:34 AdaSensor humidity: 35.8
2016-01-05_14:02:36 AdaSensor temperature: 21.8
2016-01-05_14:02:36 AdaSensor humidity: 35.7
2016-01-05_14:02:39 AdaSensor temperature: 21.8
2016-01-05_14:02:39 AdaSensor humidity: 35.7
2016-01-05_14:02:40 AdaSensor temperature: 21.8
2016-01-05_14:02:40 AdaSensor humidity: 35.7
2016-01-05_14:02:42 AdaSensor temperature: 21.8
2016-01-05_14:02:42 AdaSensor humidity: 35.7
2016-01-05_14:02:44 AdaSensor temperature: 21.8
2016-01-05_14:02:44 AdaSensor humidity: 35.8
2016-01-05_14:02:47 AdaSensor temperature: 21.8
2016-01-05_14:02:47 AdaSensor humidity: 35.9
2016-01-05_14:02:49 AdaSensor temperature: 21.8
2016-01-05_14:02:49 AdaSensor humidity: 36.0
2016-01-05_14:02:50 AdaSensor temperature: 21.8
2016-01-05_14:02:50 AdaSensor humidity: 36.0
2016-01-05_14:07:10 AdaSensor temperature: 21.8
2016-01-05_14:07:10 AdaSensor humidity: 35.6
2016-01-05_14:07:25 AdaSensor temperature: 21.8
2016-01-05_14:07:25 AdaSensor humidity: 35.9
2016-01-05_14:07:27 AdaSensor temperature: 21.8
2016-01-05_14:07:27 AdaSensor humidity: 35.9
2016-01-05_14:07:28 AdaSensor temperature: 21.8
2016-01-05_14:07:28 AdaSensor humidity: 36.0
2016-01-05_14:07:30 AdaSensor temperature: 21.8
2016-01-05_14:07:30 AdaSensor humidity: 36.0
2016-01-05_14:07:31 AdaSensor temperature: 21.8
2016-01-05_14:07:31 AdaSensor humidity: 36.0
2016-01-05_14:07:33 AdaSensor temperature: 21.8
2016-01-05_14:07:33 AdaSensor humidity: 36.0
2016-01-05_14:07:34 AdaSensor temperature: 21.8
2016-01-05_14:07:34 AdaSensor humidity: 36.0
2016-01-05_14:07:37 AdaSensor temperature: 21.8
2016-01-05_14:07:37 AdaSensor humidity: 36.0
2016-01-05_14:07:38 AdaSensor temperature: 21.8
2016-01-05_14:07:38 AdaSensor humidity: 36.0
2016-01-05_14:09:45 AdaSensor temperature: 21.8
2016-01-05_14:09:45 AdaSensor humidity: 36.0
2016-01-05_14:09:48 AdaSensor temperature: 21.8
2016-01-05_14:09:48 AdaSensor humidity: 35.9
2016-01-05_14:09:49 AdaSensor temperature: 21.8
2016-01-05_14:09:49 AdaSensor humidity: 35.8
2016-01-05_14:12:10 AdaSensor temperature: 21.7
2016-01-05_14:12:11 AdaSensor humidity: 35.8
FHEM auf Debian Stretch, HM-CFG-LAN, HM Thermostat und Rauchmelder, ESPEasy, viel selbst gebasteltes mit MQTT, Snips

klausw

#44
Ich habe das Ganze mal umgestrickt.
Jetzt wird nach anstoßen der Messung ein Timer gesetzt, der nach 1s sie Messwerte abholt.
So dauert der Vorgang zwar gut 2s aber dafür ist in dieser Zeit das FHEM nicht blockiert. (220ms ist schon recht lang).
Bitte testen und Berichten
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