#!/usr/bin/python import requests import sys import json from requests.exceptions import ChunkedEncodingError src_url = "https://api.pinocc.io/v1/" src_token = "enter your pinoccio token here" src_params = {"token" : src_token} dst_url = 'https://data.sparkfun.com/input/' dst_token = 'enter your sparkfun public key here' dst_key = 'enter your sparkfun private key here' def parse_event(jdata): if 'data' in jdata and 'type' in jdata['data']: _type = jdata['data']['type'] event = None if _type.startswith('custom'): event = CustomEvent(jdata) elif _type.startswith('connection'): event = ConnectionEvent(jdata) else: event = Event(jdata) return event class Event(object): def __init__(self, jdata): self.jdata = jdata self.type = jdata["data"]['type'] self.params = {} def parse_id(self): """ Extract scout_id and troop_id to default dict """ self.params['scout_id'] = self.jdata['data']['scout'] self.params['troop_id'] = self.jdata['data']['troop'] def to_url_params(self): pass class ConnectionEvent(Event): def __init__(self, jdata): super(ConnectionEvent, self).__init__(jdata) self.offline = jdata["data"]['value']['status'] == 'offline' class CustomEvent(Event): def __init__(self, jdata): super(CustomEvent, self).__init__(jdata) self.params = { 'private_key': dst_key, 'duration': '0', 'average_flow_rate': '0', 'gallons': '0' } def to_url_params(self): if self.type == 'custom.fixture-event': return self.parse_fixture_event() elif self.type == 'custom.gallons_at_main': return self.parse_gallons_at_main() def parse_fixture_event(self): """ Extract duration, average_flow_rate from json object and return dictionary object """ if 'value' in self.jdata['data'] and 'custom' in self.jdata['data']['value']: self.parse_id() custom_data = self.jdata['data']['value']['custom'] custom_dict = {} for data in custom_data: if 'duration' in data and 'avg_flow_rate' in data: custom_dict = dict(map(lambda x: x.split('-'), data.split('|'))) custom_dict['average_flow_rate'] = custom_dict.pop('avg_flow_rate') break else: print 'Failed to find duration or avg_flow_rate:', self.jdata if custom_dict: self.params.update(custom_dict) return self.params def parse_gallons_at_main(self): """ Extract gallons from json object and return dictionary object """ if 'value' in self.jdata['data'] and 'custom' in self.jdata['data']['value']: self.parse_id() custom_data = self.jdata['data']['value']['custom'] custom_dict = {} if len(custom_data) == 1: custom_dict['gallons'] = custom_data[0] if custom_dict: self.params.update(custom_dict) return self.params def get(_type, **kwargs): if "data" in kwargs: kwargs["data"] = dict(kwargs["data"].items() + src_params.items()) else: kwargs["data"] = src_params return requests.get(src_url + _type, **kwargs) def start_stream(): r = get("sync",stream=True) # Chunk size required to avoid buffering output too long! for line in r.iter_lines(chunk_size=1): if line: try: jdata = json.loads(line) event = parse_event(jdata) if isinstance(event, CustomEvent): url_params = event.to_url_params() if url_params: print 'Event:', event.type, url_params requests.post(dst_url + dst_token, params=url_params) elif isinstance(event, ConnectionEvent) and event.offline: print 'Error: Server is offline' except ValueError: # No JSON object could be decoded # Simply retry pass if __name__ == '__main__': while True: try: start_stream() except ChunkedEncodingError, e: # Raised when server stops sending data after alerting status as offline pass