Tweet-a-watt - comment faire un wattmètre gazouillis... (17 / 19 étapes)

Étape 17 : Design - graph

Faire de jolies images

Données sont grandes, mais les visualisations sont mieux. Dans cette étape nous allons manipuler notre histoire stockée afin que nous puissions faire graphiques vraiment sympa !

Première nous allons commencer par faire nos capteurs nommés, alors que c’est plus facile pour nous de garder une trace de qui est ce que. Puis nous allons examiner nos options de graphique et les formats de données. Enfin nous allons reformater nos données pour la rendre prête à une représentation graphique

Configurer les noms de capteur

C’est pas amusant de disposer de données marquées comme « sensor #1 » alors j’ai ajouté une page « config » où l’app engine code examine quels numéros de capteur a transmis des données à la base de données et vous permet ensuite de les nommer. Bien sûr, vous devez avoir le capteur sur et envoi de données - la première - avant que cela fonctionne

L’écran de configuration ressemble à quelque chose comme l’image ci-dessous.

Ce code utilise GET quand elle doit vraiment utiliser POST. Je suis un peu vieux et n’aime pas le débogage avec POST alors... ouais.

classe Configure (webapp. RequestHandler) :
def get(self) :
# faire l’utilisateur ouvrir une session si aucun nom d’utilisateur n’est fourni
Si self.request.get('user') :
compte = users. User(self.Request.get('user'))
autre chose :
Si ce n’est pas users.get_current_user() :
Self.Redirect(Users.create_login_url(self.Request.Uri))
compte = users.get_current_user()

Self.Response.out.Write ("< html >< corps > ensemble vers le haut de votre sensornode de noms ici : < p >')

# trouver tous les capteurs à #10
sensorset =]
car moi dans range(10) :
c = db. GqlQuery ("SELECT * de Powerusage où l’auteur =: 1 et sensornum =: 2", users.get_current_user(), i)
Si c.get() :
sensorset.Append(i)

Self.Response.out.Write ("< forment action =" / config "méthode = « get » >")
pour capteur dans sensorset :
nom = ""
currnamequery = db. GqlQuery ("SELECT * de Sensorname où l’auteur =: 1 AND sensornum =: 2", users.get_current_user(), capteur)
currname = currnamequery.get()

# tout d’abord voir si nous allons mettre !
Si self.request.get('sensornum'+str(sensor)) :
nom = self.request.get('sensornum'+str(sensor))
Si ce n’est pas currname :
currname = Sensorname() # créer une nouvelle entrée
currname.sensornum = capteur
currname.Author = users.get_current_user()
currname.sensorname = nom
currname.put()
autre chose :
# Nous ne sommes pas mettre Oui entrée actuelle de l’extraction
Si currname :
nom = currname.sensorname

Self.Response.out.Write ("capteur #' + str(sensor) +: < input type = « text » name="sensornum'+str(sensor) + "" valeur = « '+ nom +' » >< / texte >< p >')

Self.Response.out.Write ("" "< div >< input type =" submit"value ="Modifier les noms de">< / div >
< / font >
< / body >
< / html > "" ")

Maintenant, nous pouvons avoir des données plus utiles dans la décharge de l’histoire

Maintenant nous pouvons voir que Phil est principalement responsable de notre facture d’électricité !

Visualiseur de Google

Nous avons donc des données et nous aimerions voir notre historique d’utilisation de puissance. Représentation graphique de données est beaucoup de travail, et je suis paresseux. Alors j’ai regarder en ligne et trouver que Google a - aussi - une visualisation API! Cela signifie que je ne dois pas écrire un tas de code graphique et peut juste brancher sur leur système. Sweet !

OK, vérifier la Galerie de visualisations disponibles, je suis passionné de celui-ci, la Chronologie annotée

Notez comment vous pouvez facilement voir les graphiques, défilement autour, zoomer et dézoomer, et chaque parcelle est étiqueté. Parfait pour le traçage des données de puissance !

Formatage des données

Theres quelques restrictions à comment obtenir les données pour la visualisation api et notre meilleure option est de données JSon. Autant que je sache, JSON est ce qui s’est passé quand tout le monde dit « wow, XML est vraiment encombrant et inutile ». En tout cas, theres comme 4 couches de cadre et d’interprétation de données exposition tructions et en fin de compte il y avait une bibliothèque assez facile à utiliser, rédigée par l’équipe Google visualisations qui me permettre de « faites-le » avec un seul appel en mettant les données en un python « dictionnaire » dans un certain format.

Permet de passer par le code dans les sections, étant donné que la fonction est assez longue

classe JSONout(webapp. RequestHandler) :
def get(self) :

# faire l’utilisateur ouvrir une session si aucun nom d’utilisateur n’est fourni
Si self.request.get('user') :
compte = users. User(self.Request.get('user'))
autre chose :
Si ce n’est pas users.get_current_user() :
Self.Redirect(Users.create_login_url(self.Request.Uri))
compte = users.get_current_user()

# suppose que nous voulons que 24 heures de données
historytimebegin = 24
Si self.request.get('bhours') :
historytimebegin = int(self.request.get('bhours'))

# suppose que nous voulons des données à partir de 0 heures
historytimeend = 0
Si self.request.get('ehours') :
historytimeend = int(self.request.get('ehours'))

format de données # pour le bonheur JSON
magasin de données =]
columnNames = ["date"]
jeu de colonnes = set(columnnames)
Description = {« date »: ("datetime", « Date »)}

# les noms de chaque capteur, si configuré
sensornames = [None] * 10

Tout d’abord vers le haut, nous obtenons l’utilisateur que nous allons regarder vers le haut les données. Ensuite, nous avons deux variables utilisées pour définir la quantité de données à saisir. On est "ehours" (heures de la fin) et l’autre est « heures ». Donc, si vous vouliez les 5 dernières heures, heures serait 5 et ehours serait 0. Si vous vouliez 5heures d’il y a un jour, heures serait 29 et ehours serait 24. magasin de données est où nous allons corall toutes les données. columnNames et description sont les « noms » de chaque colonne. Nous avons toujours une colonne de date, puis une autre colonne pour chaque flux de capteur. Nous avons également un tableau distinct pour mettre en cache les noms de capteur spécial.

dans la section suivante ! Voici où nous en fait saisir les données de la base de données. Maintenant moteur app a cela ennuyeux de restriction, vous ne pouvez obtenir 1000 points de données à la fois donc ce que je fais, c’est passer par là 12 heures d’affilée. Le magasin de données final a tous les points, mais c’est plus facile sur la base de données, je suppose. Une chose qui est source de confusion est peut-être chaque colonne a un nom et une description. Le nom est court, par exemple « watts3 » pour capteur #3, mais la description pourrait être « Établi de Limor ». Je ne sais même plus écrire ce code alors peut-être que vous pouvez figurer dehors sur votre propre ?

# Nous ne pouvons pas saisir plus de 1000 datapoints, grâce à la restriction de la libre-app-moteur
# qui vaut d’environ 3 capteurs en une seule journée
# et nous limiterons à saisir seulement 12 heures de données à la fois, environ 7 capteurs d’une valeur

tandis que (historytimebegin > historytimeend) :
Si (historytimebegin - historytimeend) > 12 :
timebegin = datetime.timedelta (heures = - historytimebegin)
timeend = datetime.timedelta (heures =-(historytimebegin-12))
historytimebegin-= 12
autre chose :
timebegin = datetime.timedelta (heures = - historytimebegin)
historytimebegin = 0
timeend = datetime.timedelta (heures = - historytimeend)

# récupérer toutes les données de capteur pour ce segment de temps
powerusages = db. GqlQuery ("sélectionnez * de Powerusage où date >: 1 AND date <: 2 et auteur =: 3 ORDER BY date », datetime.datetime.now (), datetime.datetime.now () + timebegin, timeend, compte)

# les trier dans le format approprié et ajouter des noms de capteur de que DB si ne pas encore fait
pour powerused dans powerusages :
Coln = « watts » + str(powerused.sensornum)
entrée = {« date »: powerused.date.replace(tzinfo=utc).astimezone(est), coln : powerused.watt}
Si ce n’est pas (coln dans le jeu de colonnes) :
columnNames.Append(Coln)
jeu de colonnes = set(columnnames)
# trouver le nom de capteur, si nous ne pouvons
Si (len(sensornames) < powerused.sensornum) ou (pas de sensornames[powerused.sensornum]) :
currnamequery = db. GqlQuery ("SELECT * de Sensorname où l’auteur =: 1 AND sensornum =: 2", compte, powerused.sensornum)
nom = currnamequery.get()

Si ce n’est pas le cas, le nom :
sensornames[powerused.sensornum] = "capteur #"+str(powerused.sensornum)
autre chose :
sensornames[powerused.sensornum] = name.sensorname

Description [coln] = (« nombre », sensornames[powerused.sensornum])
#self.response.out.write(sensornames)

# Ajoute une entrée à la fois
datastore.Append(Entry)

Enfin à la fin de la boucle, nous appeler la fonction magique qui transforme le dictionnaire en JSON, enveloppez-le dans le bon paquet visualisation Google, puis cracher !

# OK, toutes les données est prêt à aller, imprimez-le au format 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 = "date"))

Si vous deviez visiter http://wattcher.appspot.com/visquery.json?user=adawattz il serait sortie quelque chose comme ceci :

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) nouveau},,, {v: 48.6947643311}]}, {c: [{v: Date(2009,1,25,21,25,3) nouveau},, {v: 228.409810208},, {v: null}]}, {c: [{v: nouvelle Date(2009,1,25,21,25,3)}, {v: 67.3574917331},,, {v: null}]}, {c: [{v: Date(2009,1,25,21,25,3) nouvelle},,, {v: 66.0046383897}, {v: null}]}, {c: [{v: Date(2009,1,25,21,25,4) nouveau},,, {v: 47.3892235642}]}, {c: [{v: Date(2009,1,25,21,30,2) nouveau}, {v: 84.9379517795},,, {v: null}]}, {c: [{v: Date(2009,1,25,21,30,3) nouvelle},,, {v: 99.7553490071}]} , {c: [{v: Date(2009,1,25,21,30,5) nouveau},, {v: 229.73642288},, {v: null}]}, {c: [{v: Date(2009,1,25,21,30,6) nouvelle},,, {v: 66.6556291818}, {v: null}]}, {c: [{v: Date(2009,1,25,21,35,2) nouveau},,, {v: 67.3146052998}, {v: null}]}, {c: [{v: nouvelle Date(2009,1,25,21,35,3)}, {v: 96.2322216676},,, {v: null}]}, {c: [{v: Date(2009,1,25,21,35,3) nouveau},, {v: 226.678267688},, {v: null}]}, {c: [{v: Date(2009,1,25,21,35,4) nouveau},,, {v: 158.428422765}]}, {c: [{v: Date(2009,1,25,21,40,3) nouvelle},, {v: 232.644574879},, {v: null}]} , {c: [{v: Date(2009,1,25,21,40,4) nouveau},,, {v: 153.666193493}]}, {c: [{v: Date(2009,1,25,21,40,6) nouveau},,, {v: 66.7874343225}, {v: null}]}, {c: [{v: Date(2009,1,25,21,40,12) nouveau}, {v: 95.0019590395},,, {v: null}]}, {c: [{v: nouvelle Date(2009,1,25,21,40,21)}, {v: 95.0144043571},,, {v: null}]}, {c: [{v: Date(2009,1,25,21,40,23) nouvelle},,, {v: 66.8060307611}, {v: null}]}, {c: [{v: Date(2009,1,25,21,45,2) nouvelle},,, {v: 66.9814723201}, {v: null}]}, {c: [{v: Date(2009,1,25,21,45,3) nouveau},, {v: 226.036818816},, {v: null}]} , {c: [{v: nouvelle Date(2009,1,25,21,45,3)}, {v: 99.2775581827},,, {v: null}]}, {c: [{v: Date(2009,1,25,21,45,4) nouveau},,, {v: 154.261889366}]}, {c: [{v: Date(2009,1,25,21,50,4) nouvelle}, {v: 102.104642018},,, {v: null}]}, {c: [{v: Date(2009,1,25,21,50,4) nouveau},,, {v: 155.441084531}]}, {c: [{v: Date(2009,1,25,21,50,5) nouveau},,, {v: 67.0087146687}, {v: null}]}, {c: [{v: Date(2009,1,25,21,50,5) nouveau},, {v: 230.678636915},, {v: null}]}, {c: [{v: Date(2009,1,25,21,55,3) nouvelle}, {v: 103.493297176},,, {v: null}]}, {c: [{v : Date(2009,1,25,21,55,3) nouveau},,, {v: 151.309223916}]}, {c: [{v: Date(2009,1,25,21,55,4) nouveau},,, {v: 66.9174858741}, {v: null}]}, {c: [{v: Date(2009,1,25,21,55,4) nouveau},, {v: 227.765325835},, {v: null}]}, {c: [{v: Date(2009,1,25,22,0,3) nouveau},,, {v: 67.0004310254}, {v: null}]}, {c: [{v: Date(2009,1,25,22,0,3) nouveau},,, {v: 150.389989112}]}, {c: [{v: Date(2009,1,25,22,0,3) nouveau},, {v: 230.892049553},, {v: null}]}, {c: [{v: Date(2009,1,25,22,0,4) nouveau}, {v: 92.2432771363},,, {v: null}]}, {c: [{v: Date(2009,1,25,22,15,3) nouveau} {v: 97.5910440774},,, {v: null}]}, {c: [{v: nouvelle Date(2009,1,25,22,15,3)},,, {v: 143.722595861}]}, {c: [{v: nouvelle Date(2009,1,25,22,15,4)},,, {v: 64.4898008851}, {v: null}]}, {c: [{v: nouvelle Date(2009,1,25,22,15,4)},,{v:222.357617868},,{v:null}]}]}}) ;

de toute façon, vous pouvez voir un peu les données, Notez également sa en fait un appel de fonction, ce truc est vraiment crépu !

Maintenant, allez à l' Aire de jeux Google visualisations et entrer cette URL dans le bac à sable

Et vous pouvez voir la visualisation se sortir ! (c’est juste un écran coup alors allez faire yerself si vous voulez perdre son temps)

OK aller perdre son temps, ajoutant et en modifiant les heures et les ehours

Envelopper la visualisation

OK, nous avons presque terminé. Maintenant, nous avons juste besoin fondamentalement saisir le code à partir du bac à sable et faire une sous-page dans notre moteur de recherche app... comme suit :

classe Visualize (webapp. RequestHandler) :
def get(self) :

# faire l’utilisateur ouvrir une session si aucun nom d’utilisateur n’est fourni
Si self.request.get('user') :
compte = users. User(self.Request.get('user'))
autre chose :
Si ce n’est pas users.get_current_user() :
Self.Redirect(Users.create_login_url(self.Request.Uri))
compte = users.get_current_user()

historytimebegin = # 24 suppose que 24 heures
Si self.request.get('bhours') :
historytimebegin = int(self.request.get('bhours'))

historytimeend = 0 # Supposons 0 heures
Si self.request.get('ehours') :
historytimeend = int(self.request.get('ehours'))

# sortir la première partie, en-têtes,
() self.Response.out.Write
< ! DOCTYPE html PUBLIC "-//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 » >
< tête >
< meta http-equiv = « content-type » content = "text/html ; charset = utf-8 "/ >
< titre > Google Visualization API exemple < /title >
< script type = « text/javascript » src = « http://www.google.com/jsapi » >< / script >
< script type = « text/javascript » >
Google.Load ("visualisation", "1", {paquets: ["annotatedtimeline"]}) ;

function drawVisualizations() {}
)

# créer notre visualisation
Self.Response.out.Write (new google.visualization.Query ("http://wattcher.appspot.com/visquery.json?user=+
Account.email() +& heures =+ str(historytimebegin) +») .send (
{function(Response)}
(google.visualization.AnnotatedTimeLine) nouveau
document.getElementById("visualization")).
Draw(Response.getDataTable(), {"displayAnnotations": true}) ;
});
)

Self.Response.out.Write (}

google.setOnLoadCallback(drawVisualizations) ;
< /script >
< / head >
< le style corps = "famille de police : Arial ; frontière: 0 none;" >
< div id = « visualisation » style = "width : 800px ; hauteur : 250px; » >< / div >
< / body >
< / html >)

La première partie est assez simple, obtenir le nom d’utilisateur ou de connexion. Ensuite, nous supposerons que l’utilisateur veut 1 dernier jour de données, donc régler les heures et les ehours. Puis nous avons littéralement juste imprimer le code que nous avons copiés à partir sandbox de visualisation de Google, fait !

Viz Viz Viz

La seule chose que je ne pouvais pas comprendre est comment obtenir 3 visualisations passait à la fois (dernière semaine, jour et heure) avec le code ci-dessus. Il s’est juste un peu cassé. Donc pour la triple vue j’ai dû utiliser les iframes:(

classe VisualizeAll(webapp. RequestHandler) :
def get(self) :

# faire l’utilisateur ouvrir une session si aucun nom d’utilisateur n’est fourni
Si self.request.get('user') :
compte = users. User(self.Request.get('user'))
autre chose :
Si ce n’est pas users.get_current_user() :
Self.Redirect(Users.create_login_url(self.Request.Uri))
compte = users.get_current_user()

() self.Response.out.Write
< h2 > consommation d’énergie au cours de la dernière heure : < / h2 >
< iframe src = "graphique? user = adawattz frameborder = « 0 » width = « 100 % » height = « 300px » >
< p > votre navigateur ne supporte pas les iframes. < /p >
< / iframe >

la consommation d’énergie au cours de la dernière journée < h2 > : < / h2 >
< iframe src = "graphique? user = adawattz frameborder = « 0 » width = « 100 % » height = « 300px » >
< p > votre navigateur ne supporte pas les iframes. < /p >
< / iframe >

< h2 > consommation d’énergie au cours de la dernière semaine : < / h2 >
< iframe src = "graphique? user = adawattz frameborder = « 0 » width = « 300 % » height = « 500px » >
< p > votre navigateur ne supporte pas les iframes. < /p >
< / iframe >

)

En tout cas, il fonctionne très bien.

Codes temporels !

La dernière chose qui ne sera pas examinée ici est comment je suis arrivé à la date et les heures pour être EST au lieu de l’UTC. Autant que je sache, ce genre de cassé et mystérieux. Vérifier le code si vous voulez le comprendre.

Articles Liés

Comment faire un baromètre

Comment faire un baromètre

Aujourd'hui je vais vous montrer comment faire un baromètre très facilement. Pour faire cela que vous allez avoir besoin d'éléments très simples autour de vous. Permet donc commencer.Étape 1 :Pour cela, vous aurez besoin des choses suivantes.1), un b
Comment faire un thermomètre en utilisant Arduino et LM35

Comment faire un thermomètre en utilisant Arduino et LM35

aujourd'hui je vais vous montrer comment faire un thermomètre avec Arduino et LM35 capteur de température, affichage LCD, sur une maquette connecté avec fils. Il indiquera la température en Celsius et Fahrenheit.Andro racineÉtape 1: Exigences:- Il s'
Watts-votre-consommation ? -Wattmètre sans fil

Watts-votre-consommation ? -Wattmètre sans fil

j'ai récemment devenue un peu obsédée par comprendre combien d'électricité est à l'aide de notre maison. Il y a certainement commerciales offres pour vous permettre de surveiller la consommation d'énergie dans votre maison et kits gagnante de prix so
Comment faire un Hypsomètre

Comment faire un Hypsomètre

Il s'agit d'un simple, mais je pense que vaut la peine et très peu coûteux à faire.  Pour l'une d'entre vous prenant trigonométrie ou physique ce semestre ce fait pourrait être utile.  Vous pouvez utiliser ceci pour mesurer (avec des résultats précis
Comment faire une fenêtre coeur Valentine s’accrochent de plaisance pour les enfants

Comment faire une fenêtre coeur Valentine s’accrochent de plaisance pour les enfants

Valentine ces accroche de fenêtre est une embarcation enfants vont adorer ! Et ils font de jolies décorations de Valentin trop.Comment faire une maison Valentine coeur fenêtre s'accrochent CraftVous aurez besoin :colle blanche Ecolesavon à vaisselle
Comment faire un clinomètre

Comment faire un clinomètre

ce clinomètre vise à mesurer l'inclinaison de ce que vous êtes à la recherche. Cette étape par étape instructable vous montrera comment faire une version DIY un inclinomètre qui fonctionne très bien.Les éléments nécessaires sont :* 1 goutte d'eau qui
Comment faire une fenêtre Cool

Comment faire une fenêtre Cool

pour faire une fenêtre cool vous avez besoin de bloc de Quartz 10 et quatre escaliers de QuartzÉtape 1: Paroi de fond Mis quatre Quartz bloquant un straight line 1 par 4 comme indiquéEtape 2: Mur gauche Soulever le côté gauche, 3 blocs de Quartz haut
Comment faire un clinomètre (mesures inclinaison)

Comment faire un clinomètre (mesures inclinaison)

liste de matériels:1 Rapporteur d'angle1 paille1 ciseaux1 chaînepince-1 NotesÉtape 1: Cordage de prise de vues Put a 15 dans string à travers l'orifice inférieur du graphomètre et morceau de ruban adhésif pour le rapporteur d'angleÉtape 2: obtenant u
Comment faire un plâtre d’une piste de l’Animal

Comment faire un plâtre d’une piste de l’Animal

faire un moulage en plâtre de traces d'animaux est une excellente activité à faire avec les enfants tandis que dans le désert. Il est facile à faire, permet aux enfants de découvrir les traces d'animaux et fait un excellent souvenir.Étape 1: Gather S
Comment faire une fenêtre dans un cadre photo !

Comment faire une fenêtre dans un cadre photo !

J'en suis sûr, comme tout le monde qui ait jamais eu un mariage, vous comprenez comment j'ai fini avec beaucoup de photos de restes qui n'ont pas fait la coupe pour mettre dans notre album de mariage et ont été assis autour en me regardant comme un g
Comment faire une fenêtre Fake - PC Prank

Comment faire une fenêtre Fake - PC Prank

il s'agit d'une farce simple mais efficace que vous pouvez faire sur n'importe quel PC en moins de 5 minutes. Il crée une fausse fenêtre qui ne répond pas et semble 100 % réel. Pensent que leur ordinateur est folle et ils essaient d'y remédier en jou
ROBLOX Tutorial - Comment faire semblant d’être un Noob

ROBLOX Tutorial - Comment faire semblant d’être un Noob

voilà à quoi ressemble un noob, maintenant je vais vous montrer comment être un noob-ardoiseÉtape 1 :Étape 2 :Étape 3 :Étape 4 :
Comment faire un baromètre de bouteille en plastique

Comment faire un baromètre de bouteille en plastique

c'est un projet facile et ferait une grande science experiment. Moyen d'un aspirateur à l'intérieur d'une bouteille en plastique avec de l'eau dedans, vous pouvez observer la pression atmosphérique changeante avec ce baromètre simple. Veuillez noter
Comment faire une fenêtre en verre mosaïque

Comment faire une fenêtre en verre mosaïque

Fournitures :Vieille fenêtre (j'ai obtenu le mien à la re-store)Morceaux de mosaïque de verre, perles de verre, tout verre à coller sur les vitresColle E6000CoulisEtape 1: Coller des morceaux de mosaïque sur les volets de fenêtre ancienne Après avoir