#!/usr/bin/env python
import serial
from xbee import xbee
# for graphing stuff
import wx
import numpy as np
import matplotlib
matplotlib.use('WXAgg') # do this before importing pylab
from pylab import *
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
MAINSVPP = 170 * 2 # +-170V is what 120Vrms ends up being (= 120*2sqrt(2))
VREF = 492 # approx ((2.4v * (10Ko/14.7Ko)) / 3
CURRENTNORM = 15.5 # conversion to amperes from ADC
# open up the FTDI serial port to get data transmitted to xbee
ser = serial.Serial(SERIALPORT, BAUDRATE)
ser.open()
# Create an animated graph
fig = plt.figure()
# with three subplots: line voltage/current, watts and watthr
mainswatch = fig.add_subplot(111)
# the mains voltage and current level subplot
mains_t = np.arange(0, 18, 1)
voltagewatchline, = mainswatch.plot(mains_t, [0] * 18, color='blue')
mainswatch.set_ylabel('Volts')
mainswatch.set_xlabel('Sample #')
mainswatch.set_ylim(-200, 200)
# make a second axies for amp data
mainsampwatcher = mainswatch.twinx()
ampwatchline, = mainsampwatcher.plot(mains_t, [0] * 18, color='green')
mainsampwatcher.set_ylabel('Amps')
mainsampwatcher.set_ylim(-15, 15)
# and a legend for both of them
legend((voltagewatchline, ampwatchline), ('volts', 'amps'))
def update_graph(idleevent):
# grab one packet from the xbee, or timeout
packet = xbee.find_packet(ser)
if packet:
xb = xbee(packet)
# 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
# Redraw our pretty picture
fig.canvas.draw_idle()
# Update with latest data
voltagewatchline.set_ydata(voltagedata)
ampwatchline.set_ydata(ampdata)
# Update our graphing range so that we always see all the data
maxamp = max(ampdata)
minamp = min(ampdata)
maxamp = max(maxamp, -minamp)
mainsampwatcher.set_ylim(maxamp * -1.2, maxamp * 1.2)
timer = wx.Timer(wx.GetApp(), -1)
timer.Start(500) # run an in every 'n' milli-seconds
wx.GetApp().Bind(wx.EVT_TIMER, update_graph)
plt.show()