print '-- %s: %s' % (e.__class__.__name__, e) # Reset our 5 minute timer sensorhistory.reset5mintimer() # We're going to twitter at midnight, 8am and 4pm # Determine the hour of the day (ie 6:42 -> '6') currhour = datetime.datetime.now().hour # twitter every 8 hours if (((time.time() - twittertimer) >= 3660.0) and (currhour % 8 == 0)): print "twittertime!" twittertimer = time.time(); if not LOGFILENAME: message = appengineauth.gettweetreport() else: # sum up all the sensors' data wattsused = 0 whused = 0 for history in sensorhistories.sensorhistories: wattsused += history.avgwattover5min() whused += history.dayswatthr message = "Currently using "+str(int(wattsused))+" Watts, "+str(int(whused))+" Wh today so far #tweetawatt" # write something ourselves if message: print message TwitterIt(twitterusername, twitterpassword, message) if GRAPHIT:
def update_graph(idleevent): global avgwattdataidx, sensorhistories, twittertimer, DEBUG, currday # DAW - 5/18/11 - wrap the whole xbee packet inspection code in an exception handler try: # grab one packet from the xbee, or timeout packet = xbee.find_packet(ser) if not packet: return # we timedout xb = xbee(packet) # parse the packet #print xb.address_16 if DEBUG: # for debugging sometimes we only want one print xb # DAW - 5/18/11 - prevent exception that was caused by invalid xbee packet address if xb.address_16 < 0 or xb.address_16 > len(vrefcalibration): LogMsg("ERROR - invalid packet address: " + xb.address_16) return # 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] if DEBUG: print "ampdata: "+str(ampdata) print "voltdata: "+str(voltagedata) # 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 if vrefcalibration[xb.address_16]: ampdata[i] -= vrefcalibration[xb.address_16] else: ampdata[i] -= vrefcalibration[0] # 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 # calculate instant. watts, by multiplying V*I for each sample point wattdata = [0] * len(voltagedata) for i in range(len(wattdata)): wattdata[i] = voltagedata[i] * ampdata[i] # sum up the current drawn over one 1/60hz cycle avgamp = 0 # DAW - 2/26/11 - check for less than 17 samples - would sometimes cause index out of range exception if (len(ampdata) < 17): return # 16.6 samples per second, one cycle = ~17 samples # close enough for govt work :( for i in range(17): avgamp += abs(ampdata[i]) avgamp /= 17.0 # DAW - average of all 18 amp readings avgamp2 = 0 for i in range(len(ampdata)): avgamp2 += abs(ampdata[i]) avgamp2 /= len(ampdata) # DAW - average of all 18 volt readings avgvolt = 0 for i in range(len(voltagedata)): avgvolt += abs(voltagedata[i]) avgvolt /= len(voltagedata) # sum up power drawn over one 1/60hz cycle avgwatt = 0 # DAW - 2/26/11 - check for less than 17 samples - would sometimes cause index out of range exception if len(wattdata) < 17: return # 16.6 samples per second, one cycle = ~17 samples for i in range(17): avgwatt += abs(wattdata[i]) avgwatt /= 17.0 # DAW - average of all 18 watt readings avgwatt2 = 0 for i in range(len(wattdata)): avgwatt2 += abs(wattdata[i]) avgwatt2 /= len(wattdata) except: LogMsg("Error in packet handling, ignoring") return # Print out our most recent measurements print str(xb.address_16)+"\tCurrent draw, in amperes: "+str(avgamp) print "\tWatt draw, in VA: "+str(avgwatt) # DAW print out extra data print "\t RSSI: " + str(xb.rssi) + " Volt: " + str(avgvolt) + " Amps: " + str(avgamp2) + " Watts: " + str(avgwatt2) if (avgamp > 13): return # hmm, bad data if GRAPHIT: # Add the current watt usage to our graph history avgwattdata[avgwattdataidx] = avgwatt avgwattdataidx += 1 if (avgwattdataidx >= len(avgwattdata)): # If we're running out of space, shift the first 10% out tenpercent = int(len(avgwattdata)*0.1) for i in range(len(avgwattdata) - tenpercent): avgwattdata[i] = avgwattdata[i+tenpercent] for i in range(len(avgwattdata) - tenpercent, len(avgwattdata)): avgwattdata[i] = 0 avgwattdataidx = len(avgwattdata) - tenpercent # retreive the history for this sensor sensorhistory = sensorhistories.find(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) if DEBUG: print "sensorhistory.avgwattover5min is " + str(sensorhistory.avgwattover5min()) print time.strftime("%Y %m %d, %H:%M")+", "+str(sensorhistory.sensornum)+", "+str(sensorhistory.avgwattover5min())+"\n" # 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")+", "+str(sensorhistory.sensornum)+", "+str(sensorhistory.avgwattover5min())+"\n" # Lets log it! Seek to the end of our log file if logfile: logfile.seek(0, 2) # 2 == SEEK_END. ie, go to the end of the file logfile.write(time.strftime("%Y %m %d, %H:%M")+", "+ str(sensorhistory.sensornum)+", "+ str(sensorhistory.avgwattover5min())+"\n") logfile.flush() # Or, send it to the app engine if not LOGFILENAME: appengineauth.sendreport(xb.address_16, avgwattsused) # DAW - 1/18/11 - log avg watts used to nimbits # avgwattstosend = "%.2f" % avgwattsused if NIMBITS_ID: try: urllib.urlopen("http://gigamega-beta.appspot.com/service/currentvalue?value=" + str(avgwattsused) + "&point=" + NIMBITS_ID + "&[email protected]&secret=e90d9c41-6529-4cf8-b248-92335c577cc7") except IOError: print 'Error sending to nimbits' # DAW - 2/7/11 - log avg watts used to Pachube if PACHUBE_ID: try: pac.update([eeml.Data(int(PACHUBE_ID), avgwattsused, unit=eeml.Watt())]) # unit=eeml.Unit('Volt', type='basicSI', symbol='V'))]) pac.put() except: print 'Error sending to Pachube' # DAW - 8/7/10 - moved here from below - otherwise, reset5mintimer can cause watts to be 0 when tweet occurs # We're going to twitter at midnight, 8am and 4pm # Determine the hour of the day (ie 6:42 -> '6') currhour = datetime.datetime.now().hour # twitter every 8 hours # DAW - if debugging, twitter (actually just log to file) every minute #if ((((time.time() - twittertimer) >= 3660.0) and (currhour % 8 == 0)) or (DEBUG and ((time.time() - twittertimer) >= 60.0))): # DAW - twitter every 4 hours if (((time.time() - twittertimer) >= 3660.0) and (currhour % 4 == 0)): print "twittertime!" twittertimer = time.time(); if not LOGFILENAME: message = appengineauth.gettweetreport() else: # sum up all the sensors' data wattsused = 0 whused = 0 if DEBUG: print "num sensor histories", len(sensorhistories.sensorhistories) newday = False thisday = datetime.datetime.now().day if currday != thisday: newday = True if DEBUG: message = "New day, clearing dayswatthr " + str(currday) + " to " + str(thisday) LogMsg(message) currday = thisday for history in sensorhistories.sensorhistories: if DEBUG: print "in twitter loop, found history", history.sensornum, history.cumulative5mwatthr wattsused += history.avgwattover5min() whused += history.dayswatthr # DAW - 8/7/10 - clear day's count when day changes if newday: history.dayswatthr = 0 message = "Currently using "+str(int(wattsused))+" Watts, "+str(int(whused))+" Wh today so far #tweetawatt" # DAW - 8/7/10 - if it's midnight, clear the day's count # write something ourselves if message: print message # DAW - if debugging, write to CSV file for debug purposes rather than twittering if DEBUG: LogMsg(message) else: #TwitterIt(twitterusername, twitterpassword, message) TwitterIt(message) # Reset our 5 minute timer sensorhistory.reset5mintimer() if GRAPHIT: # Redraw our pretty picture fig.canvas.draw_idle() # Update with latest data wattusageline.set_ydata(avgwattdata) 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) wattusage.set_ylim(0, max(avgwattdata) * 1.2)
except (IOError, socket.error), e: print '-- %s: %s' % (e.__class__.__name__, e) # Reset our 5 minute timer sensorhistory.reset5mintimer() # We're going to twitter at midnight, 8am and 4pm # Determine the hour of the day (ie 6:42 -> '6') currhour = datetime.datetime.now().hour # twitter every 8 hours if (((time.time() - twittertimer) >= 3660.0) and (currhour % 8 == 0)): print "twittertime!" twittertimer = time.time() if not LOGFILENAME: message = appengineauth.gettweetreport() else: # sum up all the sensors' data wattsused = 0 whused = 0 for history in sensorhistories.sensorhistories: wattsused += history.avgwattover5min() whused += history.dayswatthr message = "Currently using " + str( int(wattsused)) + " Watts, " + str( int(whused)) + " Wh today so far #tweetawatt" # write something ourselves if message: print message TwitterIt(twitterusername, twitterpassword, message)
def update_graph(idleevent): global avgwattdataidx, sensorhistories, twittertimer, DEBUG, incoffee, coffeecutoff shouldtweet = False # grab one packet from the xbee, or timeout packet = xbee.find_packet(ser) if not packet: return # we timedout xb = xbee(packet) # parse the packet #print xb.address_16 if DEBUG: # for debugging sometimes we only want one 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] if DEBUG: print "ampdata: "+str(ampdata) print "voltdata: "+str(voltagedata) # 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 if vrefcalibration[xb.address_16]: ampdata[i] -= vrefcalibration[xb.address_16] else: ampdata[i] -= vrefcalibration[0] # 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 # calculate instant. watts, by multiplying V*I for each sample point wattdata = [0] * len(voltagedata) for i in range(len(wattdata)): wattdata[i] = voltagedata[i] * ampdata[i] # sum up the current drawn over one 1/60hz cycle avgamp = 0 # 16.6 samples per second, one cycle = ~17 samples # close enough for govt work :( for i in range(17): avgamp += abs(ampdata[i]) avgamp /= 17.0 # sum up power drawn over one 1/60hz cycle avgwatt = 0 # 16.6 samples per second, one cycle = ~17 samples for i in range(17): avgwatt += abs(wattdata[i]) avgwatt /= 17.0 if (avgamp > 13): return # hmm, bad data # Print out our most recent measurements print str(xb.address_16)+"\tCurrent draw, in amperes: "+str(avgamp) print "\tWatt draw, in VA: "+str(avgwatt) if(avgwatt > coffeecutoff and incoffee == False): print "MAKING COFFEE!!!\n" incoffee = True shouldtweet = True elif(avgwatt < coffeecutoff and incoffee == True): print "NO MORE COFFEE :(\n" incoffee = False shouldtweet = True if GRAPHIT: # Add the current watt usage to our graph history avgwattdata[avgwattdataidx] = avgwatt avgwattdataidx += 1 if (avgwattdataidx >= len(avgwattdata)): # If we're running out of space, shift the first 10% out tenpercent = int(len(avgwattdata)*0.1) for i in range(len(avgwattdata) - tenpercent): avgwattdata[i] = avgwattdata[i+tenpercent] for i in range(len(avgwattdata) - tenpercent, len(avgwattdata)): avgwattdata[i] = 0 avgwattdataidx = len(avgwattdata) - tenpercent # retreive the history for this sensor sensorhistory = sensorhistories.find(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")+", "+str(sensorhistory.sensornum)+", "+str(sensorhistory.avgwattover5min())+"\n" # Lets log it! Seek to the end of our log file if logfile: logfile.seek(0, 2) # 2 == SEEK_END. ie, go to the end of the file logfile.write(time.strftime("%Y %m %d, %H:%M")+", "+ str(sensorhistory.sensornum)+", "+ str(sensorhistory.avgwattover5min())+"\n") logfile.flush() # Or, send it to the app engine if not LOGFILENAME: appengineauth.sendreport(xb.address_16, avgwattsused) # Reset our 5 minute timer sensorhistory.reset5mintimer() # We're going to twitter at midnight, 8am and 4pm # Determine the hour of the day (ie 6:42 -> '6') currhour = datetime.datetime.now().hour # twitter every 8 hours if (shouldtweet): #((time.time() - twittertimer) >= 3660.0) and (currhour % 8 == 0)): shouldtweet = False print "twittertime!" twittertimer = time.time(); if not LOGFILENAME: message = appengineauth.gettweetreport() else: # sum up all the sensors' data wattsused = 0 whused = 0 for history in sensorhistories.sensorhistories: wattsused += history.avgwattover5min() whused += history.dayswatthr message = "Currently using "+str(int(wattsused))+" Watts, "+str(int(whused))+" Wh today so far #tweetawatt" if(incoffee): message = "Made coffee!!! %s #happyday" % (datetime.datetime.now()) else: message = "No more coffee %s #sadface" % (datetime.datetime.now()) # write sometdatetime.datetime.now() hindatetime.datetime.now() g ourselves if message: print message TwitterIt(twitterusername, twitterpassword, message) if GRAPHIT: # Redraw our pretty picture fig.canvas.draw_idle() # Update with latest data wattusageline.set_ydata(avgwattdata) 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) wattusage.set_ylim(0, max(avgwattdata) * 1.2)
def update_graph(idleevent): global avgwattdataidx, sensorhistories, twittertimer, onlywatchfor # grab one packet from the xbee, or timeout packet = xbee.find_packet(ser) if packet: xb = xbee(packet) print xb.address_16 if (onlywatchfor != 0): if (xb.address_16 != onlywatchfor): return 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 ampdata # 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 if vrefs[xb.address_16]: ampdata[i] -= vrefs[xb.address_16] else: ampdata[i] -= vrefs[0] # 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 # calculate instant. watts, by multiplying V*I for each sample point wattdata = [0] * len(voltagedata) for i in range(len(wattdata)): wattdata[i] = voltagedata[i] * ampdata[i] # sum up the current drawn over one 1/60hz cycle avgamp = 0 # 16.6 samples per second, one cycle = ~17 samples # close enough for govt work :( for i in range(17): avgamp += abs(ampdata[i]) avgamp /= 17.0 # sum up power drawn over one 1/60hz cycle avgwatt = 0 # 16.6 samples per second, one cycle = ~17 samples for i in range(17): avgwatt += abs(wattdata[i]) avgwatt /= 17.0 # Print out our most recent measurements print str(xb.address_16)+"\tCurrent draw, in amperes: "+str(avgamp) print "\tWatt draw, in VA: "+str(avgwatt) # Add the current watt usage to our graph history avgwattdata[avgwattdataidx] = avgwatt avgwattdataidx += 1 if (avgwattdataidx >= len(avgwattdata)): # If we're running out of space, shift the first 10% out tenpercent = int(len(avgwattdata)*0.1) for i in range(len(avgwattdata) - tenpercent): avgwattdata[i] = avgwattdata[i+tenpercent] for i in range(len(avgwattdata) - tenpercent, len(avgwattdata)): avgwattdata[i] = 0 avgwattdataidx = len(avgwattdata) - tenpercent # 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" # Also, send it to the app engine appengineauth.sendreport(xb.address_16, avgwattsused) # Reset our 5 minute timer sensorhistory.reset5mintimer() # We're going to twitter at midnight, 8am and 4pm # Determine the hour of the day (ie 6:42 -> '6') currhour = datetime.datetime.now().hour if (((time.time() - twittertimer) >= 3660.0) and (currhour % 8 == 0)): print "twittertime!" twittertimer = time.time(); TwitterIt(twitterusername, twitterpassword, appengineauth.gettweetreport()) # Redraw our pretty picture fig.canvas.draw_idle() # Update with latest data wattusageline.set_ydata(avgwattdata) 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) wattusage.set_ylim(0, max(avgwattdata) * 1.2)
def update_graph(idleevent): global avgwattdataidx, sensorhistories, twittertimer, onlywatchfor # grab one packet from the xbee, or timeout packet = xbee.find_packet(ser) if packet: xb = xbee(packet) print xb.address_16 if (onlywatchfor != 0): if (xb.address_16 != onlywatchfor): return 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 ampdata # 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 if vrefs[xb.address_16]: ampdata[i] -= vrefs[xb.address_16] else: ampdata[i] -= vrefs[0] # 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 # calculate instant. watts, by multiplying V*I for each sample point wattdata = [0] * len(voltagedata) for i in range(len(wattdata)): wattdata[i] = voltagedata[i] * ampdata[i] # sum up the current drawn over one 1/60hz cycle avgamp = 0 # 16.6 samples per second, one cycle = ~17 samples # close enough for govt work :( for i in range(17): avgamp += abs(ampdata[i]) avgamp /= 17.0 # sum up power drawn over one 1/60hz cycle avgwatt = 0 # 16.6 samples per second, one cycle = ~17 samples for i in range(17): avgwatt += abs(wattdata[i]) avgwatt /= 17.0 # Print out our most recent measurements print str(xb.address_16) + "\tCurrent draw, in amperes: " + str(avgamp) print "\tWatt draw, in VA: " + str(avgwatt) # Add the current watt usage to our graph history avgwattdata[avgwattdataidx] = avgwatt avgwattdataidx += 1 if (avgwattdataidx >= len(avgwattdata)): # If we're running out of space, shift the first 10% out tenpercent = int(len(avgwattdata) * 0.1) for i in range(len(avgwattdata) - tenpercent): avgwattdata[i] = avgwattdata[i + tenpercent] for i in range(len(avgwattdata) - tenpercent, len(avgwattdata)): avgwattdata[i] = 0 avgwattdataidx = len(avgwattdata) - tenpercent # 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" # Also, send it to the app engine appengineauth.sendreport(xb.address_16, avgwattsused) # Reset our 5 minute timer sensorhistory.reset5mintimer() # We're going to twitter at midnight, 8am and 4pm # Determine the hour of the day (ie 6:42 -> '6') currhour = datetime.datetime.now().hour if (((time.time() - twittertimer) >= 3660.0) and (currhour % 8 == 0)): print "twittertime!" twittertimer = time.time() TwitterIt(twitterusername, twitterpassword, appengineauth.gettweetreport()) # Redraw our pretty picture fig.canvas.draw_idle() # Update with latest data wattusageline.set_ydata(avgwattdata) 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) wattusage.set_ylim(0, max(avgwattdata) * 1.2)
def update_graph(idleevent): global avgwattdataidx, sensorhistories, twittertimer, DEBUG, currday # DAW - 5/18/11 - wrap the whole xbee packet inspection code in an exception handler try: # grab one packet from the xbee, or timeout packet = xbee.find_packet(ser) if not packet: return # we timedout xb = xbee(packet) # parse the packet #print xb.address_16 if DEBUG: # for debugging sometimes we only want one print xb # DAW - 5/18/11 - prevent exception that was caused by invalid xbee packet address if xb.address_16 < 0 or xb.address_16 > len(vrefcalibration): LogMsg("ERROR - invalid packet address: " + xb.address_16) return # 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] if DEBUG: print "ampdata: " + str(ampdata) print "voltdata: " + str(voltagedata) # 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 if vrefcalibration[xb.address_16]: ampdata[i] -= vrefcalibration[xb.address_16] else: ampdata[i] -= vrefcalibration[0] # 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 # calculate instant. watts, by multiplying V*I for each sample point wattdata = [0] * len(voltagedata) for i in range(len(wattdata)): wattdata[i] = voltagedata[i] * ampdata[i] # sum up the current drawn over one 1/60hz cycle avgamp = 0 # DAW - 2/26/11 - check for less than 17 samples - would sometimes cause index out of range exception if (len(ampdata) < 17): return # 16.6 samples per second, one cycle = ~17 samples # close enough for govt work :( for i in range(17): avgamp += abs(ampdata[i]) avgamp /= 17.0 # DAW - average of all 18 amp readings avgamp2 = 0 for i in range(len(ampdata)): avgamp2 += abs(ampdata[i]) avgamp2 /= len(ampdata) # DAW - average of all 18 volt readings avgvolt = 0 for i in range(len(voltagedata)): avgvolt += abs(voltagedata[i]) avgvolt /= len(voltagedata) # sum up power drawn over one 1/60hz cycle avgwatt = 0 # DAW - 2/26/11 - check for less than 17 samples - would sometimes cause index out of range exception if len(wattdata) < 17: return # 16.6 samples per second, one cycle = ~17 samples for i in range(17): avgwatt += abs(wattdata[i]) avgwatt /= 17.0 # DAW - average of all 18 watt readings avgwatt2 = 0 for i in range(len(wattdata)): avgwatt2 += abs(wattdata[i]) avgwatt2 /= len(wattdata) except: LogMsg("Error in packet handling, ignoring") return # Print out our most recent measurements print str(xb.address_16) + "\tCurrent draw, in amperes: " + str(avgamp) print "\tWatt draw, in VA: " + str(avgwatt) # DAW print out extra data print "\t RSSI: " + str(xb.rssi) + " Volt: " + str( avgvolt) + " Amps: " + str(avgamp2) + " Watts: " + str(avgwatt2) if (avgamp > 13): return # hmm, bad data if GRAPHIT: # Add the current watt usage to our graph history avgwattdata[avgwattdataidx] = avgwatt avgwattdataidx += 1 if (avgwattdataidx >= len(avgwattdata)): # If we're running out of space, shift the first 10% out tenpercent = int(len(avgwattdata) * 0.1) for i in range(len(avgwattdata) - tenpercent): avgwattdata[i] = avgwattdata[i + tenpercent] for i in range(len(avgwattdata) - tenpercent, len(avgwattdata)): avgwattdata[i] = 0 avgwattdataidx = len(avgwattdata) - tenpercent # retreive the history for this sensor sensorhistory = sensorhistories.find(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) if DEBUG: print "sensorhistory.avgwattover5min is " + str( sensorhistory.avgwattover5min()) print time.strftime("%Y %m %d, %H:%M") + ", " + str( sensorhistory.sensornum) + ", " + str( sensorhistory.avgwattover5min()) + "\n" # 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") + ", " + str( sensorhistory.sensornum) + ", " + str( sensorhistory.avgwattover5min()) + "\n" # Lets log it! Seek to the end of our log file if logfile: logfile.seek(0, 2) # 2 == SEEK_END. ie, go to the end of the file logfile.write( time.strftime("%Y %m %d, %H:%M") + ", " + str(sensorhistory.sensornum) + ", " + str(sensorhistory.avgwattover5min()) + "\n") logfile.flush() # Or, send it to the app engine if not LOGFILENAME: appengineauth.sendreport(xb.address_16, avgwattsused) # DAW - 1/18/11 - log avg watts used to nimbits # avgwattstosend = "%.2f" % avgwattsused if NIMBITS_ID: try: urllib.urlopen( "http://gigamega-beta.appspot.com/service/currentvalue?value=" + str(avgwattsused) + "&point=" + NIMBITS_ID + "&[email protected]&secret=e90d9c41-6529-4cf8-b248-92335c577cc7" ) except IOError: print 'Error sending to nimbits' # DAW - 2/7/11 - log avg watts used to Pachube if PACHUBE_ID: try: pac.update([ eeml.Data(int(PACHUBE_ID), avgwattsused, unit=eeml.Watt()) ]) # unit=eeml.Unit('Volt', type='basicSI', symbol='V'))]) pac.put() except: print 'Error sending to Pachube' # DAW - 8/7/10 - moved here from below - otherwise, reset5mintimer can cause watts to be 0 when tweet occurs # We're going to twitter at midnight, 8am and 4pm # Determine the hour of the day (ie 6:42 -> '6') currhour = datetime.datetime.now().hour # twitter every 8 hours # DAW - if debugging, twitter (actually just log to file) every minute #if ((((time.time() - twittertimer) >= 3660.0) and (currhour % 8 == 0)) or (DEBUG and ((time.time() - twittertimer) >= 60.0))): # DAW - twitter every 4 hours if (((time.time() - twittertimer) >= 3660.0) and (currhour % 4 == 0)): print "twittertime!" twittertimer = time.time() if not LOGFILENAME: message = appengineauth.gettweetreport() else: # sum up all the sensors' data wattsused = 0 whused = 0 if DEBUG: print "num sensor histories", len( sensorhistories.sensorhistories) newday = False thisday = datetime.datetime.now().day if currday != thisday: newday = True if DEBUG: message = "New day, clearing dayswatthr " + str( currday) + " to " + str(thisday) LogMsg(message) currday = thisday for history in sensorhistories.sensorhistories: if DEBUG: print "in twitter loop, found history", history.sensornum, history.cumulative5mwatthr wattsused += history.avgwattover5min() whused += history.dayswatthr # DAW - 8/7/10 - clear day's count when day changes if newday: history.dayswatthr = 0 message = "Currently using " + str( int(wattsused)) + " Watts, " + str( int(whused)) + " Wh today so far #tweetawatt" # DAW - 8/7/10 - if it's midnight, clear the day's count # write something ourselves if message: print message # DAW - if debugging, write to CSV file for debug purposes rather than twittering if DEBUG: LogMsg(message) else: #TwitterIt(twitterusername, twitterpassword, message) TwitterIt(message) # Reset our 5 minute timer sensorhistory.reset5mintimer() if GRAPHIT: # Redraw our pretty picture fig.canvas.draw_idle() # Update with latest data wattusageline.set_ydata(avgwattdata) 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) wattusage.set_ylim(0, max(avgwattdata) * 1.2)