Home > Tweet-a-watt - Hoe maak je een twitteren power meter te maken ...

Tweet-a-watt - Hoe maak je een twitteren power meter te maken ...

Tags:kits
Advertisement

Tweet-a-watt - Hoe maak je een twitteren power meter te maken ...

Tweet-a-watt - Hoe maak je een twitteren power meter te maken ...

Dit project documenteert mijn avonturen in het leren hoe je de draad van mijn huis voor draadloze power monitoring. Ik woon in een gehuurd appartement, zodat ik niet hacking-toegang tot een meter of breaker panel hebben. Aangezien ik ben nog steeds erg geïnteresseerd in het meten van mijn energieverbruik op de lange termijn, ik bouwde draadloze outlet verslaggevers. Het bouwen van je eigen kracht de monitor is niet te zwaar en kan geld besparen, maar ik ben geen fan van steken mijn vingers in 120V macht. In plaats daarvan zal ik gebruik gemaakt van de bestaande Kill-a-watt monitor, die werkt geweldig en is verkrijgbaar bij mijn lokale hardware winkel.

Mijn plan is elke kamer te hebben aangesloten op een 6-stekkerdoos welke bevoegdheden alle apparaten in die kamer (elke kill-a-watt kan meten tot 15A, of ongeveer 1800W, dat is genoeg!). Op die manier kan ik bijhouden ruimte-voor-ruimte-gebruik, bijvoorbeeld "keuken", "slaapkamer", "werkbank" en "kantoor".

Elk draadloos outlet / ontvanger kan worden gebouwd voor ~ $ 55 met een paar makkelijk verkrijgbare elektronische onderdelen en licht solderen, geen microcontroller programmering of high voltage engineering is noodzakelijk!

U kunt mijn setup met inbegrip van grafieken en rapporten op te zien http://twitter.com/tweetawatt

Als u wilt er een te bouwen voor jezelf

1. Koop een kit : je krijgt alle onderdelen die u nodig hebt, is er een starter kit bij de adafruit webshop
2. Merk: draai elke Kill-a-Watt in een draadloze vermogen zender
3. Software: Download en voer het uit op uw computer om gegevens op te halen en op te slaan naar een bestand en / of publiceren

Als je wilt weten hoe het was gemaakt, kijk op:

1. Luister: schrijven eenvoudige software voor mijn computer (of Arduino, etc) voor het signaal om te luisteren en te berekenen het huidige stroomverbruik
2. Store: Maak een database backend dat het energieverbruik voor de lange termijn analyse op zal opslaan http://wattcher.appspot.com
3. Uitzicht: Grafiek en te begrijpen trends in stroomgebruik

Bekijk de laatste metingen bij http://wattcher.appspot.com

Stap 1: Make it!

Voordat je start...

Je moet alleen proberen dit project als je comfortabel en competent werken met een hoog voltage elektriciteit, elektronica en computers zijn. Zodra het project voltooid is afgesloten en er geen zichtbare hoogspanning. Echter, je moet alleen werken aan het project wanneer het in niet in het stopcontact en nooit proberen te testen, meten, open, of sonde de circuitboards terwijl ze aangesloten op een stopcontact. Als er iets niet werkt: stop, haal hem uit het stopcontact, open het vervolgens en te onderzoeken. Ja, het duurt een paar minuten, maar het is een stuk veiliger!

Uw veiligheid is je eigen verantwoordelijkheid, met inbegrip van het juiste gebruik van de apparatuur en de veiligheid vistuig, en het bepalen of u voldoende vaardigheid en ervaring. Elektrisch gereedschap, elektriciteit, en andere middelen die voor deze projecten zijn gevaarlijk, tenzij naar behoren en met voldoende voorzorgsmaatregelen, met inbegrip van de veiligheid vistuig dat wordt gebruikt. Sommige illustratieve foto's niet tonen veiligheidsmaatregelen of apparatuur, om te laten zien van het project duidelijker stappen. Dit project is niet bedoeld voor gebruik door kinderen.

Het gebruik van de instructies en suggesties is op eigen risico. Adafruit Industries LLC, wijst elke aansprakelijkheid voor de daardoor ontstane schade, letsel, of kosten. Het is uw verantwoordelijkheid om ervoor te zorgen dat uw activiteiten in overeenstemming zijn met de geldende wetten.

OK, als u het eens kunnen we verder gaan!

Maak een tweet-a-watt

Om de tweet-a-watt setup te maken, zullen we moeten gaan via een paar stappen

1. Bereid door ervoor te zorgen dat we hebben alles wat we nodig hebben en weet dat de vaardigheden die nodig zijn om het project uit te bouwen
2. Bouw de ontvanger worden ingesteld door het solderen van één van de adapter kits
3. Stel de XBee draadloze modems
4. Bouw de zender ingesteld door het wijzigen van een Kill-a-Watt te zenden via de XBee
5. Start de software, die gegevens op te halen en op te slaan in een bestand, uploaden naar een database en / of twitter

Stap 2: Prep

Tweet-a-watt - Hoe maak je een twitteren power meter te maken ...

tutorials

Leer hoe te solderen met tal van tutorials!
Vergeet niet om te leren hoe u uw multimeter te gebruiken!

Gereedschap

Er zijn een aantal gereedschappen die nodig zijn voor de montage. Geen van deze tools worden meegeleverd. Als je ze niet hebt, zou nu een goed moment om te lenen of kopen ze zijn. Ze zijn heel erg handig wanneer het assembleren / bevestiging / aanpassing van elektronische apparaten! Ik bieden links om ze te kopen, maar natuurlijk moet je ze krijgen waar het meest geschikt is / goedkoop. Veel van deze onderdelen zijn verkrijgbaar in een plaats als Radio Shack of een andere (hogere kwaliteit) DIY elektronicawinkels.

Ik beveel een "basis" elektronica tool set voor deze kit, die ik hier beschrijf.

Soldeerbout. Een met temperatuurregeling en een stand is best. Een conische of kleine 'schroevendraaier' tip is goed, bijna alle ijzers komen met een van deze.

Een lage kwaliteit (ahem, $ 10 model van Radioshack) kunnen ijzer meer problemen dan het waard veroorzaken!

Gebruik geen "ColdHeat" soldeerbout, ze zijn niet geschikt voor gevoelige elektronica werk en kan de set beschadigen ( zie hier )

Solder. Rosin kern, 60/40. Goede soldeer is een goede zaak. Bad soldeer leidt tot overbrugging en koude soldeerverbindingen die moeilijk te vinden zijn. Dont kopen van een kleine hoeveelheid, zul je opraken wanneer je het minst verwacht. Een half pond spoel is een minimum.

Multimeter / oscilloscoop. Een meter is nuttig om spanningen en continuïteit te controleren.

Flush / diagonaal frezen. Essentieel voor het snijden van leads in de buurt van de printplaat.

Desolderen tool. Als u gevoelig bent voor verkeerd solderen delen.

'Handy Hands' met Vergrootglas. Niet absoluut noodzakelijk, maar zullen dingen gaan veel sneller.

Check out my aanbevolen instrumenten en waar te kopen.

Goed licht. Belangrijker dan je denkt.

Stap 3: Maak de ontvanger

Tweet-a-watt - Hoe maak je een twitteren power meter te maken ...

Overzicht

We beginnen met de ontvanger hardware, dat is de zaak die wordt aangesloten op de computer en ontvangt gegevens van de draadloze stekker. De ontvanger hardware doet 'dubbele plicht', maar wordt ook gebruikt om de firmware van de XBee's modems '(die helaas noodzakelijk is omdat ze komen uit de fabriek met de echt oude firmware) en het configureren van de modems te werken.

Wat je nodig hebt

De ontvanger is in wezen een XBee, met een USB-aansluiting, zodat een computer om het de XBee te praten.

Naam FTDI kabel
Beschrijving USB-naar-serieel omzetter. Pluggen in keurig in de Adafruit XBee adapter om een ​​computer om de XBee te praten.
Datasheet TTL-232R 3.3V of 5.0V
Distributor Mouser
Aantal 1

Naam Adafruit XBee Adapter Kit
Beschrijving Ik zal met mijn eigen ontwerp voor de XBee breakout / carrier board, maar je kunt bijna elke vorm zo lang gebruiken als u ontbrekende onderdelen zoals the3.3V aanbod en de LED's te repliceren
Heb je 2 adapter kits, maar je moet alleen monteren een voor dit deel! De andere moet men verschillende instructies dus gewoon af te houden!
datasheet webpagina
distributeur Adafruit
Aantal 1

Naam XBee module
Beschrijving We zullen met behulp van de XBee "serie 1" point-to-multipoint 802.15.4 modules met een chip antenne deel # XB24-ACI-001. Ze zijn goedkoop en werken groot. Dit project zal waarschijnlijk niet werken met een andere versie van de XBee, en zeker niet een van de 'high power' Pro types!
Data papier
distributeur Adafruit
Aantal 1

Soldeer de adapter samen!

Deze stap is vrij eenvoudig, ga je gewoon naar de XBee adapter webpagina en solderen samen volgens de instructies!

Vergeet niet: U zult 2 adapter kits, maar moet u alleen soldeer een van hen op dit punt! De andere moet men verschillende instructies dus gewoon af te houden!

Aansluiten op de XBee

Nu is het tijd om verbinding te maken met de XBees

Hier vind je FTDI kabel - Gebruik een 3.3V of 5V. Deze kabels hebben een USB naar serieel converter chip gegoten in hen en worden ondersteund door elke OS. Zo configureren of upgraden of het aansluiten is echt triviaal. Steek de kabel in het uiteinde van de module, zodat de zwarte draad lijn staat met GND. Er is een wit overzicht laat zien waar de kabel verbindt.

Je moet om erachter te komen welke seriële poort (COM) die u gebruikt. Sluit de FTDI kabel, USB-adapter, Arduino, etc. Onder Windows, controleer de manager apparaat, op zoek naar "USB Serial Port"

Digi / Maxstream schreef een klein programma om te helpen configureren XBees, het is ook de enige manier die ik ken om ze te upgraden naar de nieuwste firmware. Helaas draait alleen op Windows. Download X-CTU bij Digi en installeer het op uw computer

Na het installeren en het programma start, selecteert u de COM-poort (COM4 hier) en baud rate (9600 is standaard). Geen flow control, 8N1. Zorg ervoor dat de aansluitkast ziet er net als het beeld (met uitzondering van de COM-poort die verschillend kunnen zijn)

Om te controleren, klikt u op Test / Query

Hopelijk zal de test zal slagen. Als u problemen ondervindt: controleer of de XBee wordt aangedreven, de groene LED op de adapter boord moeten worden knipperen, de juiste COM-poort en baudrate is geselecteerd, etc.

Nu de stekker van de adapter uit de FTDI kabel voorzichtig vervang de eerste XBee met de andere en zorg ervoor dat een mooie praat ook. Als je eenmaal weet zowel XBees werken met de adapter, is het tijd om te upgraden en te configureren, de volgende stap!

Stap 4: configureren

Tweet-a-watt - Hoe maak je een twitteren power meter te maken ...

Overzicht

OK tot nu toe heb je een van de XBee adapter platen gemonteerd en aangesloten op uw computer met de FTDI kabel. (De andere adapter is voor later dus nog niets mee doen!) De XBees reageren op de X-CTU software en knipperen prima. Vervolgens zullen we de firmware-update

Het upgraden van de firmware

Er is een goede kans dat uw XBees niet over de nieuwste firmware en er is een heleboel functies toegevoegd, waarvan sommige we nodig hebben om dit project draaiende te krijgen. Dus de volgende up is een upgrade!

Ga naar het tabblad Modem Configuration. Hier wordt het modem is geconfigureerd en bijgewerkt

Klik op Download nieuwe versies ... en selecteert u de meest recente firmware van het internet te downloaden

Zodra u de nieuwste firmware hebt gedownload, is het tijd om te upgraden!

Klik op Modem Parameters -> "Lezen" te lezen in de huidige versie en de instellingen

Nu zult u zeker weten wat de functie set, versie en instellingen worden opgeslagen in de modem

Selecteer uit de dropdown versie de laatste versie beschikbaar

Controleer de update firmware selectievakje Altijd

En klik op Write te initialiseren en programmeren van de nieuwe firmware in!

Dat is het, nu heb je de meest recente firmware voor uw modem. U moet nu schakelt u de update firmware selectievakje Altijd. Als u problemen, zoals bijvoorbeeld een time-out of niet in staat om te communiceren hebben, zorg ervoor dat de RTS pin is bedraad correct als deze pin nodig is voor het upgraden. FTDI kabels zijn al ingesteld voor dit dus moet je niet een probleem

Spoelen & Repeat

Een upgrade van de firmware op beide XBees zodat ze allebei up-to-date

Op dit punt is het misschien verstandig om de twee XBees label op een manier waarmee je ze uit elkaar zijn. U kunt een sharpie, een sticker of iets dergelijks te gebruiken om aan te geven welke is de ontvanger en dat is de zender

Configureert de zender XBee

Beide XBee's moeten worden bijgewerkt met de nieuwste firmware, maar alleen de zender (die gaat in een Kill-a-Watt worden gezet) moet worden geconfigureerd. Het configure proces vertelt het XBee wat pinnen we willen de sensor gegevens aflezen van. Het vertelt ook de XBee hoe vaak om ons gegevens te verzenden, en hoeveel.

Sluit de zender XBee in de USB-aansluiting (zet de ontvanger XBee afstand) en start X-CTU of een terminal programma. Sluit op 9600 baud, 8N1 parity.Then configureren ieder als volgt:

1. de MY-adres instellen (de identificatiecode voor de XBee) tot 1 (verhogen dit voor elke zender, zodat je ze uit elkaar kan vertellen, zullen we aannemen dat u slechts één voor nu)
2. Stel de slaapstand SM tot 4 (Cyclische slapen)
3. Stel de slaaptijd ST tot 3 (3 milliseconden na wake-up om terug te gaan slapen)
4. Stel de Sleep Period SP tot C8 (0xC8 hexadecimaal = 200 x 10 milliseconden = 2 seconden tussen zendt)
5. Stel ADC 4 D4 tot en met 2 (analoge / digitale sensor in te schakelen pin AD4)
6. Stel ADC 0 D0 tot 2 (analoge / digitale sensor in te schakelen pin AD0)
7. Stel Monsters TX IT tot en met 13 (0x13 = 19 A / D samples per pakket)
8. Set Sample Rate IR tot 1 (1 ms tussen A / D samples)

als je denkt dat er meer XBee in het gebied dat zou kunnen conflicteren met uw installatie kunt u ook wilt

1. Stel de PAN ID om een 4-cijferige hexadecimale getal (de 3332 standaard)

U kunt dit doen met X-CTU of met een terminal programma zoals hyperterm, minicom, zterm, enz. Met de commando string
Atmy = 1, SM = 4, ST = 3, SP = C8, D4 = 2, D0 = 2, IT = 13, IR = 1
Je moet om te beginnen door het verkrijgen van de aandacht van de modem door te wachten 10 seconden en in te typen +++ snel, dan pauzeren voor nog eens 5 seconden. Maak dan gebruik van AT om ervoor te zorgen dat de betaling van AT TENTION op uw commando's

Eigenlijk wat dit betekent is dat we alle XBees op één PAN netwerk zult hebben, zal elke XBee een unieke identificatiecode hebben, zullen ze blijven in de slaapstand staat het grootste deel van de tijd, dan wakker elke 2 seconden tot 19 monsters te nemen van ADC 0 en 4, 1ms elkaar. Als u problemen ondervindt, moet u de firmware upgrade!

Zorg ervoor dat u de configuratie schrijven naar permanente opslag van de XBee's zodra je het hebt gedaan. Als u gebruik maakt van X-CTU klik op de knop "Write" in de linkerbovenhoek. Als u gebruik maakt van een terminal, gebruikt u de opdracht ATWR!

Merk op dat zodra de XBee wordt verteld in de slaapstand te gaan, dan moet je resetten om te praten, want anders zal het niet reageren en X-CTU zal klagen. U kunt gewoon de stekker van de adapter uit de FTDI kabel om te resetten of raak een draad tussen de RST en GND pinnen op de onderkant van de adapter.

Nu dat de zenders zijn al opstelling met unieke mijn nummer ID's, zorg ervoor dat, terwijl ze worden gevoed vanuit de USB groene LED knippert eenmaal per 2 seconden (met vermelding van wake-up en data verzenden)

Configureert de ontvanger XBee

Steek de ontvanger XBee in de USB-aansluiting (zet de ontvanger XBee afstand) en start X-CTU . Als u de PAN-ID in de vorige stap instelt, moet u hier hetzelfde te doen

  • Stel de PAN ID hetzelfde als hierboven hexuitdraaiaantal

Als u de PAN hierboven niet heeft gewijzigd, dan is er niets voor je te doen hier, maar deze stap overslaan

Next!

Nu de XBees zijn geconfigureerd en klaar is, is het tijd om te gaan naar de volgende stap waar we de Kill-a-Watt hardware

Stap 5: Soldeer de zender - stuklijst

Tweet-a-watt - Hoe maak je een twitteren power meter te maken ...

Voordat je start...

Je moet alleen proberen dit project als je comfortabel en competent werken met een hoog voltage elektriciteit, elektronica en computers zijn. Zodra het project voltooid is afgesloten en er geen zichtbare hoogspanning. Echter, je moet alleen werken aan het project wanneer het in niet in het stopcontact en nooit proberen te testen, meten, open, of sonde de circuitboards terwijl ze aangesloten op een stopcontact. Als er iets niet werkt: stop, haal hem uit het stopcontact, open het vervolgens en te onderzoeken. Ja, het duurt een paar minuten, maar het is een stuk veiliger!

Uw veiligheid is je eigen verantwoordelijkheid, met inbegrip van het juiste gebruik van de apparatuur en de veiligheid vistuig, en het bepalen of u voldoende vaardigheid en ervaring. Elektrisch gereedschap, elektriciteit, en andere middelen die voor deze projecten zijn gevaarlijk, tenzij naar behoren en met voldoende voorzorgsmaatregelen, met inbegrip van de veiligheid vistuig dat wordt gebruikt. Sommige illustratieve foto's niet tonen veiligheidsmaatregelen of apparatuur, om te laten zien van het project duidelijker stappen. Dit project is niet bedoeld voor gebruik door kinderen.

Het gebruik van de instructies en suggesties is op eigen risico. Adafruit Industries LLC, wijst elke aansprakelijkheid voor de daardoor ontstane schade, letsel, of kosten. Het is uw verantwoordelijkheid om ervoor te zorgen dat uw activiteiten in overeenstemming zijn met de geldende wetten.

OK, als u het eens kunnen we verder gaan!

zender onderdelenlijst

Voor elk stopcontact dat u wilt controleren, moet u:

Naam: Kill-a-Watt
Beschrijving: "Off the shelf" model P4400 stroom naar de monitor
Datasheet: P3 Kill-a-watt
Distributeur: Lots! Controleer ook hardware / elektronica-winkels
Aantal: 1

Naam: Adafruit XBee Adapter
Omschrijving: Ik zal met mijn eigen ontwerp voor de XBee breakout / carrier board, maar je kunt bijna elke vorm zo lang gebruiken als u ontbrekende onderdelen zoals the3.3V aanbod en de LED's te repliceren
Datasheet: Webpagina
Distributeur: Adafruit
Aantal: 1

Naam: XBee module
Beschrijving: We zullen gebruik maken van de XBee "serie 1" point-to-multipoint 802.15.4 modules met een chip antenne deel # XB24-ACI-001. Ze zijn goedkoop en werken groot. Dit project zal waarschijnlijk niet werken met een andere versie van de XBee, en zeker niet een van de 'high power' Pro types!
Distributeur: Adafruit
Aantal: 1

Naam: D3
Beschrijving: 1N4001 diode. Elke macht diode zou moeten werken. Heck, zelfs een 1N4148 of 1n914 moet OK zijn. Maar 1N4001 voorstelt en in de kit.
Datasheet: Generic 1N4001
Distributeur: Digikey Mouser
Aantal: 1

Naam: D2
Beschrijving: Grote diffuus LED, voor het eenvoudig bekijken. De kit wordt geleverd met groen.
Aantal: 1

Naam: C3
Beschrijving: 220uF, 4V of hoger (foto toont 100uF)
Datasheet: Generic
Distributeur: Digikey Mouser
Aantal: 1

Naam: C4
Beschrijving: 10,000uF condensator (wow!) / 6.3V (foto toont slechts een 2200uF) Probeer tot 16 mm diameter te krijgen, 25mm lang
Datasheet: Generic
Distributeur: Digikey [Mouser]
Aantal: 1

Naam: R4 R6
Beschrijving: 10K 1 / 4W 1% weerstand (bruin zwart zwart rood goud) of 10K 1 / 4W 5% weerstand (bruin zwart oranje goud). 1% heeft de voorkeur, maar 5% is OK
Datasheet: Generic
Distributeur: Mouser Digikey
Aantal: 2

Naam: R3 R5
Beschrijving: 4.7K 1 / 4W 1% weerstand (geel paars zwart bruin goud) of 4.7K 1 / 4W 5% weerstand (geel violet rood goud). 1% heeft de voorkeur, maar 5% is OK.
Datasheet: Generic
Distributeur: Mouser Digikey
Aantal: 2

Naam: kabel Ribbon
Beschrijving: Ribbon-kabel, of andere flexibele draad, ten minste 6 geleiders, ongeveer 6 "lang
Datasheet: Generic Ribbon
Distributeur: Digikey
Aantal: 6 "

Naam: Heat shrink
Beschrijving: Warmte krimpen! Een paar centimeters van 1/8 "en 1/16" elk
Datasheet: Generic

Het zal u ongeveer $ 50- $ 60 voor elk stopcontact

Stap 6: Transmitter Schematische

Tweet-a-watt - Hoe maak je een twitteren power meter te maken ...

De XBee radio doet al het harde werk, het luistert op twee analoge ingangen (AD0 en AD4) voor de spanning en stroom van gegevens. Dan stuurt hij die informatie draadloos naar de hostcomputer ontvanger XBee. Er zijn een paar moeten we rond ingenieur te laten werken:

1. We willen de XBee uit interne voeding van de Kill-a-Watt's lopen. Echter zijn huidige beperkt en gewoon zorgen 50mA in een uitbarsting toen de XBee uitzendt. Wij lossen hierop door een simpele 'oplaadbare batterij' in de vorm van een zeer grote condensator C4.

2. The Kill-a-Watt draait op 5V, maar XBees kan alleen draaien op 3.3V dus we hebben een voltage regulator IC1 en twee condensatoren twee stabiliseren van de 3.3V levering, C1 en C2.

3. De XBee zal elke paar seconden te zenden, zelfs terwijl de condensator wordt opgeladen. Dit betekent dat het zal houden het aftappen van de condensator, resetten en opnieuw te proberen, in principe freaking out, terwijl de voeding is nog aan het bouwen. We voorkomen dat dit door het toevoegen van een andere vrij grote condensator C3 op de reset-lijn. Dit vertraagt ​​de XBee, het uitstellen van het opstarten van een paar seconden en houdt de XBee opstart tot we hebben stevige macht.

4. De XBee analoge sensoren draaien op 3.3V, maar de Kill-a-Watt sensoren draaien op 5V. We gebruiken eenvoudige spanningsdeler R3 / R4 en R5 / R6 het analoge signaal beneden verlagen tot een redelijk niveau

Stap 7: Monteer en maak de zender - 1

Tweet-a-watt - Hoe maak je een twitteren power meter te maken ...

Open je kit en stap uit de onderdelen voor de zender. Vergeet niet dat we de meeste, maar niet zult gebruiken al een XBee adapter kit. De twee kleine LED's, worden de 74HC125N chip, een 10K en 1K weerstand niet gebruikt en je moet ze opzij zetten voor een toekomstig project, zodat je niet per ongeluk ze hier gebruiken.

Controleer of u alles wat u nodig hebt. Het enige wat hier niet weergegeven is de XBee radio en doden-a-Watt.

Plaats de PCB adapter kit en maak je klaar om te solderen door het opwarmen van uw soldeerbout en de voorbereiding van uw handgereedschap

We beginnen met het solderen in de 3.3V regulator, die identiek is aan de standaard XBee adapter kit die u in de instructies ontvanger. Vergeet niet om de polariteit van C2 controleren en dat IC1 is op de juiste manier. solderen en vervolgens klem de drie componenten.

Nu zullen we veer uit de standaard XBee adapter instructies en voeg een veel grotere LED op de ASC lijn, zodat we gemakkelijk kunnen zien knipperen wanneer het in de Kill-a-Watt. Zorg ervoor om naar te kijken voor de LED polariteit, want een achteruit LED zal maken debuggen erg moeilijk. Hoe langer leiding gaat in de + gemarkeerde soldeer gat.

Geven de LED ongeveer een half inch ruimte voorbij het einde van de printplaat zijn. Ook solderen in de bijpassende 1K weerstand R2

Soldeer in de twee 2mm 10pin vrouwelijke headers in de adapter kit. Wees voorzichtig met het soldeer, zodat u de vrouwelijke header niet per ongeluk vullen. Gebruik een sparend bedrag om ervoor te zorgen dat er een verband, maar het is niet overvol

Stap 8: Monteer en maak de zender - 2

Tweet-a-watt - Hoe maak je een twitteren power meter te maken ...

Nu is het tijd om de draden die we nodig hebben voor de komende paar haltes te bereiden. Gebruik je diagonaal messen af ​​te kerven de bruin, rood, oranje en gele draden van het einde van de regenboog lint kabel in de kit.

scheur vervolgens de vier draden van de rest van de kabel.

Doe hetzelfde voor de zwarte en witte draden en de enkele groene draad. Snijd vervolgens de groene draad dus het is slechts ongeveer 1,5 "lang. U moet nu 3 stroken van draad, een 6" met 4 geleiders, een 6 "met 2 geleiders en een 1,5" met 1 conductor

Gebruik wirestrippers de uiteinden van de groene draad strippen, 1/4 "van de einden

Vervolgens tin de groene draad door verhitting van de uiteinden van de draad en met een lichte soldeer samenbinden de strengen.

Gebruik de groene draad aan een brug tussen de VREF pin, 7 vanaf de bovenkant aan de rechterkant en de VCC pin op de linkerbovenhoek te creëren.

Double check om ervoor te zorgen dat u dit goed te krijgen! solderen het dan op zijn plaats. Dit zal het referentiepunt van de analoogomzetter 3.3V stellen

Ga terug naar de 4-delige lintkabel. Splits de uiteinden met de diagonale cutter, dan strippen en tin alle 8 eindigt.

Zet een 4.7K weerstand in een bankschroef of de houder, en klik vervolgens de ene kant uit en tin is net als de draden.

Knip een 1/2 "piece of 1/16" warmte krimpt en zet het op de gele draad, zorg ervoor dat er speling tussen de heatshrink en het einde van de draad. Dan soldeer de gele draad aan de 4.7K weerstand.

Doe hetzelfde voor de oranje draad en de andere 4.7K weerstand. Gebruik een warmtebron (een warmte kanon of föhn is perfect) aan de krimpkous krimpen over de gesoldeerde draad / weerstand joint.Then buig de weerstand 90 graden en knip de andere kant van de 4.7K weerstanden

Stap 9: Monteer en maak de zender - 3

Tweet-a-watt - Hoe maak je een twitteren power meter te maken ...

Nu zullen we de spanning divider op te bouwen. Neem de twee 10K weerstanden en sluit ze, zoals getoond. Men gaat uit AD0 en één uit AD4. Beide vervolgens verbinding met de grond. Handig is de chip we niet gebruikt had geaarde pinnen, zodat we kunnen 'hergebruiken' die pinnen.

Nu komt het lastige deel. We willen de andere kant van de 4.7K weerstand aan te sluiten op de AD0 pin maar de 10K weerstand is er al. Gebruik je soldeerbout om een klodder soldeer smelten op de bovenkant van de 10K weerstand en dan meeliften de 4.7K weerstand door solderen aan de top van de 10K weerstand.

Soldeer de oranje draad naar de AD0 pin, het geel aan de AD4

De andere twee draden zijn voor draagkracht. De rode draad moet worden gesoldeerd aan de + 5V pin op de bodem van de adapterprintplaat. De bruine draad aan op de GND pin.

We zijn bijna klaar met de adapter solderen. Ten slotte is de 220uF reset condensator. We zullen dit aan te sluiten op de RST pin, 5 vanaf de bovenkant aan de linkerkant. Controleer de lange leiding is verbonden met de RST pin en de kortere doorlooptijden gaat naar de 4e pin waar de chip zou gaan. Controleer de foto aan de linkerkant om ervoor te zorgen dat u hebt het in de juiste.

De condensator zal niet passen onder de XBee module dus geef het wat kabellengte zodat de cilindrische bulk ligt naast de 3.3V regulator.

Ter referentie, de onderstaande afbeeldingen laten zien wat de achterkant eruit moet zien.

... En wat het eruit zou moeten zien met de XBee modem geïnstalleerd. Zorg ervoor dat de pinnen op de XBee line-up met de kop.

Stap 10: Monteer en maak de zender - 4

Tweet-a-watt - Hoe maak je een twitteren power meter te maken ...

Vervang nu de printplaat met de enorme condensator.

Knip de lange kabels naar beneden. Je moet het gebruik van "-" streep om bij te houden welke pin is negatief en dat is positief te houden.

Tin beide leidt met soldeer.

Soldeer het andere uiteinde van de rode draad lint (die naar + 5V op de XBee adapter) de positieve pen van de condensator.

Soldeer dan de bruine draad (die naar GND op de XBee adapter) met de negatieve pen.

Knip de kathode leiden van de 1N4001 diode, dat is het einde van de witte streep. ben ermee bezig. Soldeer de diode zodat de witte streep zijde verbonden met de positieve pen van de grote condensator.

Neem de zwarte en witte lint van eerder. Split, strip en tin de vier uiteinden. Snij een 1 "stuk 1/8" krimpkous en zet het op de witte draad. Slip een 1/2 "piece of 1/16" verwarmen krimpen op de zwarte draad.

Klem het andere uiteinde van de diode (de kant zonder witte streep) en soldeer de witte draad aan. Soldeer de zwarte draad aan de negatieve pin van de grote condensator.

Nu krimpen de heatshrink zodat de condensator leads en diode vallen.

Oké, hier is wat je zou moeten hebben, een adapter met twee sensor lijnen (oranje en geel) opknoping uit en twee hoogspanningsleidingen (rood en bruin) die zijn aangesloten op de grote condensator. Dan zijn er twee zwarte en witte draden aangesloten op de condensator, de witte door een diode.

Stap 11: Monteer en maak de zender - 5

Tweet-a-watt - Hoe maak je een twitteren power meter te maken ...

Nu is het tijd om de doden-a-Watt te openen! Er zijn slechts 3 schroeven die het samen te houden, en ze zijn te vinden op de rug.

Nu is het tijd om de doden-a-Watt te openen! Er zijn slechts 3 schroeven die het samen te houden, en ze zijn te vinden op de rug.

Gebruik een 3/8 boor om een ​​gat te maken in de buurt van de rechterhoek van de zaak terug. Dit is wat de LED zal vasthouden uit. (Negeren de witte tape en # 4, dit is een gerecycleerde kill-a-watt :)

Nu vindt de LM2902N chip. Dit is een quad op-amp die de kracht line gebruik zintuigen. We gaan piggy-back boven op het, en lenen de grond, 5V en 2 sensoruitgangen!

Met je soldeerbout, smelt een beetje soldeer op pin 1, 4, 11 en 14 van de chip. Zorg ervoor dat u de chip in de juiste richting, de inkeping geeft aan waar de pinnen 1 en 14

Soldeer de witte draad (5V tot de XBee) aan pin 4. Soldeer de zwarte draad (aarde) naar pin 11 direct tegenover.

Nu soldeer de gele draad aan pin 1 en de oranje draad aan pin 14.

Gebruik twee kleine stukjes van kleverige schuim en plak ze op de achterkant van de behuizing.

Plaats de XBee adapter en condensator op de band, zodat de LED steekt uit het gat eerder geboord

Plooi de overtollige lint kabel uit de weg, zodat ze niet in de buurt van de 120V aansluitingen waardoor ze poef gaan.

Sluit het op en steek hem in.

U zult merken dat het een beetje betuttelend voor een paar seconden als de grote condensator laadt. Het display kan niet komen voor 15-30 seconden, en het kan in en uit te faden op het eerste. De nummers kunnen ook verkeerd voor een beetje als het opstart zijn. Binnen ongeveer 30 seconden, ziet u op het display te stabiliseren en het lampje knippert elke 2 seconden!

Ga terug naar uw computer, sluit de ontvanger XBee in de USB-adapter en zorg ervoor dat het beschikt over de nieuwste firmware is geüpload en zet deze op dezelfde PAN ID als de zenders. U vindt de RSSI LED (rode LED) branden te zien. Dat betekent dat je een goede link!

Open de Terminal in X-CTU (of een andere terminal-programma) en sluit op 9600 baud 8N1 pariteit en je zult een hoop onzin te zien. Wat belangrijk is, is dat er een nieuw stuk van onzin wordt afgedrukt eenmaal per 2 seconden, met vermelding van een pakket van data is ontvangen.

De hardware wordt uitgevoerd. Goed werk!

Stap 12: Software

Tweet-a-watt - Hoe maak je een twitteren power meter te maken ...

Invoering

Nu de hardware is voltooid, komen we bij het spannende deel: het uitvoeren van de software die de gegevens ophaalt uit onze ontvanger XBee en slaat het op onze computer of upload deze naar een database of updates van onze Twitter-feed of .... wat je ' graag!

Hier is hoe het werkt, is de XBee in de Kill-a-Watt aangesloten op twee analoge signalen. Een daarvan is de spanning signaal dat de AC spanning aan geeft. In het algemeen is dit een sinus dat 120VAC. Een lastig om te onthouden is dat 120V is de spanning 'RMS', en de 'ware spanning' is + -170VDC. ( U kunt meer informatie over RMS spanning lezen op wikipedia in feite is het een manier om aan te geven hoeveel 'gemiddelde' spanning die er is.) De tweede lezing is de wisselstroom lezen. Dit is hoeveel stroom wordt getrokken door de Kill-a-Watt. Als u de huidige vermenigvuldigen met de spanning, vindt u het vermogen (in Watt) gebruikt te krijgen!

De XBee's analoog / digitaal converter is opgezet om een ​​'snapshot' van een sinus-cyclus op een moment. Elk double-monster (spanning en stroom) wordt 1ms uit elkaar gehaald en het duurt 17 van hen. Dat vertaalt zich naar een 17ms lange trein van de monsters. Een cyclus van de macht-gebruik is 1 / 60Hz lang dat is 16.6ms. Dus het werkt vrij goed!

Laten we kijken naar enkele voorbeelden van spanning en stroom golfvormen als XBee ze ziet.

Bijvoorbeeld deze eerste grafiek is van een laptop aangesloten. U zult zien dat het een schakelende voeding, en trekt alleen de macht tijdens de piek van de spanning curve.

Nu laten we proberen het inpluggen van een 40W gloeilamp. U zult merken dat in tegenstelling tot de schakelende voeding, de huidige volgt de spanning bijna perfect. Dat komt omdat een gloeilamp is slechts een weerstand!

Tot slot, laten we proberen het steken van de meter op een dimbare switch. Je zult zien dat de spanning wordt 'gehakt' up, niet meer sinusvormige. En hoewel de huidige volgt de spanning, het is nog steeds bijpassende vrij goed.

De XBee stuurt de ruwe data van de computer die in een python script, cijfers te komen wat de (gekalibreerde) spanning en stroomsterkte is op elk monster en vermenigvuldigt elk punt samen te krijgen van de Watts gebruikt in die cyclus. Omdat er bijna geen apparaat dat de power-toepassingen verandert van cyclus-tot-cyclus, de momentopname is een goede indicator van het totale energieverbruik dat tweede. Daarna eenmaal per 2 seconden, een snapshot verzonden naar de ontvanger XBee

Installeer python & friends

De software die praat met de XBee is geschreven in Python. Ik gebruikte python omdat het snel in te ontwikkelen, heeft multi-OS-ondersteuning en is vrij populair met software en hardware hackers. De XBees praten over de seriële poort, zodat letterlijk elke programmeertaal kan / kon worden hier gebruikt. Als u een software-geek bent en je wilt perl, C, C #, tcl / tk, verwerking, java, enz. Te gebruiken go for it! Je moet de seriële data te lezen en te ontleden uit het pakket, maar het is niet bijzonder hard.

Echter, de meeste mensen willen gewoon aan de slag met het en zo voor u gaan we door het proces van het installeren van python en de bibliotheken die we nodig hebben.

1. Download en installeer python 2,5 vanaf http://www.python.org/download/ Ik stel voor 2,5 want dat lijkt stabiel en goed ondersteund op dit moment te zijn. Als u een andere versie te gebruiken kunnen er problemen zijn
2. Download en installeer pyserial uit het pakket repository (dit zal laten ons naar de XBee praten via de seriële poort)
3. Als u werkt onder Windows te downloaden en te installeren win32file voor python 2,5 (dit zal file support toe te voegen)
4. Download en installeer de simplejson python library (dit is hoe de twitter api graag aangesproken te worden)

Nu kun je eindelijk downloaden van de Wattcher script zullen we hier laten zien! We gaan om het te downloaden in de map C: \ Wattcher directory, voor andere OS's kun je natuurlijk veranderen deze directory

Basic configure

We moeten wel een beetje van de installatie te beginnen, het openstellen van de wattcher.py script met een tekstverwerker en zoek de lijn

SerialPort = "COM4" # het com / seriële poort van de XBee is verbonden met

veranderen COM4 in wat de seriële poort wordt u verbinding maakt met de XBee met heet. Onder windows zijn sommige COMx haven, onder Linux en Mac zijn iets als /dev/cu.usbserial-xxxx controleren / dev / directory en / of dmesg

Sla het script met de nieuwe seriële poort naam

Test het uit

Zodra je python hebt geïnstalleerd en geëxtraheerd de scripts om je werkmap, het opstarten van een terminal (onder linux is dit gewoon rxvt of xterm, onder mac haar Terminal, onder Windows, het is een cmd venster)

Ik ga ervan uit dat u Windows uitvoert van nu af aan, moet het niet moeilijk om de instructies aan te passen aan linux / mac zodra de terminal venster is geopend.

Voer het commando cd C: \ Wattcher om naar de plaats waar u de bestanden ongecomprimeerd te krijgen. Door het uitvoeren van de opdracht dir kunt u zien dat u de bestanden in de directory

Zorg ervoor dat uw zender (Kill-a-Watt + Xbee) is aangesloten, en een keer knipperen elke 2 seconden. Vergeet niet dat het duurt een tijdje voor de zender op te laden macht en beginnen zenden. Het LCD-display moet duidelijk, niet vaag zijn. Zorg ervoor dat er niets is aangesloten op de Kill-a-Watt, ook. The RSSI (red) LED on the receiver connected to the computer should be lit indicating data is being received. Don't continue until that is all good to go.

Now run python by running the command C:\python25\python.exe wattcher.py

You should get a steady print out of data. The first number is the XBee address from which it received data, following is the estimated current draw, wattage used and the Watt-hours consumed since the last data came in. Hooray! We have wireless data!

Calibrating

Now that we have good data being received, its time to tweak it. For example, its very likely that even without an appliance or light plugged into the Kill-a-Watt, the script thinks that there is power being used. We need to calibrate the sensor so that we know where 'zero' is. In the Kill-a-Watt there is an autocalibration system but unfortunately the XBee is not smart enough to do it on its own. So, we do it in the python script. Quit the script by typing in Control-C and run it again this time as C:\python25\python.exe wattcher.py -d note the -d which tells the script to print out debugging information

Now you can see the script printing out a whole mess of data. The first chunk with lots of -1's in it is the raw packet. While its interesting we want to look at the line that starts with ampdata :

ampdata: [498, 498, 498, 498, 498, 498, 498, 498, 498, 498, 498, 498, 498, 498, 497, 498, 498, 498]

Now you'll notice that the numbers are pretty much all the same. That's because there's nothing plugged into the tweetawatt and so each 1/60 Hz cycle has a flat line at 'zero'. The A/D in the XBee is 10 bits, and will return values between 0 and 1023. So, in theory, if the system is perfect the value at 'zero' should be 512. However, there are a bunch of little things that make the system imperfect and so zero is only close to 512. In this case the 'zero' calibration point is really 498. When its off there is a 'DC offset' to the Amp readings, as this graph shows:

See how the Amp line (green) is steady but its not at zero, its at 0.4 amps? There is a 'DC offset' of 0.4 amps

OK, open up the wattcher.py script in a text editor.

vrefcalibration = [492, # Calibration for sensor #0]
492, # Calibration for sensor #1
489, # Calibration for sensor #2
492, # Calibration for sensor #3
501, # Calibration for sensor #4
493] # etc... approx ((2.4v * (10Ko/14.7Ko)) / 3

See the line that says # Calibration for sensor #1 ? Change that to 498

vrefcalibration = [492, # Calibration for sensor #0]
498, # Calibration for sensor #1
489, # Calibration for sensor #2
492, # Calibration for sensor #3
501, # Calibration for sensor #4
493] # etc... approx ((2.4v * (10Ko/14.7Ko)) / 3

Save the file and start up the script again, this time without the -d

Now you'll see that the Watt draw is 2W or less, instead of 40W (which was way off!) The reason its not 0W is that, first off, there's a little noise that we're reading in the A/D lines, secondly there's power draw by the Kill-a-Watt itself and finally, the XBee doesn't have a lot of samples to work with. However <2W is pretty good considering that the full sensing range is 0-1500W

Note the graph with the calibrated sensor:

See how the Amps line is now at 0 steady, there is no DC offset

Logging data

Its nice to have this data but it would be even nicer if we could store it for use. Well, thats automatically done for you! You can set the name of the log file in the wattcher.py script. By default it's powerdatalog.csv . The script collects data and every 5 minutes writes a single line in the format Year Month Day, Time, Sensor#, Watts for each sensor.As you can see, this is an example of a 40W incandescent lightbulb plugged in for a few hours. Because of the low sample rate, you'll see some minor variations in the Watts recorded. This data can be easily imported directly into any spreadsheet program

Tweeting

Finally we get to the tweeting part of the tweet-a-watt. First open up the wattcher.py script and set

# Twitter username & password
twitterusername = "username"
twitterpassword = "password"

to your username and password on twitter. You can make an account on twitter.com if you don't have one.

Then run the script as usual. Every 8 hours (midnight, 8am and 4pm) the script will sent a twitter using the Twitter API

Then check it out at your account:

Step 13: Expand

Tweet-a-watt - How to make a twittering power meter...

Overzicht

Once you've got your base system up and running here are some ideas for how to extend, improve or expand it!

Add more outlets

So you can track more rooms, of course

Graphing

If you'd like to play some more with the script, there's some extras built in. For example, you can graph the data as it comes in from the XBee, both Watts used and the actual 'power line' waveform. Simply set GRAPHIT = True you'll need to install a mess of python libraries though, including wxpython , numpy and pylab

Remove the computer

It took a few hours, but I hacked my Asus wifi router to also log data for me. There'll be more documentation soon but here's some hints:

Do basically everything in [Do basically everything in MightyOhm's tutorial. You can use the FTDI cable to reprogram the router, just move the pins around. Then add a 16mb USB key (I was given one as schwag so look in your drawers) and install python and the openssl library as well as the other libraries needed like pyserial. The code should pretty much just run! (I'll put up more detailed notes later)]

The router still works as my wifi gateway to the cablemodem, and only uses 5W MightyOhm's tutorial]. You can use the FTDI cable to reprogram the router, just move the pins around. Then add a 16mb USB key (I was given one as schwag so look in your drawers) and install python and the openssl library as well as the other libraries needed like pyserial. The code should pretty much just run! (I'll put up more detailed notes later)

The router still works as my wifi gateway to the cablemodem, and only uses 5W

Step 14: Design - overview

Design overview

For those interested in how to build a sensor node system with a Google Appengine backend, here is the process by which I created it. Of course, you should have the hardware part done first!

1. Listen - designing the parser for the computer that grabs XBee packets, and extracts the useful data
2. Store - how to use GAE to store the data in 'the cloud'
3. Graph - using Google Visualizations to make pretty graphs

Step 15: Design - listen

Tweet-a-watt - How to make a twittering power meter...

Data listening & parsing

In this section we will work on the receiver software, that will talk to a receiver XBee and figure out what the sensor data means. I'll be writing the code in python which is a fairly-easy to use scripting language. It runs on all OS's and has tons of tutorials online. Also, Google AppEngine uses it so its a good time to learn!

This whole section assumes that you only have 1 transmitter and 1 receiver, mostly to make graphing easier to cope with. In the next section we'll tie in more sensors when we get to the datalogging part!

Raw analog input

We'll start by just getting raw data from the XBee and checking it out. The packet format for XBees is published but instead of rooting around in it, I'll just use the handy XBee library written for python. With it, I can focus on the data instead of counting bytes and calculating checksums.

To use the library, first use the pyserial module to open up a serial port (ie COM4 under windows, /dev/ttyUSB0 under mac/linux/etc) You can look at the XBee project page for information on how to figure out which COM port you're looking for. We connect at the standard default baudrate for XBees, which is 9600 and look for packets

from xbee import xbee
import serial

SERIALPORT = "COM4" # the com/serial port the XBee is connected to
BAUDRATE = 9600 # the baud rate we talk to the xbee

# open up the FTDI serial port to get data transmitted to xbee
ser = serial.Serial(SERIALPORT, BAUDRATE)
ser.open()

while True:
# grab one packet from the xbee, or timeout
packet = xbee.find_packet(ser)
if packet:
xb = xbee(packet)

print xb

Running this code, you'll get the following output:

<xbee {app_id: 0x83, address_16: 1, rssi: 85, address_broadcast: False, pan_broadcast: False, total_samples: 19, digital: [[-1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1], [-1 , -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1 , -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1 , -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1 , -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1 , -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1 , -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1 , -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1 , -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1]], analog: [[190, -1, -1, -1, 489, -1], [109, -1, -1, -1, 484, -1], [150, -1, -1, -1, 492, -1], [262, -1, -1, -1, 492 , -1], [423, -1, -1, -1, 492, -1], [589, -1, -1, -1, 492, -1], [740, -1, -1, -1, 492, -1], [843, -1, -1, -1, 492, -1], [870, -1, -1, -1, 496, -1], [805, -1, -1, -1, 491, -1], [680, -1, -1, -1, 492, -1], [518, -1, -1, -1, 492, -1], [349, -1, -1, -1, 491, -1], [199, -1, -1, -1, 491, -1], [116, -1, -1, -1, 468, -1], [108, -1, -1, -1, 492, -1], [198, -1, -1, -1, 492, -1], [335, -1, -1, -1, 492, -1], [523, -1, -1, -1, 492, -1]]}>

which we will reformat to make a little more legible

<xbee {
app_id: 0x83,
address_16: 1,
rssi: 85,
address_broadcast: False,
pan_broadcast: False,
total_samples: 19,
digital: [[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1]],
analog: [[190, -1, -1, -1, 489, -1],
[109, -1, -1, -1, 484, -1],
[150, -1, -1, -1, 492, -1],
[262, -1, -1, -1, 492, -1],
[423, -1, -1, -1, 492, -1],
[589, -1, -1, -1, 492, -1],
[740, -1, -1, -1, 492, -1],
[843, -1, -1, -1, 492, -1],
[870, -1, -1, -1, 496, -1],
[805, -1, -1, -1, 491, -1],
[680, -1, -1, -1, 492, -1],
[518, -1, -1, -1, 492, -1],
[349, -1, -1, -1, 491, -1],
[199, -1, -1, -1, 491, -1],
[116, -1, -1, -1, 468, -1],
[108, -1, -1, -1, 492, -1],
[198, -1, -1, -1, 492, -1],
[335, -1, -1, -1, 492, -1],
[523, -1, -1, -1, 492, -1]]

}>

OK now its clear whats going on here. First off, we get some data like the transmitter ID (address_16) and signal strength (RSSI). The packet also tells us how many sample are available (19). Now, the digital samples are all -1 because we didn't request any to be sent. The library still fills them in tho so thats why the non-data is there. The second chunk is 19 sets of analog data, ranging from 0 to 1023. As you can see, the first sample (#0) and fifth sample (#4) contain real data, the rest are -1. That corresponds to the hardware section where we setup AD0 and AD4 to be our voltage and current sensors.

We'll tweak our code so that we can extract this data only and ignore the rest of the packet.

This code creates two arrays, voltagedata and ampdata where we will stick the data. We throw out the first sample because usually ADCs are a bit wonky on the first sample and then are good to go after that. It may not be necessary tho

#!/usr/bin/env python
import serial
from xbee import xbee

SERIALPORT = "COM4" # the com/serial port the XBee is connected to
BAUDRATE = 9600 # the baud rate we talk to the xbee
CURRENTSENSE = 4 # which XBee ADC has current draw data
VOLTSENSE = 0 # which XBee ADC has mains voltage data

# open up the FTDI serial port to get data transmitted to xbee
ser = serial.Serial(SERIALPORT, BAUDRATE)
ser.open()

while True:
# grab one packet from the xbee, or timeout
packet = xbee.find_packet(ser)
if packet:
xb = xbee(packet)

#print xb
# we'll only store n-1 samples since the first one is usually messed up
voltagedata = [-1] * (len(xb.analog_samples) - 1)
ampdata = [-1] * (len(xb.analog_samples ) -1)
# grab 1 thru n of the ADC readings, referencing the ADC constants
# and store them in nice little arrays
for i in range(len(voltagedata)):
voltagedata[i] = xb.analog_samples[i+1][VOLTSENSE]
ampdata[i] = xb.analog_samples[i+1][CURRENTSENSE]
print voltagedata
print ampdata

Now our data is easier to see:


Voltage: [672, 801, 864, 860, 755, 607, 419, 242, 143, 108, 143, 253, 433, 623, 760, 848, 871, 811]
Current: [492, 492, 510, 491, 492, 491, 491, 491, 492, 480, 492, 492, 492, 492, 492, 492, 497, 492]

Note that the voltage swings from about 100 to 900, sinusoidally.

Normalizing the data

Next up we will 'normalize' the data. The voltage should go from -170 to +170 which is the actual voltage on the line, instead of 100 to 900 which is just what the ADC reads. To do that we will get the average value of the largest and smallest reading and subtract it from all the samples. After that, we'll normalize the Current measurements as well, to get the numbers to equal the current draw in Amperes.

#!/usr/bin/env python
import serial
from xbee import xbee

SERIALPORT = "COM4" # the com/serial port the XBee is connected to
BAUDRATE = 9600 # the baud rate we talk to the xbee
CURRENTSENSE = 4 # which XBee ADC has current draw data
VOLTSENSE = 0 # which XBee ADC has mains voltage data

# open up the FTDI serial port to get data transmitted to xbee
ser = serial.Serial(SERIALPORT, BAUDRATE)
ser.open()

while True:
# grab one packet from the xbee, or timeout
packet = xbee.find_packet(ser)
if packet:
xb = xbee(packet)

#print xb
# we'll only store n-1 samples since the first one is usually messed up
voltagedata = [-1] * (len(xb.analog_samples) - 1)
ampdata = [-1] * (len(xb.analog_samples ) -1)
# grab 1 thru n of the ADC readings, referencing the ADC constants
# and store them in nice little arrays
for i in range(len(voltagedata)):
voltagedata[i] = xb.analog_samples[i+1][VOLTSENSE]
ampdata[i] = xb.analog_samples[i+1][CURRENTSENSE]

# get max and min voltage and normalize the curve to '0'
# to make the graph 'AC coupled' / signed
min_v = 1024 # XBee ADC is 10 bits, so max value is 1023
max_v = 0
for i in range(len(voltagedata)):
if (min_v > voltagedata[i]):
min_v = voltagedata[i]
if (max_v < voltagedata[i]):
max_v = voltagedata[i]

# figure out the 'average' of the max and min readings
avgv = (max_v + min_v) / 2
# also calculate the peak to peak measurements
vpp = max_v-min_v

for i in range(len(voltagedata)):
#remove 'dc bias', which we call the average read
voltagedata[i] -= avgv
# We know that the mains voltage is 120Vrms = +-170Vpp
voltagedata[i] = (voltagedata[i] * MAINSVPP) / vpp

# normalize current readings to amperes
for i in range(len(ampdata)):
# VREF is the hardcoded 'DC bias' value, its
# about 492 but would be nice if we could somehow
# get this data once in a while maybe using xbeeAPI
ampdata[i] -= VREF
# the CURRENTNORM is our normalizing constant
# that converts the ADC reading to Amperes
ampdata[i] /= CURRENTNORM

print "Voltage, in volts: ", voltagedata
print "Current, in amps: ", ampdata

We'll run this now to get this data, which looks pretty good, there's the sinusoidal voltage we are expecting and the current is mostly at 0 and then peaks up and down once in a while. Note that the current is sometimes negative but that's OK because we multiply it by the voltage and if both are negative it still comes out as a positive power draw


Voltage, in volts: [-125, -164, -170, -128, -64, 11, 93, 148, 170, 161, 114, 46, -39, -115, -157, -170, -150, -99]

Current, in amps: [0.064516129032258063, -1.096774193548387, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.096774193548387,]
0.0, 0.0, 0.0, -0.064516129032258063, 0.0, 0.0, -0.70967741935483875, 0.0, 0.0]

Basic data graphing

Finally, I'm going to add a whole bunch more code that will use the numpy graphing modules to make a nice graph of our data. Note that you'll need to install wxpython as well as numpy , and matplotlib !

At this point, the code is getting waaay to big to paste here so grab "wattcher.py Mains graph" from the download page!

Run it and you should see a graph window pop up with a nice sinusoidal voltage graph and various amperage data. For example this first graph is of a laptop plugged in. You'll see that its a switching supply, and only pulls power during the peak of the voltage curve.

Now lets try plugging in a 40W incandescent light bulb. You'll notice that unlike the switching supply, the current follows the voltage almost perfectly. Thats because a lightbulb is just a resistor!

Finally, lets try sticking the meter on a dimmable switch. You'll see that the voltage is 'chopped' up, no longer sinusoidal. And although the current follows the voltage, its still matching pretty well.

Graphing wattage!

OK neat, its all fun to watch waveforms but what we -really want- is the Watts used. Remember, P = VI otherwise known as Watts = Voltage * Current. We can calculate total Watts used by multiplying the voltages and currents at each sample point, then summing them up over a cycle & averaging to get the power used per cycle. Once we have Watts, its easy to just multiply that by 'time' to get Watt-hours!

Download and run the wattcher.py - watt grapher script from the download page

Now you can watch the last hour's worth of watt history (3600 seconds divided by 2 seconds per sample = 1800 samples) In the image above you can see as I dim a 40-watt lightbulb. The data is very 'scattered' looking because we have not done any low-pass filtering. If we had a better analog sampling rate, this may not be as big a deal but with only 17 samples to work with, precision is a little difficult

Done!

OK great! We have managed to read data, parse out the analog sensor payload and process it in a way that gives us meaningful graphs. Of course, this is great for instantaneous knowledge but it -would- be nice if we could have longer term storage, and also keep track of multiple sensors. In the next step we will do that by taking advantage of some free 'cloud computing' services!

Step 16: Design - store

Tweet-a-watt - How to make a twittering power meter...

Introduction

OK we are getting good data from our sensors, lets corral it into more useful chunks and store it in a database. We could make a database on the computer, but since we'd like to share this data, it makes more sense to put it online. There are custom services that are specifically designed to do this sort of thing like Pachube but I'm going to reinvent the wheel and design my own web-app that stores and displays energy data. (Mostly I want to play around with Google App Engine!)

You have 5 minutes!

We get data every few seconds from the XBee modem inside the kill-a-watt. We could, in theory, put data into our database every 2 seconds but that would quickly balloon the amount of storage necessary. It would also make sorting through the data difficult. So instead lets add up all the sensor data for 5 minutes and then take the average.

We'll do this by keeping two timers and one tally. One timer will track how long its been since the last sensor signal was sent, and the other will track if its been 5 minutes. The tally will store up all the Watt-hours (Watt measurements * time since last sensor data). Then at the end we can average by the 5 minutes

This chunk of code goes near the beginning, it creates the timers and tally and initializes them

...
fiveminutetimer = lasttime = time.time() # get the current time
cumulativewatthr = 0
...

Then later on, after we get our data we can put in this chunk of code:

# add up the delta-watthr used since last reading
# Figure out how many watt hours were used since last reading
elapsedseconds = time.time() - lasttime
dwatthr = (avgwatt * elapsedseconds) / (60.0 * 60.0) # 60 seconds in 60 minutes = 1 hr
lasttime = time.time()
print "\t\tWh used in last ",elapsedseconds," seconds: ",dwatthr
cumulativewatthr += dwatthr

# Determine the minute of the hour (ie 6:42 -> '42')
currminute = (int(time.time())/60) % 10
# Figure out if its been five minutes since our last save
if (((time.time() - fiveminutetimer) >= 60.0) and (currminute % 5 == 0)):
# Print out debug data, Wh used in last 5 minutes
avgwattsused = cumulativewatthr * (60.0*60.0 / (time.time() - fiveminutetimer))
print time.strftime("%Y %m %d, %H:%M"),", ",cumulativewatthr,"Wh = ",avgwattsused," W average")

# Reset our 5 minute timer
fiveminutetimer = time.time()
cumulativewatthr = 0

Note that we calculate delta-watthours, the small amount of power used every few seconds. Then we can get the average watts used by dividing the watthours by the number of hours that have passed (about 1/12th). Instead of going by exact 5 minutes, I decided to only report on the 5's of the hour (:05, :10, etc) so that its easier to send all the data at once if theres multiple sensors that started up at different times.

Download wattcher-5minreporter.py from the Download page. If you run this, you'll get a steady stream

Near the end you can see the timestamp, the Watthrs used in the last few minutes and the average Wattage

Multisensor!

We have good data but so far it only works with one sensor. Multiple sensors will mess it up! Time to add support for more than one XBee so that I can track a few rooms. I'll do that by creating an object class in python, and using the XBee address (remember that from part 1?) to track. I'll replace the code we just wrote with the following:

At the top, instead of the timer variables, I'll have a full class declaration, and create an array to store them:

####### store sensor data and array of histories per sensor
class Fiveminutehistory:
def init(self, sensornum):
self.sensornum = sensornum
self.fiveminutetimer = time.time() # track data over 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):
return self.cumulativewatthr * (60.0*60.0 / (time.time() - self.fiveminutetimer))

def str(self):
return "[id#: %d, 5mintimer: %f, lasttime; %f, cumulativewatthr: %f]" % (self.sensornum, self.fiveminutetimer, self.lasttime, self.cumulativewatthr)

######### an array of histories
sensorhistories = []

When the object is initialized with the sensor ID number, it also sets up the two timers and cumulative Watthrs tracked. I also created a few helper functions that will make the code cleaner

Right below that I'll create a little function to help me create and retrieve these objects. Given an XBee ID number it either makes a new one or gets the reference to it

####### retriever
def findsensorhistory(sensornum):
for history in sensorhistories:
if history.sensornum == sensornum:
return history
# none found, create it!
history = Fiveminutehistory(sensornum)
sensorhistories.append(history)
return history

Finally, instead of the average Watt calculation code written up above, we'll replace it with the following chunk, which retreives the object and tracks power usage with the object timers

# retreive the history for this sensor
sensorhistory = findsensorhistory(xb.address_16)
#print sensorhistory

# add up the delta-watthr used since last reading
# Figure out how many watt hours were used since last reading
elapsedseconds = time.time() - sensorhistory.lasttime
dwatthr = (avgwatt * elapsedseconds) / (60.0 * 60.0) # 60 seconds in 60 minutes = 1 hr
sensorhistory.lasttime = time.time()
print "\t\tWh used in last ",elapsedseconds," seconds: ",dwatthr
sensorhistory.addwatthr(dwatthr)

# Determine the minute of the hour (ie 6:42 -> '42')
currminute = (int(time.time())/60) % 10
# Figure out if its been five minutes since our last save
if (((time.time() - sensorhistory.fiveminutetimer) >= 60.0) and (currminute % 5 == 0)):
# Print out debug data, Wh used in last 5 minutes
avgwattsused = sensorhistory.avgwattover5min()
print time.strftime("%Y %m %d, %H:%M"),", ",sensorhistory.cumulativewatthr,"Wh = ",avgwattsused," W average"

# Reset our 5 minute timer
sensorhistory.reset5mintimer()

The code basically acts the same except now it wont choke on multiple sensor data! Below, my two Kill-a-Watts, one with a computer attached (100W) and another with a lamp (40W)

Onto the database!

The App Engine

So we want to have an networked computer to store this data so we can share the data, but we really don't want to have to run a server from home! Wat moeten we doen? Well as mentioned before, you can use Pachube or similar, but I will show how to roll-your-own with Google App Engine (GAE) . GAE is basically a free mini-webserver hosted by Google, that will run basic webapps without the hassle of administrating a database server. Each webapp has storage, some frameworks and can use Google accounts for authentication. To get started I suggest checking out the GAE website, documentation, etc. I'll assume you've gone through the tutorials and jump right into designing my power data storage app called Wattcher (a little confusing I know)

First, the app.yaml file which defines my app looks like this:

application: wattcher
version: 1
runtime: python
api_version: 1

handlers:
- url: /.*
script: wattcherapp.py

Pretty simple, just says that the app uses wattcherapp.py as the source file

Next, we'll dive into the python code for our webapp. First, the includes and database index. To create a database, we actually define it -in the python file-, GAE then figures out what kind of database to create for you by following those directions (very different than MySQL where you'd create the DB separately)

import cgi, datetime

from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db

class Powerusage(db.Model):
author = db.UserProperty() # the user
sensornum = db.IntegerProperty() # can have multiple sensors
watt = db.FloatProperty() # each sending us latest Watt measurement
date = db.DateTimeProperty(auto_now_add=True) # timestamp

We use the default includes. We have a single database table called Powerusage , and it has 4 entries: one for the user, one for the sensor number, one for the last reported Watts used and one for a datestamp

Each 'page' or function of our webapp needs its own class. Lets start with the function that allows us to store data in the DB. I'll call it PowerUpdate.

class PowerUpdate(webapp.RequestHandler):
def get(self):

# make the user log in
if not users.get_current_user():
self.redirect(users.create_login_url(self.request.uri))

powerusage = Powerusage()

if users.get_current_user():
powerusage.author = users.get_current_user()
#print self.request
if self.request.get('watt'):
powerusage.watt = float(self.request.get('watt'))
else:
self.response.out.write('Couldnt find \'watt\' GET property!')
return
if self.request.get('sensornum'):
powerusage.sensornum = int(self.request.get('sensornum'))
else:
powerusage.sensornum = 0 # assume theres just one or something

powerusage.put()
self.response.out.write('OK!')

When we send a request to do that with a GET call (ie requesting the webpage), we'll first make sure the user is authenticated and logged in so we know their name. Then we'll create a new database entry by initializing a new instantiation of Powerusage. Then we'll look the GET request for the watt data, which would be in the format watt=39.2 or similar. That's parsed for us, thankfully and we can also get the sensor number which is passed in the format sensornum=3. Finally we can store the data into the permanent database

Next is a useful debugging function, it will simply print out all the data it has received for your account!

class DumpData(webapp.RequestHandler):
def get(self):

# make the user log in
if not users.get_current_user():
self.redirect(users.create_login_url(self.request.uri))

self.response.out.write('<html><body>Here is all the data you have sent us:<p>')

powerusages = db.GqlQuery("SELECT * FROM Powerusage WHERE author = :1 ORDER BY date", users.get_current_user())

for powerused in powerusages:
if powerused.sensornum:
self.response.out.write('<b>%s</b>\'s sensor #%d' %
(powerused.author.nickname(), powerused.sensornum))
else:
self.response.out.write(<b>%s</b>' % powerused.author.nickname())

self.response.out.write(' used: %f Watts at %s<p>' % (powerused.watt, powerused.date))
self.response.out.write("</body></html>")

This function simply SELECT's (retrieves) all the entries, sorts them by date and prints out each one at a time

Finally we'll make a basic 'front page' that will show the last couple of datapoints sent

class MainPage(webapp.RequestHandler):
def get(self):

self.response.out.write('<html><body>Welcome to Wattcher!<p>Here are the last 10 datapoints:<p>')

powerusages = db.GqlQuery("SELECT * FROM Powerusage ORDER BY date DESC LIMIT 10")

for powerused in powerusages:
if powerused.sensornum:
self.response.out.write('<b>%s</b>\'s sensor #%d' %
(powerused.author.nickname(), powerused.sensornum))
else:
self.response.out.write('<b>%s</b>' % powerused.author.nickname())

self.response.out.write(' used: %f Watts at %s<p>' % (powerused.watt, powerused.date))
self.response.out.write("</body></html>")

Its very similar to the DataDump function but its only 10 points of data and from all users, nice to use when you just want to 'check it out' but don't want to log in

Finally, we have a little initializer structure that tells GAE what pages link to what functions

application = webapp.WSGIApplication(
[('/', MainPage),]
('/report', PowerUpdate),
('/dump', DumpData)],
debug=True)

def main():
run_wsgi_app(application)

if name == "main":
hoofd()

Test!

OK lets try it out, first lets visit http://wattcher.appspot.com/report

Remember we made it a requirement to supply -some- data. Lets try again http://wattcher.appspot.com/report?watt=19.22&sensornum=1

Yay we got an OK! Lets check out the data stored by visiting http://wattcher.appspot.com/dump

There's two entries because I did a little testing beforehand but you can see that there are 2 entries. Nice!

We can also visit the GAE control panel and browse the data 'by hand'

Anyways, now that that's working, lets go back and add the reporting technology to our sensor-reader script

Getting the report out

Only a little more hacking on the computer script and we're done. We want to add support for sending data to GAE. Unfortunately right now our authentication is done through Google accounts so its not easy to run on an Arduino. To adapt it you'd have to send the username in the Report GET and hope nobody else uses the same one (unless you also add a basic password system)

Anyhow, I totally ripped off how to do this from some nice people on the Internet

Download appengineauth.py from the download page , and change the first few lines if necessary. We hardcode the URL we're going to and the account/password as well as the GAE app name

users_email_address = "[email protected]"
users_password = "mypassword"
my_app_name = "wattcher"
target_authenticated_google_app_engine_uri = 'http://wattcher.appspot.com/report'

The real work happens at this function sendreport where it connects and sends the Watt data to the GAE site

def sendreport(sensornum, watt):
# this is where I actually want to go to
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 should contain the contents of the
# target_authenticated_google_app_engine_uri page - as we will have been
# redirected to that page automatically
#
# to prove this, I'm just gonna print it out
print serv_resp_body

Finally, we wrap up by adding the following lines to our computer script, which will send the data nicely over to GAE!

# Also, send it to the app engine
appengineauth.sendreport(xb.address_16, avgwattsused)

You can download the final script wattcher.py - final from the download page !

Don't forget to visit wattcher.appspot.com to check out the lastest readings

Step 17: Design - graph

Tweet-a-watt - How to make a twittering power meter...

Making pretty pictures

Data is great, but visualizations are better. In this step we'll manipulate our stored history so that we can make really nice graphs!

First we'll start by making our sensors named, so that its easier for us to keep track of which is what. Then we'll look at our graph options and data formats. Finally we'll reformat our data to make it ready for graphing

Configuring the sensor names

Its no fun to have data marked as "sensor #1" so I added a 'config' page where the app engine code looks at what sensor numbers have sent data to the database and then allows you to name them. Of course, you need to have the sensor on and sending data -first- before this will work

The configure screen looks something like the image below.

This code uses GET when it should really use POST. I'm kinda old and dont like debugging with POST so...yeah.

class Configure(webapp.RequestHandler):
def get(self):
# make the user log in if no user name is supplied
if self.request.get('user'):
account = users.User(self.request.get('user'))
else:
if not users.get_current_user():
self.redirect(users.create_login_url(self.request.uri))
account = users.get_current_user()

self.response.out.write('<html><body>Set up your sensornode names here:<p>')

# find all the sensors up to #10
sensorset = []
for i in range(10):
c = db.GqlQuery("SELECT * FROM Powerusage WHERE author = :1 and sensornum = :2", users.get_current_user(), i)
if c.get():
sensorset.append(i)

self.response.out.write('<form action="/config" method="get">')
for sensor in sensorset:
name = ""
currnamequery = db.GqlQuery("SELECT * FROM Sensorname WHERE author = :1 AND sensornum = :2", users.get_current_user(), sensor)
currname = currnamequery.get()

# first see if we're setting it!
if self.request.get('sensornum'+str(sensor)):
name = self.request.get('sensornum'+str(sensor))
if not currname:
currname = Sensorname() # create a new entry
currname.sensornum = sensor
currname.author = users.get_current_user()
currname.sensorname = name
currname.put()
else:
# we're not setting it so fetch current entry
if currname:
name = currname.sensorname

self.response.out.write('Sensor #'+str(sensor)+': <input type="text" name="sensornum'+str(sensor)+'" value="'+name+'"></text><p>')

self.response.out.write("""<div><input type="submit" value="Change names"></div>
</form>
</ Body>
</html>""")

Now we can have more useful data in the history dump

Now we can see that Phil is mostly to blame for our power bill!

Google Visualizer

So we have data and we'd like to see our power usage history. Graphing data is a lot of work, and I'm lazy. So I look online and find that Google -also- has a visualization API! This means I don't have to write a bunch of graphical code, and can just plug into their system. Zoet!

OK checking out the gallery of available visualizations , I'm fond of this one, the Annotated Time Line

Note how you can easily see the graphs, scroll around, zoom in and out and each plot is labeled. Perfect for plotting power data!

Data formatting

Theres a few restrictions to how we get the data to the visualization api and our best option is JSon data. As far as I can tell, JSON is what happened when everyone said "wow, XML is really bulky and wasteful". Anyhow, theres like 4 layers of framework and interpretive data structions and in the end there was a pretty easy to use library written by the Google Visualizations team that let me 'just do it' with a single call by putting the data into a python 'dictionary' in a certain format.

Lets go through the code in sections, since the function is quite long

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

# make the user log in if no user name is supplied
if self.request.get('user'):
account = users.User(self.request.get('user'))
else:
if not users.get_current_user():
self.redirect(users.create_login_url(self.request.uri))
account = users.get_current_user()

# assume we want 24 hours of data
historytimebegin = 24
if self.request.get('bhours'):
historytimebegin = int(self.request.get('bhours'))

# assume we want data starting from 0 hours ago
historytimeend = 0
if self.request.get('ehours'):
historytimeend = int(self.request.get('ehours'))

# data format for JSON happiness
datastore = []
columnnames = ["date"]
columnset = set(columnnames)
description ={"date": ("datetime", "Date")}

# the names of each sensor, if configured
sensornames = [None] * 10

First up we get the user we're going to be looking up the data for. Then we have two variables for defining the amount of data to grab. One is "ehours" (end hours) and the other is "bhours". So if you wanted the last 5 hours, bhours would be 5 and ehours would be 0. If you wanted 5 hours from one day ago, bhours would be 29 and ehours would be 24. datastore is where we will corall all the data. columnnames and description are the 'names' of each column. We always have a date column, then another column for each sensor stream. We also have a seperate array to cache the special sensor names.

onto the next section! Here is where we actually grab data from the database. Now app engine has this annoying restriction, you can only get 1000 points of data at once so what I do is go through it 12 hours at a time. The final datastore has all the points but its easier on the database, I guess. One thing that's confusing perhaps is each column has a name and a description. The name is short, say "watts3" for sensor #3, but the description might be "Limor's workbench". I don't even remember writing this code so maybe you can figure it out on your own?

# we cant grab more than 1000 datapoints, thanks to free-app-engine restriction
# thats about 3 sensors's worth in one day
# so we will restrict to only grabbing 12 hours of data at a time, about 7 sensors worth

while (historytimebegin > historytimeend):
if (historytimebegin - historytimeend) > 12:
timebegin = datetime.timedelta(hours = -historytimebegin)
timeend = datetime.timedelta(hours = -(historytimebegin-12))
historytimebegin -= 12
else:
timebegin = datetime.timedelta(hours = -historytimebegin)
historytimebegin = 0
timeend = datetime.timedelta(hours = -historytimeend)

# grab all the sensor data for that time chunk
powerusages = db.GqlQuery("SELECT * FROM Powerusage WHERE date > :1 AND date < :2 AND author = :3 ORDER BY date", datetime.datetime.now()+timebegin, datetime.datetime.now()+timeend, account)

# sort them into the proper format and add sensor names from that DB if not done yet
for powerused in powerusages:
coln = "watts" + str(powerused.sensornum)
entry = {"date": powerused.date.replace(tzinfo=utc).astimezone(est), coln: powerused.watt}
if not (coln in columnset):
columnnames.append(coln)
columnset = set(columnnames)
# find the sensor name, if we can
if (len(sensornames) < powerused.sensornum) or (not sensornames[powerused.sensornum]):
currnamequery = db.GqlQuery("SELECT * FROM Sensorname WHERE author = :1 AND sensornum = :2", account, powerused.sensornum)
name = currnamequery.get()

if not name:
sensornames[powerused.sensornum] = "sensor #"+str(powerused.sensornum)
else:
sensornames[powerused.sensornum] = name.sensorname

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

# add one entry at a time
datastore.append(entry)

Finally at the end of all the looping, we call the magic function that turns the dictionary into JSON, wrap it in the proper Google Visualization package, then spit it out!

# OK all the data is ready to go, print it out in JSON format!
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"))

If you were to visit http://wattcher.appspot.com/[email protected]&bhours=1 it would output something like this:

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

Anyways, you can kinda see the data, also note its actually a function call, this stuff is really kinky!

Now go to the Google Visualizations Playground and enter in that URL into the sandbox

And you can see the visualization itself pop out! (this is just a screen shot so go do it yerself if you want to mess around)

OK go mess around, adding and changing bhours and ehours

Wrapping up the visualization

OK we're nearly done. Now we just need to basically grab the code from the sandbox and make it a subpage in our app engine...like so:

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

# make the user log in if no user name is supplied
if self.request.get('user'):
account = users.User(self.request.get('user'))
else:
if not users.get_current_user():
self.redirect(users.create_login_url(self.request.uri))
account = users.get_current_user()

historytimebegin = 24 # assume 24 hours
if self.request.get('bhours'):
historytimebegin = int(self.request.get('bhours'))

historytimeend = 0 # assume 0 hours ago
if self.request.get('ehours'):
historytimeend = int(self.request.get('ehours'))

# get the first part, headers, out
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">
<Head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Google Visualization API Sample</title>
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<Script type = "text / javascript">
google.load("visualization", "1", {packages: ["annotatedtimeline"]});

function drawVisualizations() {
)

# create our visualization
self.response.out.write( new google.visualization.Query("http://wattcher.appspot.com/visquery.json?user= +
account.email()+ &bhours= +str(historytimebegin)+ ").send(
function(response) {
new google.visualization.AnnotatedTimeLine(
document.getElementById("visualization")).
draw(response.getDataTable(), {"displayAnnotations": true});
});
)

self.response.out.write( }

google.setOnLoadCallback(drawVisualizations);
</ Script>
</ Head>
<body style="font-family: Arial;border: 0 none;">
<div id="visualization" style="width: 800px; height: 250px;"></div>
</ Body>
</html> )

The first part is pretty straight forward, get the user name or login. Then we will assume the user wants 1 last day of data, so set bhours and ehours . Then we literally just print out the code we copied from Google's Visualization sandbox, done!

Viz Viz Viz

The only thing I couldn't figure out is how to get 3 visualizations going on at once (last hour, day and week) with the above code. It just kinda broke. So for the triple view I had to use iframes :(

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

# make the user log in if no user name is supplied
if self.request.get('user'):
account = users.User(self.request.get('user'))
else:
if not users.get_current_user():
self.redirect(users.create_login_url(self.request.uri))
account = users.get_current_user()

self.response.out.write(
<h2>Power usage over the last hour:</h2>
<iframe src ="[email protected]&bhours=1" frameborder="0" width="100%" height="300px">
<p>Your browser does not support iframes.</p>
</iframe>

<h2>Power usage over the last day:</h2>
<iframe src ="[email protected]&bhours=24" frameborder="0" width="100%" height="300px">
<p>Your browser does not support iframes.</p>
</iframe>

<h2>Power usage over the last week:</h2>
<iframe src ="[email protected]&bhours=168" frameborder="0" width="300%" height="500px">
<p>Your browser does not support iframes.</p>
</iframe>

)

Anyhow, it works just fine.

Timecodes!

The final thing that wont be reviewed here is how I got the date and times to be EST instead of UTC. As far as I can tell, its kind of broken and mysterious. Check the code if you want to figure it out.

Step 18: Resources

Other power monitoring projects!

Get some good ideas here!

Power monitoring products
Wanna just buy it?

Websites & Software

Step 19: Download

Software

X-CTU profiles

Design files

All this stuff (other than the XBee library and the AppEngineAuth library, which are not written by me) is for you in the Public Domain! These are for debugging and design purpose and show how the project is put together. If you just want to "run the code" see the "software" above

For the latest code, please check the google code repository where you'll find any new code . And hey, are you good at this sort of code? I could really use some help. It works OK but it could look and run much better so please commit patches and hang out on the forum!

Advertisement

Related Articles

  • Hoe maak je een XY-plotter met Makeblock maken
    Hoe maak je een XY-plotter met Makeblock maken

    CHECK NU Invoering Vorige maand heb ik een XY-plotter door Makeblock en gebruik deze om bouwde een tekening Robot. Deze tekening van de robot is gebouwd met twee Linear Motion Shaft D8x480mm, twee Long Beam0824, de distributieriem, twee stappenmotore

  • Hoe maak je een pompoen charme (met gezicht) maken
    Hoe maak je een pompoen charme (met gezicht) maken

    Fall is hier, dus hier is een schattige kleine pompoen te maken te vallen vieren. Voeg een gezicht op om het een jack-o-lantern te maken! Dit is super eenvoudig en het niet al te veel tijd in beslag nemen. Approxiament tijd: 2 minuten. Stap 1: Plaats

  • Hoe maak je een horloge gezicht met horlogemaker maken
    Hoe maak je een horloge gezicht met horlogemaker maken

    Dit hoe ziet u de basisprincipes van hoe je een wijzerplaat met behulp van deze app te maken. Vereisten Basic codering kennis Basic plaatsing kennis Basiskennis van Photoshop (vooral hoe lagen werken) Android-telefoon (of tablet, maar android niemand

  • Hoe maak je een WordPress website met Hostinger maken
    Hoe maak je een WordPress website met Hostinger maken

    Heb je wilde een website te hosten zonder gebruik te maken van de * .wordpress.com domein? Nou, ik zal je laten zien hoe dat te doen met Hostinger Verenigd Koninkrijk, die een aantal leuke subdomeinen heeft. Stap 1: Download WordPress! Ga naar wordpr

  • Hoe maak je een pennenhouder (DIY) met magneten maken
    Hoe maak je een pennenhouder (DIY) met magneten maken

    In dit Instructables, zal ik bespreken hoe ik dit pennenhouder die werd gemaakt met behulp van een beperkte gereedschappen. Neem een ​​kijkje op de YouTube-video voor een volledige build video over hoe ik maakte dit project! Stap 1: het selecteren va

  • Hoe maak je een eenvoudige auto met fles maken
    Hoe maak je een eenvoudige auto met fles maken

    Hallo! In dit instructable zal ik u laten zien hoe u een eenvoudige auto te maken met fles. Stap 1: Things Needed 1: Een fles 2: tape 3: schaar 4: Aan / uit-knop 5: Batterij. 6: Back wielen (met motor) 7: voorwielen 8: LED (optioneel)

  • Hoe maak je een tweezijdige cajon met snare maken
    Hoe maak je een tweezijdige cajon met snare maken

    Hallo! Dit is een tutorial over hoe u uw eigen dubbelzijdig kleine cajon te bouwen (niet groot genoeg om op te zitten, maar groot genoeg om een grote krachtige bas hebben). Het doel van het hebben van twee spelende kanten is zo dat men de snare klink

  • Hoe maak je een Spooky Soundscape met Audacity maken

    Hallo, Ik wil graag een grote Halloween project voor uw lezers suggereren - Spooky Soundscape. Dit project is een veel plezier voor jong en oud. Een Spooky Soundscape kan gespeeld worden in de buurt van uw voordeur naar de krijtlijnen voor trick-or-t

  • Hoe maak je een bloeiende bloem met koffiepads maken
    Hoe maak je een bloeiende bloem met koffiepads maken

    Deze tutorial legt uit hoe je een bloeiende bloem sieraden set met coffee pads kunnen maken. Mensen zullen dit niet herkennen als een upcycled product. We hopen dat dit Instructable zal u inspireren om opnieuw gebruik maken van uw eigen coffee pads o

  • Hoe maak je een origami hart met vleugels maken
    Hoe maak je een origami hart met vleugels maken

    U kunt elk soort gebruik van papier om deze origami hart vouwen. Ik gebruik een papier met dezelfde rode kleur aan beide kanten. Zorg ervoor dat het papier dat u gebruikt is een vierkant (alle zijden zijn gelijk en alle hoeken gelijk zijn aan 90 grad

  • Hoe maak je een lezing ring met Sugru maken
    Hoe maak je een lezing ring met Sugru maken

    Hoi. Dit instructable is gemaakt in Madrid Makespace tijdens Sugru's nachts workshop. Dit apparaat zal u helpen om een ​​boek vast te houden terwijl het lezen met een hand terwijl terug te leggen. Dit kan al gebeuren, maar het is vermoeiend om de pos

  • Hoe maak je een achtertuin iglo met poedersneeuw maken
    Hoe maak je een achtertuin iglo met poedersneeuw maken

    Als je veel tijd op uw handen, of als je gewoon wilt een iglo te zitten, dan is dit een instructable voor jou. Dit werkt met een relatief kleine hoeveelheid van poedersneeuw, en de iglo is sterk genoeg om een ​​115 pond jongen staande op het te onder

  • Hoe maak je een Caesar salade met garnalen maken
    Hoe maak je een Caesar salade met garnalen maken

    Ingrediënten (2-3 porties) 2 teentjes knoflook 1 citroen 2 Flat filet Ansjovis Grey Poupon Mosterd Lea & Perrins Worcestershire Sauce 1 Egg Olijfolie Geraspte kaas Locatelli 2 hoofden van Romaine sla Specerijen (zwarte peper, zout) garnaal 1 pond van

  • Hoe maak je een Kerstster Pot met Dollar Store inpakpapier Wrap
    Hoe maak je een Kerstster Pot met Dollar Store inpakpapier Wrap

    Na het maken van uw kerststerren of bloemen, het verfraaien van de pot is essentieel voor het maken van het geheel compleet. Stap 1: Hoe maak je een Pot wrap met decoratieve inpakpapier Wat je nodig hebt: Een Pot (u kunt beslissen of het een plastic

  • Hoe maak je een Rubber Band Powered Crossbow maken

    Hoe maak je een Rubber Band Powered Crossbow maken (Bekijk de video) Deze mini kruisboog werd gemaakt van de mini boog in mijn laatste video. http: //www.instructables.com/id/How-to-make-a-Rubb ... De originele boog wordt gemakkelijk aangepast om dez

  • Hoe maak je een Wifi Hack Met behulp van Kali Linux 2.0
    Hoe maak je een Wifi Hack Met behulp van Kali Linux 2.0

    Hoe maak je een wifi hacken met behulp van Kali Linux 2.0. Deze tutorial Ik zal laten zien hoe je wifi wachtwoorden met behulp van een woordenlijst scheur in Kali Linux 2.0. Stap 1: Controleer How To It Hack

  • Hoe maak je een 30 sec Peanut Butter maken op brood.
    Hoe maak je een 30 sec Peanut Butter maken op brood.

    Hoe maak je een 30 sec Peanut Butter maken op brood. ingrediënten: Boterham [Elk type] Peanut Butter [Elk type] uitrusting: Knife [mes van de lijst] snijplank Stap 1: 1. Spreid het brood met pindakaas met behulp van een mes.

  • Hoe maak je een Origami Tulip bloem te maken - Video Tutorial

    Hoe maak je een Origami Tulip bloem te maken - Video Tutorial

  • Hoe maak je een eenvoudige quilling bloem te maken - Tutorial 1 (Fiori)

    DIY Hoe maak je een eenvoudige quilling bloem te maken - Tutorial 1 - Voor beginners Flori - Quilling pentru incepatori Wij nodigen u uit om je te abonneren op dit kanaal om toekomstige video's te bekijken! http://xly.us/XI9s4 Vergeet niet te willen,