Raspberry Pi. Sensor de temperatura. Domòtica

De Wikijoan
Dreceres ràpides: navegació, cerca

Contingut

Sensor de temperatura digital: DS18B20

Els pins GPIO de la RP són digitals (a diferència de l'Arduino que tens entrades analògiques). Per tant, si es vol utilitzar un sensor de temperatura analògic com ara el LM35, és necessair un ADC (hi ha gent que ho ha fet així). Ara bé, si es disposa d'un sensor digital com el DS18B20, aleshores la part d'electrònica és molt simple.

La temperatura es pot llegir directament d'un fitxer:

$ sudo modprobe w1-gpio
$ sudo modprobe w1-therm
$ cd /sys/bus/w1/devices/
$ ls
$ cd 10-000802824e58 -> aquest és el id del dispositiu
$ cat w1_slave

Instal.lació i configuració CouchDB

El couchdb s'instal.la a la RP igual que a ubuntu.

$ sudo apt-get install couchdb

$ curl http://localhost:5984
{"couchdb":"Welcome","version":"1.2.0"}

curl és una utilitat de línia de comandes (similar a wget, però no descarrega el fitxer, el visualitza)

Vull accedir des d'un portàtil al couchdb que hi ha a la RP. He de permetre accedir-hi des d'una IP diferent de localhost. Comento la línia:

# joe /etc/couchdb/default.ini
# bind 127.0.0.1

$ sudo /etc/init.d/couchdb restart
[ ok ] Restarting database server: couchdb.

i ara ja puc accedir-hi des del portàtil:


Let's create a database:

curl -X PUT http://127.0.0.1:5984/rptemp
mozilla: http://http://192.168.7.13:5984/rtemp

http://192.168.7.13:5984/_utils/index.html

Ja tenim creada la base de dades, i per fer uns inserts el que s'ha de fer és editar el fitxer json. L'estructura del meu fitxer que emmagatzemarà les dades de la temperatura serà similar a:

{
   "_id": "70472b7aa68ec91589ddfc9c28419ac7",
   "_rev": "1-e9cb5eaf54ee197b56edecbd9b4322e4",
   "valor": [
      {"id_temp": 1, "temp": 22.34, "dia_hora": "16/05/2013 16:00" },
      {"id_temp": 2, "temp": 23.34, "dia_hora": "16/05/2013 16:30" },
      {"id_temp": 3, "temp": 24.34, "dia_hora": "16/05/2013 17:00" }
   ]
}

A partir d'aquí tenim un objectiu doble. Primer, des d'un script python, poder fer inserts de les mostres de temperatura en el couchdb. Segon, des de PHP, poder llegir les mostres de temperatura i fer alguna cosa similar a una select.

CouchDB i PHP

Volem treballar amb couchdb des de php. Necessitem una llibreria. Descarreguem couchdb-0.0.2:

primer de tot:

$ sudo apt-get install curl php5-curl
$ sudo apt-get install libcurl4-gnutls-dev

I ja ho puc instal.lar amb pecl:

$ sudo pecl install couchdb-0.0.2a.tgz

Add "extension=couchdb.so" to your php.ini file:

/etc/php5/apache2/php.ini

també es pot instal.lar des de les fonts:

$ phpize && ./configure && make && make install

ara toca parsejar el document json

prova_couchdb2.php:

<?php

 $options['host'] = "192.168.7.13";  //localhost
 $options['port'] = 5984;

 $couch = new CouchSimple($options); // See if we can make a connection
 $resp = $couch->send("GET", "/"); 
 var_dump($resp); // response: string(46) "{"couchdb": "Welcome", "version": "0.7.0a553"}"

 // Get a list of all databases in CouchDb 
 $resp = $couch->send("GET", "/_all_dbs"); 
 var_dump($resp); // string(17) "["test_suite_db"]" 

 // Get all documents in test again, seing doc 123 there
 $resp = $couch->send("GET", "/rptemp/_all_docs"); 
 var_dump($resp); // string(91) "{"total_rows":1,"offset":0,"rows":[{"id":"123","key":"123","value":{"rev":"2039697587"}}]}" 

 // Get back document with the id 123
 $resp = $couch->send("GET", "/rptemp/70472b7aa68ec91589ddfc9c28419ac7"); 
 var_dump($resp); // string(47) "{"_id":"123","_rev":"2039697587","data":"Foo"}" 

 class CouchSimple {
    function CouchSimple($options) {
       foreach($options AS $key => $value) {
          $this->$key = $value;
       }
    } 
   
   function send($method, $url, $post_data = NULL) {
      $s = fsockopen($this->host, $this->port, $errno, $errstr); 
      if(!$s) {
         echo "$errno: $errstr\n"; 
         return false;
      } 

      $request = "$method $url HTTP/1.0\r\nHost: $this->host\r\n"; 

      if ($this->user) {
         $request .= "Authorization: Basic ".base64_encode("$this->user:$this->pass")."\r\n"; 
      }

      if($post_data) {
         $request .= "Content-Length: ".strlen($post_data)."\r\n\r\n"; 
         $request .= "$post_data\r\n";
      } 
      else {
         $request .= "\r\n";
      }

      fwrite($s, $request); 
      $response = ""; 

      while(!feof($s)) {
         $response .= fgets($s);
      }

      list($this->headers, $this->body) = explode("\r\n\r\n", $response); 
      return $this->body;
   }
}
?>

I el resultat:

string(40) "{"couchdb":"Welcome","version":"1.2.0"} " string(159) "["_replicator","_users","blog","rptemp","test_database","test_suite_db_c","test_suite_foobar","test_suite_rep_db","test_suite_rep_db_a","test_suite_rep_db_b"] " string(177) "{"total_rows":1,"offset":0,"rows":[ {"id":"70472b7aa68ec91589ddfc9c28419ac7","key":"70472b7aa68ec91589ddfc9c28419ac7","value":{"rev":"5-2f1747901074707ba4e89e9e57ccc919"}} ]} " string(239) "{"_id":"70472b7aa68ec91589ddfc9c28419ac7","_rev":"5-2f1747901074707ba4e89e9e57ccc919","valors":[{"temp":"22.33","dia_hora":"16/05/2013 12:00"},{"temp":"23.33","dia_hora":"16/05/2013 13:00"},{"temp":"24.33","dia_hora":"16/05/2013 14:00"}]} "

Veiem que ja estic llegint les temperatures, però clar, en format json.

Ara volem llegir només les temperatures:

prova_couchdb3.php:

<?php

 $options['host'] = "192.168.7.13"; //localhost
 $options['port'] = 5984;

 $couch = new CouchSimple($options);

 // Get back document with the id 123
 $json_temps = $couch->send("GET", "/rptemp/70472b7aa68ec91589ddfc9c28419ac7"); 
 //var_dump($json_temps);

//http://stackoverflow.com/questions/6964403/parsing-json-with-php
$json = json_decode($json_temps, true);

foreach($json['valor'] as $item) {
    echo 'id_temp: ' . $item['id_temp'] . '<br />';
    echo 'Temp: ' . $item['temp'] . '<br />';
    echo 'Dia_hora: ' . $item['dia_hora'] . '<br />';
}


class CouchSimple {
    function CouchSimple($options) {
       foreach($options AS $key => $value) {
          $this->$key = $value;
       }
    } 
   
   function send($method, $url, $post_data = NULL) {
      $s = fsockopen($this->host, $this->port, $errno, $errstr); 
      if(!$s) {
         echo "$errno: $errstr\n"; 
         return false;
      } 

      $request = "$method $url HTTP/1.0\r\nHost: $this->host\r\n"; 

      if ($this->user) {
         $request .= "Authorization: Basic ".base64_encode("$this->user:$this->pass")."\r\n"; 
      }

      if($post_data) {
         $request .= "Content-Length: ".strlen($post_data)."\r\n\r\n"; 
         $request .= "$post_data\r\n";
      } 
      else {
         $request .= "\r\n";
      }

      fwrite($s, $request); 
      $response = ""; 

      while(!feof($s)) {
         $response .= fgets($s);
      }

      list($this->headers, $this->body) = explode("\r\n\r\n", $response); 
      return $this->body;
   }
}
?>

i el resultat:

id_temp: 1
Temp: 22.34
Dia_hora: 16/05/2013 16:00
id_temp: 2
Temp: 23.34
Dia_hora: 16/05/2013 16:30
id_temp: 3
Temp: 24.34
Dia_hora: 16/05/2013 17:00

Donada la llista de temperatures, ara ja podem filtrar per mes, buscar la temperatura màxima d'un dia, la temperatura màxima del mes, etc. Tot això s'haurà de fer per PHP, i es pot tenir una llibreria de funcions que ens donguin les operacions més habituals.

CouchDB i Python

$ sudo apt-get install python-couchdb
$ sudo apt-get install python-dev

Get a local copy of the couchdb-python repository with this command:

$ sudo apt-get install mercurial
$ hg clone https://code.google.com/p/couchdb-python/ 

$ cd couchdb-python/

I ja podem operar amb couchdb des de la consola de python:

$ cd couchdb-python

(operem des del directori couchdb-python/)

$ python
Python 2.7.3 (default, Aug  1 2012, 05:16:07) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.

>>> import couchdb
couchdb/__init__.py:14: UserWarning: Module couchdb was already imported from couchdb/__init__.py, but /usr/lib/python2.7/dist-packages is being added to sys.path
  __version__ = __import__('pkg_resources').get_distribution('CouchDB').version

>>> couch = couchdb.Server('http://localhost:5984/')
>>> db = couch.create('test')
>>> db = couch['test']
>>> doc = {'foo': 'bar'}

>>> db.save(doc)
('70472b7aa68ec91589ddfc9c28419ac7', '1-4c6114c65e295552ab1019e2b046b10e')

>>> doc
{'_rev': '1-4c6114c65e295552ab1019e2b046b10e', 'foo': 'bar', '_id': '70472b7aa68ec91589ddfc9c28419ac7'}

>>> db['70472b7aa68ec91589ddfc9c28419ac7']
<Document '70472b7aa68ec91589ddfc9c28419ac7'@'1-4c6114c65e295552ab1019e2b046b10e' {'foo': 'bar'}>

ja puc llegir el fitxer de temperatures:

>>> import couchdb
>>> couch = couchdb.Server('http://localhost:5984/')
>>> db = couch['rptemp']
>>> db['70472b7aa68ec91589ddfc9c28419ac7']
<Document '70472b7aa68ec91589ddfc9c28419ac7'@'2-9fe12e3e23c618fa3be8ba47def88048' {'valor': [{'id_temp': 1, 'temp': 22.34, 'dia_hora': '16/05/2013 16:00'}, {'id_temp': 2, 'temp': 23.34, 'dia_hora': '16/05/2013 16:30'}, {'id_temp': 3, 'temp': 24.34, 'dia_hora': '16/05/2013 17:00'}]}>

Treballant amb la consola:

>>> db['70472b7aa68ec91589ddfc9c28419ac7']

>>> doc=db['70472b7aa68ec91589ddfc9c28419ac7']
>>> doc
<Document '70472b7aa68ec91589ddfc9c28419ac7'@'2-9fe12e3e23c618fa3be8ba47def88048' {'valor': [{'id': 1, 'temp': 22.34, 'dia_hora': '16/05/2013 16:00'}, {'id': 2, 'temp': 23.34, 'dia_hora': '16/05/2013 16:30'}, {'id': 3, 'temp': 24.34, 'dia_hora': '16/05/2013 17:00'}]}>
>>> doc.id
'70472b7aa68ec91589ddfc9c28419ac7'
>>> doc.rev
'2-9fe12e3e23c618fa3be8ba47def88048'

>>> doc['valor']
[{'id': 1, 'temp': 22.34, 'dia_hora': '16/05/2013 16:00'}, {'id': 2, 'temp': 23.34, 'dia_hora': '16/05/2013 16:30'}, {'id': 3, 'temp': 24.34, 'dia_hora': '16/05/2013 17:00'}]

>>> doc['valor'][0]
{'id': 1, 'temp': 22.34, 'dia_hora': '16/05/2013 16:00'}

>>> doc['valor'][3]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

>>> doc['valor'][0]['temp']
22.34

>>> doc['valor'][0]['temp']=25
>>> doc.update()
>>> doc['valor'][0]['temp']
25

Afegir una nova mostra de temperatura

$ python
import couchdb
couch = couchdb.Server('http://localhost:5984/')
db = couch['rptemp']
db['70472b7aa68ec91589ddfc9c28419ac7']

from datetime import datetime
from couchdb.mapping import Document, TextField, IntegerField, DecimalField, DateTimeField
from couchdb.mapping import ListField, DictField, Mapping

class Mostra(Document):
   valor = ListField(DictField(Mapping.build(
      id = IntegerField(),
      temp = DecimalField(),
      dia_hora = DateTimeField(default=datetime.now)
   )))


mostra = Mostra.load(db, '70472b7aa68ec91589ddfc9c28419ac7')
mostra.valor.append(id=4, temp=42)
mostra.store(db) 
mostra.valor.append(id=5, temp=20.3)
mostra.valor.append(id=6, temp=22.44)
mostra.valor.append(id=7, temp=23.43)
mostra.store(db) 

i efectivament s'ha afegit totes aquestes mostres.

I ara el que s'ha de fer és un script python per escriure les temperatures a la base de dades rptemp.

Llegint la temperatura del sensor

$  cat /sys/bus/w1/devices/28-000004404eb3/w1_slave
b2 01 4b 46 7f ff 0e 10 8c : crc=8c YES
b2 01 4b 46 7f ff 0e 10 8c t=23125

La temperatura és de 23.12C

Script de python per gravar les temperatures

Les funcions d'aquest script seran:

Aquest script residirà en la carpeta couchdb-python.

prova1.py:

import datetime
import string
import couchdb

couch = couchdb.Server('http://localhost:5984/')
db = couch['rptemp']

now = datetime.datetime.now()

print now.strftime("%d/%m/%Y %H:%M")

ins = open( "mostra_temp.txt", "r" )
array = []
for line in ins:
    array.append( line )
    
#print line
line2=string.find(line,'t=')
#print line[line2]
#print line[line2+2:]
temp=string.atof(line[line2+2:])/1000
print 'temperatura: '+str(temp)

doc=db['70472b7aa68ec91589ddfc9c28419ac7']
id_temp = len(doc['valor'])

prova2.py:

from datetime import datetime
from couchdb.mapping import Document, TextField, IntegerField, DecimalField, DateTimeField
from couchdb.mapping import ListField, DictField, Mapping

import datetime
import string
import couchdb
   
couch = couchdb.Server('http://localhost:5984/')
db = couch['rptemp']


ins = open( "mostra_temp.txt", "r" )
array = []
for line in ins:
    array.append( line )
    
line2=string.find(line,'t=')
temp=string.atof(line[line2+2:])/1000
print 'temperatura: '+str(temp)

doc=db['70472b7aa68ec91589ddfc9c28419ac7']
id_temp = len(doc['valor'])

class Mostra(Document):
   valor = ListField(DictField(Mapping.build(
      id = IntegerField(),
      temp = DecimalField(),
      dia_hora = DateTimeField(default=datetime.datetime.now)
   )))
   
mostra = Mostra.load(db, '70472b7aa68ec91589ddfc9c28419ac7')
mostra.valor.append(id=id_temp, temp=temp)
mostra.store(db) 

#funciona!

prova3.py:

from datetime import datetime
from couchdb.mapping import Document, TextField, IntegerField, DecimalField, DateTimeField
from couchdb.mapping import ListField, DictField, Mapping

import datetime
import string
import couchdb
import time
   
couch = couchdb.Server('http://localhost:5984/')
db = couch['rptemp']

doc=db['70472b7aa68ec91589ddfc9c28419ac7']
id_temp = len(doc['valor']) #num valors a la matriu

class Mostra(Document):
   valor = ListField(DictField(Mapping.build(
      id = IntegerField(),
      temp = DecimalField(),
      dia_hora = DateTimeField(default=datetime.datetime.now)
   )))
   
while True:
	ins = open( "mostra_temp.txt", "r" )
	array = []
	for line in ins:
		 array.append( line )
		 
	line2=string.find(line,'t=')
	temp=string.atof(line[line2+2:])/1000
	print 'temperatura: '+str(temp)
	ins.close()
	
	mostra = Mostra.load(db, '70472b7aa68ec91589ddfc9c28419ac7')
	mostra.valor.append(id=id_temp, temp=temp)
	mostra.store(db) 

	time.sleep(5) #5 segons
	id_temp += 1

Sensor de temperatura DS18B20 (protocol1-wire) i Raspberry Pi Zero (abril 2017)

Segueixo:

Utilitzo una Raspberry Pi Zero, amb un llapis USB wifi. Allò ideal seria utilitzar la nova RPi Zero W, que ja porta incorporat el wifi.

Add the following line to /boot/config.txt:

dtoverlay=w1-gpio

The following two commands load the 1-Wire and thermometer drivers on GPIO 4.

$ sudo modprobe w1-gpio
$ sudo modprobe w1-therm

Veig el meu dispositiu:

$ cd /sys/bus/w1/devices/
$ ls
28-000004404eb3  w1_bus_master1

$ cd 28-000004404eb3
$ ls
driver  id  name  power  subsystem  uevent  w1_slave

I ja puc llegir la temperatura:

$ cat w1_slave
68 01 4b 46 7f ff 08 10 05 : crc=05 YES
68 01 4b 46 7f ff 08 10 05 t=22500

Per fer-ho amb un script python: DS18B20_read.py:

import os
import time

os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')

temp_sensor = '/sys/bus/w1/devices/28-000004404eb3/w1_slave'

def temp_raw():
	f = open(temp_sensor, 'r')
	lines = f.readlines()
	f.close()
	return lines

def read_temp():
	lines = temp_raw()
	while lines[0].strip()[-3:] != 'YES':
		time.sleep(0.2)
		lines = temp_raw()
	temp_output = lines[1].find('t=')
	if temp_output != -1:
		temp_string = lines[1].strip()[temp_output+2:]
		temp_c = float(temp_string) / 1000.0
		temp_f = temp_c * 9.0 / 5.0 + 32.0
		return temp_c, temp_f

while True:
	print(read_temp())
	time.sleep(1)
$ python DS18B20_read.py 
(22.375, 72.275)
(22.375, 72.275)
(22.437, 72.3866)
(22.437, 72.3866)
(23.375, 74.075)
(23.875, 74.975)
...



creat per Joan Quintana Compte, maig 2013, abril 2017

Eines de l'usuari
Espais de noms
Variants
Accions
Navegació
IES Jaume Balmes
Màquines recreatives
CNC
Informàtica musical
joanillo.org Planet
Eines