IoT, Raspberry Pi, RESTful web services

De Wikijoan
Dreceres ràpides: navegació, cerca

Contingut

Introducció

Es vol fer un exemple de Internet of Things (IoT), connectant un sensor de temperatura DS18B20 a una Raspberry Pi Zero (protocol 1-wire). La RPi està connectada a Internet per wifi. A la RPi hi ha una base de dades MongoDB, i un script python que grava cada 10 minuts la dada de la temperatura a la base de dades.

A més, hi ha un servei web (Rest API) per tal de què aplicacions externes i remotes accedeixin a les dades (en format JSON). En el present article s'expliquen els passos per fer la posta a punt de la API, que ens quedem en la versió 1, amb un únic servei: mostrar totes les dades de la bd. I en el següent article tenim la documentació de tota la API, que passarà per diferents versions:

Projectes similars

Utilitza la placa Wemos D1 Mini Pro, i com a sensor un BMP280. Penell solar i carregador de bateries (Li-Io):

Sensor DS18B20 i ESP8266 per enviar directament la lectura als servidors de Google:

API de openweathermap.org. Thingful.net

Mentre encara no tinc cap dispositiu públic de IoT que doni dades reals, puc fer proves a thingful.net, penjant una estació meteorològica virtual gràcies a la API de openweathermap.org:

Tutorial MongoDB i Python. PyMongo

Necessito MongoDB perquè les dades que agafi del meu sensor les ficaré en una base de dades.

Segueixo el següent tutorial que instal.la MongoDB i els drivers per treballar amb Python, i finalment fa una RESTful API. L'objectiu és fer-ho córrer sobre la Raspberry Pi.

Per instal.lar MongoDB segueixo:

però he de tenir en compte que ho estic instal.lant sobre una RPi, i no pas sobre el Ubuntu.

mongodb - object/document-oriented database (metapackage)
mongodb-clients - object/document-oriented database (client apps)
mongodb-dev - object/document-oriented database (development)
mongodb-server - object/document-oriented database (server package)
$ sudo apt-get install mongodb (és el metapackage que ho instal.la tot)

Directoris principals:

ls -la /var/log/mongodb
ls -la /var/lib/mongodb
$ sudo service mongodb stop (start, restart, status)

$ ps aux | grep mongo
mongodb   7391  5.7  8.9 233116 39856 ?        Ssl  22:17   0:13 /usr/bin/mongod --config /etc/mongodb.conf

$ sudo /etc/init.d/mongodb status
  mongodb.service - An object/document-oriented database
   Loaded: loaded (/lib/systemd/system/mongodb.service; enabled)
   Active: active (running) since Mon 2017-02-20 22:17:41 UTC; 5min ago
     Docs: man:mongod(1)
 Main PID: 7391 (mongod)
   CGroup: /system.slice/mongodb.service
           └─7391 /usr/bin/mongod --config /etc/mongodb.conf

Feb 20 22:17:41 raspberrypi systemd[1]: Started An object/document-oriented database.
Feb 20 22:17:42 raspberrypi mongod[7391]: all output going to: /var/log/mongodb/mongodb.log

El servei queda arrencat en l'inici del sistema.

Ara que tinc instal.lat el MongoDB he d'instal.lar el PyMongo per tal de treballar amb MongoDB des de Python:

$ python
Python 2.7.9 (default, Mar  8 2015, 00:52:26) 
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 

Tenim instal.lada la versió 2.7.9 de Python

Per tant, no instal.lo python3-pymongo sinó simplement python-pymongo:

$ sudo apt-get install python-pymongo
$ python
...
>>> import pymongo

no dóna error perquè ja està ben instal.lat. Segueixo els petits exemples del tutorial:

m.py:

# m.py

def get_db():
  from pymongo import MongoClient
  client = MongoClient('localhost:27017')
  db = client.myFirstMB
  return db

def add_country(db):
  db.countries.insert({"name" : "Canada"})

def get_country(db):
  return db.countries.find_one()

if __name__ == "__main__":
  db = get_db()
  add_country(db)
  print get_country(db)

mongo1.py:

# mongo1.py

from pymongo import MongoClient

client = MongoClient('mongodb://localhost:27017/')

# data base name : 'test-database-1'
mydb = client['test-database-1']

import datetime

myrecord = {
  "author": "Duke",
  "title" : "PyMongo 101",
  "tags" : ["MongoDB", "PyMongo", "Tutorial"],
  "date" : datetime.datetime.utcnow()
}

record_id = mydb.mytable.insert(myrecord)

print record_id
print mydb.collection_names()


mongo2.py:

# mongo2.py

from pymongo import MongoClient

client = MongoClient('mongodb://localhost:27017/')
mydb = client['test-database-1']

import datetime

myrecord2 = [
  { "author": "Duke II",
    "title" : "PyMongo II 101",
    "tags" : ["MongoDB II", "PyMongo II", "Tutorial II"],
    "date" : datetime.datetime.utcnow() },
  { "author": "Duke III",
    "title" : "PyMongo III 101",
    "tags" : ["MongoDB III", "PyMongo III", "Tutorial III"],
    "date" : datetime.datetime.utcnow() }
  ]

mydb.mytable.insert(myrecord2)
print mydb.collection_names()


mongo3.py:

# mongo3.py

from pymongo import MongoClient

client = MongoClient('mongodb://localhost:27017/')
mydb = client['test-database']

mydb.posts.drop()

import datetime
post = {
	"author": "Duke 5",
	"title" : "PyMongo 101 - 5",
	"tags" : ["MongoDB 5", "PyMongo 101 - A5", "Tutorial 5"],
	"date" : datetime.datetime.utcnow()
	}

posts = mydb.posts
post_id = posts.insert(post)

print post_id
print mydb.collection_names()

new_posts = [{"author": "Duke 6",
	"title" : "PyMongo 101-A6",
	"tags" : ["MongoDB 6", "PyMongo 6", "Tutorial 6"],
	"date" : datetime.datetime(2015, 11, 28, 01, 13)},
	{"author": "Adja",
	"title": "MongoDB 101-A7",
	"note": "Schema free MongoDB",
	"date": datetime.datetime(2015, 11, 29, 11, 42)}
	]
mydb.posts.insert(new_posts)

Per fer una select:

>>> for post in mydb.posts.find({"author": "Adja"}):
...     post
...     print post
... 
{u'note': u'Schema free MongoDB', u'date': datetime.datetime(2015, 11, 29, 11, 42), u'_id': ObjectId('58ac5336bd95cc241eeda2e8'), u'author': u'Adja', u'title': u'MongoDB 101-A7'}
{u'note': u'Schema free MongoDB', u'date': datetime.datetime(2015, 11, 29, 11, 42), u'_id': ObjectId('58ac5336bd95cc241eeda2e8'), u'author': u'Adja', u'title': u'MongoDB 101-A7'}

Per fer aquesta petita select, recordar que en aquest cas print post o post és el mateix, que s'ha de tabular, i que per sortir del bucle n'hi ha prou en recuperar la identació original.

>>> mydb.posts.find({"author": "Adja"}).count()
1
>>> for post in mydb.posts.find({"date": {"$lt": datetime.datetime(2015, 12, 1)}}).sort("author"):
...     post
... 
{u'note': u'Schema free MongoDB', u'date': datetime.datetime(2015, 11, 29, 11, 42), u'_id': ObjectId('58ac5336bd95cc241eeda2e8'), u'author': u'Adja', u'title': u'MongoDB 101-A7'}
{u'date': datetime.datetime(2015, 11, 28, 1, 13), u'_id': ObjectId('58ac5336bd95cc241eeda2e7'), u'author': u'Duke 6', u'tags': [u'MongoDB 6', u'PyMongo 6', u'Tutorial 6'], u'title': u'PyMongo 101-A6'}

Base de dades de temperatura

El projecte IoT consistirà de moment de en llegir la temperatura d'un sensor DS18B20, i emmagatzemar-la en una base de dades. Per tant, la base de dades serà senzillament una taula que guardarà la temperatura i el timestamp.

Recordatori ràpid de MongoDB:

Per entrar a la consola de MongoDB:

$ mongo
>

MongoDB use DATABASE_NAME is used to create database. The command will create a new database if it doesn't exist, otherwise it will return the existing database.

> use temperatura
switched to db temperatura
> show dbs -> encara no es veu la bd temperatura

Ara creem una col.lecció:

>db.createCollection("temperatura")
{ "ok" : 1 }

> show dbs
...
temperatura	0.0625GB -> ara ja es veu la bd temperatura

To check your currently selected database, use the command db

>db
temperatura

Anem a inserir un document en la col.lecció temperatura:

>db.COLLECTION_NAME.insert(document)

>db.mycol.insert({
   _id: ObjectId(7df78ad8902c),
   title: 'MongoDB Overview', 
   description: 'MongoDB is no sql database',
   by: 'tutorials point',
   url: 'http://www.tutorialspoint.com',
   tags: ['mongodb', 'database', 'NoSQL'],
   likes: 100
})

Compte! perquè el mes 04 és el maig! (però en canvi quan faci el script amb python sí que serà el mes d'abril...)

> db.temperatura.insert({
   temp: '23.5', 
   datetime: new Date(2017,4,3,11,50,40)
})

Però compte! Jo no vull inserir strings, vull inserir nombres. Ha de ser així:

> db.temperatura.insert({
   temp: 23.5, 
   datetime: new Date(2017,4,3,11,50,40)
})

> db.temperatura.insert({
   temp: 23.6, 
   datetime: new Date(2017,4,3,11,50,50)
})

> db.temperatura.insert({
   temp: 23.7, 
   datetime: new Date(2017,4,3,11,51,00)
})

In the inserted document, if we don't specify the _id parameter, then MongoDB assigns a unique ObjectId for this document.

The basic syntax of find() method is as follows:

> db.COLLECTION_NAME.find()

> db.temperatura.find()
{ "_id" : ObjectId("58e21b2de56ddea1ec9ba470"), "temp" : 23.5, "datetime" : ISODate("2017-05-03T11:50:40Z") }
{ "_id" : ObjectId("58e21b4de56ddea1ec9ba471"), "temp" : 23.6, "datetime" : ISODate("2017-05-03T11:50:50Z") }

o bé:

> db.temperatura.find().pretty()
{
	"_id" : ObjectId("58e21b2de56ddea1ec9ba470"),
	"temp" : 23.5,
	"datetime" : ISODate("2017-05-03T11:50:40Z")
}
{
	"_id" : ObjectId("58e21b4de56ddea1ec9ba471"),
	"temp" : 23.6,
	"datetime" : ISODate("2017-05-03T11:50:50Z")
}

Clàusula WHERE. Per ex, Greater Than:

{<key>:{$gt:<value>}}
> db.temperatura.find({"temp":23.5}).pretty()
> db.temperatura.find({"temp":{$gt:23.5}}).pretty() 

> db.temperatura.find({"datetime":{$gt:ISODate("2017-05-03T11:50:45Z")}}).pretty()
{
	"_id" : ObjectId("58e21b4de56ddea1ec9ba471"),
	"temp" : 23.6,
	"datetime" : ISODate("2017-05-03T11:50:50Z")
}

Delete document, el mètode remove().

> db.temperatura.remove({"datetime":{$gt:ISODate("2017-05-03T11:50:45Z")}})
> db.temperatura.find().pretty()
{
	"_id" : ObjectId("58e21b2de56ddea1ec9ba470"),
	"temp" : 23.5,
	"datetime" : ISODate("2017-05-03T11:50:40Z")
}

Trobar les temperatures d'un dia, mes o any

Les temperatures del 5/4/2017:

> use temperatura
> db.temperatura.find({ $and: [{"datetime":{$gt:ISODate("2017-04-05")}},{"datetime":{$lt:ISODate("2017-04-06")}}]} )

> db.temperatura.find({ "datetime":ISODate("2017-04-05")} ) -> no funciona

Ara bé, vull buscar la manera directa, que és referenciar a la data (en comptes de fer més gran que... i més petit que...)

You cannot straightly query mongodb collections by date components like day or month. But its possible by using the special $where javascript expression

db.temperatura.find({$where : function() { return this.datetime.getDate() == 4} })
or simply
db.temperatura.find({$where : 'return this.date.getMonth() == 11'})

La gràcia d'aquesta solució és adonar-se que MongoDB i Javascript estan integrats. Per tant, el que funciona per filtrar per un any, mes o dia:

> db.temperatura.find({$where : function() { return this.datetime.getFullYear() == 2017} })
> db.temperatura.find({$where : function() { return this.datetime.getMonth() == 3} })
(recordar que en Javascript els mesos són de 0-11)
> db.temperatura.find({$where : function() { return this.datetime.getDate() == 3} })

no confondre getDate() amb getDay():

De fet, és millor utilitzar getUTCFullYear(), getUTCMonth() i getUTCDate().

I si el que vull és filtrar per una data concreta, per exemple 5/4/2017:

> db.temperatura.find( { $and: [,,] } )

> db.temperatura.find( { $and: [{$where : function() { return this.datetime.getUTCFullYear() == 2017} },{$where : function() { return this.datetime.getUTCMonth() == 3} },{$where : function() { return this.datetime.getUTCDate() == 5} }] } )

o bé, que és equivalent (i més curt, però no sé si més ràpid):

> db.temperatura.find({$where : function() { return (this.datetime.getUTCFullYear() == 2017 && this.datetime.getUTCMonth() == 3 && this.datetime.getUTCDate() == 6) } })

També funciona:

> db.temperatura.find({$where : function() { return (this.datetime.getUTCFullYear() == '2017' && this.datetime.getUTCMonth() == '03' && this.datetime.getUTCDate() == '06') } })

MongoDB i Python. Base de dades temperatura

Ara anem a fer aquestes operacions bàsiques (insert, delete, select) sobre la col.lecció temperatura amb python

inserir_temperatura.py:

# inserir_temperatura.py

import datetime

def get_db():
  from pymongo import MongoClient
  client = MongoClient('localhost:27017')
  db = client.temperatura
  return db

def add_temperatura(db):
  #db.temperatura.insert({"temp" : 22.4,"datetime":"new Date(2017,4,3,11,55,55)"})
  db.temperatura.insert({"temp" : 22.4,"datetime":datetime.datetime.utcnow()})

def get_temperatura(db):
  return db.temperatura.find_one()

if __name__ == "__main__":
  db = get_db()
  add_temperatura(db)
  print get_temperatura(db)

Però no ens mostra la última temperatura, sinó la primera. Si vull que em mostri la última temperatura, és més difícil.

inserir_temperatura2.py:

# inserir_temperatura2.py

import datetime

def get_db():
	from pymongo import MongoClient
	client = MongoClient('localhost:27017')
	db = client.temperatura
	return db

def add_temperatura(db):
	#db.temperatura.insert({"temp" : 22.4,"datetime":"new Date(2017,4,3,11,55,55)"})
	db.temperatura.insert({"temp" : 22.4,"datetime":datetime.datetime.utcnow()})

def get_temperatura(db):
	for temp in db.temperatura.find().sort([("datetime", -1)]).limit(1):
		print(temp)

if __name__ == "__main__":
	db = get_db()
	add_temperatura(db)
	get_temperatura(db)
{u'_id': ObjectId('58e267adbd95cc3bfc108bd5'), u'temp': 22.4, u'datetime': datetime.datetime(2017, 4, 3, 15, 18, 5, 112000)}

mostrar_ultima_temperatura.py

ara es tracta de trobar només el valor de la temperatura última que s'ha inserit. Aquesta part ha estat bastant difícil.

#mostrar_ultima_temperatura.py

import datetime
import json
import bson
from bson.json_util import dumps

posts = []

def get_db():
	from pymongo import MongoClient
	client = MongoClient('localhost:27017')
	db = client.temperatura
	return db

def get_ultima_temperatura(db):
	cursor = db.temperatura.find().sort([("datetime", -1)]).limit(1)
	#return dumps(cursor)
	#resultat = dumps(cursor)
	#print(resultat[0]._id)
	resultat = bson.json_util.dumps({ 'success': True, 'res': cursor })
	#print(resultat)
	j = json.loads(resultat)
	return j['res'][0]['temp']

if __name__ == "__main__":
	db = get_db()
	print get_ultima_temperatura(db)
$ python mostrar_ultima_temperatura.py
20.28

inserir_temperatura_random.py: insereix una temperatura aleatòria (en el rang 15-25), cada 10 minuts. És un bucle sense fi.

# inserir_temperatura_random.py

import datetime
import random
import time

def get_db():
  from pymongo import MongoClient
  client = MongoClient('localhost:27017')
  db = client.temperatura
  return db

def add_temperatura(db):
	temp = random.uniform(15, 25)
	temp_2dec = float("{0:.2f}".format(temp))
	db.temperatura.insert({"temp" : temp_2dec,"datetime":datetime.datetime.utcnow()})

def get_temperatura(db):
  return db.temperatura.find_one()

if __name__ == "__main__":
	db = get_db()

	while True:
		add_temperatura(db)
		time.sleep(600)

Calcular la mitjana de temperatures (directament a MongoDB):

> db.temperatura.aggregate(
   [
     {
       $group:
         {
           _id: "$item",
           mitjana: { $avg: "$temp" }
         }
     }
   ]
)

Com filtrar i després agregar. Calcular la mitjana de temperatures d'aquelles temperatures que siguin més grans que 20.

> db.temperatura.aggregate(
   [
     {  $match:	{"temp":{$gt:20}}
		},
     { $group:
         {
           _id: "$item",
           mitjana: { $avg: "$temp" }
         } }
   ]
)

{ "_id" : null, "mitjana" : 22.5096 }

El que no ha funcionat és fer un find amb un filtre, i després una agregació.

db.temperatura.find(<condició>).aggregate(...) -> no ha funcionat

El que vull en definitiva és fer la mitjana de temperatures d'un dia, d'un mes, d'un any...

La mitjana de temperatures d'un dia:

$and: [ { <expression1> }, { <expression2> } , ... , { <expressionN> } ]

db.temperatura.aggregate(
   [
     {  $match:	{$and: [{"datetime":{$gt:ISODate("2017-04-03T00:00:00Z")}},{"datetime":{$lt:ISODate("2017-04-03T23:59:59Z")}}]}
		},
     { $group:
         {
           _id: "$item",
           mitjana: { $avg: "$temp" }
         } }
   ]
)
{ "_id" : null, "mitjana" : 19.697733333333336 }

La mitjana de temperatures d'un mes:

db.temperatura.aggregate(
   [
     {  $match:	{$and: [{"datetime":{$gt:ISODate("2017-04-01T00:00:00Z")}},{"datetime":{$lt:ISODate("2017-05-01T00:00:00Z")}}]}
		},
     { $group:
         {
           _id: "$item",
           mitjana: { $avg: "$temp" }
         } }
   ]
)

{ "_id" : null, "mitjana" : 19.697733333333336 }

La mitjana de temperatures d'un any:

db.temperatura.aggregate(
   [
     {  $match:	{$and: [{"datetime":{$gt:ISODate("2017-01-01T00:00:00Z")}},{"datetime":{$lt:ISODate("2018-01-01T00:00:00Z")}}]}
		},
     { $group:
         {
           _id: "$item",
           mitjana: { $avg: "$temp" }
         } }
   ]
)

{ "_id" : null, "mitjana" : 19.670625000000005 }

script mitjana_temperatures_mes_grans_que_20.py:

#mitjana_temperatures_mes_grans_que_20.py

import datetime
import json
import bson
from bson.son import SON
from bson.json_util import dumps

#http://api.mongodb.com/python/current/examples/aggregation.html

def get_db():
	from pymongo import MongoClient
	client = MongoClient('localhost:27017')
	db = client.temperatura
	return db

def get_temperatura(db):
	pipeline = [ {  "$match":	{"temp":{"$gt":20}}},{ "$group": { "_id": "$item", "mitjana": { "$avg": "$temp" } } } ]

	cursor = db.temperatura.aggregate(pipeline)
	resultat = bson.json_util.dumps({ 'success': True, 'res': cursor })
	print(resultat)
	j = json.loads(resultat)
	#return j['res'][0]['mitjana']
	return j['res']['result'][0]['mitjana']

if __name__ == "__main__":
	db = get_db()
	print get_temperatura(db)
$ python mitjana_temperatures_mes_grans_que_20.py 
{"res": [{"mitjana": 22.603962264150944, "_id": null}], "success": true}
22.6039622642

script mitjana_dia.py:

#mitjana_dia.py

import datetime
import json
import bson
from bson.son import SON
from bson.json_util import dumps

#http://api.mongodb.com/python/current/examples/aggregation.html

def get_db():
	from pymongo import MongoClient
	client = MongoClient('localhost:27017')
	db = client.temperatura
	return db

def get_temperatura(db):

	pipeline = [ {  "$match":	{"$and": [{"datetime":{"$gt":datetime.datetime(2017,4,3,0,0,0)}},{"datetime":{"$lt":datetime.datetime(2017,4,3,23,59,59)}}]} }, { "$group": { "_id": "$item", "mitjana": { "$avg": "$temp" } } } ]
	cursor = db.temperatura.aggregate(pipeline)
	resultat = bson.json_util.dumps({ 'success': True, 'res': cursor })
	#print(resultat)
	j = json.loads(resultat)
	return j['res'][0]['mitjana']


if __name__ == "__main__":
	db = get_db()
	print get_temperatura(db)
$ python mitjana_dia.py 
19.5596

script mitjana_mes.py:

	pipeline = [ {  "$match":	{"$and": [{"datetime":{"$gt":datetime.datetime(2017,4,1,0,0,0)}},{"datetime":{"$lt":datetime.datetime(2017,5,1,0,0,0)}}]} }, { "$group": { "_id": "$item", "mitjana": { "$avg": "$temp" } } } ]

script mitjana_any.py:

	pipeline = [ {  "$match":	{"$and": [{"datetime":{"$gt":datetime.datetime(2017,1,1,0,0,0)}},{"datetime":{"$lt":datetime.datetime(2018,1,1,0,0,0)}}]} }, { "$group": { "_id": "$item", "mitjana": { "$avg": "$temp" } } } ]

script dades_dun_dia.py: Aquest script el necessitaré. S'ha d'estudiar la millor manera de com filtrem les dades per una data concreta.

#dadesdun_dia.py

import datetime
import json
import bson
from bson.son import SON
from bson.json_util import dumps

ano = 2017
mes = 4
dia= 5

d1 = datetime.datetime(ano,mes,dia,0,0,0)
d2 = d1 + datetime.timedelta(days=2) 
#print d1
#print d2

def get_db():
	from pymongo import MongoClient
	client = MongoClient('localhost:27017')
	db = client.temperatura
	return db

def get_temperatura(db):
	#cursor = db.temperatura.find() #OK
	#cursor = db.temperatura.find({ "temp" : 22.75 }) #OK
	#cursor = db.temperatura.find({ "temp" :  { "$in": [22.75, 22] } }) #OK
	#cursor = db.temperatura.find( {"$or":[ {"temp" : 22.75}, {"temp" : 22} ]}) #OK
	#cursor = db.temperatura.find( {"$and":[ {"temp" : {"$gt":22}}, {"temp" : {"$lt":23}} ]}) #OK
	#cursor = db.temperatura.find({"datetime":{"$gt":datetime.datetime(ano,mes,dia,0,0,0)}}) #OK
	cursor = db.temperatura.find( {"$and":[ {"datetime":{"$gt":d1}}, {"datetime":{"$lt":d2}} ]}) #OK
	#return dumps(cursor)
	#resultat = dumps(cursor)
	#print(resultat)
	resultat = bson.json_util.dumps({ 'success': True, 'res': cursor })
	#print(resultat)
	j = json.loads(resultat)
	return j['res']

if __name__ == "__main__":
	db = get_db()
	print get_temperatura(db)

Una cosa que em preocupava era el fet de com sumar-li un dia a una data. Ja està resolt:

ano = 2017
mes = 12
dia= 30

d1 = datetime.datetime(ano,mes,dia,0,0,0)
d2 = d1 + datetime.timedelta(days=2) 
print d1
print d2

...
$ python dades_dun_dia.py 
2017-12-30 00:00:00
2018-01-01 00:00:00
[]

script temp_logging.py

Per connectar el sensor de temperatura DS18B20 a la RPi Zero està explicat a:

Ara es tracta d'executar en l'inici del sistema un script python que llegeixi la temperatura cada minuts i la inserti a la base de dades MongoDB.

script temp_logging.py:

# temp_logging.py

import os
import datetime
import random
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 get_db():
	from pymongo import MongoClient
	client = MongoClient('localhost:27017')
	db = client.temperatura
	return db

def add_temperatura(db):
	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_2dec = float("{0:.2f}".format(temp_c))
		db.temperatura.insert({"temp" : temp_2dec,"datetime":datetime.datetime.utcnow()})

if __name__ == "__main__":
	db = get_db()

	while True:
		add_temperatura(db)
		time.sleep(600) #10 minuts

Aquest script s'executarà de forma automàtica en l'inici del sistema:

$ sudo joe /etc/rc.local
/usr/bin/python /home/pi/temp_logging.py

NOTA: En una primera versió grabava el datetime en format local (datetime.datetime.now()). I això no pot ser, s'ha de gravar el datetime en format universal (UTC) (datetime.datetime.utcnow()). Així és com ha de ser. Tot l'aplicatiu (scripts python, restful API, front-ends) han de treballar amb format universal, i així m'estalvio problemes amb els horaris d'estiu o d'hivern. Recordar que a l'hivern l'hora local a Barcelona és UTC+1,i a l'estiu és UTC+2. Així és com treballa tothom, amb UTC, per exemple a meto.cat.

Scripts per calcular les mitjanes dels dies, mesos i anys

script mitjana_dia.py:

#mitjana_dia.py

import datetime
import json
import bson
from bson.son import SON
from bson.json_util import dumps

#http://api.mongodb.com/python/current/examples/aggregation.html

def get_db():
	from pymongo import MongoClient
	client = MongoClient('localhost:27017')
	db = client.temperatura
	return db

def calcular_mitjana_dia(db, today, yesterday):

	#comprovacio de que la seleccio de dates es correcta
	#cursor = db.temperatura.find({"$and": [{"datetime":{"$gte":datetime.datetime(yesterday.year,yesterday.month,yesterday.day,0,0,0)}},{"datetime":{"$lt":datetime.datetime(today.year,today.month,today.day,0,0,0)}}]});
	#print(cursor[0])

	pipeline = [ {  "$match":	{"$and": [{"datetime":{"$gte":datetime.datetime(yesterday.year,yesterday.month,yesterday.day,0,0,0)}},{"datetime":{"$lt":datetime.datetime(today.year,today.month,today.day,0,0,0)}}]} }, { "$group": { "_id": "$item", "tempavg": { "$avg": "$temp" } , "tempmax": { "$max": "$temp" }, "tempmin": { "$min": "$temp" } } } ]
	cursor = db.temperatura.aggregate(pipeline)
	resultat = bson.json_util.dumps({ 'success': True, 'res': cursor })
	#print(resultat)
	j = json.loads(resultat)
	if (len(j['res'])!=0):
		tempavg_2dec = float("{0:.2f}".format(j['res']['result'][0]['tempavg']))
		print tempavg_2dec
		tempmax_2dec = float("{0:.2f}".format(j['res']['result'][0]['tempmax']))
		print tempmax_2dec
		tempmin_2dec = float("{0:.2f}".format(j['res']['result'][0]['tempmin']))
		print tempmin_2dec

		db.mitjana.insert({"tipus": "day", "tempmax" : tempmax_2dec, "tempmin" : tempmin_2dec, "tempavg" : tempavg_2dec, "datetime":datetime.datetime(yesterday.year, yesterday.month, yesterday.day,0,0,0)})
	else:
		print "no data"
		return "no data"	

if __name__ == "__main__":
	db = get_db()
	today = datetime.datetime.utcnow()
	yesterday = today - datetime.timedelta(days=1)
	#print today.year, today.month, today.day, today.hour, today.minute, today.second	
	#print yesterday.year, yesterday.month, yesterday.day, yesterday.hour, yesterday.minute, yesterday.second
	calcular_mitjana_dia(db, today, yesterday)

El tema interessant d'aquest script és com amb python podem sumar o restar dies a una data i fer-ho bé, passant correctament al mes o a l'any anterior, mitjançant datetime.timedelta. script mitjana_mes.py:

#mitjana_mes.py

import datetime
import json
import bson
from bson.son import SON
from bson.json_util import dumps

#http://api.mongodb.com/python/current/examples/aggregation.html

def get_db():
	from pymongo import MongoClient
	client = MongoClient('localhost:27017')
	db = client.temperatura
	return db

def calcular_mitjana_mes(db, today, yesterday):
	pipeline = [ {  "$match":	{"$and": [{"datetime":{"$gte":datetime.datetime(yesterday.year,yesterday.month,1,0,0,0)}},{"datetime":{"$lt":datetime.datetime(today.year,today.month,1,0,0,0)}}]} }, { "$group": { "_id": "$item", "tempavg": { "$avg": "$temp" } , "tempmax": { "$max": "$temp" }, "tempmin": { "$min": "$temp" } } } ]

	cursor = db.temperatura.aggregate(pipeline)
	resultat = bson.json_util.dumps({ 'success': True, 'res': cursor })
	#print(resultat)
	j = json.loads(resultat)
	if (len(j['res']['result'])!=0):
		tempavg_2dec = float("{0:.2f}".format(j['res']['result'][0]['tempavg']))
		print tempavg_2dec
		tempmax_2dec = float("{0:.2f}".format(j['res']['result'][0]['tempmax']))
		print tempmax_2dec
		tempmin_2dec = float("{0:.2f}".format(j['res']['result'][0]['tempmin']))
		print tempmin_2dec

		db.mitjana.insert({"tipus": "month", "tempmax" : tempmax_2dec, "tempmin" : tempmin_2dec, "tempavg" : tempavg_2dec, "datetime":datetime.datetime(yesterday.year, yesterday.month, 1,0,0,0)})

	else:
		print "no data"
		return "no data"	

if __name__ == "__main__":
	db = get_db()
	today = datetime.datetime.utcnow()
	yesterday = today - datetime.timedelta(days=1)
	#yesterday.year i yesterday.month son correctes perque recordem que aquest script s'executa el dia 1 del mes present.
	#print yesterday.year, yesterday.month, yesterday.day, yesterday.hour, yesterday.minute, yesterday.second
	calcular_mitjana_mes(db, today, yesterday)

script mitjana_any.py:

#mitjana_any.py

import datetime
import json
import bson
from bson.son import SON
from bson.json_util import dumps

#http://api.mongodb.com/python/current/examples/aggregation.html

def get_db():
	from pymongo import MongoClient
	client = MongoClient('localhost:27017')
	db = client.temperatura
	return db

def calcular_mitjana_any(db, today, yesterday):
	pipeline = [ {  "$match":	{"$and": [{"datetime":{"$gte":datetime.datetime(yesterday.year,1,1,0,0,0)}},{"datetime":{"$lt":datetime.datetime(today.year,1,1,0,0,0)}}]} }, { "$group": { "_id": "$item", "tempavg": { "$avg": "$temp" } , "tempmax": { "$max": "$temp" }, "tempmin": { "$min": "$temp" } } } ]

	cursor = db.temperatura.aggregate(pipeline)
	resultat = bson.json_util.dumps({ 'success': True, 'res': cursor })
	#print(resultat)
	j = json.loads(resultat)
	if (len(j['res']['result'])!=0):
		tempavg_2dec = float("{0:.2f}".format(j['res']['result'][0]['tempavg']))
		print tempavg_2dec
		tempmax_2dec = float("{0:.2f}".format(j['res']['result'][0]['tempmax']))
		print tempmax_2dec
		tempmin_2dec = float("{0:.2f}".format(j['res']['result'][0]['tempmin']))
		print tempmin_2dec

		db.mitjana.insert({"tipus": "year", "tempmax" : tempmax_2dec, "tempmin" : tempmin_2dec, "tempavg" : tempavg_2dec, "datetime":datetime.datetime(yesterday.year, 1, 1,0,0,0)})

	else:
		print "no data"
		return "no data"	

if __name__ == "__main__":
	db = get_db()
	today = datetime.datetime.utcnow()
	yesterday = today - datetime.timedelta(days=1)
	#yesterday.year i yesterday.month son correctes perque recordem que aquest script s'executa el dia 1 de gener de l'any present.
	#print yesterday.year, yesterday.month, yesterday.day, yesterday.hour, yesterday.minute, yesterday.second
	calcular_mitjana_any(db, today, yesterday)

Scripts al crontab

NOTA. cron utilitza l'hora local, i per tant hauré de vigilar perquè l'hora UTC sempre va per darrera. Per ex, 1gen 0h 0min són les 31des 23h 0min, i per tant encara estic a l'any anterior (falta una hora). Per ex, 1abr 0h 0min són les 31mar 22h 0min, i per tant encara estic al dia anterior (falten dues hores). Per tant, per assegurar-me de què no hi ha problemes, els scripts per calcular les mitjanes diàries, mensuals i anuals com a mínim s'han d'executar a les dues de la matinada (hora local, que és l'hora del cron).

A les 0h 5min de cada dia executo un script que em calcula la mitjana del dia anterior i ho fica dins la taula db.mitjana:

$ sudo joe /etc/crontab

# m h dom mon dow user  command
3 2    * * *   root    /usr/bin/python /home/pi/python/mitjana_dia.py

$ sudo /etc/init.d/cron restart

mitjana_mes.py, s'executa a les 0h5min del primer dia de cada mes:

# m h dom mon dow user  command
4 2    1 * *   root    /usr/bin/python /home/pi/python/mitjana_mes.py

mitjana_any.py, s'executa a les 0h5min del 1 de gener de cada any:

# m h dom mon dow user  command
5 2    1 1 *   root    /usr/bin/python /home/pi/python/mitjana_any.py

Repàs per inserir, esborrar i modificar un registre a MongoDB

Inserir una mostra de temperatura:

insert (amb temps UTC) (són les 13h reals dels 27-abr)
db.temperatura.insert({ temp: 30.2, "datetime": new Date(2017,3,27,15,00,00) })

o bé fer-ho directament amb UTC:

db.temperatura.insert( { temp: 30.4, "datetime": ISODate("2017-04-27T13:00:00Z") } )

Per trobar aquesta mostra que acabem d'inserir, en la meva versió de Mongo (a diferència de versions anterior) no utilitzo eq per fer equal (de la mateixa manera que s'utilitzaria gt o lt), sinó que és més simple:

> db.temperatura.find( { "datetime": ISODate("2017-04-27T13:00:00Z")  } )
{ "_id" : ObjectId("5900e4740ffe6fc2dbd57f0a"), "temp" : 30.2, "datetime" : ISODate("2017-04-27T13:00:00Z") }

The ISODate is in UTC.

Per fer un update (el primer paràmetre és la condició, el filtres; i el segon paràmetre són les dades, s'han de posar tots els camps; hi ha un tercer paràmetre opcional):

> db.temperatura.update( { "datetime": ISODate("2017-04-27T13:00:00Z")  }, { temp: 31.4, "datetime":  ISODate("2017-04-27T13:00:00Z")  } )

per eliminar aquesta data:

> db.temperatura.remove( { "datetime":  ISODate("2017-04-27T13:00:00Z")  } )

MongoDB RESTful API with Flask

Com a punt de partida per començar a programar la RESTful API he estudiat aquests dos exemples, tant a ubuntu com a la Raspberry Pi:

En aquest exercici farem una RESTful API que consisteix en treballar amb una base de dades MongoDB d'estrelles, de manera que podem recuperar informació de totes les estrelles, d'una estrella específica, o bé afegir una nova estrella.

Utilitzo un entorn virtual per treballar amb Python:

$ virtualenv -p python3 venv
Already using interpreter /usr/bin/python3
Using base prefix '/usr'
New python executable in /home/joan/venv/bin/python3
Also creating executable in /home/joan/venv/bin/python
Installing setuptools, pkg_resources, pip, wheel...done.

$ source venv/bin/activate
(venv) joan@joanillo:~$

Instal.lo Flask:

(venv)$ pip install Flask-PyMongo

i executo el servidor de la RestAPI, que queda escoltant a http://127.0.0.1:5000/:

$ python mongo.py
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger pin code: 212-550-935

(veure el codi més avall)

REST API

Com podem veure mirant el codi tenim 2 GET requests i 1 POST request.

    @app.route('/star', methods=['GET'])
    def get_all_stars():
    @app.route('/star/<string:name>', methods=['GET'])
    def get_one_star(name):
    @app.route('/star', methods=['POST'])
    def add_star():

El servidor mongo.py té el següent codi:

# mongo.py

from flask import Flask
from flask import jsonify
from flask import request
from flask_pymongo import PyMongo

app = Flask(__name__)

app.config['MONGO_DBNAME'] = 'restdb'
app.config['MONGO_URI'] = 'mongodb://localhost:27017/restdb'

mongo = PyMongo(app)

@app.route('/star', methods=['GET'])
def get_all_stars():
  star = mongo.db.stars
  output = []
  for s in star.find():
    output.append({'name' : s['name'], 'distance' : s['distance']})
  return jsonify({'result' : output})

@app.route('/star/<string:name>', methods=['GET'])
def get_one_star(name):
  #print(name)
  star = mongo.db.stars
  s = star.find_one({'name' : name})
  if s:
    output = {'name' : s['name'], 'distance' : s['distance']}
  else:
    output = "No such name"
  return jsonify({'result' : output})

@app.route('/star', methods=['POST'])
def add_star():
  star = mongo.db.stars
  name = request.json['name']
  distance = request.json['distance']
  star_id = star.insert({'name': name, 'distance': distance})
  new_star = star.find_one({'_id': star_id })
  output = {'name' : new_star['name'], 'distance' : new_star['distance']}
  return jsonify({'result' : output})

if __name__ == '__main__':
    app.run(debug=True)

I després de corregir l'error ara ja funciona. Per afegir una estrella:

$ curl -i -H "Content-Type: application/json" -X POST -d '{"name" : "Andromeda" , "distance" : 2537000}' http://127.0.0.1:5000/star

I per recuperar totes les estrelles o bé una de sola:

$ curl -i http://localhost:5000/star
$ curl -i http://localhost:5000/star/Andromeda

Com que tenia problemes amb la crida, he instal.lat el Postman tal com es suggereix en l'enllaç (existeix una versió per Linux):

Postman helps you be more efficient while working with APIs. Created by Postdot Technologies, Inc.

Quan arrenco el servidor mongo.py veig que hi ha un debugger pin:

Però puc fer:

$ export WERKZEUG_DEBUG_PIN=off
joan@joanillo:~$ echo $WERKZEUG_DEBUG_PIN
off

$ python mongo.py
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger pin disabled.  DEBUGGER UNSECURED!

flask restful: passing parameters to GET request

@app.route('/v2/jsonp/temperatures/<string:yyyymmdd>', methods=['GET'])
def get_one_day2(yyyymmdd):
	args = request.args
	print (args) # For debugging
	dia1 = args['dia1']
	dia2 = args['dia2']
	print(dia1)
	print(dia2)
$ python joanillo_temperatura_restapi/v2/joanillo_tempetura_restapi.py 
 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

ImmutableMultiDict([('dia1', '20170405'), ('dia2', '20170406')])
20170405
20170406

TempLogging RESTful API with Flask

I ara ja estic en condicions de programar la meva API a la RPi.

Amb la API he de poder fer:

Instal.lem l'entorn virtual i Flask. Això ja ho havia fet al portàtil. La diferència és que ara ho faig a la Rapberry Pi Zero.

$ sudo apt-get install virtualenv
$ virtualenv -p python3 venv

I ara ja podem entrar a l'entorn virtual:

$ source venv/bin/activate
(venv)pi@raspberrypi:~ $

Instal.lo Flask:

(venv)$ pip install Flask-PyMongo

i ara he de programar el servidor de la Restful API, temp_logging_restapi.py (veure més avall). Quan la tingui programada, executaré el servidor de la RestAPI, que queda escoltant a http://127.0.0.1:5000/:

$ python temp_logging_restapi.py
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 194-636-315

Primer de tot faig un test, una API mínima que té per missió recuperar totes les temperatures:

Test restapi.png

script test_restapi.py:

from flask import Flask
from flask import jsonify
from flask import request
from flask_pymongo import PyMongo

app = Flask(__name__)

app.config['MONGO_DBNAME'] = 'temperatura'
app.config['MONGO_URI'] = 'mongodb://localhost:27017/temperatura'

mongo = PyMongo(app)

@app.route('/temperatures', methods=['GET'])
def get_all_temperatures():
	temperatura = mongo.db.temperatura
	output = []
	for s in temperatura.find():
		output.append({'temp' : s['temp'],'datetime': s['datetime']})
		#print(s['temp'])
		#print(s['datetime'])
	return jsonify({'result' : output})

if __name__ == '__main__':
	app.run(debug=True)

En una finestra executem el servidor:

$ python test_restapi.py
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 194-636-315

i en una altra finestra de la RPi, provem aquesta API:

pi@raspberrypi:~ $ curl -i http://localhost:5000/temperatures
...
    {
      "datetime": "Tue, 04 Apr 2017 10:36:34 GMT", 
      "temp": 22.5
    }, 
    {
      "datetime": "Tue, 04 Apr 2017 10:46:35 GMT", 
      "temp": 22.5
    }, 
    {
      "datetime": "Tue, 04 Apr 2017 10:56:36 GMT", 
      "temp": 22.5
    }, 
    {
      "datetime": "Tue, 04 Apr 2017 11:06:37 GMT", 
      "temp": 22.5
    }
  ]
}

Com veiem en la imatge, tenim les dues finestres. Si faig algun print en el servidor, apareixerà en la finestra del servidor. Una cosa bona és que si faig un canvi en el fitxer del servidor mentre aquest s'està executant, carrega el servidor de nou, automàticament.

Accedir remotament, obrir el port 5000 del router

Obrir port 5000.png

Router: Movistar Home Station BHS-RTA Entrem en el router de Movistar (Movistar Home Station BHS-RTA)

Obrim el port 5000 (TCP/UDP) per al dispositiu 192.168.1.37 (RPi) tal com es veu a la imatge.

Per provar la meva API remotament, he de saber quina és la IP pública del meu router:

$ wget http://checkip.dyndns.org/ -O - -o /dev/null | cut -d: -f 2 | cut -d\< -f 1
 79.154.207.42

Amb un servei com no-ip o dyndns puc tenir un nom de domini que sigui immune als possibles canvis en la IP pública.

No n'hi ha prou amb obrir el port en el router. També s'ha d'obrir el port internament a nivell de la RPi (TBD)

$ curl -i http://79.154.207.42:5000/temperatures
curl: (7) Failed to connect to 79.154.207.42 port 5000: Connection refused

Ara ja funciona:

Restapi temp.png

Per tal de què funcioni, el servidor no ha d'estar limitat a localhost sinó a qualsevol IP. Per fer-ho, en el codi ficarem host='0.0.0.0':

if __name__ == '__main__':
        #app.run(debug=True)
        app.run(host='0.0.0.0') 
$ python test_restapi.py 
 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
...

en comptes de 

$ python test_restapi.py 
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
...

Calibració. Sensor de temperatura

Calibracio temperatura.png

No sé fins a quin punt el meu sensor de temperatura em dóna el valor correcta. I he de veure quines condicions ha de tenir la meva caixa per tal de què sigui correcta la presa de mostres. Per exemple, no hi pot haver insolació directa; la caixa ha d'estar ben ventilada;...

El més pràctic podria ser comparar el meu sensor amb https://openweathermap.org/ o alguna altra font fiable.

Comparació amb meteo.cat

He calibrat comparant-ho amb meteo.cat, amb l'estació automàtica de Zona Universitària. Amb les dades que he agafat entre el 28-abr i el 6-mai-2017 (veure carpeta joanillo_temperatura_restapi/calibracio), he trobat una recta de regressió entre les dades del meu sensor i les dades reals:

temp_c = 1.571*temp_c-11.71

Dins de Barcelona, agafo l'estació Dades EMA Barcelona - Zona Universitària. Fixem-nos que tots els temps són universals (TU). Jo també he de tenir totes les dades en TU. (ja està)

El tram horari està expressat en Temps Universal (TU). Cal sumar una hora en horari d'hivern i dues en horari d'estiu per passar a l'hora oficial.

Post sobre el tema de la calibració:

Exemple de frontend per utilitzar la RestAPI

Ara que ja tenim funcionant la RestAPI i puc recollir les temperatures, puc dissenyar aplicacions (mòbil, web, CLI,...) que utilitzin la API. Anem a fer una aplicació senzilla.

Ara bé, em trobo amb un problema: el Cross domain problem/issue. Tinc la RestAPI (la Raspberry) a casa i vull accedir a la informació des de l'institut. Hauré d'utilitzar la tècnica del JSONP. Per solucionar-ho de forma ràpida, en la meva RestAPI ficaré:

        #return jsonify({'result' : output})
        return 'JSONPHandler(' + jsonify({'result' : output}).get_data(as_text=True) + ')'

és a dir, el que retorna la API és tota la informació JSON ficada de manera que sigui l'argument d'una funció JSONPHandler(), que existirà localment. D'aquesta manera ja aconsegueixo mostrar les temperatures des d'una aplicació web.

temperatures_restapi_v1.html:

Temperatures html.png
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Logging de temperatures. IoT. Sensor DS18B20</title>
<style>
body {
	background-color: black;
	color: yellow;
}

#info {
	margin-left: 100px;
	font-size: 80px;
}
</style>
</head>
<body onload="startFetch()">
  <h1>Logging de temperatures. IoT. Sensor DS18B20</h1>
  <div id="temperatures"></div>

  <script type="text/javascript">
    
    var textbox = document.getElementById("textbox");
    var button = document.getElementById("button");
    var tempscript;
    
    function startFetch() {
      tempscript = document.createElement("script");
      tempscript.type = "text/javascript";
      tempscript.id = "tempscript";
      tempscript.src = "http://79.154.207.42:5000/temperatures";
      document.body.appendChild(tempscript);
    }
    
    function JSONPHandler(data) {
      //alert(data.result[0].temp);
      var temperatures = '<ul>';
      for (var i = 0; i < data.result.length;i++) {
      	var d = Date.parse(data.result[i].datetime);
      	var n = new Date();
		n.setTime(d);

		var dia = n.getDate();
		var mes = n.getMonth()+1; //els mesos van de 0 a 11
		var hores = n.getHours();
		var minuts = n.getMinutes();
		var segons = n.getSeconds();

		if (dia.toString().length == 1) dia = '0' + dia;
		if (mes.toString().length == 1) mes = '0' + mes;
		if (hores.toString().length == 1) hores = '0' + hores;
		if (minuts.toString().length == 1) minuts = '0' + minuts;
		if (segons.toString().length == 1) segons = '0' + segons;
      	var dia_hora = dia + '/' + mes+ '/' + n.getFullYear() + ' ' + hores + ':' + minuts+ ':' + segons; 
      	//temperatures += '<li>' + minuts + '</li>';
      	temperatures += '<li>' + data.result[i].temp + ' (' + dia_hora + ')</li>';
      }
      temperatures += '</ul>';
      document.getElementById("temperatures").innerHTML = temperatures;
    }
    
  </script>
    
</body>

Exemple amb la llibreria highcharts.com

Highcharts temprestapi.png

El següent exemple ja seria fer una gràfica amb la llibreria highcharts.com.

Parteixo de l'exemple examples/line-time-series. És una sèrie temporal de valors. Té la particularitat de què podem fer un drag sobre les dades, de manera que podem fer un zoom de les dades.

Intentant seguir de forma fidedigna l'exemple, m'he trobat un problemes amb CORS. Si les dades estan en el mateix domini que el servidor web, com és el cas de www.highcharts.com, no hi ha problemes amb l'origen de les dades. Però el meu cas és diferent: jo estic fent una aplicació web local que vol agafar les dades de la Raspberry que està a 79.154.207.42, i això dóna una problema degut a CORS (origen de les dades) tempscript.src = "http://79.154.207.42:5000/temperatures"; //tempscript.src = "https://www.highcharts.com/samples/data/jsonp.php?filename=usdeur.json&callback=?"; </pre> Tampoc funciona si en comptes de http://79.154.207.42:5000 faig servir http://192.168.1.37:5000, dins de la xarxa local (el portàtil és 1.38 i la Raspberry és 1.37).

Per tant, modifico el codi original de highcharts.com, de manera que ara utilitzo la tècnica de JSONP.

Un altre problema és que les dades tal com em vénen (en el meu format JSON), s'han de transformar a un altre format JSON per tal de què la llibreria highchart reconegui les dades de l'eix de les X, i de l'eix de les Y.

Les dades de:

són del tipus:

?([
[Date.UTC(2013,5,2),0.7695],
[Date.UTC(2013,5,3),0.7648],
[Date.UTC(2013,5,4),0.7645],
[Date.UTC(2013,5,5),0.7638],
[Date.UTC(2013,5,6),0.7549],
...

console.log(data);
Array [ Array[2], Array[2], Array[2], Array[2], Array[2], Array[2], Array[2], Array[2], Array[2], Array[2], 641 more… ]  index2.htm:40:13

és un array d'arrays (bidimensionals).

Les meves dades són del tipus:

?(
{ "result": [ 
	{ "datetime": "Mon, 03 Apr 2017 21:30:51 GMT", "temp": 19.75 },
	{ "datetime": "Mon, 03 Apr 2017 21:31:02 GMT", "temp": 22.53 }, 


console.log(data.result);
Array [ Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, 169 more… ]

és un array d'objectes.

Per tal de convertir el meu array d'objectes a un array d'arrays bidimensionals farem:

        var arr1 = [];
        var arr2 = [];
        arr2.push(data.result[0].datetime);
        arr2.push(data.result[0].temp);
        arr1.push(arr2);
        arr2 = [];
        arr2.push(data.result[1].datetime);
        arr2.push(data.result[1].temp);
        arr1.push(arr2);
        arr2 = [];
        arr2.push(data.result[2].datetime);
        arr2.push(data.result[2].temp);
        arr1.push(arr2);
        arr2 = [];
        console.log(arr1);

que programàticament és:

        var arr1 = [];
        for (var i=0;i<data.result.length;i++) {
            var arr2 = [];
            var dia_hora = Date.parse(data.result[i].datetime);
            arr2.push(dia_hora);
            arr2.push(data.result[i].temp);
            arr1.push(arr2);
        }
        console.log(arr1);

Ara ja es visualitzen les dades, però les dades en l'eix de les X no es veuen bé. Això m'ha donat bastants de problemes. La solució era senzilla. La informació que he de ficar dins de l'array de l'eix de les X és:

var dia_hora = Date.parse(data.result[i].datetime);

que senzillament vol dir que la informació que fico seria el valor numèric que representa els ms que han passat des del 1/1/1970 (que és com Javascript guarda internament els Date).

Finalment, script temp_restapi_v1.htm:

<!DOCTYPE HTML>
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
		<title>Highcharts Example</title>

		<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
		<style type="text/css">
        ${demo.css}
        </style>
    </head>
    <body onload="startFetch()">
    <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
    <script src="https://code.highcharts.com/highcharts.js"></script>
    <script src="https://code.highcharts.com/modules/exporting.js"></script>

    <div id="container" style="min-width: 310px; height: 400px; margin: 0 auto"></div>



    <script type="text/javascript">
    
    var textbox = document.getElementById("textbox");
    var button = document.getElementById("button");
    var tempscript;
    
    function startFetch() {
        tempscript = document.createElement("script");
        tempscript.type = "text/javascript";
        tempscript.id = "tempscript";
        //tempscript.src = "http://192.168.1.37:5000/temperatures";
        tempscript.src = "http://79.154.207.42:5000/temperatures";
        //tempscript.src = "https://www.highcharts.com/samples/data/jsonp.php?filename=usdeur.json&callback=JSONPHandler";
        document.body.appendChild(tempscript);
    }
    
    //si la API retorna una funció de callback anomenada '?', no funciona
    function JSONPHandler(data) {
        //les dades han de ser un array d'arrays. Les meves dades data.result retornen un array d'objectes, on cada objecte són dos elements.
        //data2= [[Date.UTC(2013,1,1),5],[Date.UTC(2014,1,1),4],[Date.UTC(2015,1,1),5],[Date.UTC(2016,1,1),7]];
        //console.log(data2);
        //console.log(data.result[0].temp);
        //console.log(data.result);
        /*
        var arr1 = [];
        var arr2 = [];
        arr2.push(data.result[0].datetime);
        arr2.push(data.result[0].temp);
        arr1.push(arr2);
        arr2 = [];
        arr2.push(data.result[1].datetime);
        arr2.push(data.result[1].temp);
        arr1.push(arr2);
        arr2 = [];
        arr2.push(data.result[2].datetime);
        arr2.push(data.result[2].temp);
        arr1.push(arr2);
        arr2 = [];
        console.log(arr1);
        */
        var arr1 = [];
        for (var i=0;i<data.result.length;i++) {
            var arr2 = [];
            var dia_hora = Date.parse(data.result[i].datetime);
            arr2.push(dia_hora);
            arr2.push(data.result[i].temp);
            arr1.push(arr2);
        }
        //console.log(arr1);

        Highcharts.chart('container', {
            chart: {
                zoomType: 'x'
            },
            title: {
                text: 'Sèrie Temperatura'
            },
            subtitle: {
                text: document.ontouchstart === undefined ?
                'Click and drag in the plot area to zoom in' : 'Pinch the chart to zoom in'
            },
            xAxis: {
                type: 'datetime',
                labels: {
                   format: '{value:%d-%m-%Y - %Hh}',
                   rotation: -45,
                   align: 'right'
                }
            },
            yAxis: {
                title: {
                    text: 'Temperatura (ºC)'
                }
            },
            legend: {
                enabled: false
            },
            plotOptions: {
                area: {
                    fillColor: {
                        linearGradient: {
                            x1: 0,
                            y1: 0,
                            x2: 0,
                            y2: 1
                        },
                        stops: [
                            [0, Highcharts.getOptions().colors[0]],
                            [1, Highcharts.Color(Highcharts.getOptions().colors[0]).setOpacity(0).get('rgba')]
                        ]
                    },
                    marker: {
                        radius: 2
                    },
                    lineWidth: 1,
                    states: {
                        hover: {
                            lineWidth: 1
                        }
                    },
                    threshold: null
                }
            },

            series: [{
                type: 'area',
                name: 'Sèrie Temperatura',
                data: arr1
            }]
        });
        }

    </script>
    </body>
</html>

Com es veu en la gràfica, les dades encara no són reals. Bàsicament el sensor està dins de casa (sota els efectes del termostat, i a la tarda el sol toca directament la carcassa, amb la qual cosa el sensor s'escalfa. A més, les dades del principi són random, de quan estava fent proves.

TBD. CORS (TBD)

A l'hora de fer la API m'he trobat amb el problema del Cross Origin Problem i ho he solucionat amb la tècnica del JSONP.

Si no vull la solució JSONP i fer que la resposta sigui purament JSON, he d'habilitar CORS (Cross-Origin Resource Sharing). Això es pot fer en el servidor (que seria la bona solució), o bé en els clients.

La solució passaria per tal de què el meu servidor permeti CORS.

De fet, seria bastant senzill implementar-ho:

For simple CORS requests, the server only needs to add the following header to its response:

Access-Control-Allow-Origin: *

Quan el client fa una petició, en la capçalera de la resposta del client s'hauria d'incloure aquesta directiva.

La solució per a Flask pot estar aquí:

Altres. Llegir

Comanda scp

$ sshpass -p 'raspberry' scp joanillo_temperatura_restapi.py pi@192.168.1.37:/home/pi/joanillo_temperatura_restapi/v1

datetime local o UTC

A la RPi hem de tenir ben configurada l'hora del sistema. Això és fàcil, a raspi-config hi ha l'opció de triar el fus horari del sistema.

$ date
Wed  5 Apr 15:43:32 CEST 2017

hora universal:
$ date -u
Wed  5 Apr 13:43:32 CEST 2017

Però el problema del desfase de dues hores que em trobava no anava per aquí. El problema és que en el script de python estava escrivint l'hora UTC en comptes de l'hora real (tot i que això de fet hauria de ser el correcte...).

>>> import datetime
>>> print(datetime.datetime.utcnow())
2017-04-05 21:22:21.228799
>>> print(datetime.datetime.now())
2017-04-05 23:22:17.493516

Per tant en el script temp_logging.py utilitzaré la funció datetime.datetime.now() -> NO!!!. He d'utilitzar datetime.datetime.utcnow() i sempre hores universals. Doncs si no tindré un problema quan es faci el canvi d'hora a l'octubre o al març. Necessito tenir una referència d'hora absoluta, i aquesta és l'hora UTC. Aquesta és la manera de treballar, i així treballa tothom, per ex meteo.cat.

JSONPHandler({ "result": [ { "datetime": "Fri, 28 Apr 2017 06:29:05 GMT", "temp": 11.88 } ] } )

Ara ja estic registrant amb datetime UTC/GMT que és l'hora universal.

El canvi d'hora a l'hivern (a l'octubre) es recupera l'hora normal. Quan tenim una hora extra és a l'estiu.

Per ex, amb Javascript tenim:

var now = new Date();
document.getElementById("time").innerHTML = now;

Fri Apr 28 2017 10:16:55 GMT+0200 (CEST)

Arrencar el servei en l'inici del sistema

Fins ara arrencava el servei web de la següent manera:

$ source venv/bin/activate
(venv) joan@joanillo:~$ python /home/pi/python/test_restapi.py

Però es pot arrencar més ràpidament:

$ /home/pi/venv/bin/python /home/pi/python/test_restapi.py
 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

I per tant, en l'inici del sistema de d'iniciar els scripts del data logging, i del servei web. Quedarà:

/usr/bin/python /home/pi/python/temp_logging.py &
sleep 1 
/home/pi/venv/bin/python /home/pi/joanillo_temperatura_restapi/v1/joanillo_temperatura_restapi.py
# o bé:
#echo 'source /home/pi/venv/bin/activate; python /home/pi/joanillo_temperatura_restapi/v1/joanillo_temperatura_restapi.py' | /bin/bash

Còpia de seguretat de MongoDB

A la RPi:

$ sudo mkdir /var/backups/mongobackups
$ sudo mongodump --db temperatura --out /var/backups/mongobackups/`date +"%d%y%m%d"`

En el crontab afegeixo aquestes dues línies:

10 0    * * 1   root    mongodump --db temperatura --out /var/backups/mongobackups/`date+"%d%y%m%d"` 
15 0    * * 1   root    find /var/backups/mongobackups/ -mtime +10 -exec rm -rf {} \;

Dades de prova. Mitjanes de temperatura

Aclaració, insert amb format local i amb format UTC

insert amb hora UTC:

db.mitjana.insert({ tipus: 'day', temp: 14.0, datetime: new Date("2018-05-01T00:00:00Z")})

db.mitjana.find()
...
{ "_id" : ObjectId("590215babd2b5fb69e2f0c58"), "tipus" : "day", "temp" : 14, "datetime" : ISODate("2018-05-01T00:00:00Z") }

insert amb hora local: (el paràmetre del mes compte perquè va de 0-11 fent-ho d'aquesta manera)

db.mitjana.insert({ tipus: 'day', temp: 14.1, datetime: new Date(2018,4,2,0,0,0)})

db.mitjana.find()
...
{ "_id" : ObjectId("59021642bd2b5fb69e2f0c59"), "tipus" : "day", "temp" : 14.1, "datetime" : ISODate("2018-05-01T22:00:00Z") }

Dades de prova

Format UTC, mes de maig
db.mitjana.insert({ tipus: 'day', tempmax: 16.5, tempmin: 12.5, tempavg: 14.5, datetime: new Date("2016-05-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 15.5, tempmin: 11.5, tempavg: 13.5, datetime: new Date("2016-05-02T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 19.0, tempmin: 10.5, tempavg: 12.5, datetime: new Date("2016-05-03T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 17.5, tempmin: 8.0, tempavg: 14.5, datetime: new Date("2016-05-04T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 16.2, tempmin: 13.3, tempavg: 14.7, datetime: new Date("2016-05-05T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 17.2, tempmin: 11.5, tempavg: 14.4, datetime: new Date("2016-05-06T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 18.32, tempmin: 9.54, tempavg: 14.2, datetime: new Date("2016-05-07T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 15.55, tempmin: 11.5, tempavg: 13.5, datetime: new Date("2016-05-08T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 17.54, tempmin: 12.5, tempavg: 14.6, datetime: new Date("2016-05-09T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 18.56, tempmin: 14.5, tempavg: 16.2, datetime: new Date("2016-05-10T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 21.5, tempmin: 14.5, tempavg: 16.4, datetime: new Date("2016-05-11T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 22.5, tempmin: 14.5, tempavg: 17.3, datetime: new Date("2016-05-12T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 19.5, tempmin: 10.5, tempavg: 12.2, datetime: new Date("2016-05-13T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 14.1, tempmin: 11.1, tempavg: 12.0, datetime: new Date("2016-05-14T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 14.2, tempmin: 8.5, tempavg: 9.6, datetime: new Date("2016-05-15T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 13.5, tempmin: 7.5, tempavg: 9.8, datetime: new Date("2016-05-16T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 12.5, tempmin: 8.25, tempavg: 10.5, datetime: new Date("2016-05-17T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 12.35, tempmin: 8.75, tempavg: 10.2, datetime: new Date("2016-05-18T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 11.5, tempmin: 9.5, tempavg: 10.6, datetime: new Date("2016-05-19T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 14.25, tempmin: 10.5, tempavg: 12.2, datetime: new Date("2016-05-20T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 16.5, tempmin: 9.75, tempavg: 13.3, datetime: new Date("2016-05-21T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 16.75, tempmin: 12.5, tempavg: 14.4, datetime: new Date("2016-05-22T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 17.57, tempmin: 12.53, tempavg: 15.5, datetime: new Date("2016-05-23T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 17.75, tempmin: 11.5, tempavg: 14.5, datetime: new Date("2016-05-24T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 15.5, tempmin: 10.54, tempavg: 13.5, datetime: new Date("2016-05-25T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 16.54, tempmin: 11.5, tempavg: 14.3, datetime: new Date("2016-05-26T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 18.5, tempmin: 11.45, tempavg: 14.4, datetime: new Date("2016-05-27T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 17.5, tempmin: 11.15, tempavg: 13.5, datetime: new Date("2016-05-28T00:00:00Z")})


mes de juny
db.mitjana.insert({ tipus: 'day', tempmax: 19.5, tempmin: 14.5, tempavg: 15.5, datetime: new Date("2016-06-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 18.5, tempmin: 11.5, tempavg: 14.5, datetime: new Date("2016-06-02T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 17.35, tempmin: 9.57, tempavg: 13.5, datetime: new Date("2016-06-03T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 18.85, tempmin: 10.34, tempavg: 15.5, datetime: new Date("2016-06-04T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 19.35, tempmin: 12.5, tempavg: 15.7, datetime: new Date("2016-06-05T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 21.5, tempmin: 14.5, tempavg: 15.4, datetime: new Date("2016-06-06T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 22.22, tempmin: 13.5, tempavg: 15.2, datetime: new Date("2016-06-07T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 20.5, tempmin: 12.5, tempavg: 16.5, datetime: new Date("2016-06-08T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 14.5, tempmin: 14.5, tempavg: 15.6, datetime: new Date("2016-06-09T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 24.5, tempmin: 14.5, tempavg: 17.2, datetime: new Date("2016-06-10T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 18.5, tempmin: 14.65, tempavg: 17.4, datetime: new Date("2016-06-11T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 24.5, tempmin: 12.85, tempavg: 18.3, datetime: new Date("2016-06-12T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 20.5, tempmin: 11.5, tempavg: 13.2, datetime: new Date("2016-06-13T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 14.5, tempmin: 8.35, tempavg: 13.0, datetime: new Date("2016-06-14T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 21.5, tempmin: 8.55, tempavg: 10.6, datetime: new Date("2016-06-15T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 22.22, tempmin: 9.5, tempavg: 10.8, datetime: new Date("2016-06-16T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 14.5, tempmin: 8.5, tempavg: 11.5, datetime: new Date("2016-06-17T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 13.58, tempmin: 7.31, tempavg: 11.2, datetime: new Date("2016-06-18T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 14.5, tempmin: 8.32, tempavg: 11.6, datetime: new Date("2016-06-19T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 15.55, tempmin: 11.5, tempavg: 13.2, datetime: new Date("2016-06-20T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 14.5, tempmin: 12.0, tempavg: 12.3, datetime: new Date("2016-06-21T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 17.75, tempmin: 14.5, tempavg: 15.4, datetime: new Date("2016-06-22T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 19.59, tempmin: 14.25, tempavg: 16.5, datetime: new Date("2016-06-23T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 17.5, tempmin: 12.5, tempavg: 15.5, datetime: new Date("2016-06-24T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 15.5, tempmin: 11.11, tempavg: 14.5, datetime: new Date("2016-06-25T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 16.56, tempmin: 14.5, tempavg: 15.3, datetime: new Date("2016-06-26T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 17.57, tempmin: 13.5, tempavg: 15.4, datetime: new Date("2016-06-27T00:00:00Z")})
db.mitjana.insert({ tipus: 'day', tempmax: 18.58, tempmin: 11.51, tempavg: 14.5, datetime: new Date("2016-06-28T00:00:00Z")})

========
db.mitjana.insert({ tipus: 'month', tempmax: 13.58, tempmin: 11.51, tempavg: 13.5, datetime: new Date("2015-01-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'month', tempmax: 18.58, tempmin: 10.51, tempavg: 14.7, datetime: new Date("2015-02-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'month', tempmax: 17.72, tempmin: 9.59, tempavg: 15.2, datetime: new Date("2015-03-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'month', tempmax: 16.68, tempmin: 13.51, tempavg: 16.8, datetime: new Date("2015-04-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'month', tempmax: 21.51, tempmin: 13.51, tempavg: 17.5, datetime: new Date("2015-05-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'month', tempmax: 22.28, tempmin: 14.54, tempavg: 20.3, datetime: new Date("2015-06-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'month', tempmax: 23.53, tempmin: 13.31, tempavg: 21.3, datetime: new Date("2015-07-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'month', tempmax: 21.21, tempmin: 14.54, tempavg: 18.4, datetime: new Date("2015-08-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'month', tempmax: 22.22, tempmin: 12.22, tempavg: 17.4, datetime: new Date("2015-09-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'month', tempmax: 18.18, tempmin: 13.53, tempavg: 16.1, datetime: new Date("2015-10-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'month', tempmax: 19.19, tempmin: 12.12, tempavg: 14.1, datetime: new Date("2015-11-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'month', tempmax: 21.21, tempmin: 13.13, tempavg: 16.1, datetime: new Date("2015-12-01T00:00:00Z")})

db.mitjana.insert({ tipus: 'month', tempmax: 21.21, tempmin: 11.51, tempavg: 14.5, datetime: new Date("2016-01-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'month', tempmax: 18.58, tempmin: 12.12, tempavg: 15.5, datetime: new Date("2016-02-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'month', tempmax: 17.58, tempmin: 15.51, tempavg: 16.5, datetime: new Date("2016-03-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'month', tempmax: 18.58, tempmin: 14.51, tempavg: 17.5, datetime: new Date("2016-04-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'month', tempmax: 19.19, tempmin: 11.53, tempavg: 18.5, datetime: new Date("2016-05-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'month', tempmax: 22.21, tempmin: 9.31, tempavg: 19.5, datetime: new Date("2016-06-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'month', tempmax: 23.23, tempmin: 14.14, tempavg: 20.5, datetime: new Date("2016-07-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'month', tempmax: 17.57, tempmin: 15.15, tempavg: 19.1, datetime: new Date("2016-08-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'month', tempmax: 19.59, tempmin: 14.41, tempavg: 18.1, datetime: new Date("2016-09-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'month', tempmax: 19.91, tempmin: 15.15, tempavg: 17.1, datetime: new Date("2016-10-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'month', tempmax: 18.16, tempmin: 12.12, tempavg: 16.1, datetime: new Date("2016-11-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'month', tempmax: 17.71, tempmin: 13.13, tempavg: 15.1, datetime: new Date("2016-12-01T00:00:00Z")})
=======
db.mitjana.insert({ tipus: 'year', tempmax: 20.58, tempmin: 13.51, tempavg: 18.3, datetime: new Date("2014-01-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'year', tempmax: 28.45, tempmin: 11.51, tempavg: 18.7, datetime: new Date("2015-01-01T00:00:00Z")})
db.mitjana.insert({ tipus: 'year', tempmax: 22.22, tempmin: 9.09, tempavg: 19.2, datetime: new Date("2016-01-01T00:00:00Z")})

Però el tema UTC és un embolic i si ho fem així introdueixo les dates en format UTC per tal de què coincideixi amb les 0h0min de l'hora local (la qual cosa no és recomanable perquè ho migro tot a hora UTC): (ho faig bé perquè fico dos hores de més, però això seria incorrecte a l'hivern que hauria de ser una hora de més).

mes de maig
db.mitjana.insert({ tipus: 'day', temp: 14.5, datetime: new Date(2016,4,1,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 13.5, datetime: new Date(2016,4,2,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 12.5, datetime: new Date(2016,4,3,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 14.5, datetime: new Date(2016,4,4,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 14.7, datetime: new Date(2016,4,5,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 14.4, datetime: new Date(2016,4,6,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 14.2, datetime: new Date(2016,4,7,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 13.5, datetime: new Date(2016,4,8,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 14.6, datetime: new Date(2016,4,9,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 16.2, datetime: new Date(2016,4,10,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 16.4, datetime: new Date(2016,4,11,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 17.3, datetime: new Date(2016,4,12,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 12.2, datetime: new Date(2016,4,13,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 12.0, datetime: new Date(2016,4,14,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 9.6, datetime: new Date(2016,4,15,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 9.8, datetime: new Date(2016,4,16,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 10.5, datetime: new Date(2016,4,17,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 10.2, datetime: new Date(2016,4,18,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 10.6, datetime: new Date(2016,4,19,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 12.2, datetime: new Date(2016,4,20,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 13.3, datetime: new Date(2016,4,21,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 14.4, datetime: new Date(2016,4,22,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 15.5, datetime: new Date(2016,4,23,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 14.5, datetime: new Date(2016,4,24,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 13.5, datetime: new Date(2016,4,25,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 14.3, datetime: new Date(2016,4,26,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 14.4, datetime: new Date(2016,4,27,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 13.5, datetime: new Date(2016,4,28,2,0,0)})

mes de juny
db.mitjana.insert({ tipus: 'day', temp: 15.5, datetime: new Date(2016,5,1,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 14.5, datetime: new Date(2016,5,2,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 13.5, datetime: new Date(2016,5,3,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 15.5, datetime: new Date(2016,5,4,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 15.7, datetime: new Date(2016,5,5,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 15.4, datetime: new Date(2016,5,6,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 15.2, datetime: new Date(2016,5,7,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 14.5, datetime: new Date(2016,5,8,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 15.6, datetime: new Date(2016,5,9,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 17.2, datetime: new Date(2016,5,10,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 17.4, datetime: new Date(2016,5,11,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 18.3, datetime: new Date(2016,5,12,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 13.2, datetime: new Date(2016,5,13,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 13.0, datetime: new Date(2016,5,14,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 10.6, datetime: new Date(2016,5,15,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 10.8, datetime: new Date(2016,5,16,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 11.5, datetime: new Date(2016,5,17,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 11.2, datetime: new Date(2016,5,18,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 11.6, datetime: new Date(2016,5,19,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 13.2, datetime: new Date(2016,5,20,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 14.3, datetime: new Date(2016,5,21,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 15.4, datetime: new Date(2016,5,22,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 16.5, datetime: new Date(2016,5,23,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 15.5, datetime: new Date(2016,5,24,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 14.5, datetime: new Date(2016,5,25,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 15.3, datetime: new Date(2016,5,26,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 15.4, datetime: new Date(2016,5,27,2,0,0)})
db.mitjana.insert({ tipus: 'day', temp: 14.5, datetime: new Date(2016,5,28,2,0,0)})
========
db.mitjana.insert({ tipus: 'month', temp: 14.5, datetime: new Date(2016,0,1,2,0,0)})
db.mitjana.insert({ tipus: 'month', temp: 15.5, datetime: new Date(2016,1,1,2,0,0)})
db.mitjana.insert({ tipus: 'month', temp: 16.5, datetime: new Date(2016,2,1,2,0,0)})
db.mitjana.insert({ tipus: 'month', temp: 17.5, datetime: new Date(2016,3,1,2,0,0)})
db.mitjana.insert({ tipus: 'month', temp: 18.5, datetime: new Date(2016,4,1,2,0,0)})
db.mitjana.insert({ tipus: 'month', temp: 19.5, datetime: new Date(2016,5,1,2,0,0)})
db.mitjana.insert({ tipus: 'month', temp: 20.5, datetime: new Date(2016,6,1,2,0,0)})
db.mitjana.insert({ tipus: 'month', temp: 19.1, datetime: new Date(2016,7,1,2,0,0)})
db.mitjana.insert({ tipus: 'month', temp: 18.1, datetime: new Date(2016,8,1,2,0,0)})
db.mitjana.insert({ tipus: 'month', temp: 17.1, datetime: new Date(2016,9,1,2,0,0)})
db.mitjana.insert({ tipus: 'month', temp: 16.1, datetime: new Date(2016,10,1,2,0,0)})
db.mitjana.insert({ tipus: 'month', temp: 15.1, datetime: new Date(2016,11,1,2,0,0)})
=======
db.mitjana.insert({ tipus: 'year', temp: 18.3, datetime: new Date(2014,0,1,2,0,0)})
db.mitjana.insert({ tipus: 'year', temp: 18.7, datetime: new Date(2015,0,1,2,0,0)})
db.mitjana.insert({ tipus: 'year', temp: 19.2, datetime: new Date(2016,0,1,2,0,0)})

TODO

Logging sense connexió a Internet (todo)

Encara que no tingui connexió puc registrar les temperatures, però el problema està en què l'hora del sistema està malament. Sembla ser que perquè la RPi s'enteri de l'hora correcta he de tenir connexió a Inet. Això és el que m'ha passat en la sèrie registrada a Bagà.

TODO. Veure com s'ha de fer per tenir l'hora correcta.

La API: joanillo_temp_restapi

En tot aquest article s'ha estat discutint la posta a punt de la Rest API. La única cosa que fa és mostrar totes les temperatures que s'han registrat a la base de dades, i aquesta és la versió 1 (v1).


creat per Joan Quintana Compte, febrer 2017, 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