Skip to content

Instantly share code, notes, and snippets.

@fake-name
Created January 10, 2014 11:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fake-name/8350183 to your computer and use it in GitHub Desktop.
Save fake-name/8350183 to your computer and use it in GitHub Desktop.
Minimal script to shove data into a emoncms instance.
#!/usr/bin/python
"""
All Emoncms code is released under the GNU Affero General Public License.
See COPYRIGHT.txt and LICENSE.txt.
---------------------------------------------------------------------
Emoncms - open source energy visualisation
Part of the OpenEnergyMonitor project:
http://openenergymonitor.org
"""
'''
Modifications by Fake-Name/Connor Wolf
'''
import urllib2, httplib
import logging, logging.handlers
import time
import logging
import sys
import serial
import subprocess
import re
import datetime
import os
import signal
"""class ServerDataBuffer
Stores server parameters and buffers the data between two HTTP requests
"""
class ServerDataBuffer():
def __init__(self, protocol, domain, path, apikey, period, logger=None):
"""Create a server data buffer initialized with server settings.
protocol (string): "https://" or "http://"
domain (string): domain name (eg: 'domain.tld')
path (string): emoncms path with leading slash (eg: '/emoncms')
apikey (string): API key with write access
period (int): sending interval in seconds
logger (string): the logger's name (default None)
"""
self._protocol = protocol
self._domain = domain
self._path = path
self._apikey = apikey
self._period = period
self._data_buffer = []
self._last_send = time.time()
self._logger = logging.getLogger(logger+".EMon")
self._logger.debug("Initing EMonCMS interface")
def add_data(self, data):
# Append timestamped dataset to buffer.
# data (list): node and values (eg: '[node,val1,val2,...]')
self._logger.debug("Server " + self._domain + self._path + " -> add data: " + str(data))
self._data_buffer.append(data)
def send_data(self):
"""Send data to server."""
# Prepare data string with the values in data buffer
data_string = '['
for data in self._data_buffer:
data_string += '['
data_string += "0"
for sample in data:
data_string += ','
data_string += str(sample)
data_string += '],'
data_string = data_string[0:-1]+']' # Remove trailing comma and close bracket
self._data_buffer = []
self._logger.debug("Data string: " + data_string)
# Prepare URL string of the form
# 'http://domain.tld/emoncms/input/bulk.json?apikey=12345&data=[[-10,10,1806],[-5,10,1806],[0,10,1806]]'
url_string = self._protocol+self._domain+self._path+"/input/bulk.json?apikey="+self._apikey+"&data="+data_string
self._logger.debug("URL string: " + url_string)
# Send data to server
self._logger.info("Sending to " + self._domain + self._path)
try:
result = urllib2.urlopen(url_string)
except urllib2.HTTPError as e:
self._logger.warning("Couldn't send to server, HTTPError: " + str(e.code))
except urllib2.URLError as e:
self._logger.warning("Couldn't send to server, URLError: " + str(e.reason))
except httplib.HTTPException:
self._logger.warning("Couldn't send to server, HTTPException")
except Exception:
import traceback
self._logger.warning("Couldn't send to server, Exception: " + traceback.format_exc())
else:
if (result.readline() == 'ok'):
self._logger.info("Send ok")
else:
self._logger.warning("Send failure")
# Update _last_send
#self._last_send = time.time()
def check_time(self):
"""Check if it is time to send data to server.
Return True if sending interval has passed since last time
"""
now = time.time()
delta = now - self._last_send
if (delta > self._period):
print "Elapsed delta between updates =", delta, "seconds. overshoot =", delta-self._period, "seconds."
self._last_send = self._last_send + self._period
return True
def has_data(self):
"""Check if buffer has data
Return True if data buffer is not empty.
"""
return (self._data_buffer != [])
def initLogging():
mainLogger = logging.getLogger("Main") # Main logger
mainLogger.setLevel(logging.DEBUG)
ch = logging.StreamHandler(sys.stdout)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)
mainLogger.addHandler(ch)
def timeout_command(cmdList, timeout):
#call shell-command and either return its output or kill it
#if it doesn't normally exit within timeout seconds and return None
start = datetime.datetime.now()
process = subprocess.Popen(cmdList, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
while process.poll() is None:
time.sleep(0.1)
now = datetime.datetime.now()
if (now - start).seconds > timeout:
print "subprocess timed out. Force-killing it"
os.kill(process.pid, signal.SIGKILL)
os.waitpid(-1, os.WNOHANG)
return None
return process.stdout.read()
def getModlet(modletMac, outletNo="0"):
print "calling modlet interface"
powerRe = re.compile("INFO -- : (\d+)w")
remainingRe = re.compile("(\d+) returned, (\d+) remaining")
recPower = None
recRemain = None
cont = True
while cont:
ret = timeout_command(["hacklet", "read", "-n", modletMac, "-s", outletNo], 7)
if ret != None:
for line in ret.split("\n"):
if line:
print "Modlet ret = ", line
found = powerRe.findall(line)
if found:
recPower = int(found[0])
remaining = remainingRe.findall(line)
if remaining:
recRemain = remaining
print "Remaining =", recRemain, "-",
if recRemain[0][1] == "0": # the second digit of the "remaining samples" return is 0, so the sample in recPower is the latest one
print "Have latest power draw numbers. Stopping"
cont = False # Stop looping
else:
print "Looping more because there is data in the receive buffer"
print "recPower", recPower, "recRemain", recRemain
return recPower
class ThermBaroLogger():
def __init__(self, portStr):
self.port = serial.Serial(portStr, 115200, timeout=0)
self.tmpStr = ""
self.tmpLog = []
self.presLog = []
def procRx(self):
self.tmpStr += self.port.read(50)
if "\r" in self.tmpStr:
out, self.tmpStr = self.tmpStr.split("\r")
out = out.split()
temp = None
pres = None
for item in out:
try:
key, val = item.split(":")
#print key, float(val)
if key == "Temperature":
self.tmpLog.append(float(val))
temp = float(val)
if key == "Pressure":
self.presLog.append(float(val))
pres = float(val)
except ValueError:
print "Started part-way through a packet"
print "Pres:", temp, "Pres:", pres
def getValues(self):
if self.tmpLog == None and self.tmpLog == None:
print "TempBaro logging not working? Wat?"
return None, None
avgTmp = sum(self.tmpLog)/float(len(self.tmpLog))
avgPrs = sum(self.presLog)/float(len(self.presLog))
print "Processing", len(self.tmpLog), "temperature samples,", len(self.presLog), "pressure samples."
self.tmpLog = []
self.presLog = []
return avgTmp, avgPrs
if __name__ == "__main__":
print "Starting"
initLogging()
monBuf = ServerDataBuffer(protocol = 'https://',
domain = '10.1.1.39',
path = '/emoncms',
apikey = "[NOPE]",
period = 15,
logger="Main")
thermBaro = ThermBaroLogger('/dev/ttyUSB0')
# hacklet:
# Found device [NOT FOR YOU] on network 0xe771
# hacklet read -n [NOT FOR YOU] -s 1
modletMac = "[NOT FOR YOU]"
# Purge out all back-logged power numbers from modlets ahead of time
# (Also makes testing modlet stuff easier, since you don't have to wait 15 seconds)
print getModlet(modletMac, "0"), getModlet(modletMac, "1")
while 1:
thermBaro.procRx()
if monBuf.check_time():
print "Ready to send"
avgTmp, avgPrs = thermBaro.getValues()
if avgTmp != None and avgPrs != None:
monBuf.add_data(["1", avgTmp, avgPrs])
modletVal1, modletVal2 = getModlet(modletMac, "0"), getModlet(modletMac, "1")
if modletVal1 != None and modletVal2 != None:
print "Sending modlet packet"
monBuf.add_data(["2", modletVal1, modletVal2])
monBuf.send_data()
time.sleep(0.05)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment