Beispiel #1
0
def discover_wemo():
    """ Discover Wemo devices on the network """
    global _device_time, _device_cache

    if _device_time and _device_time - local_now() <= CACHE_DURATION:
        return _device_cache

    _device_cache = pywemo.discover_devices()
    _device_time = local_now()

    return _device_cache
Beispiel #2
0
def sunrise(zip):
    """ When the sun is up """
    global _LAST_TRIGGERED_DATE

    key = "sunrise-{}".format(zip)
    now = local_now()
    forecast = get_forecast(zip=zip)

    if not forecast.get("city") or not forecast["city"].get("sunrise"):
        log.error(
            "Unable to get sunrise from forecast for zip: {}".format(zip))
        return None

    # Only trigger this once per day
    if same_day(_LAST_TRIGGERED_DATE.get(key), now):
        log.debug("sunrise() already fired today @ {}".format(
            _LAST_TRIGGERED_DATE[key]))
        return None

    sunrisedt = datetime.utcfromtimestamp(
        forecast["city"]["sunrise"] +
        forecast["city"].get("timezone", 0)).replace(tzinfo=tzlocal())

    log.debug("Expected sunrise at {}".format(sunrisedt))

    log.debug("{} <= {} == {}".format(sunrisedt, now, sunrisedt <= now))

    if not same_day(sunrisedt, now):
        log.warn("Weather forecast is old.")

    elif sunrisedt <= now:
        _LAST_TRIGGERED_DATE[key] = now
        return sunrisedt

    return None
Beispiel #3
0
def get_forecast(zip=DEFAULT_ZIP, country_code=DEFAULT_COUNTRY_CODE):
    """ Get the 5 day forecast for a zip """
    global FORECAST_CACHE, FORECAST_CACHE_TIME

    if (FORECAST_CACHE is not None and FORECAST_CACHE_TIME is not None
            and FORECAST_CACHE_TIME + FORECAST_CACHE_DURATION > local_now()):
        return FORECAST_CACHE

    FORECAST_CACHE = fetch_forecast_data(zip, country_code)
    forecast_list = FORECAST_CACHE.get("list")

    if forecast_list is not None and len(forecast_list) > 0:

        date_string = forecast_list[0].get("dt_txt")

        if date_string is not None:
            FORECAST_CACHE_TIME = parse_owm_date(date_string)
            log.debug(
                "Set Forecast cache time to {}".format(FORECAST_CACHE_TIME))

        else:
            FORECAST_CACHE_TIME = None
            log.warn("dt_txt has invalid value or does not exist")

    else:
        FORECAST_CACHE_TIME = None
        log.error("Failed to fetch OWM data")

    return FORECAST_CACHE
Beispiel #4
0
def run_daemon():
    log.debug("run_daemon()")

    scheduler = Scheduler()

    with config() as conf:
        log.debug("config()")
        while True:
            log.debug("--tick {}".format(local_now()))

            try:
                triggers = get_triggers()

                for trig in triggers:
                    trigger_when = when(trig["when"]["name"], trig["when"].get("args"))

                    if trigger_when:
                        for action in trig["do"]:
                            scheduler.add(
                                trigger_when, action["name"], action.get("args")
                            )

                log.debug("Scheduler has {} actions".format(len(scheduler.schedule)))

                executing = True
                while executing:

                    schedule = scheduler.finalize()

                    log.info("Will perform {} actions".format(len(schedule)))

                    for event in schedule:
                        try:
                            do(event.name, event.args)
                        except MaxRetriesReached:
                            log.exception(
                                "Maximum retries reached for {}({}".format(
                                    event.name, event.cargs
                                )
                            )
                        except Exception:
                            log.exception(
                                "Exception while attempting to perform action {}({}). Retrying...".format(
                                    event.name, event.args
                                )
                            )
                            scheduler.retry(event)

                    if len(scheduler.schedule) < 1:
                        executing = False

            except Exception:
                log.exception("Unhandled exception in daemon")

            time.sleep(getint(conf, "tick", DEFAULT_TICK))
Beispiel #5
0
def test_scheduler():
    """ Test the Scheduler """

    s = Scheduler()

    one_time = local_now() + timedelta(minutes=15)
    two_time = local_now() + timedelta(minutes=20)
    three_time = local_now() + timedelta(minutes=25)

    # These stack, and the final on should prevail
    s.add(one_time, DEVICE_ON, {"mac": DEVICE_ONE})
    s.add(two_time, DEVICE_OFF, {"mac": DEVICE_ONE})
    s.add(three_time, DEVICE_ON, {"mac": DEVICE_ONE})

    schedule = s.finalize()

    assert len(schedule) == 1
    assert schedule[0].when == three_time
    assert schedule[0].name == DEVICE_ON
    assert type(schedule[0].args) == dict
    assert schedule[0].args.get("mac") == DEVICE_ONE
Beispiel #6
0
def now_is_same(interval):
    """ Check if the last triggered datetime of an interval is the same day as
    today """

    same = False
    now = local_now()

    if interval == "daily":
        same = same_day(_LAST_TRIGGERED_DT.get(interval), now)
    elif interval == "hourly":
        same = same_hour(_LAST_TRIGGERED_DT.get(interval), now)
    elif interval == "minutely":
        same = same_minute(_LAST_TRIGGERED_DT.get(interval), now)

    return same
Beispiel #7
0
def test_scheduler_max_retries():
    """ Test max retries on scheduler """

    s = Scheduler()

    when = local_now() + timedelta(minutes=15)

    s.add(when, "test.echo", {"string": "Hello, world!"})

    assert len(s.schedule) == 1

    first_schedule = s.finalize()

    assert len(first_schedule) == 1
    assert first_schedule[0].retries == 0

    s.retry(first_schedule[0])

    first_schedule = s.finalize()

    assert len(first_schedule) == 1
    assert first_schedule[0].retries == 1

    s.retry(first_schedule[0])

    first_schedule = s.finalize()

    assert len(first_schedule) == 1
    assert first_schedule[0].retries == 2

    s.retry(first_schedule[0])

    first_schedule = s.finalize()

    assert len(first_schedule) == 1
    assert first_schedule[0].retries == 3

    try:
        s.retry(first_schedule[0])
        assert False, "Should have raised an exception"
    except MaxRetriesReached:
        pass
    except AssertionError as err:
        raise err
    except Exception as err:
        assert False, "Wrong exception seen: {}".format(err)
Beispiel #8
0
def time(when):
    """ Triggers when the time matches t """
    dt = parse(when).replace(tzinfo=tzlocal())
    now = local_now()
    key = "time-{}:{}:{}".format(dt.hour, dt.minute, dt.second)

    if now < dt:
        log.debug("{} is in the future.".format(dt))
        return None

    if same_day(_LAST_TRIGGERED_DT.get(key), now):
        log.debug("datetime.time already fired today (@ {}).".format(
            _LAST_TRIGGERED_DT.get(key)))
        return None

    _LAST_TRIGGERED_DT[key] = now

    return dt
Beispiel #9
0
def _interval_trigger(interval):
    """ Generic trigger for datetime intervals """
    if now_is_same(interval):
        return None
    _LAST_TRIGGERED_DT[interval] = local_now()
    return _LAST_TRIGGERED_DT[interval]