import Adafruit_BluefruitLE
from Adafruit_BluefruitLE.services import UART
import os
import Queue
import time
from threading import Thread

packet_queue = Queue.Queue()

class PacketProcessor(Thread):
  """Class for processing packets being sent from the sensor.

  The packet processor runs on its own threads and uses a queue to communicate
  with the thread responsible to receive packets over bluetooth.
  """

  def __init__(self, out_fname):
    """Initialization method.

    Args:
      out_fname: Output file name where to write the sensor samples.
    """
    Thread.__init__(self)
    self.out_fname = out_fname

  def run(self):
    """Thread's run() method."""
    try:
      with open(self.out_fname, 'w') as out_file:
        self.run_impl(out_file)
    except Exception, e:
      print 'Error: {}'.format(e)

  def run_impl(self, out_file):
    """Loop where packets are actually processed.

    Args:
      out_file: Output file object.
    """
    packet_buffer = []
    while True:
      global packet_queue
      char = packet_queue.get()
      packet_queue.task_done();
      if char == 'Q':
        break
      elif char == 'E':
        self.process_packet(packet_buffer, out_file)
        packet_buffer = []
      else:
        packet_buffer += [char]

  def process_packet(self, packet, out_file):
    """Processes a single packet.

    Args:
      packet: A character buffer containing the packet.
      out_file: Output file object.
    """
    if len(packet) == 0:
      raise Exception('Empty packet')
    if packet[0] != 'B':
      raise Exception('Malformed packet')

    packet = int(''.join(packet[1:]))

    print 'Sample: {}'.format(packet)
    print >>out_file, '{},{}'.format(time.time(), packet)
    out_file.flush()
    os.fsync(out_file.fileno())

class PacketReceiver:
  """This class is responsible for receiving packets from the sensor."""

  def __init__(self, ble):
    """Initialization method.

    Args:
      ble: The Bluetooth LE instance.
    """
    self.ble = ble

  def __call__(self):
    """Method call from the BLE event loop."""
    try:
      (device, uart) = self.connect_to_device()
    except:
      return

    try:
      while True:
        self.receive_data(uart);
    except Exception, e:
      print 'Error: {}'.format(e)
    finally:
      device.disconnect()

    global packet_queue
    packet_queue.join()

  def connect_to_device(self):
    """Connects to the device.

    Returns:
      A pair containing the device that we connected to and the UART instance.
    """
    self.ble.clear_cached_data()

    adapter = self.ble.get_default_adapter()
    adapter.power_on()
    print('Using adapter: {}'.format(adapter.name))

    print('Disconnecting any connected UART devices...')
    UART.disconnect_devices()

    print('Searching for UART device...')
    try:
      adapter.start_scan()
      device = UART.find_device()
      if device is None:
        raise RuntimeError('Failed to find UART device!')
    finally:
      adapter.stop_scan()

    print('Connecting to device...')
    device.connect()

    try:
      print('Discovering services...')
      UART.discover(device)
      uart = UART(device)
    except:
      device.disconnect()
      raise

    return (device, uart)

  def receive_data(self, uart):
    """Receives data from the Bluetooth LE device.

    Args:
      uart: The UART instance.
    """
    received = uart.read(timeout_sec=60)
    if received is None:
      packet_queue.put('Q')
      raise Exception('Received no data!')

    for c in received:
      packet_queue.put(c)

###

ble = Adafruit_BluefruitLE.get_provider()
ble.initialize()

packet_receiver = PacketReceiver(ble)

out_fname = os.path.join(os.path.expanduser('~'), 'tmp/moisture.csv')
packet_processor = PacketProcessor(out_fname)
packet_processor.start()

ble.run_mainloop_with(packet_receiver)


@@ -68,16 +68,30 @@
 rt UART%0A
+import atexit%0A
 import o
@@ -151,35 +151,233 @@
 ad%0A%0A
-packet_queue = Queue.Queue(
+# Arduino reads the sensor once every 30 minutes%0ATIME_BETWEEN_READINGS = 30 * 60%0A%0Apacket_queue = Queue.Queue()%0A%0Adef notify_execution_end():%0A  %22%22%22Notifies the packet processor about the execution end.%22%22%22%0A  packet_queue.put('Q'
 )%0A%0Ac
@@ -827,16 +827,41 @@
 ut_fname
+%0A    self.setDaemon(True)
 %0A%0A  def 
@@ -1053,16 +1053,131 @@
 ormat(e)
+%0A    except:%0A      print 'Unexpected exception was caught'%0A    finally:%0A      print 'Packet processor is finishing'
 %0A%0A  def 
@@ -2427,35 +2427,24 @@
 nt loop.%22%22%22%0A
-    try:%0A  
     (device,
@@ -2480,33 +2480,8 @@
 ce()
-%0A    except:%0A      return
 %0A%0A  
@@ -2546,148 +2546,40 @@
     
-except Exception, e:%0A      print 'Error: %7B%7D'.format(e)%0A    finally:%0A      device.disconnect()%0A%0A    global packet_queue%0A    packet_queue.join
+finally:%0A      device.disconnect
 ()%0A%0A
@@ -3632,64 +3632,61 @@
 sec=
-60)%0A    if received is None:%0A      packet_queue.put('Q')
+(2 * TIME_BETWEEN_READINGS))%0A    if received is None:
 %0A   
@@ -4026,44 +4026,463 @@
 ()%0A%0A
-ble.run_mainloop_with(packet_receiver)
+def cleanup():%0A  %22%22%22Cleans up everything before exiting.%0A  %0A  An ending notification is sent to the packet processor. Then we wait until%0A  all the pending packets are processed.%0A  %22%22%22%0A  print 'Cleaning up before exiting'%0A  notify_execution_end()%0A  packet_queue.join()%0A  time.sleep(5)%0A%0Aatexit.register(cleanup)%0A%0Atry:%0A  ble.run_mainloop_with(packet_receiver)%0Aexcept Exception, e:%0A  print 'Error: %7B%7D'.format(e)%0Aexcept:%0A  print 'Unexpected exception was caught'
 %0A%0A

Improve Ctrl+C handling. Minor code improvements.