Inhaltsverzeichnis

1-Wire Feuchtigkeitssensor

Dr. Claus Kühnel beschreibt eine Möglichkeit, die Luftfeuchtigkeit per 1-Wire zu messen:

http://www.ckuehnel.ch/PDF/Messung%20von%20Temperatur%20und%20Feuchtigkeit.pdf

Tobias Müller hat unter http://www.tm3d.de/index.php/1wire-feuchtesensor beschrieben, wie man mit einer einfachen Schaltung die Temperatur und Luftfeuchtigkeit per 1-wire misst:

Bei Bedarf kann man die passenden Platinen, einen Bausatz oder gleich eine fertig gelötete Version bei Tobias käuflich erwerben:

http://www.tm3d.de/index.php/kontakt?view=contact

HIH-5030

Der HIH-5030, http://sensing.honeywell.com/honeywell-sensing-hih5030-5031%20series-product-sheet-009050-2-en.pdf?name=HIH-5030-001

DS-2438

Smart Battery Monitor: http://datasheets.maximintegrated.com/en/ds/DS2438.pdf

Die Vorbereitungen

Folgende Perl Module werden verwendet und müssen ggf. nachinstalliert werden:

apt-get install libwww-perl

Perl Script

#!/usr/bin/perl 
 
# Created 2014.09.13  Sebastian Vitt 
# Version: 1.1    2014.09.14
# Based on Allan Dyers 1Wire Humidity script at http://rants.dyer.com.hk/rpi/humidity_1w.html  
# If someone else also become annoyed because of the really looong running
# time of this script (like me) BUT knows how to build this
# in C (not like me) please take although a look at
# http://www.tm3d.de/index.php/1wire-feuchtesensor
 
use warnings;
use strict;
use Digest::CRC;
use LWP::UserAgent;
use Log::Log4perl;
 
my @alldevs;
my $onewire = '/sys/bus/w1/devices/';            # including last slash
my $VZURL = 'http://INSERTYOURIP/middleware.php/';  # including last slash
 
my $opt_d = 0;   # debug
 
my $name;
my $onewireaddress;
my $uuid;
my $temp;
my $humidity;
 
 
######
#    $OFF    $FATAL    $ERROR    $WARN    $INFO    $DEBUG    $TRACE    $ALL
#$log->error("No drink defined");
 
# Initialize logging
my $log_conf = q(
    log4perl.appender.Screen=Log::Dispatch::Screen
    log4perl.appender.Screen.stderr=0
    log4perl.appender.Screen.Threshold=FATAL
    log4perl.appender.Screen.layout=Log::Log4perl::Layout::SimpleLayout
    log4perl.appender.Email=Log::Dispatch::Email::MailSender
    log4perl.appender.Email.smtp=relay.mailserver.tld
    log4perl.appender.Email.subject=1Wire Humidity Read Script
    log4perl.appender.Email.to=foo@mail.de
    log4perl.appender.Email.from=bar@mail.de
    log4perl.appender.Email.Threshold=WARN
    log4perl.appender.Email.layout=Log::Log4perl::Layout::SimpleLayout
    log4perl.rootLogger=WARN, Email, LOGFILE
    log4perl.appender.LOGFILE=Log::Log4perl::Appender::File
    log4perl.appender.LOGFILE.filename=/var/log/1w_humidity.log
    log4perl.appender.LOGFILE.mode=append
    log4perl.appender.LOGFILE.layout=PatternLayout
    log4perl.appender.LOGFILE.layout.ConversionPattern=[%d %r] %p %F Line: %L %M %c - %m%n
);
Log::Log4perl::init( \$log_conf );
my $log = Log::Log4perl->get_logger();
$log->info("********* 1-Wire Humidity Script started **********");
 
 
# welche werte sollen geholt werden?
my %Daten = (           # Name => [ Adresse onewire, uuid-Volkszaehler ]
                        "KWL-Oben"       => ["26-0000019259f1", "dff9fce0-3aa0-11e4-85e7-91adc4f69e83" ] ,
                        "KWL-ELW"        => ["26-000001925c6c", "d8f6a4a0-3aa0-11e4-ad4e-d5d9b759d00c" ] 
);
my $start_run = time();
 
 
use Fcntl qw(:flock);
my $lockfile = '/tmp/1wire001.pid';
sub BailOut {
    $log->info("$0 is already running, LockFile '$lockfile' is locked - exiting");
    exit(1);
}
 
$log->debug("start of program");
open(my $fhpid, '>', $lockfile) or $log->error_die("error: open '$lockfile': $!");
flock($fhpid, LOCK_EX|LOCK_NB) or BailOut();
# Note: lock should be automatically released at end of program,
# no matter how the process is terminated. (the file persists, only the lock will be removed)
 
while (($name) = each(%Daten)){
  $onewireaddress =  $Daten{$name}[0] ;
  $log->debug("$onewire$onewireaddress/rw");
  ($Daten{$name}[2],$Daten{$name}[3]) =  DS2438reader("$onewire$onewireaddress/rw") ;
 
    $uuid     =  $Daten{$name}[1] ;
    $temp     =  $Daten{$name}[2] ;
    $humidity =  $Daten{$name}[3] ;
 
    if ($humidity) {
      $log->debug("$name $uuid $humidity");
 
      my $server_endpoint = $VZURL . "data/${uuid}.json?value=" . $humidity;
      $log->debug("serverget = $server_endpoint");
      # set custom HTTP request header fields
      my $req = HTTP::Request->new(POST => $server_endpoint);
      $req->header('content-type' => 'application/json');
      $req->header('x-auth-token' => '*********');
 
      # add POST data to HTTP request body
      $req->content(" ");
 
      my $ua = LWP::UserAgent->new;
      my $resp = $ua->request($req);
      if ($resp->is_success) {
        my $message = $resp->decoded_content;
        $log->debug("Received reply: $message");
      } else {
        $log->error("HTTP GET error code: $resp->code");
        $log->error("HTTP GET error message: $resp->message");
      }
    }
}
 
my $end_run = time();
my $run_time = $end_run - $start_run;
$log->debug("Job took $run_time seconds");
 
sub DS2438reader {
 my ($devf) = @_;
  my $rtime= time;
  $log->debug("Reading DS2438 / HIH-5030-001 $devf");
  unless (open( DS2438, "+>$devf")) {
    #$log->error("Unable to open $devf $!");
    return;
  }
  my $oldfh = select DS2438; $|= 1; select $oldfh; # autoflush
  my ($status, $vad, $vdd, $temp, $humid);
  print DS2438 "\x4e\x00\x00";
  for (my $b="\x00"; $b eq "\x00"; ) { read DS2438, $b, 1; }
  print DS2438 "\x48\x00";
  for (my $b="\x00"; $b eq "\x00"; ) { read DS2438, $b, 1; }
  print DS2438 "\x44";
  for (my $b="\x00"; $b eq "\x00"; ) { read DS2438, $b, 1; }
  print DS2438 "\xb4";
  for (my $b="\x00"; $b eq "\x00"; ) { read DS2438, $b, 1; }
  print DS2438 "\xb8\x00";
  for (my $b="\x00"; $b eq "\x00"; ) { read DS2438, $b, 1; }
  print DS2438 "\xbe\x00";
  ($status, $temp, $vad)= readTVC();
  return unless defined($vad);
  if ($status) {
    print STDERR "DS2438 incorrect status reading VAD: " . sprintf( "%02d", $status);
    return;
  }
  print DS2438 "\x4e\x00\x08";
  for (my $b="\x00"; $b eq "\x00"; ) { read DS2438, $b, 1; }
  print DS2438 "\x48\x00";
  for (my $b="\x00"; $b eq "\x00"; ) { read DS2438, $b, 1; }
  print DS2438 "\xb4";
  for (my $b="\x00"; $b eq "\x00"; ) { read DS2438, $b, 1; }
  print DS2438 "\xb8\x00";
  for (my $b="\x00"; $b eq "\x00"; ) { read DS2438, $b, 1; }
  print DS2438 "\xbe\x00";
  ($status, $temp, $vdd)= readTVC();
  return unless defined($vdd);
  if ($status ^ 0x08) {
    print STDERR "DS2438 incorrect status reading VDD: " . sprintf( "%02d", $status);
    return;
  }
  if ($vad == $vdd) {
    #$log->warn($tsh, $hostname, undef, 'D008', 1, "DS2438 voltage match $vad");
    $log->warn("DS2438 voltage match $vad");
    return;
  }
  #$log->debug("H read ", (($vad / $vdd) - 0.1515) / 0.00636, "\tComp ", 1.0546 - 0.00216 * $temp);
  $humid= ($vad / $vdd - 0.1515) / 0.00636 / (1.0546 - 0.00216 * $temp);
  $log->debug("localtime() Temperature $temp Humidity $humid");
 
#  return { temp => $temp, humid => $humid, time => (time - $rtime) };
  return $temp,$humid;
 
}
 
sub readTVC {
  my $data;
  read DS2438, $data, 9; # and CRC
  my ($status, $t, $v, $c, $th, $crc) = unpack('CvvvCC', $data);
  #$log->debug("TVC raw %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", unpack('C*', $data));
  $log->debug("TVC $status, $t, $v, $c, $th, $crc");
  unless (crcCheck(substr($data, 0, -1), substr($data, -1))) {
    #$log->error("$tsh, $hostname, undef, 'D009', 1,"DS2438 CRC error $status $t $v $c $th $crc");
    $log->error("DS2438 CRC error $status $t $v $c $th $crc");;
    return;
  }
  my $temp = ($t >> 3) * 0.03125;
  $log->debug("T $temp V $v");
  return $status, $temp, $v;
}
 
sub crcCheck {
  # Dallas/Maxim CRC8
  my ($r, $c) = @_;
  my $ctx = Digest::CRC->new(width => 8, poly => 0x31, init => 0x00, xorout => 0x00, refin => 1, refout => 1);
  $ctx->add($r);
  my $crc= $ctx->digest;
  if ($opt_d) {
    my @data = unpack('C*', $r);
    $log->debug("crcCheck %d %d | %02x %02x %02x %02x %02x %02x %02x %02x |",ord($c), $crc, @data);
  }
  $log->debug("CRC ", (ord($c) == $crc), " ", ord($c), " ", $crc);
  return (ord($c) == $crc);
}