# Path: greenpithumb/db_store.py
# _CREATE_TABLE_COMMANDS = """
# CREATE TABLE temperature
# (
#     timestamp TEXT,
#     temperature REAL    --temperature (in degrees Celsius)
# );
# CREATE TABLE humidity
# (
#     timestamp TEXT,
#     humidity REAL
# );
# CREATE TABLE soil_moisture
# (
#     timestamp TEXT,
#     soil_moisture INTEGER
# );
# CREATE TABLE light
# (
#     timestamp TEXT,
#     light REAL
# );
# CREATE TABLE watering_events
# (
#     timestamp TEXT,
#     water_pumped REAL   --amount of water pumped (in mL)
# );
# """
# _TIMESTAMP_FORMAT = '%Y-%m-%dT%H:%MZ'
# def _timestamp_to_utc(timestamp):
# def _open_db(db_path):
# def _create_db(db_path):
# def open_or_create_db(db_path):
#     def __init__(self, connection):
#     def _do_insert(self, sql, timestamp, value):
#     def _do_get(self, sql, record_type):
#     def insert(self, soil_moisture_record):
#     def get(self):
#     def insert(self, light_record):
#     def get(self):
#     def insert(self, humidity_record):
#     def get(self):
#     def insert(self, temperature_record):
#     def get(self):
#     def insert(self, watering_event_record):
#     def get(self):
# class _DbStoreBase(object):
# class SoilMoistureStore(_DbStoreBase):
# class LightStore(_DbStoreBase):
# class HumidityStore(_DbStoreBase):
# class TemperatureStore(_DbStoreBase):
# class WateringEventStore(_DbStoreBase):
# 
# Path: greenpithumb/poller.py
# _SECONDS_PER_MINUTE = 60
# _IDLE_SECONDS = 0.5
# class SensorPollerFactory(object):
# class Scheduler(object):
# class _SensorPollWorkerBase(object):
# class _TemperaturePollWorker(_SensorPollWorkerBase):
# class _HumidityPollWorker(_SensorPollWorkerBase):
# class _LightPollWorker(_SensorPollWorkerBase):
# class _SoilWateringPollWorker(_SensorPollWorkerBase):
# class _CameraPollWorker(_SensorPollWorkerBase):
# class _SensorPoller(object):
#     def __init__(self, make_scheduler_func, record_queue):
#     def create_temperature_poller(self, temperature_sensor):
#     def create_humidity_poller(self, humidity_sensor):
#     def create_light_poller(self, light_sensor):
#     def create_soil_watering_poller(self, soil_moisture_sensor, pump_manager):
#     def create_camera_poller(self, camera_manager):
# def _datetime_to_unix_time(dt):
# def _unix_time_to_datetime(unix_time):
# def _round_up_to_multiple(value, multiple):
#     def __init__(self, clock, poll_interval):
#     def _unix_now(self):
#     def _next_poll_time_unix(self):
#     def wait_until_poll_time(self, timeout):
#     def last_poll_time(self):
#     def __init__(self, scheduler, record_queue, sensor):
#     def _is_stopped(self):
#     def _wait_until_poll_time_or_stop(self):
#     def poll(self):
#     def stop(self):
#     def _poll_once(self):
#     def _poll_once(self):
#     def _poll_once(self):
#     def __init__(self, scheduler, record_queue, soil_moisture_sensor,
#                  pump_manager):
#     def _poll_once(self):
#     def _poll_once(self):
#     def stop(self):
#     def __init__(self, poll_worker):
#     def start_polling_async(self):
#     def close(self):


import contextlib
import datetime
import Queue
import threading
import unittest
import mock
import pytz
from greenpithumb import db_store
from greenpithumb import poller
            2017, 4, 9, 11, 43, 29, tzinfo=pytz.utc)
        scheduler = poller.Scheduler(
            self.mock_clock, poll_interval=datetime.timedelta(minutes=5))
        # If it's 11:43:29, at 5m polling intervals, next poll is at 11:45:00,
        # 91 seconds later, so we should only wait the length of the timeout.
        self.assertFalse(scheduler.wait_until_poll_time(timeout=90))
        self.mock_clock.wait.assert_called_with(90)

    def test_wait_equal_to_timeout_returns_True(self):
        self.mock_clock.now.return_value = datetime.datetime(
            2017, 4, 9, 11, 43, 29, tzinfo=pytz.utc)
        scheduler = poller.Scheduler(
            self.mock_clock, poll_interval=datetime.timedelta(minutes=5))
        # If it's 11:43:29, at 5m polling intervals, next poll is at 11:45:00,
        # 91 seconds later, so timeout is equal to wait time.
        self.assertTrue(scheduler.wait_until_poll_time(timeout=91))
        self.mock_clock.wait.assert_called_with(91)

    def test_no_wait_if_first_call_is_on_interval_boundary(self):
        self.mock_clock.now.return_value = datetime.datetime(
            2017, 4, 9, 11, 45, 0, tzinfo=pytz.utc)
        scheduler = poller.Scheduler(
            self.mock_clock, poll_interval=datetime.timedelta(minutes=5))
        self.assertTrue(scheduler.wait_until_poll_time(timeout=(10 * 60)))
        # 11:45:00 falls on the interval boundary of 5m, so should be no wait.
        self.mock_clock.wait.assert_not_called()

    def test_increments_wait_if_consecutive_calls_on_same_poll_boundary(self):
        self.mock_clock.now.return_value = datetime.datetime(
            2017, 4, 9, 11, 45, 0, tzinfo=pytz.utc)

# Path: greenpithumb/db_store.py
# _CREATE_TABLE_COMMANDS = """
# CREATE TABLE temperature
# (
#     timestamp TEXT,
#     temperature REAL    --temperature (in degrees Celsius)
# );
# CREATE TABLE humidity
# (
#     timestamp TEXT,
#     humidity REAL
# );
# CREATE TABLE soil_moisture
# (
#     timestamp TEXT,
#     soil_moisture INTEGER
# );
# CREATE TABLE light
# (
#     timestamp TEXT,
#     light REAL
# );
# CREATE TABLE watering_events
# (
#     timestamp TEXT,
#     water_pumped REAL   --amount of water pumped (in mL)
# );
# """
# _TIMESTAMP_FORMAT = '%Y-%m-%dT%H:%MZ'
# def _timestamp_to_utc(timestamp):
# def _open_db(db_path):
# def _create_db(db_path):
# def open_or_create_db(db_path):
#     def __init__(self, connection):
#     def _do_insert(self, sql, timestamp, value):
#     def _do_get(self, sql, record_type):
#     def insert(self, soil_moisture_record):
#     def get(self):
#     def insert(self, light_record):
#     def get(self):
#     def insert(self, humidity_record):
#     def get(self):
#     def insert(self, temperature_record):
#     def get(self):
#     def insert(self, watering_event_record):
#     def get(self):
# class _DbStoreBase(object):
# class SoilMoistureStore(_DbStoreBase):
# class LightStore(_DbStoreBase):
# class HumidityStore(_DbStoreBase):
# class TemperatureStore(_DbStoreBase):
# class WateringEventStore(_DbStoreBase):
# 
# Path: greenpithumb/poller.py
# _SECONDS_PER_MINUTE = 60
# _IDLE_SECONDS = 0.5
# class SensorPollerFactory(object):
# class Scheduler(object):
# class _SensorPollWorkerBase(object):
# class _TemperaturePollWorker(_SensorPollWorkerBase):
# class _HumidityPollWorker(_SensorPollWorkerBase):
# class _LightPollWorker(_SensorPollWorkerBase):
# class _SoilWateringPollWorker(_SensorPollWorkerBase):
# class _CameraPollWorker(_SensorPollWorkerBase):
# class _SensorPoller(object):
#     def __init__(self, make_scheduler_func, record_queue):
#     def create_temperature_poller(self, temperature_sensor):
#     def create_humidity_poller(self, humidity_sensor):
#     def create_light_poller(self, light_sensor):
#     def create_soil_watering_poller(self, soil_moisture_sensor, pump_manager):
#     def create_camera_poller(self, camera_manager):
# def _datetime_to_unix_time(dt):
# def _unix_time_to_datetime(unix_time):
# def _round_up_to_multiple(value, multiple):
#     def __init__(self, clock, poll_interval):
#     def _unix_now(self):
#     def _next_poll_time_unix(self):
#     def wait_until_poll_time(self, timeout):
#     def last_poll_time(self):
#     def __init__(self, scheduler, record_queue, sensor):
#     def _is_stopped(self):
#     def _wait_until_poll_time_or_stop(self):
#     def poll(self):
#     def stop(self):
#     def _poll_once(self):
#     def _poll_once(self):
#     def _poll_once(self):
#     def __init__(self, scheduler, record_queue, soil_moisture_sensor,
#                  pump_manager):
#     def _poll_once(self):
#     def _poll_once(self):
#     def stop(self):
#     def __init__(self, poll_worker):
#     def start_polling_async(self):
#     def close(self):


# Path: tests/test_poller.py
import contextlib
import datetime
import Queue
import threading
import unittest
import mock
import pytz
from greenpithumb import db_store
from greenpithumb import poller

            2017, 4, 9, 11, 43, 29, tzinfo=pytz.utc)
        scheduler = poller.Scheduler(
            self.mock_clock, poll_interval=datetime.timedelta(minutes=5))
        # If it's 11:43:29, at 5m polling intervals, next poll is at 11:45:00,
        # 91 seconds later, so we should only wait the length of the timeout.
        self.assertFalse(scheduler.wait_until_poll_time(timeout=90))
        self.mock_clock.wait.assert_called_with(90)

    def test_wait_equal_to_timeout_returns_True(self):
        self.mock_clock.now.return_value = datetime.datetime(
            2017, 4, 9, 11, 43, 29, tzinfo=pytz.utc)
        scheduler = poller.Scheduler(
            self.mock_clock, poll_interval=datetime.timedelta(minutes=5))
        # If it's 11:43:29, at 5m polling intervals, next poll is at 11:45:00,
        # 91 seconds later, so timeout is equal to wait time.
        self.assertTrue(scheduler.wait_until_poll_time(timeout=91))
        self.mock_clock.wait.assert_called_with(91)

    def test_no_wait_if_first_call_is_on_interval_boundary(self):
        self.mock_clock.now.return_value = datetime.datetime(
            2017, 4, 9, 11, 45, 0, tzinfo=pytz.utc)
        scheduler = poller.Scheduler(
            self.mock_clock, poll_interval=datetime.timedelta(minutes=5))
        self.assertTrue(scheduler.wait_until_poll_time(timeout=(10 * 60)))
        # 11:45:00 falls on the interval boundary of 5m, so should be no wait.
        self.mock_clock.wait.assert_not_called()

    def test_increments_wait_if_consecutive_calls_on_same_poll_boundary(self):
        self.mock_clock.now.return_value = datetime.datetime(
            2017, 4, 9, 11, 45, 0, tzinfo=pytz.utc)

        scheduler = poller.Scheduler(