Pages

Monday 4 January 2016

Raspberry PI Temperature Sensor

The Raspberry Pi (PI) is pretty nifty little device. I have done various programming projects with it over the past seven to nine months. A few days ago a had a strong drive to experiment with the PI's GPIO interface and connect a heat sensors to measure temperatures.

This project comprises of three distinct phases namely: a) Electronics Circuitry, b) Software Development and c) Testing and Integration.

a) Electronics Circuitry (EC): The EC phase entails the assembly of the temperature components as a complete unit onto the breadboard. One of the Dallas sensor is placed directly on the breadboard, The second sensor is wired on the other end of the ethernet cable.
b) Software Development (SD): The SD phase entails preparing the suitable software application to control and manage the EC assembly. Various option exist which languages could be used to develop an application to read, process and store temperature readings. Python is an excellent choice and probably the easiest. However, I am Pascal kind of person both on Windows and Linux operating systems.
Bear in mins that in the absence of any form of a software package, the PI is not able to make any temperature readings, even if the sensors are connected correctly to the GPIO pins. My SD environment is as follows:
  • Free Pascal compiler in CLI mode to develop an executable that takes readings from the senors.
  • Sqlite 3 database to store the temperature readings as per the FPC CLI program.
  • A cron job to run the FPC program every 5 minutes.
c) Testing and Integration (T&I): TI in essence means integrating the EC and SD components into a single functional module.
My bill of materials was:
  • 1x Raspberry Pi 2 B (including PSU, card and box).
  • 2x Dallas DS18B20 temperature sensors.
  • 1x 4K7 Ω resistor.
  • 1x Breadboard.
  • A dozen male to female jumper wires.
  • 1x 3m long UTP ethernet cable.

The final assembly is illustrated in the image below:
Raspberry PI with Temperature sensors on a Breadboard
The sensor on the ethernet cable is temporarily placed outside a room to measure the outdoor temperatures while the breadboard is placed indoors. Below is an extract form the temperature log file (csv formatted with the temperature in celsius degrees being the last 3 characters): 
2016-01-04 00:00:01,28-000006df1322,27.5
2016-01-04 00:00:02,28-0000059a01ed,22.7
2016-01-04 00:05:02,28-000006df1322,27.5
2016-01-04 00:05:03,28-0000059a01ed,22.6
2016-01-04 00:10:02,28-000006df1322,27.5
2016-01-04 00:10:03,28-0000059a01ed,22.6
2016-01-04 00:15:02,28-000006df1322,27.5
2016-01-04 00:15:03,28-0000059a01ed,22.4
2016-01-04 00:20:02,28-000006df1322,27.4
2016-01-04 00:20:03,28-0000059a01ed,22.4
The listing below comprises the complete Pascal program used to read and store temperature readings into  Sqlite 3 database table:
program tempsensors;

{$mode objfpc}

uses Classes, SysUtils, db, sqlite3ds;

const appVersion = '0.1';

var sl       : TStringlist;
    rows     : integer;
    temp     : string;
    slDevs   : TStringlist; //devicesList
    i        : integer;
    devCount : integer;
    devFile  : string;

    logOutput : string;

    dsTempLog : TSqlite3Dataset;
    sqlstr  : string;

function parseTemperature(tempStr: string):string;
{*
 Function parses and returns a temperature value from the given string tempStr.
 tempStr = temperature string.
*}
var
    x : integer;   //index used to parse temperature value in a string.
    c : integer;   //temperature reading in celsius.
    f : real;      //temperature value / 1000.

begin
 result := '';

 if tempStr = '' then
 exit;

 x := pos('=', tempStr) + 1;

 begin
   c := strtoint(copy(tempStr,x,5));
   f := c/1000;

   result := floatToStrF(f,ffFixed,2,1);
 end;
end;


function logDateStamp:string;
var current : TDateTime;
begin
 current := now;

 result := formatDateTime('YYYY/MM/DD hh:mm:ss', current);
end;


procedure logToTextFile(aFn, aLogdata: string);
var fh : TextFile;   //filename to log to.
begin
 assignFile(fh,aFn);

 if not fileExists(aFn) then
 begin
   rewrite(fh);
 end
 else
 begin
   append(fh);
 end;

 try
   writeln(fh,aLogData);
 finally
   closeFile(fh)
 end;
end;

begin {begin of main program.}

// writeln('Script started by user.');
// writeln('Hello Pascal on Raspberry Pi.');


 //Exit this program if prescribed file does not exists:
 if not fileExists('/home/pi/progs/pascal/sensorDevices.txt') then
 begin
   writeln('Alert: Error in opening the sensor devices descriptor file.');
   exit;
 end;


 //Load into the devces stringlist a text file that contains declared sensor devices:
 slDevs := TStringlist.create;

 dsTemplog := TSqlite3Dataset.create(nil);
 dsTemplog.Filename   := '/home/pi/progs/pascal/templog.db';
 dsTemplog.Tablename  := 'temps';
 dsTemplog.PrimaryKey := 'id';

 try
   slDevs.loadfromfile('/home/pi/progs/pascal/sensorDevices.txt');

   devCount := slDevs.count;

   //Declare String list that will hold conrtents of sensor device w1_slave file contents:
   sl := TStringlist.create;


   try
      //Iterate through each device file name
      for i := 0 to devCount-1 do
      begin
         logOutput := '';

         devFile := '/sys/bus/w1/devices/' + slDevs[i] + '/w1_slave';

         if not fileexists(devFile) then
         begin
            writeln('Alert: Sensor device system file not found.');
            exit;
         end;

         //Load fiel contents of w1_slave file to extract the temperature:
         sl.loadfromfile(devFile);

         rows := sl.count;

         //Display temperature log reading if prescribed conditions are met, else display error message.
         if (rows = 2) and (pos('YES', sl[0]) > 0)  then
         begin
            temp := sl[1];
            writeln('Processing  device with index : [' + inttostr(i) + ']. Row count: ' + inttostr(rows));
            logOutput := logDateStamp + ',' + slDevs[i] + ',' + parseTemperature(temp);

            writeln(logOutput);

            try
{               sqlstr := 'insert into temps (date_log,device_id,temp) ' +
                         'values ' +
                         '(%f, ''%s'', %f)';
}

               //Construct the SQL insert statement
               sqlstr := 'INSERT INTO temps ' +
                         '(date_log,device_id, temp) ' +
                         'VALUES '+
                         '('''+logDateStamp+''','+''''+slDevs[i]+''','+''''+parseTemperature(temp)+''')';

//               dsTemplog.sql := Format(sqlstr, [logDateStamp, slDevs[i], parseTemperature(temp)]);
//               dsTemplog.sql := Format(sqlstr, ['2016-01=03 10:00:00', slDevs[i], '28.0']);
               dsTemplog.sql := sqlstr;
               dsTemplog.ExecSql;
            except
              writeln('Alert: Error in inserting data to the DB table with sql statement:');
              writeln(sqlstr);
            end;

            logToTextFile('/home/pi/progs/pascal/tempreadings.log',logOutput);
         end
         else
         begin
            writeln('Alert: Temperature string not found');
          end;
      end;
   finally
      sl.free;
   end;
 finally
   dsTemplog.free;
   slDevs.free;
 end;

end.
Going forward my intention is to:
  • Duplicate the project on a Raspberry PI Zero.
  • Add a dozen more DS18B20 temperature sensors.
  • Provide environmental proofing of the sensors.
  • Develop a web portal that accesses the Sqlite table for display and control capabilities.

No comments:

Post a Comment