====== 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: {{:hardware:feuchte_schaltung.png?200|}} 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: * LWP::UserAgent 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); }