Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

updates to rpc, webclock, etc

adjusted models a bit
more work on rpc interfaces. made post interface of learndata work
finished und cleaned up the javascript stats display. you can now edit the supposed point so the heuristic can learn from it.
etc :-)
  • Loading branch information...
commit f3aa942f7bc6ea714f48d401e311763eec6e81dc 1 parent b9515f4
@poelzi authored
View
23 api/handlers.py
@@ -30,10 +30,25 @@ class SessionEntriesHandler(BaseHandler):
# return ('session_entries_handler', ['session'])
class SessionLearnHandler(BaseHandler):
- allowed_methods = ('GET','POST', 'PUT', 'DELETE')
+ allowed_methods = ('GET', 'POST', 'DELETE')
exclude = ('session',)
model = LearnData
-# @staticmethod
-# def resource_uri():
-# return ('session_learn_handler', ['session'])
+ def read(self, request, session=None):
+ return Session.objects.get(id=session).learndata
+
+ def create(self, request, *args, **kwargs):
+
+ session = Session.objects.get(id=kwargs["session"])
+ ld = session.learndata
+
+ for key in ["wake", "lights", "start", "stop"]:
+ if key in request.POST:
+ if session.entry_set.filter(id=request.POST[key]).count():
+ setattr(ld, "%s_id" %key, request.POST[key])
+ else:
+ setattr(ld, "%s_id" %key, None)
+
+ ld.save()
+
+ return ld
View
5 api/urls.py
@@ -11,10 +11,9 @@
urlpatterns = patterns('',
- #url(r'^docs/', show_docs),
url(r'^docs/', documentation_view),
url(r'^session/(?P<session>[^/]+)/learndata/', session_learn_handler, name="session_learn_handler"),
url(r'^session/(?P<session>[^/]+)/entries/', session_entries_handler, name="session_entries_handler"),
- url(r'^session/(?P<id>[^/]+)/', session_handler, name="session_handler"),
- url(r'^session/', session_list_handler, name="session_list_handler"),
+ url(r'^session/(?P<id>[^/]+)/$', session_handler, name="session_handler"),
+ url(r'^session/$', session_list_handler, name="session_list_handler"),
)
View
49 db/models.py
@@ -41,16 +41,32 @@ class Session(models.Model):
"""
One Sleep Session
"""
- start = models.DateTimeField("Start", null=False, auto_now_add=True, db_index=True)
- stop = models.DateTimeField("Stop", null=False, auto_now_add=True, db_index=True)
+ start = models.DateTimeField("Start", null=False, auto_now_add=True, editable=False)
+ stop = models.DateTimeField("Stop", null=False, auto_now_add=True, editable=False)
user = models.ForeignKey(User, null=True)
detector = models.ForeignKey(Detector, null=True)
typ = models.IntegerField("Type", default=0, choices=SESSION_TYPES)
wakeup = models.DateTimeField("Wakeup", null=True)
- rating = models.DecimalField("Rating", max_digits=1, decimal_places=0, null=True)
+ rating = models.IntegerField("Rating", null=True)
+ deleted = models.BooleanField("Deleted", default=False)
# Do we need this ?
#alone = models.BooleanField("Alone", null=True, default=True, help_text="Sleeping with someone else in the bed")
+ def save(self, *args, **kwargs):
+ super(Session, self).save(*args, **kwargs)
+ self.learndata
+
+ @property
+ def learndata(self):
+ if not self.id:
+ raise ValueError, "Session Object not saved"
+ try:
+ return self.learndata_set.all()[0]
+ except IndexError, e:
+ rv = LearnData(session=self)
+ rv.save()
+ return rv
+
@property
def week(self):
return self.start.isocalendar()[1]
@@ -58,6 +74,13 @@ def week(self):
def __repr__(self):
return "<Session %s %s-%s>" %(self.user, self.start, self.stop)
+ @property
+ def length(self):
+ s = (self.stop - self.start).seconds
+ hours, remainder = divmod(s, 3600)
+ minutes, seconds = divmod(remainder, 60)
+ return (hours, minutes, seconds)
+
class Entry(models.Model):
date = models.DateTimeField("Date", null=False, auto_now_add=True)
@@ -68,6 +91,24 @@ class Entry(models.Model):
def __repr__(self):
return "<Entry %s %d>" %(self.date, self.value)
+
+class LearnData(models.Model):
+ """
+ One Sleep Session
+ """
+ session = models.ForeignKey(Session, null=False)
+ lights = models.ForeignKey(Entry, related_name="learn_lights",
+ help_text="Where the lights should start dimming", null=True)
+ wake = models.ForeignKey(Entry, related_name="learn_wake",
+ help_text="Perfect wakeup point", null=True)
+ start = models.ForeignKey(Entry, related_name="learn_start",
+ help_text="When sleeping began", null=True)
+ stop = models.ForeignKey(Entry, related_name="learn_stop",
+ help_text="When sleep stopped", null=True)
+ learned = models.BooleanField(default=False)
+
+
+
class DBWriter(ez_chronos.CommandDispatcher):
def __init__(self, *args, **kwargs):
@@ -108,7 +149,7 @@ def smpl_0x03(self, data):
#FIXME add device & user
self.session[device] = session = Session(start=now, stop=now)
session.save()
- logging.debug("start new session: %s" %session.id)
+ logging.debug("start new session: %s @ %s" %(session.id, session.start))
else:
session = self.session[device]
self.last_msg[device] = now
View
27 settings.py
@@ -2,6 +2,7 @@
import os.path
+DEVELOPMENT_MODE = False
DEBUG = True
TEMPLATE_DEBUG = DEBUG
@@ -78,7 +79,8 @@
)
MIDDLEWARE_CLASSES = (
- 'django.middleware.common.CommonMiddleware',
+ 'piston.middleware.ConditionalMiddlewareCompatProxy',
+ 'piston.middleware.CommonMiddlewareCompatProxy',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
@@ -99,12 +101,14 @@
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
+ 'django.contrib.markup',
# 'django.contrib.messages',
# Uncomment the next line to enable the admin:
'django.contrib.admin',
'uberclock.db',
'uberclock.webclock',
'piston',
+ 'uberclock.api',
)
@@ -119,9 +123,30 @@
CLOCK_SESSION_TIMEOUT = 60*5
+PISTON_STREAM_OUTPUT = True
+
+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>'
+}
import os
if not os.path.exists(os.path.expanduser("~/.uberclock")):
os.mkdir(os.path.expanduser("~/.uberclock"))
+try:
+ from settings_local import *
+except ImportError:
+ import sys
+ sys.stderr.write('Unable to read settings_local.py\n')
+
+if DEVELOPMENT_MODE:
+ DATABASE_ENGINE = DATABASES['default']['ENGINE'].split('.')[-1]
+ INSTALLED_APPS += ('django_evolution',)
+
+try:
+ INSTALLED_APPS += ADDITIONAL_APPS
+except NameError:
+ pass
+
+#PISTON_DISPLAY_ERRORS = DEBUG
View
3  templates/base.html
@@ -38,7 +38,8 @@
</style>
-<script type="text/javascript" src="/static/js/jquery/jquery-1.3.2.min.js"></script>
+<!--<script type="text/javascript" src="/static/js/jquery/jquery-1.3.2.min.js"></script>-->
+<script type="text/javascript" src="/static/js/jquery/jquery-1.3.2.js"></script>
{% block header_base %}{% endblock %}
{% block header %}{% endblock %}
View
1  urls.py
@@ -15,6 +15,7 @@
(r'^static/(?P<path>.*)$', 'django.views.static.serve',
{'document_root': settings.STATIC_DOC_ROOT, 'show_indexes': True}),
+ (r'^api/', include('uberclock.api.urls')),
# Uncomment the next line to enable the admin:
(r'^admin/', include(admin.site.urls)),
(r'', include('uberclock.webclock.urls')),
View
24 webclock/templates/stats.html
@@ -1,4 +1,16 @@
{% extends "base.html" %}
+{% load webclock %}
+
+{% block menuextra %}
+<li class="toplink">
+<form id="stats_type_form">
+<select id="stats_type" name="typ">
+<option value="png" {%if "png" == current%}selected="1"{%endif%}>Image</option>
+<option value="js" {%if "js" == current%}selected="1"{%endif%}>Interactive</option>
+</select>
+</form>
+</li>
+{% endblock %}
{% block content %}
@@ -8,10 +20,16 @@
{% else %}
{% ifchanged session.week%}<h3>Week {{ session.start|date:"W" }}</h3>{% endifchanged %}
{% endif %}
-<a href="/stats/{{ session.id }}/">{{ session.start|date:"DATETIME_FORMAT" }} - {{ session.stop|date:"DATETIME_FORMAT" }}</a><br/>
-
-
+<a href="/stats/{{ session.id }}/" class="stats_detail">{{ session.start|date:"DATETIME_FORMAT" }} - {{ session.stop|date:"DATETIME_FORMAT" }} ({{session.length|timelengh}})</a><br/>
{% endfor %}
+{% block js_footer %}
+<script type="text/javascript">
+$('#stats_type').change(function() {
+ $('#stats_type_form').submit();
+});
+</script>
+{% endblock %}
+
{% endblock %}
View
210 webclock/templates/stats_detail_js.html
@@ -4,6 +4,7 @@
<!--[if IE]><script language="javascript" type="text/javascript" src="/static/js/jquery/excanvas.js"></script><![endif]-->
<script language="javascript" type="text/javascript" src="/static/js/jquery/jquery.jqplot.js"></script>
<link rel="stylesheet" type="text/css" href="/static/js/jquery/jquery.jqplot.css" />
+<script type="text/javascript" src="/static/js/jquery/jquery.json.min.js"></script>
<script type="text/javascript" src="/static/js/jquery/plugins/jqplot.dateAxisRenderer.min.js"></script>
<script type="text/javascript" src="/static/js/jquery/plugins/jqplot.canvasTextRenderer.min.js"></script>
@@ -19,29 +20,94 @@
{% if next %}<a href="{% url webclock.views.stats_detail next.id %}">Next</a>{% endif %}
</div>
<br />
-<div class="jqPlot" id="chart1" style="height:500px; width:800px;"></div>
-<div class="jqPlot" id="chart2" style="height:100px; width:200px;"></div>
+<table style="border:0px;">
+ <tr><td>
+ <div class="jqPlot" id="chart1" style="height:350px; width:600px;"></div>
+ </td>
+ <td style="text-align:center">
+ <div class="jqPlot" id="chart2" style="height:120px; width:180px;"></div>
+ <button onclick="controllerPlot1.resetZoom()">Reset Zoom</button><br/><br/><br/>
+ <p>Select type to edit:<br/>
+ <select id="selectType">
+ <option value="wake">Wakeup</option>
+ <option value="lights">Lights</option>
+ <option value="start">Start</option>
+ <option value="stop">End</option>
+ </select><br/>
+ <button id="buttonSave">Save</button>
+ </p>
+ </td></tr>
+</table>
{% endblock %}
{% block js_footer %}
<script type="text/javascript">
+
var Points = [];
+var Extra = [
+// wake
+[],
+// lights
+[],
+// start
+[],
+// end
+[]]
+
+var plot1 = null;
+var plot2 = null;
+var session_id = {{session.id}};
+
+function clickHandler(ev, gridpos, datapos, neighbor, plot) {
+ if(neighbor && plot1 && plot == plot1) {
+ typ = $("#selectType").attr("selectedIndex")
+
+ if (Extra[typ].length && neighbor.data[2] == Extra[typ][0][2]) {
+ Extra[typ] = []
+ } else {
+ date = new Date()
+ date.setTime(neighbor.data[0])
+ Extra[typ] = [[date, neighbor.data[1], neighbor.data[2]]]
+ }
+
+ plot1.series[typ+1].data = Extra[typ]
+ plot1.drawSeries(typ+1)
+ }
+}
+
+function parseLearn(data) {
+ var keys = ["wake", "lights", "start", "stop"];
+ for (i in keys) {
+ i = parseInt(i)
+ key = keys[i]
+ if(data[key]) {
+ date = new $.date(data[key].date)
+
+ Extra[i] = [[date,data[key].value,data[key].id]]
+ //Extra[i] = []
+ } else {
+ Extra[i] = []
+ }
+ }
+ // we have to replot here
+ plot1.replot()
+}
function draw(data) {
last = 0;
last_index = 0;
skiped = 0;
$.each(data, function(index, value) {
- if((last > value.value) && (last - value.value > 1000) ||
- (last < value.value) && (value.value - last > 1000)) {
+ if((last > value.value) && (last - value.value > 100) ||
+ (last < value.value) && (value.value - last > 100)) {
if(skiped)
- Points.push([skiped.date, skiped.value]);
- Points.push([value.date, value.value]);
+ Points.push([skiped.date, skiped.value, skiped.id]);
+ Points.push([value.date, value.value, value.id]);
last = value;
last_index = index;
} else if (index - last_index > 10) {
- Points.push([value.date, value.value]);
+ Points.push([value.date, value.value, value.id]);
last = value;
last_index = index;
} else {
@@ -49,66 +115,92 @@
}
});
-// $("#list").html("Name:"+datos[1].name+"<br>"+"Last Name:"+datos[1].lastname+"<br>"+"Address:"+datos[1].address);
-//console.log(Points);
- Plot();
+
+ plot();
+ $.getJSON("/api/session/{{session.id}}/learndata/","",parseLearn);
+
}
-var cosPoints = [];
-/*for (var i=0; i<2*Math.PI; i+=0.4){
- cosPoints.push([i, Math.cos(i)]);
-}
-var sinPoints = [];
-for (var i=0; i<2*Math.PI; i+=0.4){
- sinPoints.push([i, 2*Math.sin(i-.8)]);
-}
-var powPoints1 = [];
-for (var i=0; i<2*Math.PI; i+=0.4) {
- powPoints1.push([i, 2.5 + Math.pow(i/4, 2)]);
-}
-var powPoints2 = [];
-for (var i=0; i<2*Math.PI; i+=0.4) {
- powPoints2.push([i, -2.5 - Math.pow(i/4, 2)]);
-}
-*/
-function Plot() {
- plot1 = $.jqplot('chart1', [Points], {
+function send_learndata() {
+ data = {"dummy":1 }
+
+ if(Extra[0].length)
+ data["wake"] = Extra[0][0][2];
+ if(Extra[1].length)
+ data["lights"] = Extra[1][0][2];
+ if(Extra[2].length)
+ data["start"] = Extra[2][0][2];
+ if(Extra[3].length)
+ data["stop"] = Extra[3][0][2];
+ send_dict = {
+ url: "/api/session/"+session_id+"/learndata/",
+ type: "POST",
+ data: $.param(data),
+ processData: false,
+ dataType: "json",
+ contentType: "application/x-www-form-urlencoded",
+ success: function(json, textStatus) {
+ parseLearn(json);
+ //$.each([json], success_callback);
+ },
+ };
+ $.ajax(send_dict);
+ return false;
+};
+
+
+function plot() {
+ //global plot1, plot2;
+ plot1 = $.jqplot('chart1', [Points, Extra[0], Extra[1], Extra[2], Extra[3]], {
title:'{{ session.start|date }} - {{ session.stop|date }}',
axes:{xaxis:{renderer:$.jqplot.DateAxisRenderer,
- tickOptions:{formatString:'%H:%M'},
+ tickOptions:{formatString:'%H:%M:%S',
+ angle: -30},
}},
series:[
- {lineWidth:1, markerOptions:{size: 2, style:'x'}},
- /* {showLine:false, markerOptions:{size: 7, style:'x'}},
- {markerOptions:{style:'circle'}},
- {lineWidth:5, markerOptions:{style:'filledSquare', size:14}}
- */
- ]
- });
-
+ {lineWidth:1, markerOptions:{size: 2, style:'x'} },
+ {lineWidth:0, markerOptions:{size: 7, style:'filledSquare'},
+ color: "#FF0000" },
+ {lineWidth:0, markerOptions:{size: 7, style:'filledSquare'},
+ color: "#F0F000" },
+ {lineWidth:0, markerOptions:{size: 7, style:'dot'},
+ color: "#00FF00" },
+ {lineWidth:0, markerOptions:{size: 7, style:'dot'},
+ color: "#00FFFF" },
+ ],
+ }
+ );
controllerPlot1 = $.jqplot('chart2', [Points], {
- seriesDefaults:{showMarker: false},
- series:[
- {lineWidth:1, showMarker: false},
- ],
- cursor:{
- zoom:true,
- showTooltip: false
- },
- axesDefaults:{
- tickOptions:{
- showLabel:false,
- showMark:false
- }
- },
- axes:{xaxis:{renderer:$.jqplot.DateAxisRenderer,
- tickOptions:{formatString:'%H:%M'},
- }},
-});
-
-$.jqplot.Cursor.zoomProxy(plot1, controllerPlot1);
+ seriesDefaults:{showMarker: false},
+ series:[
+ {lineWidth:1, showMarker: false},
+ ],
+ cursor:{
+ zoom:true,
+ showTooltip: false
+ },
+ axesDefaults:{
+ tickOptions:{
+ showLabel:false,
+ showMark:false
+ }
+ },
+ highlighter: {
+ show:false,
+ },
+ axes:{xaxis:{renderer:$.jqplot.DateAxisRenderer,
+ tickOptions:{formatString:'%H:%M'},
+ }},
+ });
+ $.jqplot.Cursor.zoomProxy(plot1, controllerPlot1);
}
-Plot();
+// create empty plot
+plot();
+
+$.jqplot.eventListenerHooks.push(['jqplotClick', clickHandler]);
+
+
+$('#buttonSave').click(send_learndata)
$.getJSON("/api/session/{{session.id}}/entries/","",draw);
</script>
View
6 webclock/templates/webclock/index/chumby.html
@@ -1,8 +1,6 @@
{% extends "webclock/index/base_clock.html" %}
-webclock_name Chumby
-
-
{% block content %}
-<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>
+
+{{ chumby_code|safe }}
{% endblock %}
View
63 webclock/views.py
@@ -1,9 +1,12 @@
# Create your views here.
# Create your views here.
+import datetime, os, re
+
+
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
from django.http import HttpResponse
-import datetime, os, re
+from django.conf import settings
from uberclock.db.models import Entry, Session
INDEX_PATH = os.path.join(os.path.dirname(__file__),
@@ -20,23 +23,32 @@ def get_clock_types():
match = re.search("webclock_name (.*)", content)
if match:
res[os.path.basename(item)] = match.group(1)
+ for name in settings.CHUMBY_URLS:
+ res["chumby_%s" %name] = "Chumby: %s" %name
return res
def index(request):
types = get_clock_types()
+ data = {"types": types}
+
+
typ = request.COOKIES.get("webclock_clock", "simple.html")
typ = request.GET.get("typ", typ)
- if not typ in types:
- typ = "simple.html"
+
+ if typ[:7] == 'chumby_':
+ data["chumby_code"] = settings.CHUMBY_URLS.get(typ[7:], "")
+ template = "chumby.html"
+ else:
+ if not typ in types:
+ typ = "simple.html"
+ template = typ
- data = {"types": types,
- "current": typ,
- }
+ data["current"] = typ
- ret = render_to_response('webclock/index/%s' %typ,
+ ret = render_to_response('webclock/index/%s' %template,
data,
context_instance=RequestContext(request))
@@ -48,16 +60,29 @@ def index(request):
def stats(request):
now = datetime.datetime.now()
+
+ typ = request.COOKIES.get("webclock_stats", "png")
+ typ = request.GET.get("typ", typ)
+
+ if typ not in ["js", "png"]:
+ typ = "png"
+
data = {
'now': now,
'now_week': now.isocalendar()[1],
- 'sessions': Session.objects.all().order_by("-id")
+ 'sessions': Session.objects.all().order_by("-id"),
+ 'current': typ
}
- return render_to_response('stats.html',
+ ret = render_to_response('stats.html',
data,
context_instance=RequestContext(request))
+ if request.COOKIES.get("webclock_stats", "png") != typ:
+ ret.set_cookie("webclock_stats", value=typ)
+
+ return ret
+
def stats_detail(request, session):
now = datetime.datetime.now()
sess = get_object_or_404(Session, id__exact=session)
@@ -74,18 +99,34 @@ def stats_detail(request, session):
else:
prev = None
+ typ = request.COOKIES.get("webclock_stats", "png")
+ typ = request.GET.get("typ", typ)
+
+ if typ == "js":
+ template = 'stats_detail_js.html'
+
+ else:
+ template = 'stats_detail.html'
+ typ = "png"
+
data = {
'prev': prev,
'next': next,
'now': now,
'now_week': now.isocalendar()[1],
- 'session': sess
+ 'session': sess,
+ 'current': typ
}
- return render_to_response('stats_detail.html',
+ ret = render_to_response(template,
data,
context_instance=RequestContext(request))
+
+ if request.COOKIES.get("webclock_stats", "png") != "png":
+ ret.set_cookie("webclock_stats", value=typ)
+
+ return ret
# file charts.py
Please sign in to comment.
Something went wrong with that request. Please try again.