Tweet-a-watt - hoe maak je een gekwetter Energiemeter... (17 / 19 stap)

Stap 17: Ontwerp - grafiek


Mooi foto's maken

Gegevens is groot, maar de visualisaties zijn beter. In deze stap zullen wij onze opgeslagen geschiedenis manipuleren zodat we echt leuk grafieken kunt maken!

Eerste we beginnen door onze sensoren genoemd, zodat het makkelijker voor ons om bij te houden die is wat. Vervolgens zullen we kijken naar onze grafiek opties en gegevensindelingen. Ten slotte zullen we opnieuw formatteren van onze gegevens zodat het klaar voor graphing

De sensor namen configureren

Zijn geen leuk gegevens gemarkeerd als "sensor #1" dus ik voegde een 'config' pagina waar de app motor code welke sensor nummers bekijkt gegevens naar de database verzonden hebben en vervolgens kunt u een naam geven. Natuurlijk, wilt u dat de sensor op en verzenden van gegevens - eerst - voordat dit zal werken

Het configure scherm kijkt iets zoals naar de spiegelbeeld onder.

Deze code gebruikt krijg wanneer het echt POST moet gebruiken. Ik ben kinda oud en houd niet debuggen met POST so... yeah.

klasse configureren (webapp. RequestHandler):
def get(self):
# make de gebruiker inloggen als geen gebruikersnaam is opgegeven
als self.request.get('user'):
account = users. User(Self.Request.Get('user'))
anders:
zoniet users.get_current_user():
Self.Redirect(users.create_login_url(Self.Request.URI))
account = users.get_current_user()

Self.Response.out.write ("< html >< lichaam > Set up uw sensornode namen hier: < p >')

# find alle sensoren tot #10
Sensorset =]
voor ik in range(10):
c = db. GqlQuery ("SELECT * FROM Powerusage waar Auteur =: 1 en sensornum =: 2", users.get_current_user(), i)
als c.get():
Sensorset.Append(i)

Self.Response.out.write ("< vormen actie =" / config "methode ="get">")
voor sensor in sensorset:
naam = ""
currnamequery = db. GqlQuery ("SELECT * FROM Sensorname waar Auteur =: 1 en sensornum =: 2", users.get_current_user(), sensor)
currname = currnamequery.get()

# eerst zien als we het instellen van het!
als self.request.get('sensornum'+str(sensor)):
naam = self.request.get('sensornum'+str(sensor))
zoniet currname:
currname = Sensorname() # Maak een nieuwe vermelding
currname.sensornum = sensor
currname.Author = users.get_current_user()
currname.sensorname = naam
currname.put()
anders:
# we niet instelt het zo Haal huidige vermelding
Als currname:
naam = currname.sensorname

Self.Response.out.write ('Sensor #' + str(sensor) +': < input type = "text" name="sensornum'+str(sensor) +" "waarde =""+ naam +" ">< / tekst >< p >')

Self.Response.out.write ("" "< div >< input type =" submit"waarde ="Wijzig namen">< / div >
< / form >
< / body >
< / html > "" ")

Nu kunnen we meer nuttige gegevens in de geschiedenis-dump

Nu we zien kunnen dat Phil meestal te wijten aan onze energierekening is!

Google Visualizer

Dus hebben we gegevens en wij zou graag zien dat de geschiedenis van onze macht gebruik. Graphing gegevens is veel werk, en ik ben lui. Dus ik kijk online en vind dat Google heeft - ook - een visualization API! Dit betekent dat ik niet moet schrijven een heleboel grafische code, en kan gewoon aansluiten op hun systeem. Sweet!

OK checking out de galerij van beschikbare visualisaties, ben ik dol op dit één, de Geannoteerde Time Line

Merk op hoe u gemakkelijk kunt zien van de grafieken, scroll rond, in-en uitzoomen en ieder waarnemingspunt heet. Perfect voor het uitzetten van gegevens van de macht!

Gegevensopmaak

Theres een paar beperkingen aan hoe we de gegevens naar de visualisatie api en onze beste optie is JSon-gegevens. Voor zover ik vertellen kan, is JSON wat er gebeurde toen iedereen zei: "wow, XML is echt omvangrijk en verspilling". Hoe dan ook, als theres 4 lagen van kader en interpretatieve gegevens structions en uiteindelijk er een vrij makkelijk te gebruiken bibliotheek geschreven door het team van Google visualisaties die me was laat 'gewoon doen' met een enkele aanroep door de invoering van de gegevens in een python "dictionary" in een bepaald formaat.

Laat gaan door de code in secties, aangezien de functie vrij lang is

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

# make de gebruiker inloggen als geen gebruikersnaam is opgegeven
als self.request.get('user'):
account = users. User(Self.Request.Get('user'))
anders:
zoniet users.get_current_user():
Self.Redirect(users.create_login_url(Self.Request.URI))
account = users.get_current_user()

# Neem aan dat we 24 uur van gegevens wilt
historytimebegin = 24
als self.request.get('bhours'):
historytimebegin = int(self.request.get('bhours'))

# Neem aan dat we wilt gegevens vanaf 0 uur geleden
historytimeend = 0
als self.request.get('ehours'):
historytimeend = int(self.request.get('ehours'))

notatie van de gegevens van de # voor JSON geluk
datastore =]
matrices ColumnNames = ["datum"]
columnset = set(columnnames)
Beschrijving = {"datum": ("datetime", "Datum")}

# de namen van elke sensor, als geconfigureerd
sensornames = [geen] * 10

Eerst krijgen we van de gebruiker die we gonna worden de gegevens voor opzoeken. Dan hebben we twee variabelen voor het definiëren van de hoeveelheid gegevens te grijpen. Een "ehours" (einde uur) is en de andere is "bhours". Dus als je de laatste 5 uur wilde, bhours zou 5 en ehours 0 zou zijn. Als je wilde de 5 uur van de ene dag geleden, bhours zou 29 en ehours zou 24. datastore is waar we corall zullen alle gegevens. matrices ColumnNames en beschrijving worden de 'names' van elke kolom. We hebben altijd een datumkolom en een andere kolom voor elke sensor-stream. We hebben ook een aparte matrix naar de speciale sensor namen in de cache.

naar de volgende sectie! Hier is waar we eigenlijk grijpen gegevens uit de database. Nu app motor dit vervelende beperking heeft, kunt je alleen maar 1000 punten van de gegevens tegelijk dus wat ik doe is doorlopen het 12 uur op een moment. De definitieve datastore heeft alle punten maar zijn gemakkelijker op de database, veronderstel ik. Een ding dat is verwarrend misschien is elke kolom heeft een naam en een beschrijving. De naam is kort, zeggen "watts3" voor sensor #3, maar de omschrijving "Van Limor workbench" zou kunnen zijn. Ik weet niet eens herinneren dus misschien dat u het kunt uitzoeken op uw eigen schrijven van deze code?

# we meer dan 1000 datapoints, dankzij de gratis-app-engine beperking niet grijpen
# dat is ongeveer 3 sensoren van waarde in één dag
# dus we beperken zullen tot alleen grijpen 12 uren van gegevens op een moment, ongeveer 7 sensoren waard

terwijl (historytimebegin > historytimeend):
Als (historytimebegin - historytimeend) > 12:
timebegin = datetime.timedelta (uren = - historytimebegin)
timeend = datetime.timedelta (uren =-(historytimebegin-12))
historytimebegin-= 12
anders:
timebegin = datetime.timedelta (uren = - historytimebegin)
historytimebegin = 0
timeend = datetime.timedelta (uren = - historytimeend)

# Pak alle sensorgegevens voor dat stuk van de tijd
powerusages = db. GqlQuery ("Selecteer * uit Powerusage waar datum >: 1 en datum <: 2 en Auteur =: 3 ORDER BY datum", datetime.datetime.now () timebegin, (datetime.datetime.now) + timeend, account)

# sorteren hen in de juiste indeling en sensor namen uit die DB toevoegen als nog niet klaar
voor powerused in powerusages:
Coln = "watt" + str(powerused.sensornum)
post = {"datum": powerused.date.replace(tzinfo=utc).astimezone(est), coln: powerused.watt}
zoniet (coln in columnset):
ColumnNames.Append(Coln)
columnset = set(columnnames)
# de naam van de sensor, vinden als we kunnen
Als (len(sensornames) < powerused.sensornum) of (niet sensornames[powerused.sensornum]):
currnamequery = db. GqlQuery ("SELECT * FROM Sensorname waar Auteur =: 1 en sensornum =: 2", account, powerused.sensornum)
naam = currnamequery.get()

Als niet een naam geven:
sensornames[powerused.sensornum] = "sensor #"+str(powerused.sensornum)
anders:
sensornames[powerused.sensornum] = name.sensorname

beschrijving [coln] = ("nummer", sensornames[powerused.sensornum])
#self.response.out.write(sensornames)

# één post tegelijk toevoegen
datastore.Append(entry)

Ten slotte aan het einde van de lus, we noemen de magische functie die het woordenboek in JSON verandert, wikkel het in de juiste Google Visualization pakket, dan spuug het uit!

# OK alle gegevens is klaar om te gaan, uitprinten in JSON-formaat!
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 = "datum"))

Als u moest http://wattcher.appspot.com/visquery.json?user=adawattz bezoek zou het zoiets output:

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

Hoe dan ook, u kunt kinda de gegevens bekijken, er ook rekening mee zijn eigenlijk een functie-aanroep, dit spul is echt kinky!

Ga nu naar de Google Visualisaties Speeltuin en voer in die URL in de zandbak

En je ziet de visualisatie zelf pop uit! (dit is gewoon een scherm schot dus ga doen yerself wilt u prutsen)

OK gaan prutsen, bhours en ehours toevoegen en wijzigen

Het verpakken omhoog de visualisatie

OK zijn we bijna klaar. Nu we alleen moeten in feite grijpen de code uit de zandbak en maak het een subpagina in onze app engine... als volgt:

klasse visualiseren (webapp. RequestHandler):
def get(self):

# make de gebruiker inloggen als geen gebruikersnaam is opgegeven
als self.request.get('user'):
account = users. User(Self.Request.Get('user'))
anders:
zoniet users.get_current_user():
Self.Redirect(users.create_login_url(Self.Request.URI))
account = users.get_current_user()

historytimebegin = 24 # 24 uur nemen
als self.request.get('bhours'):
historytimebegin = int(self.request.get('bhours'))

historytimeend = 0 # veronderstellen 0 uur geleden
als self.request.get('ehours'):
historytimeend = int(self.request.get('ehours'))

# krijgen uit het eerste deel, headers,
Self.Response.out.write)
<! DOCTYPE html publiek "-//W3C//DTD XHTML 1.0 Strict / / nl" "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 "/ >
< titel > Google Visualization API steekproef < / title >
< script type = ' text/javascript' src = "http://www.google.com/jsapi" >< / script >
< script type = "text/javascript" >
Google.load ("visualization", "1", {pakketten: ["annotatedtimeline"]});

functie drawVisualizations() {}
)

# Maak onze visualisatie
Self.Response.out.write (nieuwe google.visualization.Query ("http://wattcher.appspot.com/visquery.json?user=+
account.email() +& bhours =+ str(historytimebegin) +") .send (
function(Response) {}
nieuwe google.visualization.AnnotatedTimeLine)
document.getElementById("visualization")).
draw(Response.getDataTable(), {"displayAnnotations": true});
});
)

Self.Response.out.write (}

google.setOnLoadCallback(drawVisualizations);
< / script >
< / head >
< body style = "lettertype-familie: Arial; rand: 0 geen;" >
< div id = "Visualisatie" style = "width: 800px; hoogte: 250px; " >< / div >
< / body >
< / html >)

Het eerste deel is vrij ongecompliceerd, krijgen de gebruikersnaam of login. Vervolgens zullen we veronderstellen dat de gebruiker wil 1 van de laatste dag van gegevens, dus stel bhours en ehours. Vervolgens afdrukken we letterlijk net uit de code die we gekopieerd uit Google Visualization zandbak, gedaan!

Viz Viz Viz

Het enige wat ik niet kon achterhalen hoe krijg ik 3 visualisaties tegelijk gaande is (laatste uur, dag en week) met de bovenstaande code. Het is gewoon een beetje brak. Dus moest ik voor de triple weergave gebruiken iframes :(

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

# make de gebruiker inloggen als geen gebruikersnaam is opgegeven
als self.request.get('user'):
account = users. User(Self.Request.Get('user'))
anders:
zoniet users.get_current_user():
Self.Redirect(users.create_login_url(Self.Request.URI))
account = users.get_current_user()

Self.Response.out.write)
< h2 > stroomverbruik over het afgelopen uur: < / h2 >
< iframe src = "grafiek? user = adawattz frameborder ="0"width ="100% "height ="300px">
< p > uw browser ondersteunt geen iframes. < /p >
< / iframe >

< h2 > energieverbruik over de laatste dag: < / h2 >
< iframe src = "grafiek? user = adawattz frameborder ="0"width ="100% "height ="300px">
< p > uw browser ondersteunt geen iframes. < /p >
< / iframe >

< h2 > stroomverbruik de afgelopen week: < / h2 >
< iframe src = "grafiek? user = adawattz frameborder ="0"width ="300% "height ="500px">
< p > uw browser ondersteunt geen iframes. < /p >
< / iframe >

)

Hoe dan ook, het werkt prima.

Tijdcodes!

Het laatste ding dat niet zal worden herzien hier is hoe ik de datum en de tijdstippen als EST in plaats van UTC. Voor zover ik kan vertellen, zijn soort gebroken en mysterieus. Controleer de code als u wilt uitzoeken.

Gerelateerde Artikelen

Hoe maak je een wenskaart van klassieke auto Pop Up kaart (Kirigami 3D)

Hoe maak je een wenskaart van klassieke auto Pop Up kaart (Kirigami 3D)

Hoe maak je een wenskaart Pop Up kaart (Kirigami 3D) klassieke auto - TCGames [HD]Share op FACEBOOK: http://on.fb.me/15TrVYfTWEET: http://bit.ly/15Ts5P6 REDDIT: http://bit.ly/16qHt5L TUMBLR: http://bit.ly/10K8fhzDownload hier het gratis patroon: http
Hoe maak je een trui Lamp

Hoe maak je een trui Lamp

Hey u alle mooie burgers,Ik miste instructables en alle de awesome die jullie hebben. Dus ik ben terug na een goede onderbreking en ik ben terug met een andere opwindende instructable u:).Trui lamp...??? Ja... geen grapje. In dit instructable ga ik o
Hoe maak je een mooie Origami Rose (boeket) voor Valentijnsdag!

Hoe maak je een mooie Origami Rose (boeket) voor Valentijnsdag!

In deze tutorial, ik zal u tonen hoe maak je een origami mooi Rose. Geniet van: D!Share op FACEBOOK: http://on.fb.me/15TrVYfTWEET: http://bit.ly/15Ts5P6REDDIT: http://bit.ly/16qHt5LTUMBLR: http://bit.ly/10K8fhzTips: zorg voor uw plooien aan het begin
Hoe maak je een Origami-gevechtsvliegtuig (papieren vliegtuigje)!

Hoe maak je een Origami-gevechtsvliegtuig (papieren vliegtuigje)!

In deze tutorial, ik zal u tonen hoe maak je een origami gevechtsvliegtuig (papieren vliegtuigje). Geniet van: D!Model: Gevechtsvliegtuig (papieren vliegtuigje)Door: traditioneleShare op FACEBOOK: http://on.fb.me/15TrVYfTWEET: http://bit.ly/15Ts5P6RE
Hoe maak je een Origami papier Jet Plane!

Hoe maak je een Origami papier Jet Plane!

In deze tutorial, ik zal u tonen hoe maak je een origami JET papieren vliegtuigje. Geniet van: D!Model: JET papieren vliegtuigjeDoor: traditioneleShare op FACEBOOK: http://on.fb.me/15TrVYfTWEET: http://bit.ly/15Ts5P6REDDIT: http://bit.ly/16qHt5LTUMBL
Hoe maak je een Origami papier Squid vliegtuig!

Hoe maak je een Origami papier Squid vliegtuig!

In deze tutorial, ik zal u tonen hoe maak je een origami Squid papieren vliegtuigje. Geniet van: D!Model: Squid papieren vliegtuigjeDoor: traditioneleShare op FACEBOOK: http://on.fb.me/15TrVYfTWEET: http://bit.ly/15Ts5P6REDDIT: http://bit.ly/16qHt5LT
Hoe maak je een LED Fairy-Light String met behulp van de MR16

Hoe maak je een LED Fairy-Light String met behulp van de MR16

dit instructable is een super eenvoudige, gemakkelijke en leuke manier om een string van de LED Fairy-licht met behulp van MR16 LED downlighters.Het is ook mijn eerste instructable!, eindelijk na jaren van verschillende DIY en knutselen leuk. ^_^Dus,
Hoe maak je een DIY Tiki fakkel van de sneeuw Ski's

Hoe maak je een DIY Tiki fakkel van de sneeuw Ski's

Een paar ski's van oude van Habitat voor herstel van de mensheid nu een vet gele tiki fakkel, klaar voor onze volgende achtertuin feest is.Mark en ik waren door onze vrienden bij Krylon uitgedaagd om een fakkel tiki van iets out-of-the-gewone.Stap 1:
Hoe maak je een citroen-accu

Hoe maak je een citroen-accu

In dit instructable leert u hoe maak je een citroen-batterij. De citroenen maken ongeveer 4 en een halve volt, genoeg te lopen van iets dat maakt gebruik van lage spanning. De citroenen produceren deze spanning door het proces van elektrolyse is de c
Hoe maak je een Lamp Nuka Cola Quantum

Hoe maak je een Lamp Nuka Cola Quantum

Ik maakte deze lamp als een cadeau voor een zeer goede vriend. Ik maak rekwisieten als een hobbie en besloot: "Ik wil mijn vriend iets!" Ik dacht en dacht over wat te maken van hem, toen drong het tot me dat hij hield van Fallout. Deze prop werd
Hoe maak je een spuit Pen

Hoe maak je een spuit Pen

https://www.YouTube.com/watch?v=qutcj6xwLjo&feature=Youtu.beStap 1: Om te doen een spuit Pen moet je!In deze Instructables ga ik om u te tonen hoe maak je een pen met de spuit!Een handgemaakte pen met de spuit die we moeten maken:-Insuline spuit,-Bal
Hoe maak je een periscoop! / Tutorial / DIY

Hoe maak je een periscoop! / Tutorial / DIY

https://www.YouTube.com/watch?v=Pb24i2mru7c&feature=Youtu.beStap 1: Om te doen een periscoop moet je! In hedendaagse instructables 'm I gonna Toon u het idee van hoe maak je een periscoop.Stap 2: Periscoop is een van de eenvoudigste optische toestell
Hoe maak je een boot van de stoom met een kaars

Hoe maak je een boot van de stoom met een kaars

https://www.YouTube.com/watch?v=sWJqCubW1ic&feature=Youtu.beStap 1: Om te doen een boot van de stoom met een kaars u nodig!In deze instructables ik zal je laten zien een geweldig idee van hoe maak je een boot van de stoom met de kaars.Stap 2: Kindere
Hoe maak je een kleine uil!

Hoe maak je een kleine uil!

Dit instructable leert u hoe maak je een kleine uil! Het was bedoeld als een toegang tot de First-Time Auteur wedstrijd in instructables, maar ik hoop dat velen van u grote vreugde van het vinden! Zodra u klaar bent met uw uil, wat gaat u doen? Zal u