Paso 16: Diseño - tienda
OK nos está consiguiendo buenos datos de nuestros sensores, permite corral en trozos más útiles y almacenar en una base de datos. Podríamos hacer una base de datos en el ordenador, pero ya que nos gustaría compartir esta información, tiene más sentido poner en línea. Hay servicios especiales que están diseñados específicamente para hacer este tipo de cosas como Pachube , pero voy a reinventar la rueda y diseñar mi propia aplicación web que almacena y muestra datos de energía. (Sobre todo quiero jugar con Google App Engine!)
Tienes 5 minutos!
Tenemos datos cada pocos segundos del módem XBee en el kill a watt. Podríamos, en teoría, poner los datos en nuestra base de datos cada 2 segundos pero que globo rápidamente la cantidad de almacenamiento necesario. También se haría clasificando los datos difícil. Así que en lugar de otro permite añadir todos los datos del sensor durante 5 minutos y luego tomar la media.
Lo haremos manteniendo dos contadores y un recuento. Un contador de tiempo seguimiento cuánto su ya fue enviada la última señal del sensor, y el otro seguirá si su sido 5 minutos. El recuento se acumulen todos lo vatios-hora (medición de vatios * tiempo desde último datos del sensor). Entonces al final podemos media por 5 minutos
Este trozo de código va casi al principio, crea los temporizadores y tally y los Inicializa
...
fiveminutetimer = lasttime = time.time() # obtener la hora actual
cumulativewatthr = 0
...
Entonces, después de recibir nuestros datos podemos poner en este trozo de código:
# sumar delta-watthr desde la última lectura
# Averiguar cuántos vatios por hora fueron utilizados desde la última lectura
elapsedSeconds = time.time() - lasttime
dwatthr = (avgwatt * elapsedseconds) / (60.0 * 60.0) # 60 segundos 60 minutos = 1 hora
lasttime = time.time()
Imprimir "\t\tWh utilizado en el pasado", elapsedseconds, "segundos:", dwatthr
cumulativewatthr += dwatthr
# Determinar el minuto de la hora (es decir 6:42 -> '42')
currminute = (int(time.time())/60) % 10
# Figura hacia fuera si su estado cinco minutos desde nuestra última guardar
Si (((time.time()-fiveminutetimer) > = 60.0) y (currminute % 5 == 0)):
# Imprimir los datos de depuración, Wh utilizado en los últimos 5 minutos
avgwattsused = cumulativewatthr * (60.0 * 60.0 / (time.time() - fiveminutetimer))
impresión time.strftime («%y %m %d, % H: %M"),",", cumulativewatthr," Wh = ", avgwattsused,"Promedio de W")
# Reiniciar el temporizador de 5 minutos
fiveminutetimer = time.time()
cumulativewatthr = 0
Tenga en cuenta que se calcula delta-watthours, la pequeña cantidad de energía que utiliza cada pocos segundos. Entonces podemos obtener la potencia promedio utilizada dividiendo la watthours por el número de horas que han pasado (aproximadamente 1/12). En vez de ir por 5 minutos exactos, he decidido informar sólo sobre las 5 de la hora (: 05: 10, etc.) para que fácil de enviar todos los datos a la vez si theres múltiples sensores que puso en marcha en diferentes momentos.
Descargar wattcher-5minreporter.py de la página de descarga. Si ejecuta esto, tendrás un flujo constante
Cerca del final se puede ver la fecha y hora, el Watthrs utilizado en los últimos minutos y la potencia promedio
Multisensor!
Tenemos buenos datos pero hasta ahora sólo funciona con un sensor. Múltiples sensores lo arruinara! Tiempo para añadir soporte para más de un XBee para que puedo realizar un seguimiento de algunas habitaciones. Voy a hacer que al crear una clase de objeto en python y utilizando la dirección de XBee (Recuerde que de la parte 1?) para seguir. Reemplazaré el código que acabo de escribir lo siguiente:
En la parte superior, en lugar de las variables del contador de tiempo, tendré una declaración de clase completo y crear una matriz para almacenarlas:
### almacenar datos del sensor e historias por sensor
clase Fiveminutehistory:
DEF init (sí, sensornum):
Self.sensornum = sensornum
Self.fiveminutetimer = time.time() # pista datos durante 5 minutos
Self.lasttime = time.time()
Self.cumulativewatthr = 0
DEF addwatthr (self, deltawatthr):
Self.cumulativewatthr += float(deltawatthr)
DEF reset5mintimer(self):
Self.cumulativewatthr = 0
Self.fiveminutetimer = time.time()
DEF avgwattover5min(self):
volver self.cumulativewatthr * (60.0 * 60.0 / (time.time() - self.fiveminutetimer))
DEF str(self):
volver "[id #: %d, 5mintimer: %f, lasttime; %f, cumulativewatthr: %f] "% (self.sensornum, self.fiveminutetimer, self.lasttime, self.cumulativewatthr)
### una serie de historias
sensorhistories =]
Cuando el objeto se inicializa con el número de identificación del sensor, también establece los dos temporizadores y acumulado Watthrs siguieron. También he creado algunas funciones auxiliares que hará que el código más limpio
Justo debajo crearé una pequeña función que me ayude a crear y recuperar estos objetos. Dado un número de identificación de XBee o hace una nueva o es la referencia a ella
### retriever
DEF findsensorhistory(sensornum):
para la historia en sensorhistories:
si history.sensornum == sensornum:
volver historia
# no se encuentran, ¡ Créalo!
historia = Fiveminutehistory(sensornum)
sensorhistories.Append(History)
volver historia
Finalmente, en lugar del promedio vatios cálculo código escrito anteriormente, que lo reemplazamos con el siguiente fragmento, que retreives el objeto y las pistas de alimentación uso con los temporizadores de objeto
# recuperar la historia de este sensor
sensorhistory = findsensorhistory(xb.address_16)
#print sensorhistory
# sumar delta-watthr desde la última lectura
# Averiguar cuántos vatios por hora fueron utilizados desde la última lectura
elapsedSeconds = time.time() - sensorhistory.lasttime
dwatthr = (avgwatt * elapsedseconds) / (60.0 * 60.0) # 60 segundos 60 minutos = 1 hora
sensorhistory.lasttime = time.time()
Imprimir "\t\tWh utilizado en el pasado", elapsedseconds, "segundos:", dwatthr
sensorhistory.addwatthr(dwatthr)
# Determinar el minuto de la hora (es decir 6:42 -> '42')
currminute = (int(time.time())/60) % 10
# Figura hacia fuera si su estado cinco minutos desde nuestra última guardar
Si (((time.time()-sensorhistory.fiveminutetimer) > = 60.0) y (currminute % 5 == 0)):
# Imprimir los datos de depuración, Wh utilizado en los últimos 5 minutos
avgwattsused = sensorhistory.avgwattover5min()
imprimir time.strftime («%y %m %d, % H: %M"),","sensorhistory.cumulativewatthr,"Wh = ", avgwattsused," promedio de W "
# Reiniciar el temporizador de 5 minutos
sensorhistory.reset5mintimer()
El código actúa básicamente lo mismo excepto ahora no ahogarse con múltiples datos de sensores! A continuación, mis dos Kill-a-w, uno con un ordenador conectado (100W) y otro con una lámpara (40W)
Sobre la base de datos!
App Engine
Así que queremos tener una computadora en red para almacenar estos datos asi podemos compartir los datos, pero realmente no queremos tener que ejecutar un servidor desde casa! ¿Qué hacer? Así como se ha mencionado antes, se puede utilizar Pachube o similar, pero voy a mostrar cómo a rodar su propia con Motor de aplicaciones de Google (GAE). GAE es básicamente un mini-webserver gratis organizado por Google, que ejecutará la webapps básica sin la molestia de administrar un servidor de base de datos. Cada aplicación tiene algunos marcos de almacenamiento y puede utilizar cuentas de Google para la autenticación. Para empezar te sugiero revisar la Página Web GAE, documentación, etc. Supongo que te has pasado con los tutoriales y saltar a la derecha en diseñar mi aplicación de almacenamiento de datos energía llamada Wattcher (un poco confuso que saber)
En primer lugar, el archivo app.yaml que define mi aplicación tiene este aspecto:
aplicación: wattcher
versión: 1
tiempo de ejecución: python
api_version: 1
Controladores de:
-url: /. *
script: wattcherapp.py
Bastante simple, solo dice que la aplicación utiliza wattcherapp.py como el archivo de origen
A continuación, a bucear en el código python para nuestra aplicación. Primero, los incluye y el índice de base de datos. Para crear una base de datos, realmente definimos - en el archivo de python-, GAE figuras entonces qué tipo de base de datos para crear para usted siguiendo las indicaciones (muy diferentes a MySQL, donde se crearía la DB por separado)
cgi de importación, fecha y hora
de google.appengine.api import usuarios
de google.appengine.ext import webapp
de google.appengine.ext.webapp.util importación run_wsgi_app
de google.appengine.ext import db
clase Powerusage(db. Modelo):
autor = db. UserProperty() # el usuario
sensornum = db. IntegerProperty() # puede tener múltiples sensores
vatios = db. FloatProperty() # cada envío última medición de vatios
fecha = db. DateTimeProperty(auto_now_add=True) # timestamp
Utilizamos el valor por defecto incluye. Tenemos una tabla de base de datos llamada Powerusagey tiene 4 entradas: una para el usuario, uno para el número del sensor, para el último informó Watts usados y uno para un datestamp
Cada 'página' o el funcionamiento de nuestra aplicación web necesita su propia clase. Deja comienzo con la función que nos permite almacenar datos en la DB. Voy a llamar PowerUpdate.
clase PowerUpdate(webapp. RequestHandler):
DEF get(self):
# hacer que el usuario inicie sesión en
Si no users.get_current_user():
Self.Redirect(users.create_login_url(self.request.Uri))
powerusage = Powerusage()
Si users.get_current_user():
powerusage.Author = users.get_current_user()
#print self.request
Si self.request.get('watt'):
powerusage.Watt = float(self.request.get('watt'))
otra cosa:
Self.Response.out.Write ('Couldnt encontrar \'watt\ 'GET propiedad!')
volver
Si self.request.get('sensornum'):
powerusage.sensornum = int(self.request.get('sensornum'))
otra cosa:
powerusage.sensornum = 0 # asumir theres un solo o algo
powerusage.put()
Self.Response.out.Write('OK!')
Cuando enviamos una solicitud para hacer que con un GET call (es decir solicitar la página web), primero haremos que el usuario esté autenticado y conectado así que sabemos su nombre. Entonces vamos a crear una nueva entrada de la base de datos por inicializar una nueva instancia de Powerusage. A continuación veremos la solicitud GET para los datos de watt, que serían en el vatio de formato = 39,2 o similar. Que se analiza por suerte para nosotros, y también podemos conseguir el número de sensor que se pasa en el formato sensornum = 3. Finalmente podemos almacenar los datos en la base de datos permanente
A continuación es una útil función de depuración, simplemente mostrará todos los datos que ha recibido para su cuenta!
clase DumpData(webapp. RequestHandler):
DEF get(self):
# hacer que el usuario inicie sesión en
Si no users.get_current_user():
Self.Redirect(users.create_login_url(self.request.Uri))
Self.Response.out.Write ('< html >< cuerpo > es aquí todos los datos que nos ha enviado: < p >')
powerusages = db. GqlQuery ("SELECT * de Powerusage donde el autor =: 1 ORDER BY fecha", users.get_current_user())
para salidaUtilizado en powerusages:
Si powerused.sensornum:
Self.Response.out.Write (' sensor de < b > %s < /b > \'s #%d ' %
(powerused.author.nickname(), powerused.sensornum))
otra cosa:
Self.Response.out.Write (< b > %s < /b >' % powerused.author.nickname())
Self.Response.out.Write (' usa: %f vatios en %s < p >' % (powerused.watt, powerused.date))
Self.Response.out.Write ("< cuerpo/>< / html >")
Esta función simplemente seleccione (recupera) todas las entradas, ordena por fecha e imprime a cada uno en un momento
Por último vamos a hacer una página frontal básica que mostrará los últimos datapoints enviado
clase MainPage(webapp. RequestHandler):
DEF get(self):
Self.Response.out.Write ('< html >< cuerpo > Bienvenido a Wattcher! < p > aquí está los últimos 10 datapoints: < p >')
powerusages = db. GqlQuery ("SELECT * de Powerusage ORDER BY fecha DESC LIMIT 10")
para salidaUtilizado en powerusages:
Si powerused.sensornum:
Self.Response.out.Write (' sensor de < b > %s < /b > \'s #%d ' %
(powerused.author.nickname(), powerused.sensornum))
otra cosa:
Self.Response.out.Write ('< b > %s < /b >' % powerused.author.nickname())
Self.Response.out.Write (' usa: %f vatios en %s < p >' % (powerused.watt, powerused.date))
Self.Response.out.Write ("< cuerpo/>< / html >")
Muy similar a la función DataDump pero sus solamente 10 puntos de datos y de todos los usuarios, bueno cuando sólo quiere 'check out' pero no quiero entrar
Por último, tenemos una pequeña estructura de inicializador que le dice a GAE que páginas de enlace a qué funciones
aplicación = webapp. () WSGIApplication
[('/', Página principal)]
('/ informe', PowerUpdate),
('/ de la descarga,' DumpData)],
debug = True)
DEF main():
run_wsgi_app(Application)
Si nombre == "principal":
Main()
Prueba!
OK deja probarlo, primero permite visitar http://wattcher.appspot.com/report
Recuerdo que hicimos un requerimiento para suministrar - algunos datos. Permite probar otra vez http://wattcher.appspot.com/report?watt=19.22&sensornum=1
¡ Yay tenemos un OK! Permite comprobar los datos almacenados por visitar http://wattcher.appspot.com/dump
Hay dos entradas porque hice la prueba un poco antes pero se puede ver que hay 2 entradas. ¡ Agradable!
También podemos visitar el panel de control GAE y ver los datos de 'a mano'
de todos modos, ahora que está trabajando, permite volver atrás y añadir la tecnología de información a nuestro script lector sensor
Sacar el informe
Sólo un poco más piratería en el equipo de guión ya terminados. Queremos añadir soporte para enviar datos a GAE. Por desgracia ahora nuestra autenticación se realiza a través de cuentas de Google así que no es fácil de ejecutar en un Arduino. Para adaptarla tienes que enviar el nombre de usuario en el informe y espero que nadie más usa el mismo que (a menos que también agregue un sistema de contraseña básica)
De todos modos, yo totalmente estafado Cómo hacerlo desde algunas personas agradables en Internet
Descargar appengineauth.py desde la Página de descargay cambiar las primeras líneas si es necesario. Codificar la URL que vamos a la cuenta y contraseña como el nombre de la aplicación GAE
users_email_address = "mi cuenta
users_password = "micontraseña"
my_app_name = "wattcher"
target_authenticated_google_app_engine_uri = 'http://wattcher.appspot.com/report'
El verdadero trabajo sucede en esta función sendreport donde se conecta y envía los datos de Watt en el sitio GAE
DEF sendreport (sensornum, watt):
# Esto es donde quiero ir a
serv_uri = target_authenticated_google_app_engine_uri + "? watt="+str(watt) + "& sensornum="+str(sensornum)
serv_args = {}
serv_args [continuar] = serv_uri
serv_args ['auth'] = authtoken
full_serv_uri = "http://wattcher.appspot.com/_ah/login?%s" % (urllib.urlencode(serv_args))
serv_req = urllib2. Request(full_serv_uri)
serv_resp = urllib2.urlopen(serv_req)
serv_resp_body = serv_resp.read()
# serv_resp_body debe contener el contenido de la
target_authenticated_google_app_engine_uri # page - que habrá sido
# Redirigido automáticamente a la página
#
# para comprobar esto, solo voy a imprimir
imprimir serv_resp_body
Por último, nos envuelva añadiendo las siguientes líneas a nuestro script de ordenador, que enviará los datos bien sobre a GAE!
# Además, enviarlo al motor de la aplicación
appengineauth.sendreport (xb.address_16, avgwattsused)
Puede descargar el script final wattcher.py - final de la Página de descarga.
No olvides visitar wattcher.appspot.com para conocer las últimas lecturas