{"id":175,"date":"2012-01-02T11:59:35","date_gmt":"2012-01-02T17:59:35","guid":{"rendered":"http:\/\/www.netfluvia.org\/layer8\/?p=175"},"modified":"2013-01-31T05:50:21","modified_gmt":"2013-01-31T11:50:21","slug":"trivial-python-interface-to-update-pachube-data-feeds","status":"publish","type":"post","link":"https:\/\/www.netfluvia.org\/layer8\/?p=175","title":{"rendered":"Trivial python interface to update Pachube data feeds"},"content":{"rendered":"<p><a href=\"https:\/\/pachube.com\/\" target=\"_blank\">Pachube<\/a> provides an API-exposed store of sensor data from pretty much anything, but with a focus on sensor data. \u00c2\u00a0It&#8217;s free to use and has what seems to be a pretty complete, reasonably designed, and easy to use <a href=\"http:\/\/api.pachube.com\/v2\/\" target=\"_blank\">API<\/a> with a nicely flexible authorization model.<\/p>\n<p>I&#8217;ve been working on some code to scrape data out of the <a href=\"http:\/\/www.netbotz.com\/products\/appliances.html\" target=\"_blank\">Netbotz<\/a> web UI (which does <em>not<\/em>\u00c2\u00a0have an easy to use API) and, as I got to working on the data storage backend for the scraper, remembered Pachube and decided to give it a try rather than reinventing what was effectively the same wheel.<\/p>\n<p>I have generally positive impressions of Pachube after a couple of days messing around with it. \u00c2\u00a0It was pretty easy to get going, and after stumbling into one quickly-fixed bug was up and sending data in from my prototype scraper pretty quickly.<\/p>\n<p>I&#8217;m using the following python class to simplify the interaction. \u00c2\u00a0It&#8217;s trivial, but I didn&#8217;t see anything similar already done, so am throwing it here for future google results:<\/p>\n<blockquote>\n<pre>\r\n\r\n#!\/usr\/bin\/python\r\n\r\n# This code is released into the public domain (though I'd be interested in seeing\r\n#  improvements or extensions, if you're willing to share back).\r\n\r\nimport mechanize\r\nimport json\r\nimport time\r\n\r\nclass PachubeFeedUpdate:\r\n\r\n  _url_base = \"http:\/\/api.pachube.com\/v2\/feeds\/\"\r\n  _feed_id = None\r\n  _version = None\r\n  ## the substance of our update - list of dictionaries with keys 'id' and 'current_value'\r\n  _data = None\r\n  ## the actual object we'll JSONify and send to the API endpoint\r\n  _payload = None\r\n  _opener = None\r\n\r\n  def __init__(self, feed_id, apikey):\r\n    self._version = \"1.0.0\"\r\n    self._feed_id = feed_id\r\n    self._opener = mechanize.build_opener()\r\n    self._opener.addheaders = [('X-PachubeApiKey',apikey)]\r\n    self._data = []\r\n    self._payload = {}\r\n\r\n  def addDatapoint(self,dp_id,dp_value):\r\n    self._data.append({'id':dp_id, 'current_value':dp_value})\r\n\r\n  def buildUpdate(self):\r\n    self._payload['version'] = self._version\r\n    self._payload['id'] = self._feed_id\r\n    self._payload['datastreams'] = self._data\r\n\r\n  def sendUpdate(self):\r\n    url = self._url_base + self._feed_id + \"?_method=put\"\r\n    try:\r\n      self._opener.open(url,json.dumps(self._payload))\r\n    except mechanize.HTTPError as e:\r\n      print \"An HTTP error occurred: %s \" % e<\/pre>\n<\/blockquote>\n<p>Usage is pretty straightforward. \u00c2\u00a0For example, assuming you have defined key (with a valid API key from Pachube) and feed (a few clicks in the browser once you&#8217;ve registered) it&#8217;s basically like:<\/p>\n<blockquote>\n<pre>\r\n\r\npfu = PachubeFeedUpdate(feed,key)\r\n# do some stuff; gather data, repeating as necessary for any number of datastreams\r\npfu.addDatapoint(&lt;datastream_id&gt;,&lt;data_value&gt;))\r\n# finish up and submit the data\r\npfu.buildUpdate()\r\npfu.sendUpdate()<\/pre>\n<\/blockquote>\n<p>The resulting datapoints basically end up looking like they were logged at the time the sendUpdate() call is made. \u00c2\u00a0In my situation, I want to send readings from a couple of dozen sensors each into their own Pachube datastream in one shot, so this works fine. \u00c2\u00a0If, instead, for some reason you need to accumulate updates over time without posting them, you&#8217;d need to take a different approach.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Pachube provides an API-exposed store of sensor data from pretty much anything, but with a focus on sensor data. \u00c2\u00a0It&#8217;s free to use and has what seems to be a pretty complete, reasonably designed, and easy to use API with a nicely flexible authorization model. I&#8217;ve been working on some code to scrape data out <a href='https:\/\/www.netfluvia.org\/layer8\/?p=175'>[&#8230;]<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[23,21,22],"class_list":["post-175","post","type-post","status-publish","format-standard","hentry","category-tech","tag-code","tag-pachube","tag-sensors","category-6-id","post-seq-1","post-parity-odd"],"_links":{"self":[{"href":"https:\/\/www.netfluvia.org\/layer8\/index.php?rest_route=\/wp\/v2\/posts\/175","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.netfluvia.org\/layer8\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.netfluvia.org\/layer8\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.netfluvia.org\/layer8\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.netfluvia.org\/layer8\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=175"}],"version-history":[{"count":8,"href":"https:\/\/www.netfluvia.org\/layer8\/index.php?rest_route=\/wp\/v2\/posts\/175\/revisions"}],"predecessor-version":[{"id":192,"href":"https:\/\/www.netfluvia.org\/layer8\/index.php?rest_route=\/wp\/v2\/posts\/175\/revisions\/192"}],"wp:attachment":[{"href":"https:\/\/www.netfluvia.org\/layer8\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=175"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.netfluvia.org\/layer8\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=175"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.netfluvia.org\/layer8\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=175"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}