Since this post is a snapshot in time. I recommend that you download a copy of the book which is updated frequently to improve and expand the content.
---------------------------------------
This is the second of three posts working through a project looking at Measuring Recording and Exploring temperature measurements with the Raspberry Pi.
Record the temperature values
The following Python code (which is based on the code that is part of the great temperature sensing tutorial on iot-project) is a script which allows us to check the temperature reading from multiple sensors and write them to our database with a separate entry for each sensor.
The full code can be found in the code samples bundled with this book (m_temp.py).
#!/usr/bin/python
# -*- coding: utf-8 -*-
import
os
import
fnmatch
import
time
import
MySQLdb
as
mdb
import
logging
logging
.
basicConfig
(
filename
=
'/home/pi/DS18B20_error.log'
,
level
=
logging
.
DEBUG
,
format
=
'
%(asctime)s
%(levelname)s
%(name)s
%(message)s
'
)
logger
=
logging
.
getLogger
(
__name__
)
# Load the modules (not required if they are loaded at boot)
# os.system('modprobe w1-gpio')
# os.system('modprobe w1-therm')
# Function for storing readings into MySQL
def
insertDB
(
IDs
,
temperature
):
try
:
con
=
mdb
.
connect
(
'localhost'
,
'pi_insert'
,
'xxxxxxxxxx'
,
'measurements'
);
cursor
=
con
.
cursor
()
for
i
in
range
(
0
,
len
(
temperature
)):
sql
=
"INSERT INTO temperature(temperature, sensor_id)
\
VALUES ('
%s
', '
%s
')"
%
\
(
temperature
[
i
],
IDs
[
i
])
cursor
.
execute
(
sql
)
sql
=
[]
con
.
commit
()
con
.
close
()
except
mdb
.
Error
,
e
:
logger
.
error
(
e
)
# Get readings from sensors and store them in MySQL
temperature
=
[]
IDs
=
[]
for
filename
in
os
.
listdir
(
"/sys/bus/w1/devices"
):
if
fnmatch
.
fnmatch
(
filename
,
'28-*'
):
with
open
(
"/sys/bus/w1/devices/"
+
filename
+
"/w1_slave"
)
as
f_obj
:
lines
=
f_obj
.
readlines
()
if
lines
[
0
]
.
find
(
"YES"
):
pok
=
lines
[
1
]
.
find
(
'='
)
temperature
.
append
(
float
(
lines
[
1
][
pok
+
1
:
pok
+
6
])
/
1000
)
IDs
.
append
(
filename
)
else
:
logger
.
error
(
"Error reading sensor with ID:
%s
"
%
(
filename
))
if
(
len
(
temperature
)
>
0
):
insertDB
(
IDs
,
temperature
)
This script can be saved in our home directory (
/home/pi
) and can be run by typing;
While we won’t see much happening at the command line, if we use our web browser to go to the phpMyAdmin interface and select the ‘measurements’ database and then the ‘temperature’ table we will see a range of temperature measurements for the different sensors and their associated time of reading.
Now you can be forgiven for thinking that this is not going to collect the sort of range of data that will let us ‘Explore’ very much, but let’s do a quick explanation of the Python code first and then we’ll work out how to record a lot more data :-).
Code Explanation
The script starts by importing the modules that it’s going to use for the process of reading and recording the temperature measurements;
import
os
import
fnmatch
import
time
import
MySQLdb
as
mdb
import
logging
Python code in one module gains access to the code in another module by the process of importing it. The
import statement invokes the process and combines two operations; it searches for the named module, then it binds the results of that search to a name in the local scope. |
Then the code sets up the
logging
module. We are going to use the basicConfig() function to set up the default handler so that any debug messages are written to the file /home/pi/DS18B20_error.log
.logging
.
basicConfig
(
filename
=
'/home/pi/DS18B20_error.log'
,
level
=
logging
.
DEBUG
,
format
=
'
%(asctime)s
%(levelname)s
%(name)s
%(message)s
'
)
logger
=
logging
.
getLogger
(
__name__
)
Later in the section where we are getting our readings or writing to the database we write to the log file if there is an error.
The program can then issues the
modprobe
commands that start the interface to the sensor;# os.system('modprobe w1-gpio')
# os.system('modprobe w1-therm'))
Our code has them commented out since we have already edited the
/etc/modules
file, but if you didn’t want to start the modules at start-up (for whatever reasons), you can un-comment these.
We then declare the function that will insert the readings into the MySQL database;
def
insertDB
(
IDs
,
temperature
):
try
:
con
=
mdb
.
connect
(
'localhost'
,
'pi_insert'
,
'xxxxxxxxxx'
,
'measurements'
);
cursor
=
con
.
cursor
()
for
i
in
range
(
0
,
len
(
temperature
)):
sql
=
"INSERT INTO temperature(temperature, sensor_id)
\
VALUES ('
%s
', '
%s
')"
%
\
(
temperature
[
i
],
IDs
[
i
])
cursor
.
execute
(
sql
)
sql
=
[]
con
.
commit
()
con
.
close
()
except
mdb
.
Error
,
e
:
logger
.
error
(
e
)
This is a neat piece of script that uses arrays to recall all the possible temperature and ID values.
Then we have the main body of the script that finds all our possible sensors and reads the IDs and the temperatures;
temperature
=
[]
IDs
=
[]
for
filename
in
os
.
listdir
(
"/sys/bus/w1/devices"
):
if
fnmatch
.
fnmatch
(
filename
,
'28-*'
):
with
open
(
"/sys/bus/w1/devices/"
+
filename
+
"/w1_slave"
)
as
f_obj
:
lines
=
f_obj
.
readlines
()
if
lines
[
0
]
.
find
(
"YES"
):
pok
=
lines
[
1
]
.
find
(
'='
)
temperature
.
append
(
float
(
lines
[
1
][
pok
+
1
:
pok
+
6
])
/
1000
)
IDs
.
append
(
filename
)
else
:
logger
.
error
(
"Error reading sensor with ID:
%s
"
%
(
filename
))
if
(
len
(
temperature
)
>
0
):
insertDB
(
IDs
,
temperature
)
After declaring our two arrays
temperature
and IDs
we start the for loop that checks all the file names in /sys/bus/w1/devices
;for
filename
in
os
.
listdir
(
"/sys/bus/w1/devices"
):
If it finds a filename that starts with
28-
then it processes it; if
fnmatch
.
fnmatch
(
filename
,
'28-*'
):
First it opens the
w1_slave
file in the 28-*
directory… with
open
(
"/sys/bus/w1/devices/"
+
filename
+
"/w1_slave"
)
as
f_obj
:
… then it pulls out the lines in the file;
lines
=
f_obj
.
readlines
()
If it finds the word “YES” in the first line (line 0) of the file…
if
lines
[
0
]
.
find
(
"YES"
):
…then it uses the position of the equals (=) sign in the second line (line 1)…
pok
=
lines
[
1
]
.
find
(
'='
)
… to pull out the characters following the ‘=’, and manipulate them to form the temperature in
degrees Centigrade;
degrees Centigrade;
temperature
.
append
(
float
(
lines
[
1
][
pok
+
1
:
pok
+
6
])
/
1000
)
We then add the filename to the IDs array;
IDs
.
append
(
filename
)
If we didn’t find a “yes” in the first line we log the error in the log file
logger
.
error
(
"Error reading sensor with ID:
%s
"
%
(
filename
))
Then finally if we have been successful in reading at least one temperature value, we push the
IDs
and temperature
array to the insertDB
function;if
(
len
(
temperature
)
>
0
):
insertDB
(
IDs
,
temperature
)
Recording data on a regular basis with cron
As mentioned earlier, while our code is a thing of beauty, it only records a single entry for each sensor every time it is run.
What we need to implement is a schedule so that at a regular time, the program is run. This is achieved using
cron
via the crontab
. While we will cover the requirements for this project here, you can read more about the crontab
in the Glossary.
To set up our schedule we need to edit the
crontab
file. This is is done using the following command;
Once run it will open the crontab in the nano editor. We want to add in an entry at the end of the file that looks like the following;
*/1 * * * * /usr/bin/python /home/pi/m_temp.py
This instructs the computer that exert minute of every hour of every day of every month we run the command
/usr/bin/python /home/pi/m_temp.py
(which if we were at the command line in the pi home directory we would run as python m_temp.py
, but since we can’t guarantee where we will be when running the script, we are supplying the full path to the python
command and the m_temp.py
script.
Save the file and the next time the computer boots up is will run out program on its designated schedule and we will have sensor entries written to our database every minute.
The post above (and heaps of other stuff) is in the book 'Raspberry Pi: Measure, Record, Explore' that can be downloaded for free (or donate if you really want to :-)).
No comments:
Post a Comment