Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

simple threshold based logic and tests

started writing unittests.
implemented cleanup command that removes empty sessions
added a simple threshold based alarm logic
  • Loading branch information...
commit 89cbae5389aa531e24f5436a43b0b9e69a5d3c75 1 parent c14d2f1
@poelzi authored
View
85 .pida-metadata/python/config.py
@@ -0,0 +1,85 @@
+# The default ``config.py``
+
+
+def set_prefs(prefs):
+ """This function is called before opening the project"""
+
+ # Specify which files and folders to ignore in the project.
+ # Changes to ignored resources are not added to the history and
+ # VCSs. Also they are not returned in `Project.get_files()`.
+ # Note that ``?`` and ``*`` match all characters but slashes.
+ # '*.pyc': matches 'test.pyc' and 'pkg/test.pyc'
+ # 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc'
+ # '.svn': matches 'pkg/.svn' and all of its children
+ # 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o'
+ # 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o'
+ prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject',
+ '.hg', '.svn', '_svn', '.git']
+
+ # Specifies which files should be considered python files. It is
+ # useful when you have scripts inside your project. Only files
+ # ending with ``.py`` are considered to be python files by
+ # default.
+ #prefs['python_files'] = ['*.py']
+
+ # Custom source folders: By default rope searches the project
+ # for finding source folders (folders that should be searched
+ # for finding modules). You can add paths to that list. Note
+ # that rope guesses project source folders correctly most of the
+ # time; use this if you have any problems.
+ # The folders should be relative to project root and use '/' for
+ # separating folders regardless of the platform rope is running on.
+ # 'src/my_source_folder' for instance.
+ #prefs.add('source_folders', 'src')
+
+ # You can extend python path for looking up modules
+ #prefs.add('python_path', '~/python/')
+
+ # Should rope save object information or not.
+ prefs['save_objectdb'] = True
+ prefs['compress_objectdb'] = False
+
+ # If `True`, rope analyzes each module when it is being saved.
+ prefs['automatic_soa'] = True
+ # The depth of calls to follow in static object analysis
+ prefs['soa_followed_calls'] = 0
+
+ # If `False` when running modules or unit tests "dynamic object
+ # analysis" is turned off. This makes them much faster.
+ prefs['perform_doa'] = True
+
+ # Rope can check the validity of its object DB when running.
+ prefs['validate_objectdb'] = True
+
+ # How many undos to hold?
+ prefs['max_history_items'] = 32
+
+ # Shows whether to save history across sessions.
+ prefs['save_history'] = True
+ prefs['compress_history'] = False
+
+ # Set the number spaces used for indenting. According to
+ # :PEP:`8`, it is best to use 4 spaces. Since most of rope's
+ # unit-tests use 4 spaces it is more reliable, too.
+ prefs['indent_size'] = 4
+
+ # Builtin and c-extension modules that are allowed to be imported
+ # and inspected by rope.
+ prefs['extension_modules'] = []
+
+ # Add all standard c-extensions to extension_modules list.
+ prefs['import_dynload_stdmods'] = True
+
+ # If `True` modules with syntax errors are considered to be empty.
+ # The default value is `False`; When `False` syntax errors raise
+ # `rope.base.exceptions.ModuleSyntaxError` exception.
+ prefs['ignore_syntax_errors'] = False
+
+ # If `True`, rope ignores unresolvable imports. Otherwise, they
+ # appear in the importing namespace.
+ prefs['ignore_bad_imports'] = False
+
+
+def project_opened(project):
+ """This function is called after opening the project"""
+ # Do whatever you like here!
View
94 db/alarm.py
@@ -2,6 +2,14 @@
Alarm clock logic
"""
+from uberclock.tools import Enumeration
+from django.conf import settings
+
+import datetime
+
+
+ACTIONS = Enumeration("ACTIONS",
+ (("LIGHTS",1), "WAKEUP"))
class Manager(object):
"""Manages Alarm Programs"""
@@ -69,6 +77,7 @@ class BaseAction(object):
def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
+ self.background = kwargs.get("background", False)
def execute(self):
raise NotImplemented
@@ -80,8 +89,11 @@ class ExecuteAction(BaseAction):
"""
def execute(self):
import subprocess
- self.popen = subprocess.Popen(self.args)
- self.popen.communicate()
+ if self.background:
+ self.popen = subprocess.Popen(self.args)
+ else:
+ self.popen = subprocess.Popen(self.args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ return self.popen.communicate()
class BaseAlarm(object):
"""
@@ -92,22 +104,30 @@ class BaseAlarm(object):
name = None
short_name = None
- def __init__(self, manager, session):
+ def __init__(self, manager, session, **kwargs):
self.manager = manager
self.session = session
self.next_alarm = None
+ self.snooze_time = kwargs.get('snooze_time', settings.DEFAULT_SNOOZE_TIME)
def check(self):
"""
Returns a alarm action to execute
"""
- return None
+ return False
- def snooze(self):
+ def snooze(self, snooze_time=None):
"""
User pressed snooze
"""
- pass
+ if snooze_time is None:
+ snooze_time = self.snooze_time
+
+ self.next_alarm = datetime.datetime.now() + \
+ datetime.timedelta(seconds=snooze_time)
+
+ def stop(self):
+ self.next_alarm = None
def feed(self, entry):
"""
@@ -120,4 +140,64 @@ class BasicAlarm(BaseAlarm):
name = "Basic Alarm"
short_name = "basic"
-manager.register(BasicAlarm)
+ def check(self, dt=None):
+ """
+ Returns a alarm action to execute
+ """
+ if not dt:
+ dt = datetime.datetime.now()
+ if not self.next_alarm:
+ return False
+ if self.next_alarm < dt:
+ return ACTIONS.WAKEUP
+ return False
+
+manager.register(BasicAlarm)
+
+class MovementAlarm(BasicAlarm):
+ key = "simple_movement"
+ name = "Simple Movement"
+ short_name = "smplmv"
+
+ DEFAULT_THRESHHOLDS = {
+ 0: 20000, # OpenChronos
+ None: 1000, # Unknown, default
+ }
+
+ def __init__(self, *args, **kwargs):
+ super(MovementAlarm, self).__init__(*args, **kwargs)
+
+ th = self.DEFAULT_THRESHHOLDS[None]
+ if self.session:
+ if self.session.detector:
+ th = self.DEFAULT_THRESHHOLDS.get(session.detector.typ, None)
+ if self.session.program:
+ th = self.session.program.get_var("movement_threshhold", th)
+ if "threshhold" in kwargs:
+ th = kwargs["threshhold"]
+ self.threshold = th
+
+ def check(self, dt=None):
+ """
+ Returns a alarm action to execute
+ """
+ if not dt:
+ dt = datetime.datetime.now()
+ # if the default action is already fireing
+ rv = super(MovementAlarm, self).check(dt)
+ if rv:
+ return rv
+ if not self.session.window:
+ return
+ fwin = dt - datetime.timedelta(minutes=self.session.window)
+ for entry in self.session.entry_set.order_by('-date')[:3]:
+ # stop when the entry is befor the considered window
+ if entry.date < fwin:
+ break
+ if entry.value > self.threshold:
+ if self.session.action_in_window(ACTIONS.WAKEUP, dt):
+ return ACTIONS.WAKEUP
+
+
+manager.register(MovementAlarm)
+
View
15 db/management/commands/cleanup.py
@@ -0,0 +1,15 @@
+from django.core.management.base import BaseCommand, CommandError
+from uberclock.db.models import cleanup_db
+from django.conf import settings
+from optparse import make_option
+import logging
+
+class Command(BaseCommand):
+ args = ''
+ help = 'Cleanup the database'
+
+ def handle(self, *args, **options):
+ logging.basicConfig(level=logging.DEBUG)
+ logging.info("cleanup database")
+ cleanup_db()
+ logging.info("done")
View
175 db/models.py
@@ -1,5 +1,8 @@
from django.db import models
+
from uberclock.tools import ez_chronos
+from uberclock.tools.date import time_to_next_datetime
+
from django.contrib.auth.models import User
from django.contrib import admin
from django.conf import settings
@@ -10,6 +13,12 @@
import datetime
import time
import random
+import base64
+#import simplejson
+try:
+ import cPickle as pickle
+except ImportError:
+ import pickle
# Create your models here.
DETECTOR_TYPES = (
@@ -67,15 +76,21 @@ def get_users_default(self, user):
class UserProgram(models.Model):
"""
Maps a alarm program to user and his choosen id
+
+ Object can be used to save settings that are serialsable by simplejson
"""
user = models.ForeignKey(User, null=True, db_index=True)
users_id = models.IntegerField(null=False, db_index=True)
default = models.BooleanField(default=False)
alarm_key = models.CharField(null=False, max_length=30, choices=alarm.manager.choices_programs)
- rname = models.CharField(max_length=30, null=True, blank=True)
+ rname = models.CharField("name", max_length=30, null=True, blank=True)
short_name = models.CharField(max_length=5, null=True, blank=True)
- settings = models.TextField()
+ default_wakeup = models.TimeField("Wakeup", null=True)
+ default_sleep_time = models.IntegerField(null=True, help_text="Minutes of wanted sleep")
+ default_window = models.IntegerField(null=True, help_text="Window of Minutes how many minutes before wakeup can be alarmed")
+
+ settings = models.TextField(default=None, editable=False, null=True)
objects = UserProgramManager()
@@ -92,10 +107,60 @@ def _set_name(self, val):
name = property(_get_name, _set_name)
+ def get_var(self, name, *args):
+ if not hasattr(self, "_settings"):
+ if self.settings:
+ try:
+ #self._settings = simplejson.loads(self.settings)
+ self._settings = pickle.loads(base64.b64decode(self.settings))
+ except Exception, e:
+ logging.warning("could not unpickle settings: %s" %e)
+ print self.settings
+ self._settings = {}
+ else:
+ self._settings = {}
+
+ if name and len(args):
+ return self._settings.get(name, args[0])
+ elif name:
+ return self._settings.get(name)
+
+ if not self.settings or not isinstance(self.settings, dict):
+ self.settings = {}
+
+ def set_var(self, name, value):
+ if not hasattr(self, "_settings"):
+ self.get_var(None)
+ self._settings[name] = value
+
+ def del_var(self, name):
+ if not hasattr(self, "_settings"):
+ self.get_var(None)
+ del self._settings[name]
+
+
+ def save(self, *args, **kwargs):
+ if hasattr(self, "_settings"):
+ #self.settings = simplejson.dumps(self._settings, ensure_ascii=False)
+ self.settings = base64.b64encode(pickle.dumps(self._settings))
+ return super(UserProgram, self).save(*args, **kwargs)
+
@property
def program_class(self):
return alarm.manager.get_program(self.alarm_key)
+ def set_program(self, program):
+ if program:
+ self.alarm_key = program.key
+ else:
+ self.alarm_key = None
+
+ def get_program(self, session):
+ if hasattr(self, "_program") and self._program.key == self.alarm_key:
+ return self._program
+ self._program = self.program_class(alarm.manager, session)
+ return self._program
+
def __unicode__(self):
return u"%s of %s" %(self.name, self.user)
@@ -149,6 +214,21 @@ def get_new_session(self, user):
# create a new session
pass
+ def cleanup_sessions(self):
+ """
+ Clean up session garbage
+ """
+ self.delete_empty_sessions()
+
+ def delete_empty_sessions(self):
+ # delete empty sessions older then one day
+ datelimit = datetime.datetime.now() - datetime.timedelta(days=1)
+ for session in Session.objects.annotate(entry_count=models.Count('entry')).filter(entry_count=0, stop__lt=datelimit):
+ logging.info("delete %s" %session)
+ session.learndata.delete()
+ session.delete()
+
+
class Session(models.Model):
"""
One Sleep Session
@@ -159,6 +239,9 @@ class Session(models.Model):
detector = models.ForeignKey(Detector, null=True)
program = models.ForeignKey(UserProgram, null=True)
wakeup = models.DateTimeField("Wakeup", null=True)
+ #FIXME messure real slept length
+ sleep_time = models.IntegerField(null=True, help_text="Minutes of wanted sleep")
+ window = models.IntegerField(null=True, help_text="Window of Minutes how many minutes before wakeup can be alarmed")
rating = models.IntegerField("Rating", null=True)
deleted = models.BooleanField("Deleted", default=False)
rf_id = models.IntegerField("RF Id", null=True)
@@ -167,19 +250,54 @@ class Session(models.Model):
objects = SessionManager()
- # Do we need this ?
- #alone = models.BooleanField("Alone", null=True, default=True, help_text="Sleeping with someone else in the bed")
-# def __init__(self, *args, **kwargs):
-# if not "user" in kwargs:
-# if "detector" in kwargs:
-# kwargs["user"] = get_user_or_default(kwargs["device"].default_user)
-# else:
-# kwargs["user"] =
-# if not "program" in kwargs:
-# self.kwargs["program"] = UserProgram.objects.get_users_default(kwargs["user"])
-#
-# return super(Session, self).__init__(*args, **kwargs)
+ def __init__(self, *args, **kwargs):
+ # copy default values from program
+ if "program" in kwargs:
+ prog = kwargs["program"]
+ if not "wakeup" in kwargs:
+ kwargs["wakeup"] = time_to_next_datetime(prog.default_wakeup)
+ if not "sleep_time" in kwargs:
+ kwargs["sleep_time"] = prog.default_sleep_time
+ if not "window" in kwargs:
+ kwargs["window"] = prog.default_window
+ return super(Session, self).__init__(*args, **kwargs)
+
+
+ def action_in_window(self, action, dt=None):
+ """
+ Checks if a action is allowed to run
+ """
+ if self.closed:
+ return False
+ if self.wakeup:
+ if not dt:
+ dt = datetime.datetime.now()
+ if dt > self.wakeup:
+ return True
+ elif self.window:
+ if action == alarm.ACTIONS.LIGHTS:
+ # lights get an aditional larger timedelta
+ if dt >= self.wakeup - datetime.timedelta(minutes=self.window+15):
+ return True
+ else:
+ if dt >= self.wakeup - datetime.timedelta(minutes=self.window):
+ return True
+ return False
+
+
+ def get_param(self, name):
+ """
+ Returns paramenter of the Sessions alarm
+ """
+ # get the value of the program first
+ if name in ["wakeup", "sleep_time", "window"]:
+ if getattr(self, name):
+ return getattr(self, name)
+ # lookup default values of the program
+ if self.program:
+ return self.program.get_var(name)
+
def save(self, *args, **kwargs):
super(Session, self).save(*args, **kwargs)
@@ -222,7 +340,7 @@ def __unicode__(self):
return u"Session from %s %s (%s:%0.2d) (%s Entries)" %(self.user, format(self.start, settings.DATETIME_FORMAT), length[0], length[1], entries)
def merge(self, source):
- # FIXME: add a zero datapoint maybe if the time
+ # FIXME: add a zero datapoint if the time between entries is to long
source.entry_set.all().update(session=self)
source.learndata_set.all().delete()
@@ -245,6 +363,8 @@ def cifn(key):
@property
def length(self):
+ if self.start > self.stop:
+ return (0, 0, 0)
s = (self.stop - self.start).seconds
hours, remainder = divmod(s, 3600)
minutes, seconds = divmod(remainder, 60)
@@ -257,11 +377,22 @@ class Entry(models.Model):
counter = models.IntegerField(max_length=3, null=True)
session = models.ForeignKey(Session, null=True, db_index=True)
+ def save(self, *args, **kwargs):
+ super(Entry, self).save(*args, **kwargs)
+ # update the session new flag to false if any entry is saved to it.
+ # it is used then
+ if self.session and self.session.new:
+ self.session = False
+ self.session.save()
+
def __repr__(self):
return "<Entry %s %d>" %(self.date, self.value)
def __unicode__(self):
- return u"Entry at %s: %s" %(self.date, time_format(self.date, settings.TIME_FORMAT))
+ return u"Entry at %s: %s" %(format(self.date, settings.DATETIME_FORMAT), self.value)
+
+ class Meta:
+ ordering = ('date',)
class LearnData(models.Model):
@@ -279,6 +410,18 @@ class LearnData(models.Model):
help_text="When sleep stopped", null=True)
learned = models.BooleanField(default=False)
+ @property
+ def placed(self):
+ if any([self.lights, self.wake, self.start, self.stop]):
+ return True
+ return False
+
+
+def cleanup_db():
+ # cleanup sessions
+ Session.objects.cleanup_sessions()
+
+
SIMPLICITI_PHASE_CLOCK_START_RESPONSE = 0x54
View
215 db/tests.py
@@ -7,17 +7,206 @@
from django.test import TestCase
-class SimpleTest(TestCase):
- def test_basic_addition(self):
- """
- Tests that 1 + 1 always equals 2.
- """
- self.failUnlessEqual(1 + 1, 2)
-
-__test__ = {"doctest": """
-Another way to test that 1 + 1 is equal to 2.
-
->>> 1 + 1 == 2
-True
-"""}
+from models import *
+import alarm
+import time, datetime
+
+class DBTest(TestCase):
+ def test_cleanup(self):
+ dt = datetime.datetime.now() - datetime.timedelta(days=2)
+ # emulate an old session
+ session = Session()
+ session.save()
+ session.stop = dt
+ session.save()
+ sid = session.id
+ Session.objects.cleanup_sessions()
+ self.assertEqual(Session.objects.filter(id=sid).count(), 0)
+
+ def test_learndata(self):
+ session = Session()
+ session.save()
+ ld = session.learndata
+ ent = Entry(session=session, value=10)
+ ent.save()
+ self.assertEqual(ld.placed, False)
+ for key in ["wake", "start", "stop", "lights"]:
+ setattr(ld, key, ent)
+ self.assertEqual(ld.placed, True)
+ setattr(ld, key, None)
+ self.assertEqual(ld.placed, False)
+
+ def test_userprogram(self):
+ up = UserProgram(users_id=0)
+ up.save()
+ uid = up.id
+ self.assertEqual(up.get_var("bla"), None)
+ self.assertEqual(up.get_var("bla",1), 1)
+ up.set_var("bla", 23)
+ self.assertEqual(up.get_var("bla",1), 23)
+ self.assertEqual(up.get_var("bla"), 23)
+ up.set_var("wakeup", datetime.time(7, 30))
+ up.save()
+ up = UserProgram.objects.get(id=uid)
+ # json is not used anymore
+ #self.assertEqual(up.settings, '{"bla": 23}')
+ self.assertEqual(up.get_var("bla"), 23)
+ self.assertEqual(up.get_var("wakeup"), datetime.time(7, 30))
+
+
+
+ up.delete()
+
+ def test_session_params(self):
+ prog = UserProgram(users_id=123)
+ #prog.set_var("wakeup", datetime.time(6,30))
+ prog.default_wakeup = datetime.time(3, 45)
+ prog.default_window = 29
+ #prog.default_sleep_time = None
+
+ prog.save()
+ session = Session(program=prog)
+ self.assertEqual(session.wakeup, time_to_next_datetime(prog.default_wakeup))
+ self.assertEqual(session.window, prog.default_window)
+ self.assertEqual(session.sleep_time, None)
+
+ prog.default_window = 24
+ prog.default_wakeup = datetime.time(3, 23)
+ prog.save()
+
+ self.assertEqual(session.wakeup, time_to_next_datetime(datetime.time(3, 45)))
+ self.assertEqual(session.window, 29)
+ self.assertEqual(session.sleep_time, None)
+
+ session.program = prog
+
+ self.assertEqual(session.wakeup, time_to_next_datetime(datetime.time(3, 45)))
+ self.assertEqual(session.window, 29)
+ self.assertEqual(session.sleep_time, None)
+
+ prog.default_sleep_time = 300
+
+ session = Session(program=prog)
+ self.assertEqual(session.sleep_time, 300)
+
+ prog.delete()
+
+ def test_session_functions(self):
+ prog = UserProgram(users_id=123)
+ #prog.set_var("wakeup", datetime.time(6,30))
+ prog.default_wakeup = datetime.time(3, 45)
+ prog.default_window = 29
+ prog.save()
+
+ session = Session(program=prog)
+
+ now = datetime.datetime.now()
+ session.window = 15
+ session.wakeup = now + datetime.timedelta(minutes=20)
+ self.assertEqual(session.action_in_window(alarm.ACTIONS.WAKEUP), False)
+ self.assertEqual(session.action_in_window(alarm.ACTIONS.LIGHTS), True)
+ session.window = 21
+ self.assertEqual(session.action_in_window(alarm.ACTIONS.WAKEUP), True)
+ self.assertEqual(session.action_in_window(alarm.ACTIONS.LIGHTS), True)
+
+
+
+class AlarmTest(TestCase):
+ def test_basic_alarm(self):
+ session = Session()
+ session.save()
+ basic = alarm.BasicAlarm(alarm.manager, session)
+ self.assertEqual(basic.check(), False)
+ basic.snooze(0.001)
+ time.sleep(0.01)
+ self.assertEqual(basic.check(), alarm.ACTIONS.WAKEUP)
+
+
+ def test_action(self):
+ ea = alarm.ExecuteAction("echo", "-n", "testrun")
+ rv = ea.execute()
+ self.assertEqual(rv[0], "testrun")
+
+ def test_movement(self):
+ prog = UserProgram(users_id=2)
+ #prog.set_var("wakeup", datetime.time(6,30))
+ prog.default_wakeup = datetime.time(5, 00)
+ prog.default_window = 10
+ prog.save()
+
+ session = Session(program=prog)
+
+ now = datetime.datetime.now()
+ start = datetime.datetime.now()
+ session.window = 15
+ session.wakeup = now + datetime.timedelta(minutes=20)
+ self.assertEqual(prog.alarm_key, "")
+ self.assertEqual(prog.program_class, alarm.BasicAlarm)
+ prog.set_program(alarm.manager.get_program("simple_movement"))
+ self.assertEqual(prog.alarm_key, "simple_movement")
+ self.assertEqual(prog.program_class, alarm.MovementAlarm)
+ ai = prog.get_program(session)
+ ai.threshold = 3000
+ self.assertTrue(isinstance(ai, prog.program_class))
+
+ ok = session.wakeup - datetime.timedelta(minutes=session.window)
+ end = now + datetime.timedelta(minutes=15)
+ import random
+ random.seed(0)
+ ctime = now - datetime.timedelta(minutes=15)
+ for i in xrange(4000):
+ # we should stop here with random tests, they should never have stopped
+ # yet
+ jit = random.randrange(0, 30)
+ ctime += datetime.timedelta(seconds=20+0.3*jit)
+ var = random.randrange(0,3242)
+ # emulate packet drop
+ if jit < 5:
+ continue
+ if ctime > end:
+ var = 3102
+
+ ent = Entry(value=var, date=ctime, session=session)
+ ent.save()
+ ent.date = ctime
+ ent.save()
+ ai.feed(ent)
+ res = ai.check(ctime)
+ if ctime >= ok and var >= 3000 :
+ self.assertEquals(res, alarm.ACTIONS.WAKEUP)
+ # we can stop now
+ break
+ else:
+ self.assertFalse(res)
+
+ if ctime > end:
+ break
+
+
+
+
+
+ def test_neuro1(self):
+ pass
+
+
+
+from uberclock.tools.date import time_to_next_datetime
+# test some code from tools
+class ToolsTest(TestCase):
+ def test_time_to_next_datetime(self):
+ now = datetime.datetime.now()
+ prev = now - datetime.timedelta(minutes=1)
+ nd = time_to_next_datetime(prev.time())
+ # past test
+ self.assertTrue(nd > now)
+ self.assertTrue(nd - datetime.timedelta(hours=23, minutes=55) > now)
+
+ # futur test
+ next = now + datetime.timedelta(minutes=1)
+ nd = time_to_next_datetime(next.time())
+
+ self.assertTrue(nd > now)
+ self.assertTrue(nd - datetime.timedelta(minutes=2) < now)
+
View
7 settings.py
@@ -2,7 +2,7 @@
import os, os.path
-CONFIG_PATH = os.path.expanduser("~/.uberclock")
+CONFIG_PATH = os.path.expanduser("~/.config/uberclock")
if not os.path.exists(CONFIG_PATH):
os.mkdir(CONFIG_PATH)
@@ -20,7 +20,7 @@
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
- 'NAME': os.path.expanduser('~/.uberclock/db.sqlite'), # Or path to database file if using sqlite3.
+ 'NAME': os.path.join(CONFIG_PATH, "db.sqlite"), # Or path to database file if using sqlite3.
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
@@ -137,6 +137,9 @@
# hight in meters above normal hight
CLOCK_ALTITUDE = None
+# 5 minutes snooze time
+DEFAULT_SNOOZE_TIME = 5 * 60
+
CHUMBY_URLS = {
'default' : '<embed width="800" height="480" quality="high" bgcolor="#FFFFFF" wmode="transparent" name="virtualchumby" type="application/x-shockwave-flash" src="http://www.chumby.com/virtualchumby_noskin.swf" FlashVars="_chumby_profile_url=http%3A%2F%2Fwww.chumby.com%2Fxml%2Fvirtualprofiles%2FE8E34C1E-726B-11DF-BA50-001B24F07EF4&amp;baseURL=http%3A%2F%2Fwww.chumby.com" pluginspage="http://www.macromedia.com/go/getflashplayer"></embed>'
}
View
40 tools/__init__.py
@@ -0,0 +1,40 @@
+class Enumeration(object):
+ """
+ Enumeration class for constants
+ """
+ __slots__ = '_name', '_lookup'
+
+ def __init__(self, name, enumlist):
+ self._name = name
+ lookup = {}
+ i = 0
+ for x in enumlist:
+ if type(x) is tuple:
+ x, i = x
+ if type(x) is not str:
+ raise TypeError, "enum name is not a string: " + x
+ if type(i) is not int:
+ raise TypeError, "enum value is not an integer: " + i
+ if x in lookup:
+ raise ValueError, "enum name is not unique: " + x
+ if i in lookup:
+ raise ValueError, "enum value is not unique for " + x
+ lookup[x] = i
+ lookup[i] = x
+ i = i + 1
+ self._lookup = lookup
+
+ def __getattr__(self, attr):
+ try:
+ return self._lookup[attr]
+ except KeyError:
+ raise AttributeError, attr
+
+ def whatis(self, value):
+ """
+ Return the name that represents this value
+ """
+ return self._lookup[value]
+
+ def __repr__(self):
+ return '<Enumeration %s>' %self._name
View
15 tools/date.py
@@ -0,0 +1,15 @@
+import datetime
+
+def time_to_next_datetime(time, dt=None):
+ """
+ Returns the next valid datetime object for a given
+ datetime.time object
+ """
+ if not dt:
+ dt = datetime.datetime.now()
+
+ res = datetime.datetime.combine(dt.date(), time)
+ if res < datetime.datetime.now():
+ res = res + datetime.timedelta(days=1)
+ return res
+
Please sign in to comment.
Something went wrong with that request. Please try again.