started
|
|
@ -0,0 +1,20 @@
|
||||||
|
|
||||||
|
from flask import Flask, Response, json, jsonify, render_template, send_from_directory
|
||||||
|
import requests
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
thermoRoute = "http://192.168.178.25:5000/"
|
||||||
|
|
||||||
|
@app.route('/<path:path>')
|
||||||
|
def send_js(path):
|
||||||
|
return send_from_directory('', path)
|
||||||
|
|
||||||
|
@app.route("/")
|
||||||
|
def root():
|
||||||
|
return render_template("index2.html")
|
||||||
|
|
||||||
|
@app.route("/stats")
|
||||||
|
def stats():
|
||||||
|
return jsonify(requests.get(thermoRoute).json())
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
/* colours */
|
||||||
|
:root{
|
||||||
|
--primary: #FFE9D2;
|
||||||
|
--secondary: #FFE1C4;
|
||||||
|
--title: #FF8816;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* layout styles */
|
||||||
|
nav{
|
||||||
|
background: var(--primary);
|
||||||
|
border-bottom: 10px solid var(--secondary);
|
||||||
|
}
|
||||||
|
nav a{
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--title);
|
||||||
|
}
|
||||||
|
nav a span{
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
nav .sidenav-trigger{
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* recipe styles */
|
||||||
|
.recipes{
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.card-panel.recipe{
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px;
|
||||||
|
box-shadow: 0px 1px 3px rgba(90,90,90,0.1);
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 2fr 6fr 1fr;
|
||||||
|
grid-template-areas: "image details delete";
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.recipe img{
|
||||||
|
grid-area: image;
|
||||||
|
max-width: 60px;
|
||||||
|
}
|
||||||
|
.recipe-details{
|
||||||
|
grid-area: details;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
.recipe-delete{
|
||||||
|
grid-area: delete;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0px;
|
||||||
|
right: 0px;
|
||||||
|
}
|
||||||
|
.recipe-delete i{
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
.recipe-title{
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.recipe-ingredients{
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* form-styles */
|
||||||
|
.add-btn{
|
||||||
|
background: var(--title) !important;
|
||||||
|
}
|
||||||
|
input{
|
||||||
|
box-shadow: none !important;
|
||||||
|
-webkit-box-shadow: none !important;
|
||||||
|
}
|
||||||
|
.side-form button{
|
||||||
|
background: var(--title);
|
||||||
|
box-shadow: 1px 1px 3px rgba(90,90,90,0.2);
|
||||||
|
}
|
||||||
|
form .input-field{
|
||||||
|
margin-top: 30px;
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
|
@ -0,0 +1,5 @@
|
||||||
|
if('serviceWorker' in navigator){
|
||||||
|
navigator.serviceWorker.register('/static/sw.js')
|
||||||
|
.then(reg => console.log('service worker registered', reg))
|
||||||
|
.catch(err => console.log('service worker not registered', err));
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
const dbconnect = window.indexedDB.open('temps', 1);
|
||||||
|
var db = null
|
||||||
|
|
||||||
|
const interval = setInterval(writeTo, 5000);
|
||||||
|
|
||||||
|
|
||||||
|
dbconnect.onupgradeneeded = ev => {
|
||||||
|
console.log('Upgrade DB');
|
||||||
|
const db = ev.target.result;
|
||||||
|
let store = db.createObjectStore('Temperatures', { keyPath: 'timestamp'});
|
||||||
|
store.createIndex("timestamp", "timestamp", { unique: false });
|
||||||
|
store.createIndex("temp", "temp", { unique: false });
|
||||||
|
|
||||||
|
store = db.createObjectStore('Humidities', { keyPath: 'timestamp'});
|
||||||
|
store.createIndex("timestamp", "timestamp", { unique: false });
|
||||||
|
store.createIndex("humidity", "humidity", { unique: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dbconnect.onsuccess = ev => {
|
||||||
|
console.log('DB-Upgrade erfolgreich');
|
||||||
|
db = ev.target.result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function write(type, data){
|
||||||
|
const transaction = db.transaction(type, 'readwrite');
|
||||||
|
const store = transaction.objectStore(type);
|
||||||
|
|
||||||
|
data.forEach(el => store.add(el));
|
||||||
|
|
||||||
|
transaction.onerror = ev => {
|
||||||
|
console.error('Ein Fehler ist aufgetreten!', ev.target.error.message);
|
||||||
|
};
|
||||||
|
|
||||||
|
transaction.oncomplete = ev => {
|
||||||
|
//console.log('Daten wurden erfolgreich hinzugefügt! ' + type);
|
||||||
|
const store = db.transaction(type, 'readonly').objectStore(type);
|
||||||
|
//const query = store.get(1); // Einzel-Query
|
||||||
|
const query = store.openCursor()
|
||||||
|
query.onerror = ev => {
|
||||||
|
console.error('Anfrage fehlgeschlagen!', ev.target.error.message);
|
||||||
|
};
|
||||||
|
|
||||||
|
query.onsuccess = ev => {
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeTo(){
|
||||||
|
|
||||||
|
getJSON("/stats",
|
||||||
|
function (error, data) {
|
||||||
|
let date = new Date()
|
||||||
|
let time = date.getTime()
|
||||||
|
let writeData = [
|
||||||
|
{timestamp: time, temp: data["temperature"]}
|
||||||
|
];
|
||||||
|
|
||||||
|
write("Temperatures", writeData)
|
||||||
|
|
||||||
|
writeData = [
|
||||||
|
{timestamp: time, temp: data["humidity"]}
|
||||||
|
];
|
||||||
|
|
||||||
|
write("Humidities", writeData)
|
||||||
|
},
|
||||||
|
function(){
|
||||||
|
console.log("Error while getting temps")
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: replace with fetch
|
||||||
|
function getJSON(url, callback, fallback) {
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('GET', url, true);
|
||||||
|
xhr.responseType = 'json';
|
||||||
|
xhr.onload = function () {
|
||||||
|
var status = xhr.status;
|
||||||
|
if (status < 400) {
|
||||||
|
callback(null, xhr.response);
|
||||||
|
} else {
|
||||||
|
fallback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhr.send();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function readLast(n){
|
||||||
|
let objectStore = db.transaction("Temperatures").objectStore("Temperatures");
|
||||||
|
let data = [];
|
||||||
|
|
||||||
|
objectStore.openCursor(null, "prev").onsuccess = function(event) {
|
||||||
|
var cursor = event.target.result;
|
||||||
|
if (cursor && data.length < n) {
|
||||||
|
//console.log(cursor.value);
|
||||||
|
data.push(cursor.value)
|
||||||
|
cursor.continue();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
{
|
||||||
|
"name": "Thermo",
|
||||||
|
"short_name": "thermo",
|
||||||
|
"start_url": "/index.html",
|
||||||
|
"display": "standalone",
|
||||||
|
"background_color": "#FFE9D2",
|
||||||
|
"theme_color": "#FFE1C4",
|
||||||
|
"orientation": "portrait-primary",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "/static/img/icons/icon-72x72.png",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "72x72"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/static/img/icons/icon-96x96.png",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "96x96"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/static/img/icons/icon-128x128.png",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "128x128"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/static/img/icons/icon-144x144.png",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "144x144"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/static/img/icons/icon-152x152.png",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "152x152"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/static/img/icons/icon-192x192.png",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "192x192"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/static/img/icons/icon-384x384.png",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "384x384"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/static/img/icons/icon-512x512.png",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "512x512"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
// install event
|
||||||
|
self.addEventListener('install', evt => {
|
||||||
|
console.log('service worker installed');
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<title>thermo</title>
|
||||||
|
<link type="text/css" href="/static/css/styles.css" rel="stylesheet">
|
||||||
|
|
||||||
|
<link rel="manifest" href="/static/manifest.json">
|
||||||
|
<!-- ios support -->
|
||||||
|
<link rel="apple-touch-icon" href="/static/img/icons/icon-96x96.png">
|
||||||
|
<meta name="apple-mobile-web-app-status-bar" content="#FFE1C4">
|
||||||
|
</head>
|
||||||
|
<body class="grey lighten-4">
|
||||||
|
<script src="/static/js/app.js"></script>
|
||||||
|
<script src="/static/js/ui.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<title>thermo</title>
|
||||||
|
<link type="text/css" href="/static/css/styles.css" rel="stylesheet">
|
||||||
|
<!-- ios support -->
|
||||||
|
<link rel="apple-touch-icon" href="/static/img/icons/icon-96x96.png">
|
||||||
|
<meta name="apple-mobile-web-app-status-bar" content="#FFE1C4">
|
||||||
|
</head>
|
||||||
|
<body class="grey lighten-4">
|
||||||
|
<canvas id="line-chart" width="800" height="450"></canvas>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
|
||||||
|
<script>
|
||||||
|
//https://www.chartjs.org/docs/latest/developers/updates.html
|
||||||
|
new Chart(document.getElementById("line-chart"), {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
labels: [1500,1600,1700,1750,1800,1850,1900,1950,1999,2050],
|
||||||
|
datasets: [{
|
||||||
|
data: [86,114,106,106,107,111,133,221,783,2478],
|
||||||
|
label: "Temperature",
|
||||||
|
borderColor: "#3e95cd",
|
||||||
|
fill: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
title: {
|
||||||
|
display: true,
|
||||||
|
text: 'Climate'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script src="/static/js/ui.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||