Practical DigiTemp on Mac OS X - hardware and software.
Post ReplyPractical DigiTemp on Mac OS X - hardware and software.Posted: Monday, July 15, 2013 [13:29:35] - 1
I wanted to buy a weather station for home use. Turned-out it's quite expensive. I basically was interested in simple data reading and collection for temperature and maybe atmospheric pressure and humidity. Google brought unexpectedly large number of results on DigiTemp for Linux. Did read some articles thinking USB adapter should work on Mac. Purchased DS9490R from Digi-Key and a week later since I've got it - it did not work. I was unable to find a proper driver for it. Then found the Indigo DigiTemp forum and bought DS9097U-S09 Serial adapter for One-Wire network. DS9097U-S09 did not work at first as I used Belkin F5U409 USB to Serial adapter. Belkin adapter did not work for this application. Went on eBay and bought Smart USB to RS-232 with PL2303 Chipset with driver readily available for Mac OS X Lions and Leopards. Paid around $6 delivered. Digi Key website for DS9097U-S09 http://www.digikey.com/product-detail/en/DS9097U-S09%23/DS9097U-S09%23-ND/1768830 I also bought three DS18S20+PAR-ND temperature sensors from Digi-Key. For some reason 2 out of 3 either went bad or were bad even though I was very careful soldering wires to them. That is DS18S20+PAR-ND outdoor temperature sensor sealed with silicone and epoxy. Digi Key website for DS18S20+PAR-ND http://www.digikey.com/product-detail/en/DS18S20%2BPAR/DS18S20%2BPAR-ND/1197288 That is pretty much hardware I am currently using. It is all over the Internet - Mac compiled DigiTemp is available but it took me a while to find the proper version that works on my Macs: http://www.perceptiveautomation.com/userforum/viewtopic.php?f=26&t=8016 download the DigiTemp plugin from the link provided on the forum and use the appropriate version for your Mac architecture. It does not have to be installed in any specific location as long as you provide the full path to the program and supporting files when calling it from the terminal or bash. This is how I call the program on my Mac from Perl: Install PL2303 driver: http://prolificusa.com/pl-2303hx-drivers and run the following in your Terminal: and make sure you have cu.usbserial listed then check your digitemp: you should see something similar to this: GNU Public License v2.0 - http://www.digitemp.com Turning off all DS2409 Couplers . Devices on the Main LAN 102F84350208004D : DS1820/DS18S20/DS1920 Temperature Sensor If all goes well - you can start building your one-wire network by permanently soldering, sealing, running wires etc. My live reports can be found here: http://www.wd-co.com/digitemp reports updated every 15 minutes. |
RE: Practical DigiTemp on Mac OS X - hardware and software.Posted: Wednesday, July 17, 2013 [08:12:42] - 2
Continuing with software side on my DigiTemp project. I ran DigiTemp from crontab every 15 minutes. This is the program that does the job: unless($ENV{'SECURITYSESSIONID'}) { $ENV{'PATH'} = '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local:/usr/local/bin:/opt/local/bin'; } # LOGGING THE RESULT IN READABLE TXT FILE open STDOUT, '>/http/digitemp/start.prog.result.txt'; $frtm=time; print "$frtm\t"; if(-f "/http/digitemp/digitemp_i386") { print "digitemp_i386 exist\n"; my $program = "/http/digitemp/digitemp_i386"; my $foundit = 0; open (IN, "ps axw |"); while (<IN>) { print "daemon was runnig - need to kill it\n"; $_ =~ s/(\d{1,6})\s/$&/; `kill -9 $pid`; } close IN; print "No $program was running - starting it\n"; $program = "/http/digitemp/digitemp_i386 -q -c /http/digitemp/digitemp.conf -l /http/digitemp/temperature.txt -a"; $did = ''; } ## END IF FILE PRESENT exit(0); The reason I am running it this way is to have readable TXT log file in case something goes wrong. Once output is written - the other Perl Daemon picks the process if it sees "/http/digitemp/temperature.txt" file present. It runs the actual processing Perl program that reads the last DigiTemp readings, logs them and creates graphs using Fly program: unless($ENV{'SECURITYSESSIONID'}) { $ENV{'PATH'} = '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local:/usr/local/bin:/opt/local/bin'; } open STDOUT, '>/http/digitemp/last.run.txt' or die "Can't write to /http/digitemp/last.run.txt: $!"; ## CREATE SUPPORTING DIRECTORIES IF NOT PRESENT unless(-f "/http/digitemp/temperature.txt") {print "No file /http/digitemp/temperature.txt found - exit\n"; unless(-d "/http/digitemp/logs") {`mkdir -p /http/digitemp/logs`;} unless(-d "/http/web/digitemp/maps") {`mkdir -p /http/web/digitemp/maps`;} unless(-d "/http/web/digitemp/byday") {`mkdir -p /http/web/digitemp/byday`;} unless(-d "/http/web/digitemp") {`mkdir -p /http/web/digitemp`;} %weekDays = ('Sun','Sunday','Mon','Monday','Tue','Tuesday','Wed','Wednesday','Thu','Thursday','Fri','Friday','Sat','Saturday'); %let_month = ('Jan','January','Feb','February','Mar','March','Apr','April', 'May','May','Jun','June','Jul','July','Aug','August', 'Sep','September','Oct','October','Nov','November','Dec','December'); $kztme = time; if($moK eq 'Jan' && $daK == 1) { ($chkHr,$chkMi,$chkSec) = split(/\:/,$tiK); if($chkHr < 1 && $chkMi < 5) {$adye=$ye-1;} } $urlsendd = "http://Your_Server_URL/digitemp/upload.file.cgi";; $d = `cat /http/digitemp/temperature.txt`; @all = split(/\n/,$d); foreach $l (@all) {$l =~ s/\r//g; #Jul 13 16:06:42 Sensor 0 C: 23.12 F: 73.62 - SAMPLE OF DATA FOUND IN DIGITEMP LOG FILE $l =~ s#(.*?)Sensor (\d{1,2})\sC\: (\d{1,3}\.\d{1,2})\sF\: (\d{1,3}\.\d{1,2})#$1#; $sensor=$2; $l =~ s/\s+$//; ($mo,$da,$ti) = split(/ /,$l); $daymatch=$da; $byall{$mo}{$da}{$ti}{$sensor}{'C'}=$tempc; $byall{$mo}{$da}{$ti}{$sensor}{'F'}=$tempf; $lastTemp{$sensor}="$tempc °C $tempf °F"; $ye1=$ye; if($adye && $mo eq 'Dec') {$ye1=$adye;} $donerun = "$let_month{$mo} $da, $ye1 at $ti EDT"; } ## FOREACH LINE END @all=(); @months = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'); ## ADD SENSORS HERE TO DESCRIBE WHAT THE MEASURE AND WHERE - HUMAN READABLE DATA %sensors = ('0','Outside Temperature'); $monmatch="$let_month{$moK}.$ye"; $dayfile="$moK.$daK.$ye"; open(TXT,">/http/digitemp/last.temps.txt"); foreach $sens (sort keys(%lastTemp)) {$blnk=''; unless($lnkwritten) {$lnkwritten=1; print TXT "$blnk$sensors{$sens}$blnke: <span style=\"font-size:1.8em;font-weight:bold;\">$lastTemp{$sens}</span>\n"; if($sensors{$sens} eq 'Outside Temperature') {$savetotop = $lastTemp{$sens}; } ## print TXT "<span style=\"font-size:.9em;\">Updated: $donerun</span>\n"; foreach $mo (keys(%byall)) {$mnchk{$mo}=1;} if($mnchk{'Dec'} && $mnchk{'Jan'}) {$decyear=$ye-1; foreach $mo (keys(%byall)) { ########### MO if($corryear{$mo}) {$year=$corryear{$mo};} else {$year=$ye;} $dorecs{"$year.$mo"}="$let_month{$mo} $year"; open(LOG,">>/http/digitemp/logs/$year.$mo.txt"); } ## FOREACH MONTH END ################# MO ## DONE READING RECORDS ################### ## COLORS USED IN GRAPH IN FORMAT FLY WOULD UNDERSTAND (RGB) %colors = ('Outside Temperature','232,25,25', 'Text','0,0,0', 'Grid','235,235,235', 'Box','99,99,99', 'Weekend','232,25,25' ); %monDig = ('January','01','February','02','March','03','April','04','May','05','June','06','July','07','August','08','September','09','October','10','November','11','December','12'); foreach $file (keys(%dorecs)) { ## $maxtemp=-100; $fstartx=45; unless(-f "/http/digitemp/logs/$file.txt") {next;} $datestring = $file; ## USE MAC OS X BUILT-IN CALENDAR TO FIND WEEKENDS FOR THE GRAPH $calendar = `cal $rmon $ryear`; $moshort=substr($rmon,0,3); $calendar =~ s#\W+$##; while($calendar =~ /(\d{1,2})(\n)/gs) {$wkend{$1}=1;} while($calendar =~ /(\n)( \d{1,2}|\d{1,2})(\s)/gs) {$wkend{$2}=1;} foreach $we (keys(%wkend)) {delete $wkend{$we}; ## RUN SMALL BASH FILE TO FIND A NUMBER OF DAYS IN A MONTH $daysread = `/http/digitemp/getdate.sh $ryear $monDig{$rmon}`; $dawritte=''; $d = `cat /http/digitemp/logs/$file.txt`; foreach $l (@all) { ####### ($my,$da,$ti,$sens,$fahr,$celc) = split(/\t/,$l); unless($ddone{$sens}) { if($fstarty > 689) {$fstartx += $xmv; $fstarty=650;} $fstartytxt = $fstarty - 7; print FLY "fcircle $fstartx,$fstarty,10,$colors{$sens}\nstring $colors{$sens},$fstartxtxt,$fstartytxt,small, - $sens\n"; $toToday .= "fcircle $fstartx,$fstarty,10,$colors{$sens}\nstring $colors{$sens},$fstartxtxt,$fstartytxt,small, - $sens\n"; $fstarty += $ymv; } ## END UNLESS MADE if($sens =~ m/Temperature/i && $mintemp > $celc) {$mintemp = $celc; if($sens =~ m/Temperature/i && $maxtemp < $celc) {$maxtemp = $celc; $ti =~ s#\:\d{1,2}$##; $write{$sens}{$da}{$ti}="$celc\t$fahr"; } ## FOREACH LINE END ##### $byday = 1080 / $daysread; $hiplot=550; ## V SIZE FOR PLOT $botstart=620; ## PLOT COORD BOTTOM $toplimit=$botstart-$hiplot; ## PLOT TOP MAX COORD $sttx=45; print "Step: $step\tEndX: $endx\tByDay: $byday\n"; ## PRINT VERTICAL GRID FOR DAYS IN A MONTH $xxrrem=''; for(1..$daysread) { $sttx += $byday; $digday = $_; print FLY "frect $sttx,$toplimit,$sttx,$botstart,$colors{'Grid'}\nstringup $ftext,$sttxt,634,small,$digday\n"; unless($xxrrem) {$xxrrem=45;} $dayfile1="$moshort.$digday.$ryear"; print "\t/http/web/digitemp/byday/$dayfile1.gif to check\n"; print "\tGot map record for $dayfile1.gif\n"; $xxrrem=$sttx; } ## FOR END $toplmprint = $toplimit - 8; print FLY "line 45,$toplimit,$endx,$toplimit,$colors{'Grid'}\nstring $colors{'Text'},10,$toplmprint,small,$maxtemp\n"; print FLY "string $colors{'Text'},$frhtxt,$toplmprint,small,$maxfahr\n"; print FLY "string $colors{'Text'},10,612,small,$mintemp\n"; print FLY "string $colors{'Text'},$frhtxt,612,small,$minfahr\n"; $difftmp = $maxtemp - $mintemp; ($maxtempe,$sh) = split(/\./,$maxtemp); $perdeg = $hiplot / $difftmp; $frstup = $mintemp + 1; $cdif = $frstup - $mintemp; if($prf > $toplimit) {print FLY "line 45,$prf,$endx,$prf,$colors{'Grid'}\nstring $colors{'Text'},10,$txtp,small,$frstup\n";} $strfahr = ($frstup * 1.8) + 32; print FLY "string $colors{'Text'},$frhtxt,$txtp,small,$strfahr\nstring 232,25,25,$frhtxt1,45,giant,F\n"; $toToday .= "string 232,25,25,$frhtxt1,45,giant,F\n"; if($frstup < $maxtempe) { } ## END IF LESS THAN MAX ## PRINT "LEFT AND BOTTOM OF THE GRID print FLY "line 45,$botstart,$endx,$botstart,$colors{'Box'}\nfrect 45,$toplimit,45,$botstart,$colors{'Box'}\n"; print "Writing Temp values..\n______________\n"; $byhr = $byday / 24; foreach $sens (keys(%write)) { ########### SENSOR #print "Day Start: $daystart\tBy HR: $byhr\n"; $daystart = $byday * $da; print "Sensor: $sens\tDay: $da\n"; print "$ti\t$temp"; print "\tX: $xhr\n"; print "\t$xhr $ycoord\n"; $xhr2=$remx+4; print FLY "string $colors{$sens},$xhr2,$ycoord2,small,$tmprem\n"; print "string $colors{$sens},$xhr2,$ycoord2,small,$tmprem\n"; $remx=''; } ## FOREACH SENSOR END ################### SENSOR close(FLY); print "Min: $mintemp\tMax: $maxtemp\n\n"; if($bydaymap) {open(TXT,">/http/web/digitemp/maps/$file.txt"); $bydaymap=''; # SEND MAP FILE TO YOUR SERVER $report = `curl --connect-timeout 30 -F file=@/PATH_TO_FILE/$file.txt -F pass=PASSWORD -F fn=$file.txt $urlsendd`; # SEND MONTH IMAGE FILE TO YOUR SERVER $report = `curl --connect-timeout 30 -F file=@/PATH_TO_FILE/$file.gif -F pass=PASSWORD -F fn=$file.gif $urlsendd`; } ## FOREACH FILE END ############ ## FINISHED WITH MONTHLY GRAPH IMAGE FILE - NOW CREATE DAILY GRAPH $sttx=45; $byday = 1080 / 24; $toToday1 = "line 45,$botstart,$endx,$botstart,$colors{'Box'}\nfrect 45,$toplimit,45,$botstart,$colors{'Box'}\n"; print "line 45,$botstart,$endx,$botstart,$colors{'Box'}\nfrect 45,$toplimit,45,$botstart,$colors{'Box'}\n"; for(1..24) { #### $hour=$_; $sttx += $byday; unless(length($hour) == 2) {$hour = '0'.$hour;} $ftext=$colors{'Text'}; $toToday .= "frect $sttx,$toplimit,$sttx,$botstart,$colors{'Grid'}\nstringup $ftext,$sttxt,635,small,$hour\n"; } ## FOR END #### $hrstr=$endx+10; $toToday .= "string 232,25,25,$hrstr,$hrystr,giant,HRs\n"; $difftmp = $todayhigh - $todaylow; $txtp = $botstart - 8; $txtp1 = $toplimit - 7; $toToday .= "string $colors{'Text'},10,$txtp,small,$todaylow\nstring $colors{'Text'},10,$txtp1,small,$todayhigh\n"; $toToday .= "string $colors{'Text'},$frhtxt,$txtp,small,$todaylowf\nstring $colors{'Text'},$frhtxt,$txtp1,small,$todayhighf\n"; $toToday .= "line 45,$toplimit,$endx,$toplimit,$colors{'Grid'}\n"; $perdeg = $hiplot / $difftmp; print "Day $dayfile\: PerDeg $perdeg\tTmpDiff: $difftmp\tHigh: $todayhigh\tLow: $todaylow\n"; $frstup = $mintemp + 1; $cdif = $frstup - $mintemp; $strfahr = ($frstup * 1.8) + 32; if($prf > $toplimit) {$toToday .= "line 45,$prf,$endx,$prf,$colors{'Grid'}\nstring $colors{'Text'},10,$txtp,small,$frstup\nstring $colors{'Text'},$frhtxt,$txtp,small,$strfahr\n"; print "line 45,$prf,$endx,$prf,$colors{'Grid'}\nstring $colors{'Text'},10,$txtp,small,$frstup\nstring $colors{'Text'},$frhtxt,$txtp,small,$strfahr\n";} print "\nBy degree grid\n"; if($frstup < $maxtempe) { print "line 45,$prf1,$endx,$prf1,$colors{'Grid'}\nstring $colors{'Text'},10,$txtp,small,$frstup\nstring $colors{'Text'},$frhtxt,$txtp,small,$strfahr\n"; } ## END IF LESS THAN MAX $toToday .= $toToday1; $remx=''; #$todayhsh{$sens}{$ti}=$tmprem; $byday = 1080 / 24; $daystart=45; print "By Hour: $byhr\n"; foreach $sens (sort keys(%todayhsh)) { ############# foreach $ti (sort num keys %{$todayhsh{$sens}}) { ## TIME ###### print "\tX: $xhr\tY: $ycoord\n"; print "\t$xhr $ycoord\n"; } ## FOREACH TIME END ########################################## } ## FOREACH SENSOR END ############################ open(FLY,">/http/ipLog/day.$daymatch.flybuilt.txt"); # SEND DAILY GRAPH TO YOUR SERVER $report = `curl --connect-timeout 30 -F file=@/PASS_TO_YOUR_FILE/$dayfile.gif -F pass=PASSWORD -F fn=$dayfile.gif $urlsendd`; ## NOW WRITE A LOCAL FILES TO DISPLAY INFORMATION ON HOME NETWORK unlink "/http/digitemp/temperature1.txt"; @all = glob("/http/web/digitemp/*"); foreach $file (@all) { unless($file =~ m/\.gif$/) {next;} $fn=$file; $files{$year}{$month}=1; } ## $nbsp=' '; foreach $year (sort num keys(%files)) { @months1=@months; $topage .= "<tr><td colspan=7><b>$year</b></td></tr>\n<tr><td>$nbsp</td>"; $topage .= "</tr>\n"; } ## FOREACH YEAR END $topage = "<p>More records<br>\n<table border=0>$topage</table></p>"; unless(-f "/http/web/digitemp/index.cgi") {$chmod=1;} open(TXT,">/http/web/digitemp/index.cgi"); print TXT <<EOH; #!/usr/bin/perl if(-f "/http/web/digitemp/maps/$imchk.txt") {\$immap=" usemap=\\"#$imchk\\""; \$map=`cat /http/web/digitemp/maps/$imchk.txt`;} \$pagetext = '$topage'; \$currimage = '<p><a href="/digitemp/$imchk.gif"><img src="/digitemp/$imchk.gif" border=1 width=1200 height=700'.\$immap.'></a></p>'; \$body = '<html> <head><title>Temperature Graphs by Year and Month</title> <link rel="stylesheet" type="text/css" href="/Album/all.css" media="screen,projection"/> </head><body bgcolor="#ffffff">'; print "Content-type: text/html\\n\\n\$body\\n<h2>Temperature Graphs by Year and Month</h2>\\n\$currimage\\n\$pagetext\\n\$map\\n</body>\\n</html>\\n"; exit(0); EOH close(TXT); if($chmod) {`chmod 755 /http/web/digitemp/index.cgi`;} exit(0); sub num {$a <=> $b;} and a small Bash program "getdate.sh" used in above Perl program to get the number of days in a given month: # last day for month lastday() { # ja fe ma ap ma jn jl ag se oc no de mlength=('xx' '31' '28' '31' '30' '31' '30' '31' '31' '30' '31' '30' '31') year=$1 month=$2 if [ $month -ne 2 ] ; then echo ${mlength[$month]} return 0 fi leap=0 ((!(year%100))) && { ((!(year%400))) && leap=1 ; } || { ((!(year%4))) && leap=1 ; } feblength=28 ((leap)) && feblength=29 echo $feblength } # date to Julian date date2jd() { year=$1 month=$2 day=$3 lday=$(lastday $year $month) || exit $? if ((day<1 || day> lday)) ; then echo day out of range exit 1 fi echo $(( jd = day - 32075 + 1461 * (year + 4800 - (14 - month)/12)/4 + 367 * (month - 2 + (14 - month)/12*12)/12 - 3 * ((year + 4900 - (14 - month)/12)/100)/4 - 2400001 )) } jd2dow() { days=('Sunday' 'Monday' 'Tuesday' 'Wednesday' 'Thursday' 'Friday' 'Saturday') jd=$1 if ((jd<1 || jd>782028)) ; then echo julian day out of range return 1 fi ((dow=(jd+3)%7)) echo ${days[dow]} } echo -n "The first day is 01.$1.$2, " jd2dow $(date2jd $1 $2 01) echo -n "The last day is $(lastday $1 $2).$1.$2, " jd2dow $(date2jd $1 $2 $(lastday $1 $2)) Fly program can be downloaded here: http://www.w3perl.com/fly |