====== 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);
}