Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5e6b4153e6 | |||
| 66e86ab621 |
@@ -0,0 +1,74 @@
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.utils import timezone
|
||||
from django.conf import settings
|
||||
from coffee_scale.models import Brewing
|
||||
|
||||
import paho.mqtt.client as mqtt
|
||||
import random
|
||||
|
||||
brewing = False
|
||||
lastbrew = timezone.now()
|
||||
lastcups = 0
|
||||
|
||||
|
||||
def on_connect(client, userdata, flags, rc):
|
||||
if rc != 0:
|
||||
print("Failed to connect with result code: {}".format(rc))
|
||||
|
||||
print("Connected with result code: {}".format(rc))
|
||||
client.subscribe(settings.MQTT_SETTINGS.HOST.TOPICS.CUPS)
|
||||
client.subscribe(settings.MQTT_SETTINGS.HOST.TOPICS.BREWING)
|
||||
client.subscribe(settings.MQTT_SETTINGS.HOST.TOPICS.BREW_TIME)
|
||||
|
||||
|
||||
def on_message(client, userdata, message):
|
||||
print("%s %s".format(message.topic, message.payload.decode()))
|
||||
|
||||
|
||||
def on_message_cups(client, userdata, message):
|
||||
cups = int(message.payload.decode())
|
||||
print("cups: {}".format(cups))
|
||||
print("{}".format(timezone.now()))
|
||||
|
||||
# checks if new coffee was brewed so we don't add the same brewing again to db
|
||||
global lastcups # ;/ have to use global to store state instead of class
|
||||
if cups > lastcups:
|
||||
new_brew = Brewing(cups=cups, time=timezone.now())
|
||||
print(new_brew.time)
|
||||
new_brew.save()
|
||||
lastcups = cups
|
||||
|
||||
|
||||
def on_message_brewtime(client, userdata, message):
|
||||
brewtime = datetime.fromtimestamp(int(message.payload.decode()))
|
||||
print("brewtime: {}".format(brewtime))
|
||||
|
||||
|
||||
def on_message_brewing(client, userdata, message):
|
||||
brewing = bool(int(message.payload.decode()))
|
||||
print("brewing: {}".format(brewing))
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Fetches coffee mqtt messages"
|
||||
|
||||
def add_arquments(self, parser):
|
||||
pass
|
||||
|
||||
def handle(self, *args, **options):
|
||||
self.username = "coffee-user-%d".format(random.randint(0, 100))
|
||||
self.client = mqtt.Client("coffee")
|
||||
self.client.username_pw_set(self.username, password=None)
|
||||
self.client.tls_set()
|
||||
|
||||
# callbacks for different topics
|
||||
self.client.message_callback_add(settings.MQTT_SETTINGS.HOST.TOPICS.BREW_TIME, on_message_brewtime)
|
||||
self.client.message_callback_add(settings.MQTT_SETTINGS.HOST.TOPICS.CUPS, on_message_cups)
|
||||
self.client.message_callback_add(settings.MQTT_SETTINGS.HOST.TOPICS.BREWING, on_message_brewing)
|
||||
|
||||
# self.client.connect("localhost", port=1883) # used for local testing
|
||||
self.client.connect(settings.MQTT_SETTINGS.HOST, port=settings.MQTT_SETTINGS.PORT)
|
||||
self.client.on_message = on_message
|
||||
self.client.on_connect = on_connect
|
||||
while True:
|
||||
self.client.loop()
|
||||
@@ -0,0 +1,24 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2017-11-19 10:55
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Brewing',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('cups', models.PositiveSmallIntegerField()),
|
||||
('time', models.DateTimeField()),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -1,3 +1,6 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
|
||||
class Brewing(models.Model):
|
||||
cups = models.PositiveSmallIntegerField()
|
||||
time = models.DateTimeField()
|
||||
|
||||
@@ -5,6 +5,7 @@ from infoscreen.models import Rotation, InfoItem, InfoInstance
|
||||
from infoscreen.models import ImageInfoItem, ExternalImageInfoItem, ABBInfoItem
|
||||
from infoscreen.models import ExternalWebsiteInfoItem
|
||||
from infoscreen.models import VideoInfoItem
|
||||
from infoscreen.models import CoffeeStatsInfoItem
|
||||
|
||||
# Register your models here.
|
||||
admin.site.register(Rotation)
|
||||
@@ -15,3 +16,4 @@ admin.site.register(ABBInfoItem)
|
||||
admin.site.register(InfoInstance)
|
||||
admin.site.register(ExternalWebsiteInfoItem)
|
||||
admin.site.register(VideoInfoItem)
|
||||
admin.site.register(CoffeeStatsInfoItem)
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2017-11-19 14:41
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('infoscreen', '0006_delete_hsldatamodel'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='CoffeeStatsInfoItem',
|
||||
fields=[
|
||||
('infoitem_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='infoscreen.InfoItem')),
|
||||
],
|
||||
bases=('infoscreen.infoitem',),
|
||||
),
|
||||
]
|
||||
@@ -269,6 +269,21 @@ class HslInfoItem(InfoItem):
|
||||
return "/static/html/hsl_create.html"
|
||||
|
||||
|
||||
class CoffeeStatsInfoItem(InfoItem):
|
||||
"""Class for Coffee statistics Infoscreen item."""
|
||||
|
||||
display_name = _("Coffee statistics")
|
||||
|
||||
def get_template_url(self):
|
||||
"""Return HSL infoitem template url."""
|
||||
return "/static/html/coffee_stats.html"
|
||||
|
||||
@staticmethod
|
||||
def get_create_template_url():
|
||||
"""Call create HSL infoitem template url command."""
|
||||
return "/static/html/coffee_stats_create.html"
|
||||
|
||||
|
||||
class ExternalImageInfoItem(InfoItem):
|
||||
"""Class for External Image Infoscreen item."""
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<link rel="stylesheet" href="/static/css/hsl.css">
|
||||
<link href="https://fonts.googleapis.com/css?family=Droid+Sans+Mono" rel="stylesheet">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.19.1/locale/fi.js"></script>
|
||||
<script type="text/javascript" src="dygraph.js"></script>
|
||||
<link rel="stylesheet" src="dygraph.css" /></head>
|
||||
|
||||
<div class="container" ng-controller="CoffeeStatsController">
|
||||
<div id="div_g"></div>
|
||||
</div>
|
||||
@@ -0,0 +1,11 @@
|
||||
<div ng-controller="infoadmin_coffeestatsitem_create" style="margin-top:20px;">
|
||||
<div>
|
||||
Create new item to show coffee statistics. Name is used only as identifier
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Name:</label>
|
||||
<input type="text" ng-model="item.name"></input>
|
||||
</div>
|
||||
<input type="button" class="btn btn-success" ng-click="send()" value="create"></input>
|
||||
</div>
|
||||
<!--maybe later add option to choose data range, daily, monthly...etc.
|
||||
@@ -186,5 +186,6 @@ var simple_controllers = [
|
||||
"hslitem",
|
||||
"websiteitem",
|
||||
"apyitem",
|
||||
"coffeestatsitem",
|
||||
];
|
||||
_.each(simple_controllers, controllerGenerator);
|
||||
|
||||
@@ -142,5 +142,19 @@ app.controller('timetableCtrl',
|
||||
|
||||
update_clock();
|
||||
load();
|
||||
});
|
||||
|
||||
app.controller('CoffeeStatsController', function($scope, $http) {
|
||||
function load() {
|
||||
$http.get('/infoscreen/coffee_data')
|
||||
.then(function(response) {
|
||||
const g = new Dygraph(document.getElementById('div_g'), response.data, {
|
||||
drawPoints: true,
|
||||
valueRange: [0, 10],
|
||||
labels: ['Time', 'Cups']
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
load();
|
||||
});
|
||||
|
||||
@@ -26,6 +26,8 @@ from infoscreen.views import CurrentHSLView
|
||||
from infoscreen.views import createApyItem
|
||||
from infoscreen.views import hsl_timetable_settings
|
||||
from infoscreen.views import get_apy_json
|
||||
from infoscreen.views import createCoffeeStatsItem
|
||||
from infoscreen.views import CoffeeStatsView
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', default),
|
||||
@@ -45,6 +47,7 @@ urlpatterns = [
|
||||
url(r'^create_sossoitem$', createSossoItem),
|
||||
url(r'^create_eventitem$', createEventItem),
|
||||
url(r'^create_hslitem$', createHslItem),
|
||||
url(r'^create_coffeestatsitem$', createCoffeeStatsItem),
|
||||
url(r'^create_apyitem$', createApyItem),
|
||||
url(r'^create_websiteitem$', createExternalWebsiteItem),
|
||||
url(r'^create_rotation$', create_rotation),
|
||||
@@ -52,5 +55,6 @@ urlpatterns = [
|
||||
url(r'^hsl_data$', CurrentHSLView),
|
||||
url(r'^hsl_data/settings$', hsl_timetable_settings),
|
||||
url(r'^apyjson', get_apy_json),
|
||||
url(r'^coffee_data$', CoffeeStatsView),
|
||||
|
||||
]
|
||||
|
||||
@@ -22,6 +22,7 @@ from infoscreen.models import ExternalWebsiteInfoItem
|
||||
from infoscreen.models import ImageUploadForm
|
||||
from infoscreen.models import ApyInfoItem
|
||||
from infoscreen.models import VideoInfoItem
|
||||
from infoscreen.models import CoffeeStatsInfoItem
|
||||
|
||||
|
||||
@login_required(login_url='/login')
|
||||
@@ -188,3 +189,4 @@ createExternalWebsiteItem = create_item_generator(ExternalWebsiteInfoItem)
|
||||
createEventItem = create_item_generator(EventInfoItem)
|
||||
createApyItem = create_item_generator(ApyInfoItem)
|
||||
createVideoItem = create_item_generator(VideoInfoItem)
|
||||
createCoffeeStatsItem = create_item_generator(CoffeeStatsInfoItem)
|
||||
|
||||
@@ -2,8 +2,11 @@ from django.shortcuts import render
|
||||
from django.http import HttpResponse, JsonResponse, HttpResponseBadRequest
|
||||
from django.views.decorators.http import require_http_methods
|
||||
from django.conf import settings
|
||||
from django.utils import timezone
|
||||
from django.db.models.functions import ExtractWeek
|
||||
|
||||
from infoscreen.models import Rotation, InfoItem, InfoInstance
|
||||
from coffee_scale.models import Brewing
|
||||
from infoscreen.hsl_fetcher import fetch as hsl_fetch
|
||||
|
||||
import json
|
||||
@@ -99,3 +102,15 @@ def CurrentHSLView(request, *args, **kwargs):
|
||||
return JsonResponse(error, status=200)
|
||||
|
||||
return JsonResponse(api_resp, status=200, safe=False)
|
||||
|
||||
|
||||
@require_http_methods(["GET"])
|
||||
def CoffeeStatsView(request, *args, **kwargs):
|
||||
# stats_data = Brewing.objects.annotate(
|
||||
# week=ExtractWeek('time')).values('week').get(time__week=timezone.now().isocalendar()[2])
|
||||
# do filtering here based on the data we want to show
|
||||
stats_data = {}
|
||||
for entry in Brewing.objects.all():
|
||||
stats_data[entry.id] = {'cups': entry.cups, 'time': entry.time}
|
||||
|
||||
return JsonResponse(stats_data, status=200, safe=False)
|
||||
|
||||
+4
-1
@@ -14,11 +14,14 @@
|
||||
"author": "SIK ry",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"dygraphs": "^2.0.0",
|
||||
"eslint": "3.19.0",
|
||||
"remark-cli": "^4.0.0",
|
||||
"remark-preset-lint-recommended": "^3.0.1"
|
||||
},
|
||||
"remarkConfig": {
|
||||
"plugins": ["remark-preset-lint-recommended"]
|
||||
"plugins": [
|
||||
"remark-preset-lint-recommended"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,3 +33,4 @@ django-import-export==0.5.1
|
||||
django-password-reset==1.0
|
||||
pyexcel==0.5.6
|
||||
pyexcel-xlsx==0.5.2
|
||||
paho-mqtt==1.3.1
|
||||
|
||||
Reference in New Issue
Block a user