'''Example script to update Pachube feeds with SNAP

This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
Contributor: Synapse Wireless Inc., Huntsville, Alabama, 35806, USA
'''

import logging
from snapconnect import snap
import os
import pachUpdater
import sys
import snapConversions


PACHUBE_KEY = '**** your key here ****'
UPDATE_PERIOD = 20  # seconds per Pachube update

def average(iterable):
    return sum(iterable) / len(iterable)

def last(iterable):
    return iterable[-1]

UPDATE_PROCESS = average  # function to process values comprising an update (takes iterable arg)

log = logging.getLogger('pachSnapE10')

snaplib_log = logging.getLogger('snaplib')
snaplib_log.setLevel(logging.INFO)

snap_log = logging.getLogger('snap')
snap_log.setLevel(logging.INFO)


def setGreenLed(value):
    if sys.platform.startswith('linux'):
        os.system("echo "+str(value)+" >> /sys/class/leds/greenled/brightness")

def setRedLed(value):
    if sys.platform.startswith('linux'):
        os.system("echo "+str(value)+" >> /sys/class/leds/redled/brightness")

    
# Periodically, we update all streams with new values
pach_streams = {}   # { feed_id : [(stream_id,value), ] , }

def update_stream(feed_id, stream_id, value, conversion=None):
    '''RPC call from SNAP device to update a pachube stream.
       Optional 'conversion' is name of func in snapConversions.py
    '''

    if feed_id not in pach_streams:
        pach_streams[feed_id] = []
        
    # Apply conversion if specified, and found in snapConversions module
    if type(conversion) == str:
        try:
            cooked_val = getattr(snapConversions, conversion)(stream_id, value)
        except:
            cooked_val = value
        
    cooked_val = float(cooked_val)
    log.debug("update_stream: id=%s, raw=%d, cooked=%f" % (stream_id, value, cooked_val))
    
    pach_streams[feed_id].append((stream_id, cooked_val))
    
    
def pach_poll():
    '''Iterate over feed updates received via RPC, and update Pachube with processed values.
       NOTE: Calls to this function MUST be rate-limited.  The free "Basic" plan only allowed just
             5 API requests per minute at the time of this writing.  See: https://pachube.com
    '''
    global pach_streams

    log.debug("pach_poll")
    
    for feed_id, update_list in pach_streams.iteritems():
        streams = {}   # { stream_id:values }
        for stream_id, value in update_list:
            if stream_id not in streams:
                streams[stream_id] = []
            streams[stream_id].append(value)

        # Process multiple stream updates into single scalar update per stream
        for stream_id, value_list in streams.iteritems():
            streams[stream_id] = UPDATE_PROCESS(value_list)
            
        pachUpdater.pach_update_feed(PACHUBE_KEY, feed_id, streams)
   
    # Clear stream updates for next poll interval
    pach_streams = {}
    
    return True  # Reschedule

def main():
    global server, snapCom

    print "Start"
    log.debug("Started Pachube")
    
    # Create SNAP instance and establish serial (bridge) link
    snapCom = snap.Snap(funcs={'update_stream': update_stream})
    snapCom.open_serial(snap.SERIAL_TYPE_RS232, '/dev/ttyS1')   # E10 bridge connection
    #snapCom.open_serial(snap.SERIAL_TYPE_RS232, 0)   # COM1 on a PC

    # Schedule periodic updates to Pachube service
    snapCom.scheduler.schedule(UPDATE_PERIOD, pach_poll)
    
    
if __name__ == '__main__':
    logging.basicConfig(level=logging.DEBUG, format='%(asctime)s:%(msecs)03d %(levelname)-8s %(name)-8s %(message)s', datefmt='%H:%M:%S')
    
    main()
    snapCom.loop()

    
