Étape 16 : Design - magasin
OK, nous obtiennent des données d’intérêt de nos capteurs, permet il corral en morceaux plus utile et la stocker dans une base de données. Nous pourrions faire une base de données sur l’ordinateur, mais étant donné que nous aimerions partager ces données, il est plus logique de mettre en ligne. Il existe des services personnalisés qui sont spécifiquement conçus pour faire ce genre de chose comme Pachube , mais je vais réinventer la roue et de concevoir mon propre web-app qui stocke et affiche les données sur l’énergie. (Surtout que je veux jouer avec Google App Engine!)
Vous avez 5 minutes !
Nous obtenons des données toutes les quelques secondes du modem XBee à l’intérieur de la kill-a-watt. Nous pourrions, en théorie, mettre des données dans notre base de données toutes les 2 secondes, mais qui serait rapidement gonfler le volume de stockage nécessaire. Il rendrait également trier les données difficiles. Pour remédier à cela permet d’ajouter toutes les données du capteur pendant 5 minutes et puis prendre la moyenne.
Nous ferons tout cela en gardant 2 timers et un décompte. Une minuterie permettra de suivre combien de temps sa fait depuis le dernier signal de la sonde a été envoyé, et l’autre suivra si sa été 5 minutes. Le décompte va stocker vers le haut tous les wattheures (mesures de Watt * temps depuis les dernières données du capteur). Puis à la fin nous pouvons en moyenne d’ici les 5 minutes
Ce morceau de code va vers le début, il crée les minuteries et tally et les Initialise
...
fiveminutetimer = lasttime = time.time() # obtenir l’heure courante
cumulativewatthr = 0
...
Puis plus tard, après que nous obtenons de nos données, nous pouvons mettre dans ce morceau de code :
# additionnent le delta-watthr utilisée depuis la dernière lecture
# Comprendre combien watt heures ont été utilisées depuis la dernière lecture
elapsedSeconds = time.time() - lasttime
dwatthr = (avgwatt * elapsedseconds) / (60,0 * 60,0) # 60 secondes en 60 minutes = 1 h
LastTime = time.time()
imprimer "\t\tWh utilisé en dernier", elapsedseconds, » secondes: ", dwatthr
cumulativewatthr += dwatthr
# Déterminer la minute de l’heure (c’est à dire 06:42 -> "42")
currminute = (10 % int(time.time())/60)
# Figure out si sa été cinq minutes depuis notre dernier enregistrement
Si (((time.time()-fiveminutetimer) > = 60,0) et (currminute % 5 == 0)) :
# Imprimer les données de débogage, Wh utilisé au cours des 5 dernières minutes
avgwattsused = cumulativewatthr * (60,0 * 60,0 / (time.time() - fiveminutetimer))
impression time.strftime ("%Y %m %d, % H: %M"),",", cumulativewatthr, "Wh =", avgwattsused, "Moyenne W")
# Réinitialiser la minuterie de nos 5 minutes
fiveminutetimer = time.time()
cumulativewatthr = 0
Notez que nous calculons delta-wattheures, la petite quantité d’énergie consommée toutes les quelques secondes. Ensuite, nous pouvons obtenir les moyennes watts utilisés en divisant les wattheures par le nombre d’heures écoulées (environ 1/12). Au lieu d’aller exactement 5 minutes, j’ai décidé de ne rendre compte sur les 5 de l’heure (: 05,: 10, etc.) alors que c’est plus facile d’envoyer toutes les données à la fois si theres plusieurs capteurs qui a commencé vers le haut à des moments différents.
Télécharger wattcher-5minreporter.py à partir de la page de téléchargement. Si vous exécutez ceci, vous obtiendrez un flux régulier
Vers la fin, vous pouvez voir l’horodatage, le Watthrs utilisé au cours des quelques minutes et la puissance moyenne
Multisensor !
Nous avons de bonnes données, mais jusqu'à présent il ne fonctionne qu’avec un capteur. Plusieurs capteurs il salira vers le haut ! Temps d’ajouter le support pour plus d’un XBee afin que je peux suivre quelques chambres. Je vais le faire en créant une classe d’objet en python et en utilisant l’adresse XBee (n’oubliez pas que de la partie 1?) pour assurer le suivi. Je remplacerai le code que nous viens d’écrire par ce qui suit :
En haut, au lieu des variables de la minuterie, je vais avoir une déclaration de classe complet et créer un tableau pour les stocker :
### stocker les données des capteurs et tableau des histoires par capteur
classe Fiveminutehistory :
init def (self, sensornum) :
Self.sensornum = sensornum
Self.fiveminutetimer = time.time() # piste données pendant 5 minutes
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) :
retour self.cumulativewatthr * (60,0 * 60,0 / (time.time() - self.fiveminutetimer))
def str(self) :
retour "[id #: %d, 5mintimer: %f, lasttime ; %f, cumulativewatthr: %f] "% (self.fiveminutetimer, self.lasttime, self.sensornum, self.cumulativewatthr)
### un tableau des histoires
sensorhistories =]
Lorsque l’objet est initialisé avec le numéro d’identification de capteur, il met également en place les deux minuteries et cumulatifs Watthrs suivis. J’ai aussi créé quelques fonctions d’assistance qui rendront le code plus propre
Juste en dessous de qui je vais créer une petite fonction pour m’aider à créer et récupérer ces objets. Étant donné un numéro d’identification de XBee rend soit un nouveau ou obtient la référence à celui-ci
### retriever
def findsensorhistory(sensornum) :
pour l’histoire de sensorhistories :
Si history.sensornum == sensornum :
Retour histoire
# aucun trouvé, créez-le !
histoire = Fiveminutehistory(sensornum)
sensorhistories.Append(History)
Retour histoire
Enfin, au lieu du code moyen de calcul du Watt écrit plus haut, que nous allons le remplacer avec le morceau suivant, qui récupère l’objet et les pistes électriques utilisation avec les compteurs de l’objet
# récupérer l’historique de ce capteur
sensorhistory = findsensorhistory(xb.address_16)
#print sensorhistory
# additionnent le delta-watthr utilisée depuis la dernière lecture
# Comprendre combien watt heures ont été utilisées depuis la dernière lecture
elapsedSeconds = time.time() - sensorhistory.lasttime
dwatthr = (avgwatt * elapsedseconds) / (60,0 * 60,0) # 60 secondes en 60 minutes = 1 h
sensorhistory.LastTime = time.time()
imprimer "\t\tWh utilisé en dernier", elapsedseconds, » secondes: ", dwatthr
sensorhistory.addwatthr(dwatthr)
# Déterminer la minute de l’heure (c’est à dire 06:42 -> "42")
currminute = (10 % int(time.time())/60)
# Figure out si sa été cinq minutes depuis notre dernier enregistrement
Si (((time.time()-sensorhistory.fiveminutetimer) > = 60,0) et (currminute % 5 == 0)) :
# Imprimer les données de débogage, Wh utilisé au cours des 5 dernières minutes
avgwattsused = sensorhistory.avgwattover5min()
imprimer time.strftime ("%Y %m %d, % H: %M"), "," sensorhistory.cumulativewatthr,"Wh =", avgwattsused, "moyenne W"
# Réinitialiser la minuterie de nos 5 minutes
sensorhistory.reset5mintimer()
Le code agit fondamentalement les mêmes, sauf que maintenant il ne sera pas s’étouffer avec des données de capteurs multiples ! Ci-dessous, mes deux Kill-a-Watts, une avec un ordinateur relié (100W) et l’autre avec une lampe (40W)
Sur la base de données !
L’App Engine
Si nous voulons avoir un ordinateur en réseau pour stocker ces données, donc nous pouvons partager les données, mais nous ne voulons vraiment pas d’avoir à exécuter un serveur de la maison ! Que faut-il faire ? Ainsi que mentionné précédemment, vous pouvez utiliser Pachube ou similaire, mais je vais montrer comment à rouler soi-même avec Google App Engine (GAE). GAE est fondamentalement un gratuit mini-serveur Web hébergé par Google, qui exécutera la base webapps sans les tracas de l’administration d’un serveur de base de données. Chaque webapp a stockage, certaines infrastructures et peut utiliser les comptes Google pour l’authentification. Pour commencer je vous suggère de vérifier le site Web de GAE, documentation, etc. Je supposerai que vous avez disparu à travers les tutoriaux et aller à droite dans la conception de mon application de stockage de données puissance appelée Wattcher (un peu déroutant, que je sais)
Tout d’abord, le fichier app.yaml qui définit mon application ressemble à ceci :
application : wattcher
version: 1
Duree : python
API_VERSION: 1
gestionnaires :
-url: /. *
script : wattcherapp.py
Assez simple, il suffit, dit que l’application utilise wattcherapp.py comme le fichier source
Ensuite, nous allons plonger dans le code python pour notre webapp. Tout d’abord, la comprend et index de la base de données. Pour créer une base de données, nous en fait définir - dans le fichier python-, GAE chiffres alors quel genre de base de données pour créer pour vous en suivant ces indications (très différentes de celle où vous devez créer la DB séparément de MySQL)
importation de cgi, datetime
google.appengine.api importation utilisateurs
google.appengine.ext importons webapp
de google.appengine.ext.webapp.util importation run_wsgi_app
google.appengine.ext importons db
classe Powerusage(db. Modèle) :
auteur = db. UserProperty() # l’utilisateur
sensornum = db. IntegerProperty() # peut avoir plusieurs capteurs
Watt = db. FloatProperty() # chaque envoi nous dernière mesure Watt
Date = db. DateTimeProperty(auto_now_add=True) # timestamp
Nous utilisons la valeur par défaut inclut. Nous avons une table de base de données unique appelée Powerusage, et il a 4 entrées : une pour l’utilisateur, un pour le nombre de capteurs, pour le dernier rapporté Watts utilisés et l’autre pour un horodatage
Chaque « page » ou le fonctionnement de notre webapp a besoin de sa propre classe. Permet de démarrer avec la fonction qui permet de stocker des données dans la BD. Je vais l’appeler PowerUpdate.
classe PowerUpdate(webapp. RequestHandler) :
def get(self) :
# faire l’utilisateur ouvrir une session
Si ce n’est pas 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'))
autre chose :
Self.Response.out.Write (« ne pourrait pas trouver \'watt\ « GET property! »)
retour
Si self.request.get('sensornum') :
powerusage.sensornum = int(self.request.get('sensornum'))
autre chose :
powerusage.sensornum = 0 # suppose que theres juste un ou quelque chose
powerusage.put()
Self.Response.out.Write('OK!')
Lorsque nous envoyez une demande à faire qu’avec un GET appeler (c’est à dire qui demande la page Web), nous allons tout d’abord faire sûr que l’utilisateur est authentifié et connecté afin que nous sachions leur nom. Ensuite, nous allons créer une nouvelle entrée de la base de données en initialisant une nouvelle instanciation de Powerusage. Puis nous allons examiner la requête GET pour les données de watt, qui seraient dans le watt format = 39,2 ou similaire. Qui est analysé pour nous, heureusement et nous pouvons également obtenir le numéro du capteur qui est passé dans le format sensornum = 3. Enfin, nous pouvons stocker les données dans la base de données permanente
Next est un outil utile fonction de débogage, il sera simplement imprimer toutes les données qu’elle a reçu pour votre compte !
classe DumpData(webapp. RequestHandler) :
def get(self) :
# faire l’utilisateur ouvrir une session
Si ce n’est pas users.get_current_user() :
Self.Redirect(Users.create_login_url(self.Request.Uri))
Self.Response.out.Write ("< html >< corps > Voici toutes les données que vous nous avez envoyé : < p >')
powerusages = db. GqlQuery ("SELECT * de Powerusage où l’auteur =: 1 ORDER BY date", users.get_current_user())
pour powerused dans powerusages :
Si powerused.sensornum :
Self.Response.out.Write ("< b > %s < /b > \'s capteur #%d ' %
(powerused.author.nickname(), powerused.sensornum))
autre chose :
Self.Response.out.Write (< b > %s < /b >' % powerused.author.nickname())
Self.Response.out.Write (' utilisé : %f Watts à %s < p >' % (powerused.watt, powerused.date))
Self.Response.out.Write ("< body/>< / html >")
Cela fonctionne simplement SELECT (extrait) toutes les entrées, les trie par date et imprime chacun d’eux à la fois
Enfin, nous allons faire une base « front page » qui affichera des dernières datapoints envoyé
classe MainPage(webapp. RequestHandler) :
def get(self) :
Self.Response.out.Write ("< html >< corps > Bienvenue sur Wattcher! < p > ici est les 10 derniers datapoints : < p >')
powerusages = db. GqlQuery ("SELECT * de Powerusage ORDER BY date DESC LIMIT 10")
pour powerused dans powerusages :
Si powerused.sensornum :
Self.Response.out.Write ("< b > %s < /b > \'s capteur #%d ' %
(powerused.author.nickname(), powerused.sensornum))
autre chose :
Self.Response.out.Write (« %s < /b > < b > » % powerused.author.nickname())
Self.Response.out.Write (' utilisé : %f Watts à %s < p >' % (powerused.watt, powerused.date))
Self.Response.out.Write ("< body/>< / html >")
Son très similaire à la fonction DataDump mais ses seulement 10 points de données et de tous les utilisateurs, agréable à utiliser lorsque vous juste envie de « check it out » mais ne veux pas ouvrir une session
Enfin, nous avons une petite structure d’initialiseur qui indique quelles pages un lien vers quelles fonctions GAE
demande = webapp. () WSGIApplication
[('/', MainPage)]
(« / rapport », PowerUpdate),
('/ dump', DumpData)],
DEBUG = True)
def main() :
run_wsgi_app(application)
Si name == « principale » :
main()
Test !
OK laisse essayer, tout d’abord permet de visiter http://wattcher.appspot.com/report
N’oubliez pas que nous avons fait une obligation de fournir - quelques données. Permet d’essayer de nouveau http://wattcher.appspot.com/report?watt=19.22&sensornum=1
Yay, nous avons obtenu un OK ! Permet de vérifier les données stockées en visitant http://wattcher.appspot.com/dump
Il y a deux entrées parce que j’ai fait un petit test au préalable, mais vous pouvez voir qu’il y a 2 entrées. Sympa !
Nous pouvons aussi visiter le panneau de commande GAE et parcourir les données « à la main »
en tout cas, maintenant que c’est au travail, permet de revenir en arrière et ajouter la technologie considérée à notre script de capteur-lecteur
Sortir le rapport
Seulement un peu plus de hacking sur l’ordinateur, scénario et nous avons faits. Nous tenons à ajouter le support pour l’envoi des données vers GAE. Malheureusement en ce moment notre l’authentification est effectuée par le biais de comptes Google donc pas facile de courir sur un Arduino. Pour l’adapter, vous devrez envoyer le nom d’utilisateur dans le rapport GET et espère que personne d’autre utilise le même que celui (sauf si vous ajoutez également un système de base de mot de passe)
En tout cas, j’ai totalement arraché Comment faire partir des gens sympas sur Internet
Télécharger appengineauth.py à partir de la page de téléchargementet modifiez les premières lignes, si nécessaire. Nous coder en dur l’URL que nous allons et le compte/mot de passe ainsi que le nom de l’application GAE
users_email_address = "myaccount
users_password = « MonMotpasse »
my_app_name = « wattcher »
target_authenticated_google_app_engine_uri = « http://wattcher.appspot.com/report »
Le vrai travail se passe à cette fonction de sendreport où il se connecte et envoie les données de Watt sur le site GAE
def sendreport (sensornum, watt) :
# Ceci est où je veux en fait aller à
serv_uri = target_authenticated_google_app_engine_uri + "? watt="+str(watt) + "& sensornum="+str(sensornum)
serv_args = {}
serv_args ['continue'] = 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 devrait contenir le contenu de la
page # target_authenticated_google_app_engine_uri - que nous aurons été
# redirigé vers cette page automatiquement
#
# pour le prouver, je vais me contenter d’imprimer
impression serv_resp_body
Enfin, nous envelopper en ajoutant les lignes suivantes à notre script de l’ordinateur, qui enverra les données bien sur à GAE !
# Également, envoyez-le pour l’app engine
appengineauth.sendreport (xb.address_16, avgwattsused)
Vous pouvez télécharger le script final wattcher.py - finale de la page de téléchargement!
N’oubliez pas de visiter wattcher.appspot.com pour vérifier les dernières lectures