Created
July 29, 2014 12:33
-
-
Save errkk/e51da8468809ac7349b6 to your computer and use it in GitHub Desktop.
Data Display for solar panel data
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django import forms | |
from .models import Temperature, PumpEvent | |
class TemperatureForm(forms.ModelForm): | |
class Meta: | |
model = Temperature | |
exclude = ('timestamp', ) | |
class PumpEventForm(forms.ModelForm): | |
class Meta: | |
model = PumpEvent | |
fields = ('is_on', ) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.db import models | |
FLOW_RATE = 25 # Measured for our system | |
class BaseReading(models.Model): | |
class Meta: | |
abstract = True | |
ordering = ['timestamp', ] | |
get_latest_by = 'timestamp' | |
timestamp = models.DateTimeField(auto_now_add=True) | |
class Temperature(BaseReading): | |
""" Model to reperesent a temperature reading | |
""" | |
t1 = models.FloatField('Input to pool', blank=True, null=True) | |
t2 = models.FloatField('Output from panels', blank=True, null=True) | |
t3 = models.FloatField('Output from pool', blank=True, null=True) | |
t4 = models.FloatField('Air Temp', blank=True, null=True) | |
def __unicode__(self): | |
return '{0}, {1}, {2}, {3} @ {4}'.format( | |
self.t1, | |
self.t2, | |
self.t3, | |
self.t4, | |
self.timestamp, | |
) | |
def get_uplift(self): | |
if self.t1 and self.t2: | |
return self.t2 - self.t1 | |
return 0 | |
def get_power(self): | |
""" Calculate power from temperature uplift to known flow rate | |
""" | |
uplift = self.get_uplift() | |
grams = 1000.0 * FLOW_RATE / 60 | |
calories = uplift * grams | |
return int(calories * 4.2) | |
class PumpEvent(BaseReading): | |
""" Logs the switching of the pump | |
""" | |
is_on = models.BooleanField(default=False) | |
def __unicode__(self): | |
return 'On' if self.is_on else 'Off' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import redis | |
import json | |
from datetime import timedelta, datetime | |
from django.http import HttpResponse, HttpResponseRedirect | |
from django.shortcuts import render | |
from django.core.urlresolvers import reverse | |
from django.views.generic.base import View | |
from django.views.generic import (FormView, CreateView, WeekArchiveView, | |
RedirectView, TemplateView) | |
from django.views.generic.dates import DateMixin, WeekMixin | |
from .forms import TemperatureForm, PumpEventForm | |
from .models import Temperature, PumpEvent | |
conn = redis.StrictRedis() | |
from django.views.decorators.csrf import csrf_exempt | |
class TemperatureView(CreateView): | |
form_class = TemperatureForm | |
template_name = 'bootstrap/form.html' | |
def get_success_url(self): | |
return reverse('panel:temperature_form') | |
class PumpEventView(CreateView): | |
form_class = PumpEventForm | |
template_name = 'bootstrap/form.html' | |
def get_success_url(self): | |
return reverse('panel:pumpevent_form') | |
class ChartDataMixin: | |
""" Formatter for temperature data to make it go into the D3 chart | |
""" | |
def get_chart_data(self, **kwargs): | |
queryset = kwargs.pop('object_list') | |
t1, t2, t3, t4 = [], [], [], [] | |
power = [] | |
for i in queryset: | |
timestamp = i.timestamp.strftime("%s") | |
t1.append({'x': timestamp, 'y': i.t1}) | |
t2.append({'x': timestamp, 'y': i.t2}) | |
t3.append({'x': timestamp, 'y': i.t3}) | |
t4.append({'x': timestamp, 'y': i.t4}) | |
data = [ | |
{'key': 'Into Pool', 'values' : t1}, | |
{'key': 'From Panel', 'values' : t2}, | |
{'key': 'From Pool', 'values' : t3}, | |
{'key': 'Air', 'values' : t4}, | |
] | |
context = { | |
'data': json.dumps(data), | |
'object_list': queryset, | |
} | |
return context | |
class DataLp(TemplateView, ChartDataMixin, DateMixin, WeekMixin): | |
""" Landing page for the data section. | |
Has current data from sensors and external services, also the chart | |
for the current week | |
""" | |
template_name = 'panel/index.html' | |
model = Temperature | |
date_field = 'timestamp' | |
def get_today_queryset(self): | |
""" Get temperature datapoints for the current day | |
Different to how WeekArchiveView does it, as that filters qs after | |
""" | |
now = datetime.now() | |
since = self._make_date_lookup_arg(now) | |
until = self._make_date_lookup_arg(self._get_next_week(now)) | |
qs = Temperature.objects.filter(timestamp__range=[since, until]) | |
return qs | |
def get_power(self): | |
t = Temperature.objects.latest() | |
return t.get_power() | |
def get_context_data(self, **kwargs): | |
power = 0 | |
try: | |
pump = PumpEvent.objects.latest() | |
except PumpEvent.DoesNotExist: | |
pump = None | |
else: | |
if pump.is_on: | |
power = self.get_power() | |
weather = json.loads(conn.get('FORECAST.IO')) | |
now = datetime.now() | |
last_week = now - timedelta(weeks=1) | |
object_list = self.get_today_queryset() | |
context = self.get_chart_data(object_list=object_list) | |
context['previous_week'] = last_week | |
context['pump'] = pump | |
context['power'] = power / 1000.0 | |
if weather: | |
context['weather_updated'] = datetime.fromtimestamp( | |
int(weather['time'])) | |
context['summary'] = weather['summary'] | |
context.update(kwargs) | |
return super(DataLp, self).get_context_data(**context) | |
data = DataLp.as_view() | |
class TemperatureArchive(WeekArchiveView, ChartDataMixin): | |
""" Display temperature data in a weekly chart, using CBV magic to filter | |
by date field | |
""" | |
date_field = 'timestamp' | |
make_object_list = True | |
allow_future = False | |
queryset = Temperature.objects.all() | |
allow_empty = False | |
def get_context_data(self, **kwargs): | |
context = self.get_chart_data(**kwargs) | |
context.update(kwargs) | |
return super(TemperatureArchive, self).get_context_data(**context) | |
temperature_archive_view = TemperatureArchive.as_view() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment