Dla nieuświadomionych Sheevaplug to taki dziadek RaspberryPi. Kiedy jeszcze nie sprzedawali Rpi kupiłem Sheevaplug i używam do dzisiaj. Na obu komputerach jest zainstalowany Debian, ale w różnych wersjach.
Listy mam wysyłać skryptem Perla więc
rozpoczynam od zainstalowania stosowego modułu Net::SMTP::TLS
:
sudo apt-cache search TLS | grep perl libnet-smtp-tls-butmaintained-perl - Perl module for providing SMTP... libnet-smtp-tls-perl - Perl SMTP client library supporting TLS and AUTH libwww-curl-perl - Perl bindings to libcurl sudo apt-get install libnet-smtp-tls-perl
W Debianie
działającym na Sheevaplug (Debian Lenny) nie ma gotowego pakietu
więc instaluję co trzeba za pomocą cpan
:
cpan install Net::SMTP::TLS
Skrypt do wysyłania listu (mail-snd.pl
):
#!/usr/bin/perl # http://dipinkrishna.com/blog/2010/12/sending-emails-gmail-smtp-perl/ use Net::SMTP::TLS; my $smtp = new Net::SMTP::TLS( 'smtp.gmail.com', Port => 587, User => 'USER1@gmail.com', Password=> '??PASSWORD??', Timeout => 30 ); # -- Enter email FROM below. -- $smtp->mail('USER1@gmail.com'); # -- Enter recipient mails addresses below -- my @recipients = ('USER2@gmail.com'); $smtp->recipient(@recipients); $smtp->data(); #This part creates the SMTP headers you see $smtp->datasend("To: USER2\@gmail.com\n"); $smtp->datasend("From: USER1\@gmail.com\n"); $smtp->datasend("Content-Type: text/html \n"); $smtp->datasend("Subject: A Test Mail"); # line break to separate headers from message body $smtp->datasend("\n"); $smtp->datasend("This is a test mail body"); $smtp->datasend("\n"); $smtp->dataend(); $smtp->quit;
W Sheevaplug działa i wysyła, a Raspberry Pi nie:
invalid SSL_version specified at /usr/share/perl5/IO/Socket/SSL.pm line 332
Żeby było śmieszniej w Debianie Lenny z Sheevaplug jest
jakaś bardzo stara wersja IO::Socket:SSL
:
## sprawdź numer wersji modułu cpan -D IO::Socket::SSL Installed: 1.16
A na Raspberry Pi znacznie nowsza (ale nie działa):
cpan -D IO::Socket::SSL Installed: 1.76 CPAN: 1.994 Not up to date
Aktualizuję
sudo cpan cpan> install IO::Socket:SSL
Ale to nie pomaga:
invalid SSL_version specified at /usr/local/share/perl/5.14.2/IO/Socket/SSL.pm
Rozwiązanie jest podane tutaj. Należy:
## w pliku SSL.pm sudo nano usr/share/perl5/IO/Socket/SSL.pm ## zmienić m{^(!?)(?:(SSL(?:v2|v3|v23|v2/3))|(TLSv1[12]?))$}i ## na m{^(!?)(?:(SSL(?:v2|v3|v23|v2/3))|(TLSv1[12]?))}i
Zamiast rzeźbienia w Perlu można zainstalować gotowe rozwiązanie
pn. sendemail
:
apt-get install sendemail
List wysyłamy w następujący sposób:
sendEmail -f USER1@gmail.com -t USER2@other.com \ -u "Title1" -m "this is a test message" \ -s smtp.gmail.com \ -o tls=yes \ -xu USER1 -xp '??PASSWORD??'
From time to time internet connection to my Raspberry Pi disappears (AFAIK it is well known feature of Pi). Removing and reconnecting the ethernet cables did not work, so one has to reboot by pulling the plug (risking to corrupt file systems from improper shutdown).
To reconnect I use the following bash script (found here):
#!/bin/bash # Check if Internet connection is still alive *** # Insert into crontab at *.16 LOGLOG="/home/pi/Logs/Cron/Reboot.log" WLAN=eth0 if /sbin/ifconfig $WLAN | grep -q "inet addr:" ; then echo "Network connection up!" else echo "Attempting reconnect [`date +%Y%m%d%H%M`]" >> $LOGLOG /usr/bin/sudo /sbin/ifup --force $WLAN fi
Note: use ifconfig -a
to identify relevant interface (WLAN
):
pi@raspberryberrystar ~ $ ifconfig -a ifconfig -a eth0 Link encap:Ethernet HWaddr b8:27:eb:f5:9a:d7 inet addr:192.168.1.146 Bcast:192.168.1.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
My other Pi is connected to internet not through a cable but with WiFi dongle. The relevant interface is:
pi@blackberrystar ~ $ ifconfig -a wlan2 Link encap:Ethernet HWaddr 10:fe:ed:12:ef:2c inet addr:192.168.1.144 Bcast:192.168.1.255 Mask:255.255.255.0
The connection is checked every 20 minutes with the following crontab entry:
## Check Internet connection every 7th, 27th, 47th minute: 7,27,47 * * * * /home/pi/bin/chk_www_alive.sh > /dev/null 2>&1
Because my tomatoes are growing unexpectedly fast I had to stop capturing pictures quicker than I have planned as they do not fit in the frame.
So 2664 pictures was taken from 16.03 to 23.04 at 20 minutes interval. The video size is about 715 Mb and the video length is 3min 43 seconds (at 12 fps or 1:47 at 25 fps).
Ustaliłem empirycznie w jaki sposób podłączyć aparat do Raspberry Pi (do SheevaPlug zresztą też) żeby nic się nie zacinało. W skrócie:
Używam kompakta Nikon S3000 (Canon A620 się zacinał/odłączał--sprzedałem go na Allegro).
Podłączam aparat poprzez aktywny USB hub (kupiłem w tym celu cztero-portowy HUB firmy Vivanco).
Po każdym zdjęciu wykonuję reset stosownego portu USB za pomocą programiku pn. usb_reset
(zobacz tutaj
oraz tutaj).
Używam dwóch aparatów Nikon S3000 (kupionych na Allegro oczywiście), więc jest problem z ustaleniem który jest który:
$gphoto2 --auto-detect Model Port ---------------------------------------------------------- Nikon Coolpix S3000 (PTP mode) usb:001,022 Nikon Coolpix S3000 (PTP mode) usb:001,021
Można użyć opcji --port usb:001,022
aby wykonać coś
z ,,pierwszym'' aparatem oraz --port usb:001,021
, aby dostać się do drugiego.
Oczywiście umieszczenie numerów portów na-zicher w skryptach byłoby kiepskim pomysłem
ponieważ nie są one ustalone, ale się zmienią jeżeli urządzenie zostanie odłączone/przyłączone ponownie.
Lepszym sposobem zidentyfikowania aparatów jest wykorzystanie numeru seryjnego:
## $gphoto2 --get-config serialnumber --port PORT ## example $gphoto2 --get-config serialnumber --port usb:001,022 Label: Serial Number Type: TEXT Current: 000047514512
Mam czarnego Nikona o numerze 000041076602 oraz różowego o numerze 000047514512. Używam następującego skryptu do wykonania zdjęcia określonym aparatem:
#!/bin/bash PINK_CAM_ID='000047514512' BLACK_CAM_ID='000041076602' while test $# -gt 0; do case "$1" in -b|--black) REQ_CAM="$BLACK_CAM_ID";; -p|--pink) REQ_CAM="$PINK_CAM_ID";; esac shift done ## Nazwa pliku ze zdjęciem: FILENAME="NIK`date +"%Y%m%d%H%M"`.jpg" ## Przejrzyj wszystkie podłączone aparaty: while read PORT_ID do ##echo $PORT_ID ## -n means string is non-empty if [ -n "$PORT_ID" ] ; then CAM_ID=`gphoto2 --get-config serialnumber --port $PORT_ID | awk '/Current:/ { print $2 }' ` if [ $CAM_ID = "$REQ_CAM" ] ; then REQ_CAM_PORT="$PORT_ID" ##echo "*** Req Camera ID: #$CAM_ID." fi fi done <<< "`gphoto2 --auto-detect | grep usb | awk '{ print $6}'`" # Na wypadek błędu wyślij alarmowego SMSa if [ -z "$REQ_CAM_PORT" ] ; then echo "*** Error: Camera $REQ_CAM not found ***" ## sent a SMS cf http://pinkaccordions.homelinux.org/wblog/sms_alerts_with_google_calendar.html sms_reminder.sh exit 1 fi ## reset USB REQ_CAM_PORT_DEVNAME=`echo $REQ_CAM_PORT | sed 's/^.*://' | sed 's/,/\//'` usb_reset /dev/bus/usb/${REQ_CAM_PORT_DEVNAME} LANG=C gphoto2 --port "$REQ_CAM_PORT" --force-overwrite --set-config flashmode=1 \ --set-config d002=4 \ --capture-image-and-download --filename "$FILENAME" ## reset USB (powtórny) usb_reset /dev/bus/usb/${REQ_CAM_PORT_DEVNAME}
Właściwość d002
ustawia rozdzielczość zdjęcia (4 oznacza 2592x1944).
Wartość 1 właściwościflashmode
wyłącza flash.
Z moich eksperymentów wynika, że bez wykonania
usb_reset
bateria aparatu nie jest doładowywana (czemu?) i po
pewnym czasie z powodu braku zasilania aparat odłącza się.
Po czterech tygodniach mam wystarczająco dużo zdjęć aby spróbować zrobić pierwszy film.
Najpierw konwertuję wszystkie zdjęcia do rozdzielczości 1920x1080 za pomocą
programu convert
(z zestawu ImageMagick)
uruchamianego z ,,wewnątrz'' prostego skryptu Perla. Ponieważ nazwy plików wejściowych są
konstruowane wg schematu NIKYYYYMMDDHHMM.jpg
(gdzie YYY to rok, MM oznacza miesiąc, itd.)
sortowanie alfabetyczne oznacza ustawienie ich także we właściwym porządku chronologicznym.
Nazwy plików wynikowych są zaś konstruowane jako:
hd1920_00001.jpg
, hd1920_00002.jpg
, itd.
#!/usr/bin/perl opendir (DIR, "."); my @files = sort { $a cmp $b } readdir(DIR); while (my $file = shift @files ) { if ($file =~ /.jpg$/) { $fileNo++; $file_out = sprintf "hd1920_%05d.jpg", $fileNo; print "$file -> $file_out\n"; system ("convert", $file, "-geometry", "1920x1080", "$file_out"); } }
Okazało się, że jest dokładnie 1784 zdjęć:
$ls -l hd1920_0* | wc -l 1784
Konwersja trwała około 30 min na moim przeciętnym zupełnie PC-cie. Każdy plik wynikowy miał około 0,5Mb; wszystkie razem zajmowały około 0,85Gb:
$ls -l hd1920_0* | awk '{t+=$5}; END{print t}' 853332231
Film został wykonany za pomocą programu ffmpeg
:
ffmpeg -r 12 -qscale 2 -i hd1920_%05d.jpg Tomato_12.mp4
Gdzie -r 12
oznacza liczbę klatek na sekundę (12 fps)
a -qscale
określa jakość (1 oznacza najlepszą,
32 najgorszą jakość).
Film ma około 450 Mb. Konwersja zajmuje około 3min (on my decent PC) a długość filmu to 2min i 29 sekundy.
Film przedstawia sadzonkę pomidora (Pinkaccordion oczywiście :-). Zdjęcia były robione co 20 minut od 16 marca do 11 kwietnia.
After almost 4 weeks I have enough pictures to create my first video production. (How to capture images with a still camera attached to Raspberry Pi is described here and here.)
I started from converting all pictures to 1920x1080 resolution with convert
run from a simple Perl script. As the input file
names are constructed as NIKYYYYMMDDHHMM.jpg
(where YYY denotes year, MM denotes month etc)
alphabetic sorting is OK. The resulting files
are named as hd1920_00001.jpg
, hd1920_00002.jpg
, etc.
#!/usr/bin/perl opendir (DIR, "."); my @files = sort { $a cmp $b } readdir(DIR); while (my $file = shift @files ) { if ($file =~ /.jpg$/) { $fileNo++; $file_out = sprintf "hd1920_%05d.jpg", $fileNo; print "$file -> $file_out\n"; system ("convert", $file, "-geometry", "1920x1080", "$file_out"); } }
There are exactly 1784 pictures:
$ls -l hd1920_0* | wc -l 1784
Conversion of all images lasted circa half an hour on my decent PC. Each picture size is about 0,5Mb, while the total size is 0,85Gb:
$ls -l hd1920_0* | awk '{t+=$5}; END{print t}' 853332231
To create a video from the images I run ffmpeg
now:
ffmpeg -r 12 -qscale 2 -i hd1920_%05d.jpg Tomato_12.mp4
Where -r 12
means frames ratio (12 fps) and -qscale
determines
video quality (1 denotes best quality and 32 is the lowest one).
The video size is about 450 Mb. The conversion takes circa 3min (on my decent PC) and the video length is 2min 29 seconds.
The movie's subject is a growing tomato (Pinkaccordion variety of course:-). The photographs were taken every 20 minutes from March 16th to April 11th.
I have made some progress in accessing still camera with gphoto2
(cf. here).
The detailed description of my set-up will be disclosed within a few weeks (as I am still not sure
if it is 100% success:-). In short:
I changed camera from Canon A620 to Nikon S3000.
I connected camera with active USB hub.
On every capture USB port is reset with usb_reset
utility
(cf here
and here)
I use two Nikon S3000 compact cameras so there is a problem how to identify which is which.
$gphoto2 --auto-detect Model Port ---------------------------------------------------------- Nikon Coolpix S3000 (PTP mode) usb:001,022 Nikon Coolpix S3000 (PTP mode) usb:001,021
So one can use --port usb:001,022
option to access first attached
camera and --port usb:001,021
to access the second one. Of
course hard-coded port numbers are troublesome as they are not fixed and change
if the device is disconnected/connected again.
Better way to identify the camera is to use it's serial number:
## $gphoto2 --get-config serialnumber --port PORT ## example $gphoto2 --get-config serialnumber --port usb:001,022 Label: Serial Number Type: TEXT Current: 000047514512
I have black Nikon with 000041076602 serial number and pink one with 000047514512 serial number. I use the following bash script to access the cameras:
#!/bin/bash PINK_CAM_ID='000047514512' BLACK_CAM_ID='000041076602' while test $# -gt 0; do case "$1" in -b|--black) REQ_CAM="$BLACK_CAM_ID";; -p|--pink) REQ_CAM="$PINK_CAM_ID";; esac shift done ## Picture filename: FILENAME="NIK`date +"%Y%m%d%H%M"`.jpg" ## Scan all attached cameras: while read PORT_ID do ##echo $PORT_ID ## -n means string is non-empty if [ -n "$PORT_ID" ] ; then CAM_ID=`gphoto2 --get-config serialnumber --port $PORT_ID | awk '/Current:/ { print $2 }' ` if [ $CAM_ID = "$REQ_CAM" ] ; then REQ_CAM_PORT="$PORT_ID" ##echo "*** Req Camera ID: #$CAM_ID." fi fi done <<< "`gphoto2 --auto-detect | grep usb | awk '{ print $6}'`" if [ -z "$REQ_CAM_PORT" ] ; then echo "*** Error: Camera $REQ_CAM not found ***" ## sent a SMS cf http://pinkaccordions.homelinux.org/wblog/sms_alerts_with_google_calendar.html sms_reminder.sh exit 1 fi ## reset the USB device REQ_CAM_PORT_DEVNAME=`echo $REQ_CAM_PORT | sed 's/^.*://' | sed 's/,/\//'` usb_reset /dev/bus/usb/${REQ_CAM_PORT_DEVNAME} LANG=C gphoto2 --port "$REQ_CAM_PORT" --force-overwrite --set-config flashmode=1 \ --set-config d002=4 \ --capture-image-and-download --filename "$FILENAME" ## reset the USB device again usb_reset /dev/bus/usb/${REQ_CAM_PORT_DEVNAME}
Property d002
sets picture resolution (4 means 2592x1944).
Value 1 of flashmode
turns-off flash.
It seems that without usb_reset
there are problems with battery charging (why?)
I would like to remote control a still camera via gphoto2
.
After consulting a list of supported cameras I bought (used) Canon A620
from Allegro (local Internet auction site, sort of E-bay).
This camera has many great features (I suspect even too great as Canon stop producing cheap cameras of this sort):
viewfinder, retractable LCD and can be powered with Compact Power Adapter CA-PS500 instead of batteries
(an important feature in my project).
The plan was simple: connect camera via USB cable to computer and power it with PSU. Capture photos periodically with
gphoto2
:
gphoto2 --auto-detect pi@raspberrystar ~/bin $ gphoto2 --auto-detect Model Port ---------------------------------------------------------- Canon PowerShot A620 (PTP mode) usb:001,006
So far, so good.
Now, I tried to capture a photo:
# one shot without flash, download the file and store in a file named as: GPHyyyymmddhhmm.jpg LANG=C gphoto2 --set-config flashmode=0 --capture-image-and-download --filename "GPH%Y%m%d%H%M.jpg"
As the creation time is wrong (due to camera wrong clock) I modified
the above as follows (note that touch
is used to adjust file's timestamp):
#!/bin/basg FILENAME="GPH`date +"%Y%m%d%H%M"`.jpg" LANG=C gphoto2 --set-config flashmode=0 --capture-image-and-download --filename "$FILENAME" touch "$FILENAME"
Unfortunately there are problems: I am able to remotely capture only one photo. Next remote capture try results in an error and the camera has to be hard reset (with power on/off button). The problem is reported by others too.
BTW: when I connected the camera to my PC the reliability is much better (but seems not perfect---I experienced camera disconnection too.)
My first try to resolve the problems was to update gphoto2
(raspbian contains version 2.4.14 of gphoto2
).
## optionally remove old version (there are no dependencies) apt-get remove gphoto2
There is no need to remove gphoto2
as compiled one
will be installed in another directory (/usr/local/
vs
/usr/
).
First install/compile the necessary packages:
apt-get install -y libltdl-dev libusb-dev libexif-dev libpopt-dev ## Download and install newer version of libusb 1.0.11 wget http://ftp.de.debian.org/debian/pool/main/libu/libusbx/libusbx_1.0.11.orig.tar.bz2 tar xjvf libusbx_1.0.11.orig.tar.bz2 cd libusbx-1.0.11/ ./configure && make && sudo make install ## Download and install newer version of libgphoto wget http://garr.dl.sourceforge.net/project/gphoto/libgphoto/2.5.1.1/libgphoto2-2.5.1.1.tar.bz2 tar xjf libgphoto2-2.5.0.tar.bz2 cd libgphoto2-2.5.1.1 ./configure && make && sudo make install
Download and install newer version of gphoto2
wget http://downloads.sourceforge.net/project/gphoto/gphoto/2.5.1/gphoto2-2.5.1.tar.gz tar xzvf gphoto2-2.5.1.tar.gz cd gphoto2-2.5.1 ./configure && make && sudo make install ## run ldconfig sudo ldconfig gphoto2 --version gphoto2 2.5.1 Copyright (c) 2000-2013 Lutz Mueller i inni
BTW compiling gphoto2
on my fedora 14 box requires
to install libtool-ltdl-devel
popt-devel
first:
#configure: error: cannot compile and link against libltdl #libgphoto2 requires libltdl (the libtool dl* library), #but cannot compile and link against it. yum -y install libtool-ltdl-devel popt-devel
Upon installing above two packages, the compilation of
libusb
, libgphoto
and gphoto2
proceeds smoothly.
Unfortunately installing new version of gphoto2
did not help.
The problem will be further examined...
To build the installation one has to buy:
DHT-22 temperature/humidity sensor (8 USD per sensor). Not cheap...
0,25W 10K OHM carbon resistor (very cheap).
female connectors (pol. kable połączeniowe żeńskie), telephone cables or similar four core cable (pol. kabel czterożyłowy), terminal block (pol. kostka połączeniowa) and heat shrink tubing (pol. rurka termokurczliwa) to insulate and strengthen connections. The recommended way is to use a breadboard (pol. płytka stykowa/prototypowa) as described in learn.adafruit.com. My interest in electronics is limited, I've never used breadboards etc... I had some spare cables and terminal blocks so I designed it that way (cf. pictures).
NOTE: The cheaper version of the DHT-22 is a DHT-11 (aka SHT-11). Tempted by the lower price I bought two DHT-11 sensors but I do not recommend it. First of all, the temperature is measured in the range of 0 °C to 50 °C (with poor accuracy of +/- 2 °C) so is not suitable for outdoor (at least in Europe). Second, the humidity seems to be understated. Third, it does not work when DQ line is connected to other GPIO pins than pin #24 (maybe it's a software problem). For comparison, DHT-22 measures the temperature in the range of-40C to +80 C with an accuracy of +/- 0.5 °C.
I follow the tutorial available at learn.adafruit.com but some details were modified.
There are four pins in DHT-22 (see Figure # 1). I connected data line (DQ) of each sensor to pins P22, P24 and P25 respectively (each sensor must have a separate data line). Vdd pin of each sensor to P1 (3.3 V supply). GND (ground) pin of each sensor to P6. In addition, each DQ was connected via the resistor with the power line Vdd.
Pin Null is not used.
The sensors were connected to GPIO pins via terminal blocks, cables and some soldering.
One has to download, compile and install the necessary library:
pi@raspberrystar $ wget http://www.open.com.au/mikem/bcm2835/bcm2835-1.8.tar.gz pi@raspberrystar $ tar -zxvf bcm2835-1.8.tar.gz pi@raspberrystar $ cd bcm2835-1.8 pi@raspberrystar $ ./configure && make && sudo make install
then the application retrieving the data from the sensors has to be installed:
pi@raspberrystar $ git clone https://github.com/adafruit/Adafruit-Raspberry-Pi-Python-Code.git pi@raspberrystar $ cd Adafruit-Raspberry-Pi-Python-Code pi@raspberrystar $ cd Adafruit_DHT_Driver
One has to modify Makefile file, namely add -l rt
at the end of the line that starts with CFLAGS:
CFLAGS = -std=c99 -I. -lbcm2835 -l rt
now:
## in Adafruit_DHT_Driver directory pi@raspberrystar $ make
If everyting works, then:
# Run ./Adafruit_DHT sensor-type DQ-pin-number pi@raspberrystar $ sudo ./Adafruit_DHT 22 25 Using pin #25 Data (40): 0x3 0xe7 0x0 0x17 0x1 Temp = 2.3 *C, Hum = 99.9 %
The directory Adafruit_DHT_Driver
contains also
Adafruit_DHT_googledocs.ex.py
Python script which can upload
sensor readings directly to google.docs spreadsheet.
To run Adafruit_DHT_googledocs.ex.py
one has to install
gspread module first:
pi@raspberrystar $ wget http://pypi.python.org/packages/source/g/gspread/gspread-0.0.13.tar.gz pi@raspberrystar $ tar -zxvf gspread-0.0.13.tar.gz pi@raspberrystar $ cd gspread pi@raspberrystar $ sudo python setup.py install
Adafruit_DHT_googledocs.ex.py
script: 1) in an infinite loop runs
every 30 seconds the program Adafruit_DHT
, 2) retrieves
temperature/humidity, 3) sends temperature/humidity readings to
google.docs. A fragment of the script looks like:
while(True): output = subprocess.check_output(["./Adafruit_DHT", "2302", "4"]); print output # search for humidity printout matches = re.search("Hum =\s+([0-9.]+)", output) if (not matches): time.sleep(3) continue humidity = float(matches.group(1)) ## omitted code ... time.sleep(30)
Because I want to process somehow the data (not only to retrieve and upload
to google.docs
)
I modify Adafruit_DHT_googledocs.ex.py
script.
My version Adafruit_DHT_googledocs.ex.py
is limited to sending to
google.docs
values passed as arguments to the call:
temp = float(sys.argv[1]) humidity = float(sys.argv[2]) ## omitted code ...
The following bash script takes care of the rest:
#!/bin/bash # LOG_DIR=/home/pi/Logs/DHT BIN_DIR=/home/pi/bin SENSTYPE=22 SLEEP_TIME=5 function ReadSensor() { local sensorType="$1" local sensorId="$2" local WYNIK="" local SUCCESS="" ## 5 tries with 5s sleep between them for i in 1 2 3 4 5; do WYNIK=`sudo $BIN_DIR/Adafruit_DHT $sensorType $sensorId | tr '\n' ' '` SUCCESS=`echo $WYNIK | awk ' { if (NF > 10) {print "YES"} else { print "NO"}}'` if [ "$SUCCESS" = "YES" ] ; then echo "$sensorId=$i $WYNIK" >> $LOG_DIR/DHT22.log DHT_CURR_TEMP=`echo $WYNIK | awk '{print $13}'` DHT_CURR_HUM=`echo $WYNIK | awk '{print $17}'` break fi sleep $SLEEP_TIME; done ## All attempts to read sensors were unsuccessful if [ $SUCCESS = "NO" ] ; then echo "$sensorId=? $WYNIK" >> $LOG_DIR/DHT22.log DHT_CURR_TEMP="999.9" DHT_CURR_HUM="999.9" fi } echo "@`date "+%Y%m%d%H%M%S"`" >> $LOG_DIR/DHT22.log ## A sensor in the room: ReadSensor $SENSTYPE "24" READINGS="$DHT_CURR_TEMP $DHT_CURR_HUM" sleep 12 ## Outdoor sensor: ReadSensor $SENSTYPE "25" READINGS="$READINGS $DHT_CURR_TEMP $DHT_CURR_HUM" sleep 12 ## A sensor in the porch: ReadSensor $SENSTYPE "22" READINGS="$READINGS $DHT_CURR_TEMP $DHT_CURR_HUM" ## HTML + chart /usr/bin/perl /home/pi/bin/dht2ht.pl > /var/www/stats/DHT22.html # Upload to google /home/pi/bin/DHT_googledocs.ex.py $READINGS
As in the case of 1-Wire bus there are problems with the reading of
the sensor. That's why the function ReadSensor
is trying to
read the sensor several times.
Maximum number of failed attempts, we have
observed during several days of operation is 3.
The script runs every 30 minutes from cron:
1,31 * * * * /home/pi/bin/dht2ht.sh
LOG file looks something like this:
@20121113230101 24=1 Using pin #24 Data (40): 0x2 0x22 0x0 0xc9 0xed Temp = 20.1 *C, Hum = 54.6 % 25=1 Using pin #25 Data (40): 0x3 0xe7 0x0 0x1c 0x6 Temp = 2.8 *C, Hum = 99.9 % 22=4 Using pin #22 Data (40): 0x2 0x73 0x0 0xb0 0x25 Temp = 17.6 *C, Hum = 62.7 %
Row starting with the @
contains the date and
time (@
is added for subsequnt easy parsing).
Lines that begin with nn = m
contain the data retrived from
the sensor
(nn
is the sensor number, m
denotes the number of successful
attempt or ?
in case when all attempts were unsuccessful)
Note: I noticed that higher system load (including
intensive I/O operations) cause problems to retrieve data from the sensors.
I tried to run motion detection application (motion
) configured
to use as little system resources as possible with no success.
Rapberry overclocked to 900 Mhz performs
significantly better but still only about
20% tries returns some data. Exact nature of the problem is a mystery to me
as for example
top
indicates that still more there 80% of CPU is free.
Other question to consider is: whether the readings are correct during high humidity? My outdoor sensors tend to indicate 99% humidity pretty frequently which seems suspicious. I have compared data obtained from 3 different sensors (namely WH 2080 clone, Oregon Scientific's RMS300 and DHT-22) and some differ significantly.
dht2ht.pl
Perl script dht2ht.pl
creates a HTML table and charts showing
temperature/humidity readings as well as dew point,
calculated with the following approximation formula:
$$
D_p = (237.7 \cdot \gamma(T, H) ) / (17.271 - \gamma(T, H) )
$$
where: $$ \gamma(T, H) = 17.271 \cdot T / (237.7 + T) + \log (H / 100.0) $$
Script outcome is available here. All scripts and other stuff discussed in this blog post are available here.
Google.docs sheet containing readings from all my 3 sensors is available
here.
(Note: for some important reasons Adafruit_DHT_googledocs.ex.py
script
started adding data from the 162th line of the spreadsheet.)
First I find the device with SDHC card mounted:
pi@raspberrypi ~ $ sudo fdisk -l Disk /dev/mmcblk0: 7969 MB, 7969177600 bytes 4 heads, 16 sectors/track, 243200 cylinders, total 15564800 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x000108cb Device Boot Start End Blocks Id System /dev/mmcblk0p1 8192 122879 57344 c W95 FAT32 (LBA) /dev/mmcblk0p2 122880 15564799 7720960 83 Linux
Now I mount a USB stick for storing a copy of the system:
pi@raspberrypi ~ $ mkdir /media/sda1 ## Assume USB stick is /dev/sda1 pi@raspberrypi ~ $ mount /dev/sda1 /media/sda1
Raw copy with dd
pi@raspberrypi ~ $ sudo dd if=/dev/mmcblk0 | gzip -1 > /media/sda1/sd_backup.img.gz ## w/o compression: pi@raspberrypi ~ $ sudo dd if=/dev/mmcblk0 of=/media/sda1/sd_backup.img ## over ssh in case there is no USB stick at hand: user@othercomputer ~ $ sudo ssh root@raspberrystar dd if=/dev/mmcblk0 | gzip -1 | dd of=sd_backup.img.gz
Note: raspberrystar
is the name of my
system---change it to appropriate IP address or name.
Restoring system image:
pi@raspberrypi ~ $ zcat sd_backup.img.gz > /dev/sdX
Where /dev/sdX
denotes the device with blank SDHC card mounted.
More details can be found here.
Copying over sshfs
:
pi@raspberrypi ~ $ sudo apt-get install sshfs fuse-utils pi@raspberrypi ~ $ mkdir -p ~/Dist/jupiter ## mounting (as user tomek) remote directory /public/raspberry at jupiter; ## mounting point is: ~/Dist/jupiter pi@raspberrypi ~ $ sshfs tomek@jupiter:/public/raspberry/ ~/Dist/jupiter failed to open /dev/fuse: Permission denied
On first try failure (as usual). Only fuse group members can read/write from/to /dev/fuse
.
User pi should be added to group "fuse":
pi@raspberrypi ~ $ sudo usermod -a -G fuse pi
To activate the modifications made in /etc/group
one should log out/log in now.
pi@raspberrypi ~ $ sshfs tomek@jupiter:/public/raspberry/ ~/Dist/jupiter pi@raspberrypi ~ $ ls -l /home/pi/Dist/jupiter total 0 ## Raw copy with dd (with compression): sudo dd if=/dev/mmcblk0 | gzip -1 > /home/pi/Dist/jupiter/raspberrystar.iso
Added 3 Oct 2012:
15564800+0 przeczytanych recordów 15564800+0 zapisanych recordów skopiowane 7969177600 bajtów (8,0 GB), 3504,04 s, 2,3 MB/s
Raw copying of 8Gb SDHC card with compression over sshfs took about 1 hr. The resulting image size is about 1,6 Gb.
It is said to overclock Raspberry Pi one has to upgrade the system:
sudo apt-get update && sudo apt-get install raspberrypi* raspi-config
Then configure it with raspi-config
utility:
sudo raspi-config
It is good anyhow to check the system version first:
uname -a Linux raspberrystar.pinkaccordions.org 3.2.27+ #174 PREEMPT Wed Sep 26 14:09:47 BST 2012 armv6l GNU/Linux
The kernel is up to date. Inspecting raspi-config
I have discovered
it is not updated, but I prefer to configure the system via CLI (command line or console) interface
rather than GUI one (no need to connect the RPi to a TV set which is in another room:-).
So I decided not to upgrade the system but rather manually configure it.
To achieve overclocking one has to add the following lines to
/boot/config.txt
file:
pi@raspberrystar ~ $ sudo vim /boot/config.txt ## add the following: temp_limit=80 arm_freq=900 sdram_freq=500
Now reboot:
pi@raspberrystar ~ $ sudo reboot
Check the dmesg
:
pi@raspberrystar ~ $ dmesg | grep 7000 [ 1.956412] bcm2835-cpufreq: min=700000 max=900000 cur=700000
CPU frequency is still 700Mhz. To increase it one has to
edit scaling_governor
file:
pi@raspberrystar ~ $ sudo bash root@raspberrystar:/home/pi# echo "performance" > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor ## check if the above works:-) pi@raspberrystar ~ $ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor performance # display available options: pi@raspberrystar ~ $ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors conservative ondemand userspace powersave performance
The ondemand
option
allows for adjusting CPU frequency depending
on CPU utilization.
Without any further reboot the new settings work:
# check current CPU frequency pi@raspberrystar ~ $ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq 900000
There is even a temperature sensor available so one can check if the CPU is not overheated:
# check processor temperature: pi@raspberrystar ~ $ /opt/vc/bin/vcgencmd measure_temp temp=46.5'C
To boot the system with scaling_governor
set to appropriate
value one has to edit /etc/rc.local
:
pi@raspberrystar ~ $ sudo vim /etc/rc.local # Add the following line # echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
I have performed a simple test:
#!/bin/bash # N=5 START=$(date +%s) for ((i=1;i<=$N;i++ )) ; do echo "**** Iteration $i ****" STARTI=$(date +%s) perl -e 'for ($i=0;$i<=10000000;$i++) { $s .= "xx"; }' ENDI=$(date +%s) ; TOTALI=$(( $ENDI - $STARTI )) echo "*** $TOTALI s." done END=$(date +%s) TOTAL=$(( $END - $START )) MEAN=`awk -v m=$TOTAL -v n=$N 'BEGIN { print m/n }'` echo "total: " $TOTAL "mean: " $MEAN ##
The test uses the following perl program:
perl -e 'for ($i=0;$i<=10000000;$i++) { $s .= "xx"; }'
Because computing time can vary, the program has to be run N
times
and the mean time is reported.
My Rpi runs 28--29s at 700 Mhz, 25,8s at 800 Mhz and 21s at 900 Mhz.
So running at 900 Mhz results in almost 30% reduction of computing time.
Do wykonania instalacji potrzebne są:
Czujnik DHT-22 temperatury/wilgotności (ok. 30 zł za sztukę). Droga sprawa...
REZYSTOR 0,25W 10K OHM węglowy (1,00 zł za 100 sztuk na Allegro).
Do tego: przewody połączeniowe żeńskie, przewód telefoniczny czterożyłowy lub inny podobny, kostka elektryczna oraz rurka termokurczliwa do izolacji i wzmocnienia połączeń. (Por. Raspberry Pi: magistrala 1-Wire i rejestracja temperatury.)
UWAGA: tańszą wersja DHT-22 jest DHT-11 (aka SHT-11). Połasiłem się nawet na takowy, bo taniej ale nie polecam. Przede wszystkim mierzy temperaturę w przedziale od 0C do 50C (z kiepską dokładnością +/- 2C) więc nie nadaje się do pomiaru temperatury zewnętrznej. Do tego odczyt wilgotności jest zaniżony i nie działa podłączony do niektórych pinów GPIO (być może jest to problem oprogramowania, którego używam). Dla porównania DHT-22 mierzy temperaturę w przedziale od -40C do +80C z dokładnością +/- 0,5C.
Na stronie learn.adafruit.com znajduje się tutorial, z którego korzystałem...
Sensor DHT-22 ma cztery piny (por. rys #1). Podłączyłem linie danych (DQ) do pinów P22, P24 i P25 (każdy sensor musi mieć oddzielną linię danych). Vdd każdego sensora do pina P1 (zasilanie 3,3V). GND (masa) każdego czujnika do pina P6. Ponadto każde DQ należało połączyć za pomocą rezystora z linią zasilania Vdd.
Pin Null nie jest wykorzystywany.
Lutowanie i łączenie wszystkiego do kupy wykonałem w sposób identyczny (kostka elektryczna, rurka termokurczliwa itp.) z opisanym bardziej szczegółowo we wpisie Raspberry Pi: magistrala 1-Wire i rejestracja temperatury.
Pobieram, kompiluję i instaluję niezbędną bibliotekę:
pi@raspberrystar $ wget http://www.open.com.au/mikem/bcm2835/bcm2835-1.8.tar.gz pi@raspberrystar $ tar -zxvf bcm2835-1.8.tar.gz pi@raspberrystar $ cd bcm2835-1.8 pi@raspberrystar $ ./configure && make && sudo make install
Pobieram program do obsługi czujników:
pi@raspberrystar $ git clone https://github.com/adafruit/Adafruit-Raspberry-Pi-Python-Code.git pi@raspberrystar $ cd Adafruit-Raspberry-Pi-Python-Code pi@raspberrystar $ cd Adafruit_DHT_Driver
W pliku Makefile należy dopisać -l rt
na końcu wiersza
zaczynającego się od CFLAGS
:
CFLAGS = -std=c99 -I. -lbcm2835 -l rt
teraz:
## w katalogu Adafruit_DHT_Driver pi@raspberrystar $ make
Jeżeli wszystko działa, to:
# Uruchomienie ./Adafruit_DHT typ-czujnika nr-pina-DQ pi@raspberrystar $ sudo ./Adafruit_DHT 22 25 Using pin #25 Data (40): 0x3 0xe7 0x0 0x17 0x1 Temp = 2.3 *C, Hum = 99.9 %
W katalogu Adafruit_DHT_Driver znajduje się też skrypt Pythona
pn. Adafruit_DHT_googledocs.ex.py
służący do wysyłania odczytanych danych do arkusza
google.docs. Skrypt Adafruit_DHT_googledocs.ex.py
do działania potrzebuje modułu gspread
:
pi@raspberrystar $ wget http://pypi.python.org/packages/source/g/gspread/gspread-0.0.13.tar.gz pi@raspberrystar $ tar -zxvf gspread-0.0.13.tar.gz pi@raspberrystar $ cd gspread pi@raspberrystar $ sudo python setup.py install
Skrypt Pythona Adafruit_DHT_googledocs.ex.py
:
1) w nieskończonej pętli uruchamia co 30 sekund program
Adafruit_DHT
,
2) wyłuskuje z wydruku wartości temperatury/wilgotności, 3) wysyła co trzeba
na google.docs. Fragment skryptu wygląda następująco:
while(True): output = subprocess.check_output(["./Adafruit_DHT", "2302", "4"]); print output # search for humidity printout matches = re.search("Hum =\s+([0-9.]+)", output) if (not matches): time.sleep(3) continue humidity = float(matches.group(1)) ## pominięty kod ... time.sleep(30)
Ponieważ ja chcę oprócz wysłania na google.docs coś tam jeszcze zrobić z danymi,
to miałem do wyboru albo rozbudować Adafruit_DHT_googledocs.ex.py
o dodatkową
funkcjonalność albo go uprościć. Wybrałem to drugie:
moja wersja Adafruit_DHT_googledocs.ex.py
ogranicza się wyłącznie do wysłania
na google.docs wartości przekazanych jako argumenty wywołania:
temp = float(sys.argv[1]) humidity = float(sys.argv[2]) ## pominięty kod ...
Resztą zajmie się poniższy skrypt basha:
#!/bin/bash # LOG_DIR=/home/pi/Logs/DHT BIN_DIR=/home/pi/bin SENSTYPE=22 SLEEP_TIME=5 function ReadSensor() { local sensorType="$1" local sensorId="$2" local WYNIK="" local SUCCESS="" ## zwiększyłem powtórzenia do 5 (sleep zmniejszony do 5s/było 10) for i in 1 2 3 4 5; do WYNIK=`sudo $BIN_DIR/Adafruit_DHT $sensorType $sensorId | tr '\n' ' '` SUCCESS=`echo $WYNIK | awk ' { if (NF > 10) {print "YES"} else { print "NO"}}'` if [ "$SUCCESS" = "YES" ] ; then echo "$sensorId=$i $WYNIK" >> $LOG_DIR/DHT22.log DHT_CURR_TEMP=`echo $WYNIK | awk '{print $13}'` DHT_CURR_HUM=`echo $WYNIK | awk '{print $17}'` break fi sleep $SLEEP_TIME; done ## Wszystkie próby okazały się nieudane if [ $SUCCESS = "NO" ] ; then echo "$sensorId=? $WYNIK" >> $LOG_DIR/DHT22.log DHT_CURR_TEMP="999.9" DHT_CURR_HUM="999.9" fi } echo "@`date "+%Y%m%d%H%M%S"`" >> $LOG_DIR/DHT22.log ## Czujnik w pokoju: ReadSensor $SENSTYPE "24" READINGS="$DHT_CURR_TEMP $DHT_CURR_HUM" sleep 12 ## Czujnik na zewnątrz: ReadSensor $SENSTYPE "25" READINGS="$READINGS $DHT_CURR_TEMP $DHT_CURR_HUM" sleep 12 ## Czujnik weranda: ReadSensor $SENSTYPE "22" READINGS="$READINGS $DHT_CURR_TEMP $DHT_CURR_HUM" ## zamiana na HTML + wykres /usr/bin/perl /home/pi/bin/dht2ht.pl > /var/www/stats/DHT22.html # Wyslanie na google /home/pi/bin/DHT_googledocs.ex.py $READINGS
Podobnie jak w przypadku magistrali 1-Wire zdarzają się problemy
z odczytaniem wartości czujnika. Na tą okoliczność funkcja ReadSensor
próbuje
odczytu kilkukrotnie. Maksymalna nieudana liczba prób, którą zaobserwowałem
w ciągu kilkudniowej eksploatacji to 3.
Skrypt jest uruchamiany co 30 min przez crona:
1,31 * * * * /home/pi/bin/dht2ht.sh
Plik LOG
wygląda jakoś tak:
@20121113230101 24=1 Using pin #24 Data (40): 0x2 0x22 0x0 0xc9 0xed Temp = 20.1 *C, Hum = 54.6 % 25=1 Using pin #25 Data (40): 0x3 0xe7 0x0 0x1c 0x6 Temp = 2.8 *C, Hum = 99.9 % 22=4 Using pin #22 Data (40): 0x2 0x73 0x0 0xb0 0x25 Temp = 17.6 *C, Hum = 62.7 %
Wiersz zaczynający się od @
zawiera datę i czas
odczytu. Wiersze zaczynające się od nn=m zawierają odczytane
dane (nn to numer czujnika, m numer próby w której
odczytano wartości lub ?
jeżeli wszystkie próby były
nieudane)
Uwaga: zauważyłem, że przy intensywnych operacjach I/O są duże problemy z odczytaniem wskazań czujników.
Perlowy skrypt dht2ht.pl
tworzy tabelę oraz wykresy prezentujące odczytane
wartości plus obliczoną na ich podstawie
temperaturę punktu rosy.
Rezultat działania można
oglądać tutaj.
Omawiane w tym wpisie skrypty są
zaś tutaj.
Arkusz google.docs zawierający odczyty z moich trzech czujników jest
dostępny tutaj.
(Uwaga: z jakiś ważnych powodów skrypt Adafruit_DHT_googledocs.ex.py
zaczął dopisywanie
danych od 162 wiersza arkusza.)
W temacie kopii zapasowej na stronach poświęconych Raspberry Pi znaleźć można wyłącznie(?)
opisy jak to zrobić za pomocą dd
. Ten sposób nie podoba mi się
na dłużą metę z uwagi na czas -- kopiowanie karty 8Gb z kompresją przez sshfs zajęło
około 1 godziny. Tworzenie kopii przyrostowych (za pomocą rsync
) wydaje się lepszym pomysłem...
Załóżmy, że do /etc/fstab
wpisano:
/dev/disk/by-id/usb-WD_5000AAV_External_57442D574341535535303634313031-0:0-part1 \ /mnt/external-disk ext4 noauto,user,rw 0 0
Utworzenie kopii systemu sprowadza się wykonania:
rsync -av --exclude=/proc/ --exclude=/sys/ --exclude=/tmp/ \ --exclude=/mnt/ --exclude=/home/pi/Dist/ --delete / /mnt/external-disk/backup/rpi
Opcja --exclude
pomija wymienione pliki/katalogi. W szczególności należy
koniecznie umieścić tam katalogi, w których są/mogą być montowane inne systemy plików,
np. /mnt/
(uniknięcie pętli, bo przecież /mnt/
zawiera zamontowany dysk USB)
oraz /home/pi/Dist/
(moje zwyczajowe miejsce montowania systemów plików przez sshfs
)
Kopia systemu z raspberry będzie tworzona na innym komputerze dostępnym poprzez sieć.
Konfigurowanie rsynca
należy rozpocząć od jego zainstalowania na obu
komputerach (źródłowym i odbiorcy):
apt-get install rsync
Zawartość pliku /etc/rsyncd.conf
po stronie źródła (czyli raspberry):
uid = 0 gid = 0 hosts allow = 192.168.1.*** transfer logging = no read only = yes [wholefs] path = / comment whole root fs
W pliku /etc/default/rsync
(także po stronie źródła,
tj. raspberry) należy wpisać lub ,,odhaszować'':
RSYNC_ENABLE=true
Teraz trzeba wystartować rsync
(po ustawnieniu RSYNC_ENABLE
, rsync
będzie już uruchamiany
w momencie startu systemu -- nie potrzeba
do tego żadnych dodatkowych zabiegów w konfiguracji)
# /etc/init.d/rsync restart
Można sprawdzić czy działa
podając polecenie (moje raspberry nazywa się raspberrystar)
na komputerze odbiorcy (jako root
):
rsync raspberrystar::wholefs/
Jeżeli wszystko jest OK to wyświetlona zostanie zawartość katalogu /
na raspberrystar (czyli źródle).
Utworzenie kopii systemu sprowadza się wykonania:
rsync -av --exclude=/proc/ --exclude=/sys/ --exclude=/tmp/ \ --exclude=/mnt/ --exclude=/home/pi/Dist/ --delete \ raspberrystar::wholefs/ /public/sheeva/backup/raspberrystar/rootfs
W razie potrzeby kopia może być szybko przeniesiona na inną kartę SDHC.
# uwaga: nazwy katalogów odpowiadają wariantowi #2 tworzenia kopii: rsync -av --log-file=rsync_`date +%Y%m%d%H`.log --delete \ /public/sheeva/backup/raspberrystar/rootfs/ /public/sdX
Gdzie /public/sdX
oznacza miejsce zamontowania karty SDHC.
Karta musi być wcześniej sklonowana z ,,pierwszej'' kopii systemu wykonanej za pomocą dd
, tj.:
zcat sd_backup.img.gz > /dev/sdX
Teraz można gdybać czy użycie samego dd
nie będzie prostsze. Być może -- ja wolę korzystać
na co dzień z rsynca
.
Zauważyłem, że przy intensywnych operacjach I/O są problemy z odczytem
danych przez GPIO (temperatura/wilgotność).
Problem nie jest duży, ponieważ tworzenie pierwszej kopii systemu zajęło mi jakieś 20 min
(można się spodziewać, że kolejne będą tworzone w ciągu kilku minut),
ale dla większej pewności dodałem ionice
i --bwlimit
(specjalnie tego nie testując, oprócz sprawdzenia, że działa)
ionice -c3 rsync -av --bwlimit=500 --exclude=/proc/ --exclude=/sys/ --exclude=/tmp/ \ --exclude=/mnt/ --exclude=/home/pi/Dist/ --delete \ raspberrystar::wholefs/ /public/sheeva/backup/raspberrystar/rootfs
Jeżeli powyższe zapisane zostanie do skryptu, np. o nazwie backup_raspberry.sh
,
to teraz aby ten skrypt był uruchamiany raz na tydzień, np. w niedzielę o 4:00
należy wpisac do pliku crontab (na komputerze odbiorcy) coś takiego:
0 4 * * 7 /root/bin/backup_raspberry.sh >> /root/logs/RSync/RSync.log 2>&1
Poniższy opis w dużym stopniu jest oparty na tekście Raspberry Pi odczyt temperatury przez nodejs.
Czujniki temperatury DS18B20 firmy Dallas należy dołączyć do portu GPIO (styki P1, P4 oraz P7)
Do wykonania instalacji potrzeba:
Tzw. przewody połączeniowe żeńskie (4 zł za 10 sztuk); w oryginale to się nazywa jumper wire.
REZYSTOR 0,25W 4,7K OHM węglowy (1,50 zł za 100 sztuk).
DS18B20 termometr 1-wire (4,00--5,00 zł za sztukę).
Kostka elektryczna (około 3 zł za 10 sztuk).
Rurka termokurczliwa do izolacji i wzmocnienia połączeń.
Przewód telefoniczny czterożyłowy lub inny podobny.
Trzy wyprowadzenia układu DS18B20 to: masa (GND), linia danych (DQ) i zasilanie (Vdd). Jeżeli położymy układ ,,napisem do góry''/,,stykami do dołu'' (por. rys. #1), to pierwszy styk od lewj (#1) to GND, środkowy (#2) to DQ a prawy (#3) to Vdd.
Styki DQ oraz Vdd należy złączyć za pomocą rezystora 4K7 (4k7 ohm resistor).
Ja to zrobiłem w ten sposób, że obciąłem złącza żeńskie po jednej stronie przewodów połączeniowych i wsadziłem je do kostki elektrycznej. Następnie dolutowałem dwa kilkucentymetrowe przewody po obu stronach rezystora i końce tych przewodów wsadziłem do odpowiednich styków w kostce elektrycznej. W ten sposób połączyłem DQ oraz Vdd za pomocą rezystora (rys. #5).
Styki czujnika DS18B20 dolutowuję do poszczególnych żył przewodu telefonicznego (jedna żyła jest zbędna). Ponieważ DS18B20 jest bardzo mały, to żeby piny się nie stykały izoluję każdą żyłę cienką rurką termokurczliwą (por. zdjęcie #2, umieszczone obok). Żeby ładniej wyglądało, ale przede wszystkim żeby połączenie czujnik-kabel było mocniejsze (żyły są bardzo cienkie) to na cały przewód naciągam szerszą rurkę (por. zdjęcie #3) i też zgrzewam (por. zdjęcie #4). Zgrzewam zapalniczką....
Odpowiednie żyły przewodu telefonicznego z dolutowanym na końcu układem DS18B20 łączę z kostką. Wydaje mi się, że tak jest lepiej--można łatwiej dodać kolejny termometr lub wydłużyć przewód. Układ jest gotowy i można go podłączyć: Vdd do pina P1, GND do pina P4 a DQ do pina P7. Który pin jest P1 jest jasno oznaczone na płytce.
Moja instalacja ma dwa układy DS18B20: jeden do mierzenia temperatury w pokoju a drugi do mierzenia temperatury na zewnątrz (por. rysunek #5/schemat #6).
Aby Raspberry obsługiwał 1-Wire należy dokonać aktualizacji systemu, co można wykonać na kilka sposobów. Zgodnie z sugestią ze strony Raspberry Pi odczyt temperatury przez nodejs zdecydowałem się na Hexxeh's easy updater tool:
wget http://goo.gl/1BOfJ -O rpi-update sudo mv rpi-update /usr/bin/rpi-update sudo chmod +x /usr/bin/rpi-update # Na wszelki wypadek: sudo apt-get install ca-certificates # rpi-update wymaga zainstalowania gita sudo apt-get install git-core
Teraz można wykonać aktualizację (zabieg zawsze potencjalnie ryzykowny dlatego lepiej się zabezpieczyć wykonaniem kopii systemu, co opisano tutaj.)
pi@raspberrystar ~ $ sudo rpi-update Raspberry Pi firmware updater by Hexxeh, enhanced by AndrewS Performing self-update Autodetecting memory split Using ARM/GPU memory split of 192MB/64MB We're running for the first time Setting up firmware (this will take a few minutes) Using HardFP libraries If no errors appeared, your firmware was successfully setup A reboot is needed to activate the new firmware
Teraz należy dodać do jądra moduły niezbędne do obsługi instalacji pomiaru temperatury:
sudo modprobe w1-gpio sudo modprobe w1-therm
Uwaga: aby moduły były dodawana automatycznie, przy starcie systemu należy
dodać w1-gpio
oraz w1-therm
do pliku /etc/modules
.
Mój plik /etc/modules
wygląda następująco:
pi@raspberrystar ~ $ less /etc/modules snd-bcm2835 w1-gpio w1-therm
Po podłączeniu ,,magistrali 1-Wire'' (czytaj kabelków z czujnikami DS18B20
w opisany wyżej sposób) wykonanie polecenia ls
w katalogu /sys/bus/w1/devices/
powinno ujawnić urządzenia
dołączone do magistrali:
pi@raspberrystar ~ $ ls -l /sys/bus/w1/devices/ lrwxrwxrwx 1 root root 0 paź 3 13:45 w1_bus_master1 -> ../../../devices/w1_bus_master1 lrwxrwxrwx 1 root root 0 paź 3 13:58 28-0000032562aa -> ../../../devices/w1_bus_master1/28-0000032562aa lrwxrwxrwx 1 root root 0 paź 3 19:27 10-000802012743 -> ../../../devices/w1_bus_master1/10-000802012743
W przypadku mojej ,,magistrali'' są
to dwa termometry: 28-0000032562aa
oraz 10-000802012743
.
Do odczytania temperatury korzystamy z pliku w1_slave
:
pi@raspberrystar ~ $ cat /sys/bus/w1/devices/28-0000032562aa/w1_slave 60 01 4b 46 7f ff 10 10 b5 : crc=b5 YES 60 01 4b 46 7f ff 10 10 b5 t=22000
Wielkość temperatury to 22,000 stopnie Celsjusza (t=22000
).
Aby odczytać dwa termometry na raz, dodać datę i czas odczytu, a następnie
zapisać wszystko do pliku LOG można zastosować następujący
skrypt (,,prywatne'' skrypty umieszczam w katalogu ~/bin/
):
#!/bin/bash LOG_DIR=/home/pi/Logs/Digitemp ## Data/czas odczytu echo "@`date "+%Y%m%d%H%M%S"`" >> $LOG_DIR/digitemp.log ## Czujnik nr1 echo "28-0000032562aa `cat /sys/bus/w1/devices/28-0000032562aa/w1_slave | tr '\n' ' '`" >> $LOG_DIR/digitemp.log ## Czujnik nr2 echo "10-000802012743 `cat /sys/bus/w1/devices/10-000802012743/w1_slave | tr '\n' ' '`" >> $LOG_DIR/digitemp.log
Zapis wygląda jakoś tak (przy założeniu, że powyższy skrypt znajduje się w pliku ~/bin/dt2ht.sh
):
pi@raspberrystar ~ $ ~/bin/dt2ht.sh @20121004100001 28-0000032562aa 5f 01 4b 46 7f ff 01 10 9b : crc=9b YES 5f 01 4b 46 7f ff 01 10 9b t=21937 10-000802012743 1e 00 4b 46 ff ff 0d 10 38 : crc=38 YES 1e 00 4b 46 ff ff 0d 10 38 t=14937
Gdzie: @20121004100001
oznacza datę i czas,
28-0000032562aa
/10-000802012743
to identyfikatory
czujników a zapis w stylu t=21937
,
to temperatura (21,937 stopni Celsjusza).
Teraz wystarczy dodać odpowiedni wpis do pliku crontab
użytkownika pi
,
aby, przykładowo temperatura była rejestrowana
co godzinę (dt2ht.sh
to nazwa opisanego wyżej
skryptu służącego odczytu temperatury i zapisania wyników do pliku LOG):
pi@raspberrystar ~ $ mkdir ~/Crontab pi@raspberrystar ~ $ vi ~/Crontab/crontab # do pliku ~/Crontab/crontab wpisuję jeden wiersz: # 0 * * * * /home/pi/bin/dt2ht.sh # zapisuję/kończę pracę vi # dodanie zawartości ~/Crontab/crontab do zadań crona pi@raspberrystar ~ $ crontab ~/Crontab/crontab # sprawdzenie czy wszystko jest OK: pi@raspberrystar ~ $ crontab -l 0 * * * * /home/pi/bin/dt2ht.sh
Pozostaje tylko wykonanie (np. za pomocą prostego skryptu PeHaPe) jakiś bardziej efektownego sposobu wyświetlania zawartości pliku LOG.
Dopisane 14 października 2012: W zasadzie działa, ale nie do końca. Czasami nie odczytuje temperatury wypisując CRC error, co wygląda następująco:
62 01 4b 46 7f ff 0e 10 03 : crc=03 NO 62 01 4b 46 7f ff 0e 10 03 t=-1250
Nie mam pojęcia czemu tak się dzieje. Jako workaround wymyśliłem kilkukrotny odczyt:
#!/bin/bash LOG_DIR=/home/pi/Logs/Digitemp function ReadSensor() { local sensorId=$1 local WYNIK="" local SUCCESS="" ## próbuj odczytać max 3 razy for i in 1 2 3; do WYNIK=`cat /sys/bus/w1/devices/$sensorId/w1_slave | tr '\n' ' '` ## pole 12 ($12) to wynik odczytu (YES albo NO): SUCCESS=`echo $WYNIK | awk '{ print $12}'` if [ "$SUCCESS" = "YES" ] ; then ## zapisuje numer próby oraz odczytaną informację : echo "$sensorId=$i $WYNIK" >> $LOG_DIR/digitemp.log ## przerwij pętlę odczytano temperaturę: break fi sleep 3; done ## Trzy próby okazały się nieudane: if [ $SUCCESS = "NO" ] ; then echo "$sensorId=? $WYNIK" >> $LOG_DIR/digitemp.log fi } echo "@`date "+%Y%m%d%H%M%S"`" >> $LOG_DIR/digitemp.log ## Czujnik w pokoju: ReadSensor "28-0000032562aa" ## Czujnik na zewnątrz: ReadSensor "10-000802012743"
Plik LOG wygląda jakoś tak:
@20121014220001 28-0000032562aa=1 62 01 4b 46 7f ff 0e 10 03 : crc=03 YES 62 01 4b 46 7f ff 0e 10 03 t=22125 10-000802012743=1 0e 00 4b 46 ff ff 0f 10 fd : crc=fd YES 0e 00 4b 46 ff ff 0f 10 fd t=6812
gdzie pierwszy wyraz to numer sensora, znak równości, numer próby
w której odczytano temperaturę lub ?
, jeżeli temperatury nie
odczytano.
Ustalamy jak nazywa się urządzenie, w którym jest zamontowana karta SDHC:
pi@raspberrypi ~ $ sudo fdisk -l Disk /dev/mmcblk0: 7969 MB, 7969177600 bytes 4 heads, 16 sectors/track, 243200 cylinders, total 15564800 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x000108cb Device Boot Start End Blocks Id System /dev/mmcblk0p1 8192 122879 57344 c W95 FAT32 (LBA) /dev/mmcblk0p2 122880 15564799 7720960 83 Linux
Teraz można zamontować pendrive'a, na którym zostanie zapisana kopia:
pi@raspberrypi ~ $ mkdir /media/sda1 ## zakładamy że pendrive jest oznaczony jako /dev/sda1 pi@raspberrypi ~ $ mount /dev/sda1 /media/sda1
Kopiowanie za pomocą dd
pi@raspberrypi ~ $ sudo dd if=/dev/mmcblk0 | gzip -1 > /media/sda1/sd_backup.img.gz ## bez kompresji będzie szybciej: pi@raspberrypi ~ $ sudo dd if=/dev/mmcblk0 of=/media/sda1/sd_backup.img ## po sieci, w przypadku gdy nie mamy wolnego pendrive'a ktos@inny-komputer ~ $ sudo ssh root@raspberrystar dd if=/dev/mmcblk0 | gzip -1 | dd of=sd_backup.img.gz
Uwaga: raspberrystar
powinno być zamienione na odpowieni adres IP (lub nazwę).
Przywracanie systemu z kopii zapasowej:
pi@raspberrypi ~ $ zcat sd_backup.img.gz > /dev/sdX
Gdzie /dev/sdX
to nazwa urządzenia z zamontowaną czystą kartą SDHC.
Więcej szczegółów i bardziej detalicznie jest tutaj.
Kopiowanie do pliku zamontowanego za pomocą sshfs
:
pi@raspberrypi ~ $ sudo apt-get install sshfs fuse-utils pi@raspberrypi ~ $ mkdir -p ~/Dist/jupiter ## montuję (jako użytkownik tomek) zdalny katalog /public/raspberry na ## komputerze jupiter; punkt montowania to ~/Dist/jupiter pi@raspberrypi ~ $ sshfs tomek@jupiter:/public/raspberry/ ~/Dist/jupiter failed to open /dev/fuse: Permission denied # Za pierwszym strzałem (jak zwykle) nie wyszło, a to dlatego, że # wyłącznie członkowie grupy "fuse" mogą czytać/pisać do/na /dev/fuse. # Należy zatem dodać użytkownika pi do grupy "fuse": pi@raspberrypi ~ $ sudo usermod -a -G fuse pi ## Teraz trzeba się wy/zalogować żeby zadziałały modyfikacje w /etc/group pi@raspberrypi ~ $ sshfs tomek@jupiter:/public/raspberry/ ~/Dist/jupiter pi@raspberrypi ~ $ ls -l /home/pi/Dist/jupiter razem 0 ## kopiowanie za pomocą dd (z kompresją `w locie'): sudo dd if=/dev/mmcblk0 | gzip -1 > /home/pi/Dist/jupiter/raspberrystar.iso
Dopisane 3 października 2012: 15564800+0 przeczytanych recordów 15564800+0 zapisanych recordów skopiowane 7969177600 bajtów (8,0 GB), 3504,04 s, 2,3 MB/s
Kopiowanie karty 8Gb z kompresją przez sshfs zajęło około 1 godziny. Plik z kopią systemu zajmuje około 1,6Gb
Urządzenie kupiłem w firmie Farnell. Z dostawą z UK wyszło 180 PLN. Do tego obudowa za ca 30 PLN (do kupienia np. na ebay.pl na aukcjach firmy A1 Items Ltd. Akrylowe obudowy oferowane na allegro.pl nie podobają mi się) i ładowarka z wyjściem mikroUSB, też za 30 PLN. No i karta 8GB Toshiba (do kupienia np. na Allegro.pl), przetestowana w Sheevaplugza -- 43 PLN.
Razem jak widać około 300 PLN. Dla porównania, Sheevaplug (plus karta) = 600 PLN.
Zainstalowanie systemu jest tak proste jak:
1. Ściągnięcie obrazu karty:
[tomek@darkstar ~]$ wget http://downloads.raspberrypi.org/images/raspbian/2012-08-16-wheezy-raspbian/2012-08-16-wheezy-raspbian.zip [tomek@darkstar ~]$ sha1sum 2012-08-16-wheezy-raspbian.zip [tomek@darkstar ~]$ unzip 2012-08-16-wheezy-raspbian.zip
2. Nagranie obrazu:
[root@darkstar]# df -h ## wsadzamy kartę do czytnika kart ## w moim przypadku się okazało że system `widzi' kartę jako /dev/sdc1 [root@darkstar]# umount /dev/sdc1 ## w poniższym, koniecznie of=/dev/sdc a nie of=/dev/sdc1 [root@darkstar]# dd bs=1M if=2012-08-16-wheezy-raspbian.img of=/dev/sdc 1850+0 przeczytanych recordów 1850+0 zapisanych recordów skopiowane 1939865600 bajtów (1,9 GB), 499,495 s, 3,9 MB/s [root@darkstar]# sync
3. Powiększenie wielkości partycji w programie gparted
(dla kart
o pojemności większej od 2Gb):
[root@darkstar]# gparted
Za pierwszym razem nie poszło -- nie wiem czemu. Gparted odmawiał stanowczo
powiększenia partycji. Zamontowałem kartę niepowiększoną, uruchomiłem RPi, żeby sprawdzić
czy w ogóle działa (Rysunek 1).
Potem wyłączyłem urządzenie.
Dla świętego spokoju spróbowałem drugi raz z gparted
i tym razem poszło (Rysunek 2).
Połączyć się z RPi można przez ssh, ponieważ raspbian jest tak skonfigurowany, że demon ssh jest uruchamiany przy starcie systemu.
[tomek@darkstar ~]$ ssh -l pi 192.168.1.115
Aby dokończyć konfigurację zalecane jest uruchomienie raspi-config
:
pi@raspberrypi ~ $ sudo raspi-config
Narzędzie to pozwala na (por. rys. 3): 1) powiększenie partycji, 2) ustawienie klawiatury, 3) zmianę hasła użytkownika o nazwie pi, 4) zmianę locale, 5) zmianę strefy czasu, 6) zmianę podziału pamięci (domyślnie 64Mb z dostępnych 256 Mb jest wykorzystywane przez GPU), 7) włączanie/wyłączanie serwera ssh, 8) start systemu w trybie graficznym lub tekstowym (domyślne).
Z powyższych interesowało mnie jedynie 2--5, reszta jest albo wykonana
(punkt jeden wykonałem za pomocą gparted
) albo domyślne nastawy mnie satysfakcjonują
(serwer ssh chcę mieć włączony, start systemu ma być w trybie tekstowym). Narzędzie
raspi-config
można uruchomić zresztą w każdej chwili.
Ponieważ wiem jak ustawić klawiaturę, locale, zmienić strefę czasu oraz hasło
w Debianie ,,tak w ogóle'', bez uciekania się do konfiguratorów, ostatecznie
nie uruchamiałem raspi-config
, tylko wykonałem następujące polecenia:
pi@raspberrypi ~ $ sudo apt-get update pi@raspberrypi ~ $ sudo apt-get install debconf ## zmiana stefy czasowej pi@raspberrypi ~ $ sudo dpkg-reconfigure tzdata ## zmiana locale na pl_PL.UTF-8 pi@raspberrypi ~ $ sudo dpkg-reconfigure locales ## zmiana hasła: pi@raspberrypi ~ $ sudo passwd pi ## klawiatura (nie przewiduję na razie podłączenia klawiatury) pi@raspberrypi ~ $ sudo vi /etc/default/keyboard
Instalowanie serwera apache
pi@raspberrypi ~ $ sudo groupadd www-data groupadd: group 'www-data' already exists pi@raspberrypi ~ $ sudo apt-get install apache2
Instalowanie serwera MySQL
pi@raspberrypi ~ $ sudo apt-get install mysql-server mysql-client php5-mysql
Instalowanie PHP
pi@raspberrypi ~ $ sudo sudo apt-get install php5-cgi php5-mysql \ php5-curl php5-gd php5-idn php-pear php5-imagick php5-imap \ php5-mcrypt php5-memcache php5-mhash php5-ming php5-pspell \ php5-recode php5-snmp php5-sqlite php5-tidy php5-xmlrpc \ php5-xsl php5-fpm php5-cgi php5-cli php5-common
Instalowanie różnych przydatnych rzeczy:
pi@raspberrypi ~ $ sudo apt-get install fuse-utils pi@raspberrypi ~ $ sudo apt-get install make zip unzip ## digitemp -- program do obsługi sensorów temperatury DS18B20 pi@raspberrypi ~ $ sudo apt-get install digitemp pi@raspberrypi ~ $ sudo apt-get install vim pi@raspberrypi ~ $ sudo apt-cache search emacs | grep 23 pi@raspberrypi ~ $ sudo apt-get install emacs23-nox
Apache działa o czym świadczy rysunek 4.
Sprawdzam też czy demon ntpd (synchronizacja czasu) jest uruchomiony:
ps aux | grep ntpd ntp 1840 0.0 0.8 5424 1544 ? \ Ss 20:04 0:03 /usr/sbin/ntpd -p /var/run/ntpd.pid -g -u 102:104
Okazuje się, że jest...
Dopisane 18 września 2012: Zainstalowałem TeXa i zrobiłem test pt. jak szybki jest RPI. Otóż kompilacja dokumentu o objętości 150 stron zajmuje na RPi (real) 0m36.751s. Ten sam dokument na moim PC 0m2.541s, czyli 14,4 raza szybciej:-)