Tweet-a-watt - cómo hacer un medidor de potencia canto... (17 / 19 paso)

Paso 17: Diseño - gráfico

Hacer fotos bonitas

Datos están grandes, pero son mejores visualizaciones. En este paso a manipular nuestra historia almacenado por lo que podemos hacer gráficos muy agradables!

Primero empezaremos haciendo nuestros llamados, los sensores para su más fácil para nosotros saber que es lo que. Luego veremos nuestro gráfico opciones y formatos de datos. Finalmente podrán formatear nuestros datos para que quede listo para graficar

Configuración de los nombres de sensor

Su no divertido tener datos marcados como "sensor #1" por lo que he añadido una página de 'configuración' donde el código del motor de la aplicación mira qué números sensor ha enviado datos a la base de datos y luego le permite nombrarlos. Por supuesto, usted necesita tener el sensor y el envío de datos - primero - antes de que esto funcionará

La pantalla configurar espera algo como la imagen de abajo.

Este código utiliza GET cuando realmente debería usar el POST. Soy un poco viejo y no como depuración con POST así... yeah.

clase configurar (webapp. RequestHandler):
DEF get(self):
# hacer que el usuario iniciar sesión si ningún nombre de usuario se suministra
Si self.request.get('user'):
cuenta = usuarios. User(self.request.get('user'))
otra cosa:
Si no users.get_current_user():
Self.Redirect(users.create_login_url(self.request.Uri))
cuenta = users.get_current_user()

Self.Response.out.Write ('< html >< cuerpo > sistema para arriba su sensornode nombres aquí: < p >')

# encontrar todos los sensores hasta #10
sensorset =]
para que en range(10):
c = db. GqlQuery ("SELECT * de Powerusage donde el autor =: 1 y sensornum =: 2", users.get_current_user(), i)
Si c.get():
sensorset.Append(i)

Self.Response.out.Write ('< forma acción = "/ config" método = "get" >')
sensor de sensorset:
nombre = ""
currnamequery = db. GqlQuery ("SELECT * de Sensorname donde el autor =: 1 y sensornum =: 2", users.get_current_user(), sensor)
currname = currnamequery.get()

# primero ver si la establecemos.
Si self.request.get('sensornum'+str(sensor)):
nombre = self.request.get('sensornum'+str(sensor))
Si no currname:
currname = Sensorname() # crear una nueva entrada
currname.sensornum = sensor de
currname.Author = users.get_current_user()
currname.sensorname = nombre
currname.put()
otra cosa:
# no establecemos lo que trae la entrada actual
Si currname:
nombre = currname.sensorname

Self.Response.out.Write ('Sensor #' + str(sensor) +': < entrada tipo = "texto" name="sensornum'+str(sensor) +" "valor ="' + nombre +' ">< / texto >< p >')

Self.Response.out.Write ("" "< div >< tipo de entrada =" enviar"valor ="Cambiar nombre">< / div >
< / form >
< /body >
< / html > "" ")

Ahora podemos tener datos más útiles en el basurero de la historia

Ahora podemos ver que Phil sobre todo tiene la culpa de nuestra factura de energía.

Visualizador de Google

Así tenemos datos y nos gustaría ver nuestra historia de uso de la energía. Graficación de datos es mucho trabajo, y soy perezoso. Así que mira en línea y encontrar que Google - también - tiene una visualización API! Esto significa que no hay que escribir un montón de código gráfico y sólo se puede conectar a su sistema. Dulce!

OK revisar la Galería de visualizaciones disponibles, soy amigo de éste, la Línea de tiempo anotado

Observe cómo usted puede ver fácilmente los gráficos, desplazamiento, zoom in y out y se etiqueta cada parcela. Ideal para trazar datos de energía!

Formato de datos

Hay algunas restricciones a cómo conseguir los datos para la visualización api y nuestra mejor opción es datos JSon. Lo puedo decir, JSON es lo que sucedió cuando todos decían "wow, XML es muy voluminosos y derrochadores". De todos modos, hay como 4 capas de marco y de instrucciones de interpretación de datos y al final había una biblioteca muy fácil de usar, escrita por el equipo de visualizaciones de Google que me deja 'just do it con una sola llamada al poner los datos en un pitón 'Diccionario' en un determinado formato.

Permite recorrer el código en secciones, ya que la función es bastante larga

clase JSONout(webapp. RequestHandler):
DEF get(self):

# hacer que el usuario iniciar sesión si ningún nombre de usuario se suministra
Si self.request.get('user'):
cuenta = usuarios. User(self.request.get('user'))
otra cosa:
Si no users.get_current_user():
Self.Redirect(users.create_login_url(self.request.Uri))
cuenta = users.get_current_user()

# asume que queremos 24 horas de datos
historytimebegin = 24
Si self.request.get('bhours'):
historytimebegin = int(self.request.get('bhours'))

# asumir queremos datos a partir de hace 0 horas
historytimeend = 0
Si self.request.get('ehours'):
historytimeend = int(self.request.get('ehours'))

formato de los datos # para felicidad JSON
almacén de datos =]
columnnames = ["fecha"]
columnset = set(columnnames)
Descripción = {"fecha": ("datetime", "Fecha")}

# los nombres de cada sensor, si ha configurado
sensornames = [ninguno] * 10

Primero para arriba obtenemos el usuario para que vamos a estar buscando los datos. Entonces tenemos dos variables para definir la cantidad de datos para agarrar. Uno es "ehours" (horas de la final) y el otro es "bhours". Así que si desea las últimas 5 horas, bhours 5 y ehours sería 0. Si desea 5 horas desde hace un dia, bhours sería 29 y ehours sería 24. almacén de datos es donde podremos corall todos los datos. columnnames y descripción son los nombres de cada columna. Siempre tenemos una columna de fecha, luego otra columna para cada corriente de sensor. También tenemos una matriz distinta para almacenar en caché los nombres del sensor especial.

en la siguiente sección. Aquí es donde nosotros realmente los datos de la base de datos. Ahora la aplicación tiene esta molesta restricción, sólo se pueden obtener 1000 puntos de datos a la vez así que lo que hago es pasar 12 horas en un momento. El almacén de datos final tiene todos los puntos pero fácil en la base de datos, supongo. Una cosa que es confusa es quizás cada columna tiene un nombre y una descripción. El nombre es corto, digamos "watts3" sensor #3, pero la descripción podría ser "Banco de trabajo de Limor". ¿Ni siquiera recuerdo escribiendo este código así que tal vez que puede figura hacia fuera por su cuenta?

# no podemos agarrar datapoints más de 1000, gracias al motor de aplicación libre de restricción
# que vale la pena de 3 sensores en un solo día
# por lo que restringirá a sólo tomar 12 horas de datos en un momento, alrededor de 7 sensores vale la pena

mientras que (historytimebegin > historytimeend):
Si (historytimebegin - historytimeend) > 12:
timebegin = datetime.timedelta (horas = - historytimebegin)
timeend = datetime.timedelta (= horas-(historytimebegin-12))
historytimebegin-= 12
otra cosa:
timebegin = datetime.timedelta (horas = - historytimebegin)
historytimebegin = 0
timeend = datetime.timedelta (horas = - historytimeend)

# tomar todos los datos del sensor para ese fragmento de tiempo
powerusages = db. GqlQuery ("seleccionar * de Powerusage donde Fecha >: 1 fecha y <: autor y 2 =: 3 ORDER BY fecha", (datetime.datetime.now), timebegin, datetime.datetime.now () + timeend, cuenta)

# ordenar en el formato adecuado y añadir nombres de sensor de DB si todavía no ha terminado
para salidaUtilizado en powerusages:
Coln "watts" = str(powerused.sensornum)
entrada = {"fecha": powerused.date.replace(tzinfo=utc).astimezone(est), coln: powerused.watt}
Si no (coln en columnset):
columnnames.Append(Coln)
columnset = set(columnnames)
# buscar el nombre del sensor, si podemos
Si (len(sensornames) < powerused.sensornum) o (no sensornames[powerused.sensornum]):
currnamequery = db. GqlQuery ("SELECT * de Sensorname donde el autor =: 1 y sensornum =: 2", cuenta, powerused.sensornum)
nombre = currnamequery.get()

Si no nombre:
sensornames[powerused.sensornum] = "sensor #"+str(powerused.sensornum)
otra cosa:
sensornames[powerused.sensornum] = name.sensorname

Descripción [coln] = ("número", sensornames[powerused.sensornum])
#self.response.out.write(sensornames)

# Añadir una entrada en un momento
DataStore.Append(Entry)

Finalmente al final de todo el bucle, llamar a la función mágica que convierte el Diccionario en JSON, envuélvalo en el paquete de Google visualización apropiado, después escupirla!

# OK todos los datos está listo para ir, imprime en formato JSON.
data_table = gviz_api. DataTable(description)
data_table. LoadData(datastore)
Self.Response.Headers ['Content-Type'] = ' text/plain'
Self.Response.out.Write (data_table. ToJSonResponse(columns_order=(columnnames),
order_by = "fecha"))

Si fueras a visitar http://wattcher.appspot.com/visquery.json?user=adawattz salida a algo como esto:

google.visualization.Query.setResponse({'version':'0.5', 'reqId':'0', 'status':'OK', 'table': {cols: [{id:'date',label:'Date',type:'datetime'},{id:'watts1',label:'Limor',type:'number'},{id:'watts5',label:'Workbench',type:'number'},{id:'watts2',label:'Adafruit',type:'number'},{id:'watts4',label:'Phil2',type:'number'}],rows: [{c:[{v:new Date(2009,1,25,21,20,2)},{v:64.8332291619},,,{v:null}]},{c:[{v:new Date(2009,1,25,21,20,3)},,{v:230.122099757},,{v:null}]},{c:[{v:new Date(2009,1,25,21,20,3)} ,,, {v: 65.4923925044}, {v: null}]}, {c: [{v: Date(2009,1,25,21,20,4) nuevo},,, {v: 48.6947643311}]}, {c: [{v: Date(2009,1,25,21,25,3) nuevo},, {v: 228.409810208}, {v: null}]}, {c: [{v: Date(2009,1,25,21,25,3) nuevo}, {v: 67.3574917331}, {v: null}]}, {c: [{v: Date(2009,1,25,21,25,3) nuevo},,, {v: 66.0046383897}, {v: null}]}, {c: [{v: Date(2009,1,25,21,25,4) nuevo},,, {v: 47.3892235642}]}, {c: [{v: Date(2009,1,25,21,30,2) nuevo}, {v: 84.9379517795},,, {v: null}]}, {c: [{v: Date(2009,1,25,21,30,3) nuevo},,, {v: 99.7553490071}]} , {c: [{v: Date(2009,1,25,21,30,5) nuevo},, {v: 229.73642288}, {v: null}]}, {c: [{v: Date(2009,1,25,21,30,6) nuevo},,, {v: 66.6556291818}, {v: null}]}, {c: [{v: Date(2009,1,25,21,35,2) nuevo},,, {v: 67.3146052998}, {v: null}]}, {c: [{v: Date(2009,1,25,21,35,3) nuevo}, {v: 96.2322216676}, {v: null}]}, {c: [{v: Date(2009,1,25,21,35,3) nuevo},, {v: 226.678267688}, {v: null}]}, {c: [{v: Date(2009,1,25,21,35,4) nuevo},,, {v: 158.428422765}]}, {c: [{v: Date(2009,1,25,21,40,3) nuevo},, {v: 232.644574879}, {v: null}]} , {c: [{v: Date(2009,1,25,21,40,4) nuevo},,, {v: 153.666193493}]}, {c: [{v: Date(2009,1,25,21,40,6) nuevo},,, {v: 66.7874343225}, {v: null}]}, {c: [{v: Date(2009,1,25,21,40,12) nuevo}, {v: 95.0019590395}, {v: null}]}, {c: [{v: Date(2009,1,25,21,40,21) nuevo}, {v: 95.0144043571},,, {v: null}]}, {c: [{v: Date(2009,1,25,21,40,23) nuevo},,, {v: 66.8060307611}, {v: null}]}, {c: [{v: Date(2009,1,25,21,45,2) nuevo},,, {v: 66.9814723201}, {v: null}]}, {c: [{v: Date(2009,1,25,21,45,3) nuevo},, {v: 226.036818816}, {v: null}]} , {c: [{v: Date(2009,1,25,21,45,3) nuevo}, {v: 99.2775581827},,, {v: null}]}, {c: [{v: Date(2009,1,25,21,45,4) nuevo},,, {v: 154.261889366}]}, {c: [{v: Date(2009,1,25,21,50,4) nuevo}, {v: 102.104642018}, {v: null}]}, {c: [{v: Date(2009,1,25,21,50,4) nuevo},,, {v: 155.441084531}]}, {c: [{v: Date(2009,1,25,21,50,5) nuevo},,, {v: 67.0087146687}, {v: null}]}, {c: [{v: Date(2009,1,25,21,50,5) nuevo},, {v: 230.678636915}, {v: null}]}, {c: [{v: Date(2009,1,25,21,55,3) nuevo}, {v: 103.493297176},,, {v: null}]}, {c: [{v : Date(2009,1,25,21,55,3) nuevo},,, {v: 151.309223916}]}, {c: [{v: Date(2009,1,25,21,55,4) nuevo},,, {v: 66.9174858741}, {v: null}]}, {c: [{v: Date(2009,1,25,21,55,4) nuevo},, {v: 227.765325835}, {v: null}]}, {c: [{v: Date(2009,1,25,22,0,3) nuevo},,, {v: 67.0004310254}, {v: null}]}, {c: [{v: Date(2009,1,25,22,0,3) nuevo},,, {v: 150.389989112}]}, {c: [{v: Date(2009,1,25,22,0,3) nuevo},, {v: 230.892049553}, {v: null}]}, {c: [{v: Date(2009,1,25,22,0,4) nuevo}, {v: 92.2432771363}, {v: null}]}, {c: [{v: Date(2009,1,25,22,15,3) nuevo} {v: 97.5910440774}, {v: null}]}, {c: [{v: Date(2009,1,25,22,15,3) nuevo},,, {v: 143.722595861}]}, {c: [{v: Date(2009,1,25,22,15,4) nuevo},,, {v: 64.4898008851}, {v: null}]}, {c: [{v: Date(2009,1,25,22,15,4)},,{v:222.357617868},,{v:null}]}]}}) nuevo;

de todos modos, puedes ver un poco los datos, tenga en cuenta también su llamada a una función, este material es realmente muy rizado!

Ahora ve al Patio de visualizaciones de Google y entrar en esa URL en la caja de arena

Y se puede ver la visualización sí mismo estallar hacia fuera! (esto es sólo una pantalla de tiro así que ir hacerlo yerself si quieres ensuciar)

OK, vaya lío alrededor, añadiendo y cambiando bhours y ehours

Terminando la visualización

OK hemos casi terminado. Ahora solo falta básicamente el código de la caja de arena y hacer una subpágina en nuestra app engine... así:

clase Visualize (webapp. RequestHandler):
DEF get(self):

# hacer que el usuario iniciar sesión si ningún nombre de usuario se suministra
Si self.request.get('user'):
cuenta = usuarios. User(self.request.get('user'))
otra cosa:
Si no users.get_current_user():
Self.Redirect(users.create_login_url(self.request.Uri))
cuenta = users.get_current_user()

historytimebegin = 24 # 24 horas de asumir
Si self.request.get('bhours'):
historytimebegin = int(self.request.get('bhours'))

historytimeend = 0 # asumir hace 0 horas
Si self.request.get('ehours'):
historytimeend = int(self.request.get('ehours'))

# salga a la primera parte, cabeceras,
() self.Response.out.Write
<! Html DOCTYPE público "-//W3C//DTD XHTML 1.0 Strict / / EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" >
< html xmlns = "http://www.w3.org/1999/xhtml" >
< head >
< meta http-equiv = "content-type" content = "text/html; charset = utf-8 "/ >
< title > Google visualización API muestra < / title >
< script tipo = "texto/javascript" src = "http://www.google.com/jsapi" >< / script >
< script tipo = "texto/javascript" >
Google.Load ("visualización", "1", {paquetes: ["annotatedtimeline"]});

función drawVisualizations() {}
)

# crear la visualización
Self.Response.out.Write (nuevo google.visualization.Query ("http://wattcher.appspot.com/visquery.json?user=+
Account.email() +& bhours =+ str(historytimebegin) +") .enviar (
{function(Response)}
(nueva) google.visualization.AnnotatedTimeLine
document.getElementById("visualization")).
Draw(Response.getDataTable(), {"displayAnnotations": true});
});
)

Self.Response.out.Write (}

google.setOnLoadCallback(drawVisualizations);
< /script >
< /HEAD >
< cuerpo estilo = "font-family: Arial; frontera: 0 ninguno;" >
< div id = "visualización" style = "width: 800px; altura: 250px; " >< / div >
< /body >
< / html >)

La primera parte es bastante sencilla, obtener el nombre de usuario o login. Entonces se asume que el usuario quiere 1 último día de los datos, así que set bhours y ehours. Entonces literalmente a imprimir el código que copiamos de sandbox de visualización de Google, hecho!

Viz Viz Viz

Lo único que no pude averiguar es cómo hacer 3 visualizaciones sucediendo a la vez (última hora, día y semana) con el código anterior. Sólo un poco se rompió. Para el triple punto de vista tuve que utilizar iframes :(

clase VisualizeAll(webapp. RequestHandler):
DEF get(self):

# hacer que el usuario iniciar sesión si ningún nombre de usuario se suministra
Si self.request.get('user'):
cuenta = usuarios. User(self.request.get('user'))
otra cosa:
Si no users.get_current_user():
Self.Redirect(users.create_login_url(self.request.Uri))
cuenta = users.get_current_user()

() self.Response.out.Write
< h2 > uso de la energía sobre la última hora: < / h2 >
< iframe src = "gráfico? usuario = adawattz frameborder ="0"width ="100% "height ="300px">
< p > tu navegador no soporta iframes. < /p >
< / iframe >

< h2 > uso de la energía sobre el último día: < / h2 >
< iframe src = "gráfico? usuario = adawattz frameborder ="0"width ="100% "height ="300px">
< p > tu navegador no soporta iframes. < /p >
< / iframe >

< h2 > uso de la energía durante la última semana: < / h2 >
< iframe src = "gráfico? usuario = adawattz frameborder ="0"width ="300% "height ="500px">
< p > tu navegador no soporta iframes. < /p >
< / iframe >

)

De todos modos, funciona muy bien.

Códigos de tiempo!

La última cosa que no revisará aquí es cómo conseguí la fecha y tiempos que EST en lugar de UTC. Lo puedo decir, su tipo de roto y misterioso. Comprobar el código si desea descubrirlo.

Artículos Relacionados

Cómo se mide la potencia del láser de CO2 láser máquina de grabado y corte por láser utilizando un simplificado (bajo coste) CO2 láser medidor de potencia

Cómo se mide la potencia del láser de CO2 láser máquina de grabado y corte por láser utilizando un simplificado (bajo coste) CO2 láser medidor de potencia

medidores de potencia láser más CO2 son muy costosos y están equipadas con capacidades mucho más allá de lo que necesita el común láser máquina operador/propietario.  Estas instrucciones muestran una sub-$100 laser power meter sonda en el trabajo, to
Medidor de potencia $5

Medidor de potencia $5

permite construir un medidor de potencia basado en la web de $5 y romper nuestro uso para ésos con las soluciones a nuestra red anticuada y estilos de vida.Esto es un gran comienzo = > en tiempo real basado en casa poder uso Monitor WebY aquí es un p
Medidor de potencia láser CNI

Medidor de potencia láser CNI

CNI lanzó un medidor de potencia láser termoeléctrico, que es capaz de medir con precisión diferentes potencia del láser. El medidor de energía termoeléctrica láser está equipado con software de PC para almacenar los datos medidos, fácil de operar y
REUTILIZAR su vieja batería del ordenador portátil para hacer un banco de potencia

REUTILIZAR su vieja batería del ordenador portátil para hacer un banco de potencia

Hace unos meses mi batería del ordenador portátil de Dell no funciona. Siempre desenchúfelo de la fuente principal de AC, el portátil apagado inmediatamente. Después de algunos días de frustración, me sustituye la batería y mantiene los muertos uno (
Cómo hacer un banco de potencia Mini Tic Tac / TUTORIAL

Cómo hacer un banco de potencia Mini Tic Tac / TUTORIAL

https://www.youtube.com/watch?v=yLVG9OcHP9c&feature=youtu.bePaso 1: Hacer un banco de potencia Mini Tic Tac necesita!!!!!! En el video de hoy voy a compartir una idea impresionante sobre como hacer un cargador de portátil o de un banco de energía com
Cómo hacer un arco de potencia de goma

Cómo hacer un arco de potencia de goma

Cómo hacer un arco de potencia de goma(Ver Video)Se trata de un gran arco de juguete pequeño que es alimentado con una sola banda de goma. Puede ajustar la potencia del arco simplemente cambiando hacia fuera la goma por una más fuerte.(Tener mucho cu
Fácil de hacer el medidor de empuje

Fácil de hacer el medidor de empuje

Hola. En anterior instructable veíamos cómo controlar sin cepillo motor(link). En este vídeo te mostrará cómo hacer un helicóptero primitivo y un medidor de empuje. En realidad, vamos a hacer sólo una cosa. Un helicóptero que también es un medidor de
Hacer un medidor de la colmena

Hacer un medidor de la colmena

recortar muchas de mis trajes con volantes, pero si estoy haciendo que entro en lugar de usar un patrón necesito alguna manera de averiguar cuántos pies de tela se necesita recoger para obtener un resultado bonito.  Telas de diferentes pesos y tipos
Cómo hacer un medidor de corte

Cómo hacer un medidor de corte

Paso 1: materiales Fuentes:1 "x 2" x 24" tablero roble rojo (área de arte/hobby) - $2,24Tornillo moleteado - $0,92Tuerca insertable a leña - $1,24Pack Junior 5 de hojas de sierra para metales - 2.881/4 barra de espiga (opcional si tienes un
Hacer un medidor de Panel

Hacer un medidor de Panel

Si usted quiere marcar líneas paralelas a una arista, necesita un panel indicador.Son fáciles de hacer de cualquier desechos tienes ahí el taller, y voy a explicar cómo en los siguientes pasos.Si gustaría ver este otro, entonces tengo un video aquí:U
Hacer un "medidor de gancho agarrador"

Hacer un "medidor de gancho agarrador"

este es un juego de reacción rápida que es fácil de hacer.Se necesita:papellápizregla2 personasPaso 1: Conseguir que son papel Bien tomar un regular pedazo de papel y cortar para que tenga la parte roja.Paso 2: Marcarlo! Bueno esta es la parte más di
¿Hacer un medidor de sonido o

¿Hacer un medidor de sonido o

has querido una de esas luces que ves frente a un equipo estéreo?bueno, aquí es cómo hacer uno!necesario realizar herramientas y esas cosas:-los niños la luz del disco-de alambre-destornillador-soldador-5 LEDs-un trozo de cartón-un taladro de 4mmDivi
REUTILIZAR su viejo móvil a hacer clave tamaño potencia banco de baterías

REUTILIZAR su viejo móvil a hacer clave tamaño potencia banco de baterías

como sabemos para cargar cualquier móvil tenemos 5V, así que tenemos el antiguo batería de 3.7V y célula recargable de 1.2V juntos será producir 4.9V que es suficiente para cargar cualquier móvil.Por lo tanto, aquí presentamos Banco de energía del ta