diff --git a/api/get_data.py b/api/get_data.py index 944dd34..3c053e3 100644 --- a/api/get_data.py +++ b/api/get_data.py @@ -39,6 +39,9 @@ def get_data(): else: amount = int(request.args["amount"]) + if amount > row_count: + amount = row_count + compress_count = round(row_count / amount) print(">> Compressing from %s to %s values with interval %s" % (row_count, amount, compress_count)) diff --git a/api/insert_data.py b/api/insert_data.py index aef43ef..30c4153 100644 --- a/api/insert_data.py +++ b/api/insert_data.py @@ -23,7 +23,7 @@ def insert_data(): if current["weight"] - float(r_data["w"]) > 0.5: notifications.Feed().push_notification("warning", "Gewichtsabfall!", - "Das Gewicht ist bei der aktuellen Messung um %skg abgefallen!" + "Das Gewicht ist bei der aktuellen Messung um %sg abgefallen!" % str(round(float(r_data["w"]) - current["weight"], 2))) except Exception as e: print("Error while performing data checks!\n" diff --git a/pages/components/charts.html b/pages/components/charts.html index 5e4a5aa..ad58f65 100644 --- a/pages/components/charts.html +++ b/pages/components/charts.html @@ -5,13 +5,13 @@

Vergleichsansicht

-
- -
+
+ +

Gewicht

diff --git a/pages/components/current-data.html b/pages/components/current-data.html index 798a674..e653608 100644 --- a/pages/components/current-data.html +++ b/pages/components/current-data.html @@ -1,6 +1,6 @@

Aktuell

- +
diff --git a/pages/components/header.html b/pages/components/header.html index 3183b73..59232ef 100644 --- a/pages/components/header.html +++ b/pages/components/header.html @@ -1,12 +1,14 @@
- +
\ No newline at end of file diff --git a/pages/components/mainpage.html b/pages/components/mainpage.html new file mode 100644 index 0000000..048a44c --- /dev/null +++ b/pages/components/mainpage.html @@ -0,0 +1,52 @@ +
+ {% include './components/about-modal.html' %} + {% include './components/modals.html' %} + + + + + {% with weather=weather_data %} + {% include './components/weather.html' %} + {% endwith %} + + {% include './components/current-data.html' %} + +
+ +
+
+
+ Daten werden geladen... +
+
+
+

Die Daten werden aus unserer Datenbank abgerufen. Dies kann einen Moment dauern.

+
+
+
+ +
+ {% include './components/charts.html' %} +
+ + {% include './components/footer.html' %} +
\ No newline at end of file diff --git a/pages/components/modals.html b/pages/components/modals.html index 16db74e..21fb927 100644 --- a/pages/components/modals.html +++ b/pages/components/modals.html @@ -70,6 +70,13 @@

Zeitraum ändern Experimentelle Funktion< Datum an dem die angezeigten Daten enden sollen: +

+ +

+ Zeitspanne für die Berechnung von Delta Werten (in Minuten): diff --git a/pages/components/sidenav.html b/pages/components/sidenav.html index bce30a7..3edd3df 100644 --- a/pages/components/sidenav.html +++ b/pages/components/sidenav.html @@ -1,4 +1,4 @@ - diff --git a/pages/index.html b/pages/index.html index 6452bfe..b9a6d6e 100644 --- a/pages/index.html +++ b/pages/index.html @@ -1,71 +1,21 @@ {% extends "base.html" %} {% block custom_header %} - + {% endblock %} -{% block content %} -
-
-
- Daten werden geladen... -
-
-
-

Die Daten werden aus unserer Datenbank abgerufen. Dies kann einen Moment dauern.

-
-
-
+{% include './components/header.html' %} -
- {% include './components/header.html' %} - +{% block content %} {% with links=pages %} {% include './components/sidenav.html' %} {% endwith %} - {% include './components/about-modal.html' %} - {% include './components/modals.html' %} - - - - refresh - - - {% with weather=weather_data %} - {% include './components/weather.html' %} - {% endwith %} - - {% include './components/current-data.html' %} - -
- -
-
-
- Daten werden geladen... -
-
-
-

Die Daten werden aus unserer Datenbank abgerufen. Dies kann einen Moment dauern.

-
-
-
- -
- {% include './components/charts.html' %} -
- - {% include './components/footer.html' %} -
+ {% include './components/mainpage.html' %} {% endblock %} {% block custom_footer %} - - - + + + {% endblock %} \ No newline at end of file diff --git a/public/css/app.css b/public/css/app.css index 10483fb..ca4e239 100644 --- a/public/css/app.css +++ b/public/css/app.css @@ -1,3 +1,7 @@ +*, html { + scroll-behavior: smooth !important; +} + body { background-color: #fff; } @@ -35,7 +39,7 @@ header a:hover { color: #fff; } -main, #chart { +#chart { height: 90vh !important; } @@ -120,7 +124,7 @@ h3.chart-title { text-align: center; color: #fff; margin: 5px 20px 5px 20px; - padding: 0px 30px 0px 30px; + padding: 0 30px 0 30px; } footer { @@ -145,4 +149,45 @@ footer { position: fixed; bottom: 100px; right: 23px; -} \ No newline at end of file +} + +#reload-button { + position: fixed; + bottom: 100px; + right: 23px; +} + +/* Credit: https://stackoverflow.com/a/55788640/18085012 */ +.loader { + position: absolute; + margin: auto; + top: 50vh; + bottom: 50vh; + left: 0; + right: 0; +} + +main { + position: fixed; + right: 0; + width: calc(100vw - 300px); + height: calc(100vh - 64px); + overflow-y: scroll; +} +@media screen and (max-width: 992px) { + main { + width: 100vw; + } +} +@media screen and (min-width: 992px) { + .modal { + width: calc(100vw - 400px) !important; + margin-right: 50px !important; + } +} +#slide-out { + position: fixed; + height: calc(100vh - 64px); + top: 64px; + left: 0; +} diff --git a/public/js/app.js b/public/js/app.js index 6eb95bc..2194b80 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -19,21 +19,44 @@ document.addEventListener('DOMContentLoaded', async () => { M.Modal.init(document.querySelectorAll('.modal'), {}); M.FormSelect.init(document.querySelectorAll('select'), {}); M.Dropdown.init(document.querySelectorAll('.dropdown-trigger'), {}); + M.ScrollSpy.init(document.querySelectorAll('.scrollspy'), {}); + + let fromDate = window.localStorage.getItem("daterange-from"); + let toDate = window.localStorage.getItem("daterange-to"); + let deltaTimespan = window.localStorage.getItem('delta-timespan'); + + if (fromDate === null || toDate === null || deltaTimespan === null) { + console.warn("Cleared localStorage because one or more saved values are not initialized."); + window.localStorage.clear(); + // If no date range is set, use the last 7 days + fromDate = luxon.DateTime.now().minus({ days: 7 }).toJSDate(); + toDate = luxon.DateTime.now().toJSDate(); + } else { + fromDate = luxon.DateTime.fromISO(fromDate).toJSDate(); + toDate = luxon.DateTime.fromISO(toDate).toJSDate(); + } + // Set daterange save checkbox to setting saved in localStorage + document.getElementById("daterange-save-to").checked = window.localStorage.getItem("daterange-save-to") === "1"; + if (window.localStorage.getItem("daterange-save-to") === "0") { + toDate = luxon.DateTime.now().toJSDate(); + } datePickerFrom = M.Datepicker.init(document.getElementById('from-date-input'), { - minDate: luxon.DateTime.now().minus({ years: 1 }).toJSDate(), + //minDate: luxon.DateTime.now().minus({ years: 1 }).toJSDate(), maxDate: luxon.DateTime.now().toJSDate(), - defaultDate: luxon.DateTime.now().minus({ days: 4 }).toJSDate(), + defaultDate: fromDate, setDefaultDate: true }); datePickerTo = M.Datepicker.init(document.getElementById('to-date-input'), { - minDate: luxon.DateTime.now().minus({ years: 1 }).toJSDate(), + //minDate: luxon.DateTime.now().minus({ years: 1 }).toJSDate(), maxDate: luxon.DateTime.now().toJSDate(), - defaultDate: luxon.DateTime.now().toJSDate(), + defaultDate: toDate, setDefaultDate: true }); + document.getElementById("delta-span-input").value = window.localStorage.getItem("delta-timespan"); + // Get data from the last 24 hours and populate beeLogger.currentData var data = await beeLogger.getCurrentData() .catch(err => errorHandler('current-data', err)); @@ -67,22 +90,16 @@ document.addEventListener('DOMContentLoaded', async () => { // Load charts when the library is ready await createChartsForDateRange(); - checkbox = document.getElementById('scale-switch'); + let checkbox = document.getElementById('scale-switch'); checkbox.addEventListener('change', async (e) => { - let fromDate = luxon.DateTime.fromJSDate(datePickerFrom.date); - let toDate = luxon.DateTime.fromJSDate(datePickerTo.date); - - // Calculate difference between dates - let diff = fromDate.diff(toDate, 'days'); - diff = Math.abs(diff.toObject().days); - // Redraw chart when the state of the switch changed element = document.getElementById('scale-switch'); + window.localStorage.setItem("separate-weight", element.checked ? '1' : '0'); await drawCompareChart(beeLogger.cachedData['data'], element.checked); }); - checkbox.checked = false; + checkbox.checked = window.localStorage.getItem("separate-weight") == true; // Timeout function in variable to later be able to stop it again // when the window was resized again @@ -109,23 +126,30 @@ document.addEventListener('DOMContentLoaded', async () => { * @returns {Promise} Resolves when done re-drawing the charts and rejects on error */ function applyDateRange() { + console.log('Applying date range'); return new Promise(async (resolve, reject) => { document.getElementById('beelogger-charts-error-box').classList.add('hide'); var fromDate = luxon.DateTime.fromJSDate(datePickerFrom.date); var toDate = luxon.DateTime.fromJSDate(datePickerTo.date); - + + window.localStorage.setItem('daterange-from', fromDate.toISO()); + window.localStorage.setItem('daterange-to', toDate.toISO()); + window.localStorage.setItem('daterange-save-to', document.getElementById("daterange-save-to").checked ? '1' : '0'); + window.localStorage.setItem('delta-timespan', document.getElementById("delta-span-input").value) + // Calculate difference between dates var diff = fromDate.diff(toDate, 'days'); diff = Math.abs(diff.toObject().days); // Append 'compressed' option when difference is > 10 days - var compressed = diff > 10 ? true : false; + var compressed = diff > 10; fromDate = fromDate.toISODate(); toDate = toDate.toISODate(); - document.getElementById('beelogger-charts-loader').classList.remove('hide'); + document.getElementById('beelogger-daterange-icon').classList.add('hide'); + document.getElementById('beelogger-preloader').classList.add('active'); // Get data for the specified time span var data = await beeLogger.getData(fromDate, toDate, compressed) @@ -157,11 +181,8 @@ function applyDateRange() { */ async function createChartsForDateRange() { var chartsSection = document.getElementById('charts'); - // Hide charts section for the time being - chartsSection.classList.add('hide'); applyDateRange() - .then(() => chartsSection.classList.remove('hide')) // Error already handled by `applyDateRange()` .catch(() => chartsSection.classList.add('hide')); } @@ -182,20 +203,24 @@ async function updateCurrentData(data) { return; } - // Get the measured timestamp from latest record - var measuredLast = data[Object.keys(data).length - 1].measured; - var measured = luxon.DateTime.fromISO(measuredLast).toRelative({ locale: 'de' }); + // Get the latest record in the dataset. + let latestRecord = data[Object.keys(data).length - 1]; + + // Get values for current data displays and round them to 2 decimals + let temperature = Number(latestRecord.temperature).toFixed(2); + let weight = Number(latestRecord.weight).toFixed(2); + let humidity = Number(latestRecord.humidity).toFixed(2); + let weightDelta = getWeightDeltaString(data); + + // Get date and time of the last record and convert it to a relative string + // Example: 'Measured 2 minutes ago.' + let measured = luxon.DateTime.fromISO(latestRecord.measured).toRelative({ locale: 'de' }); document.querySelector('main').classList.remove('hide'); - document.querySelector('#temperature').innerHTML = data[Object.keys(data).length - 1].temperature + ' °C'; - - var weightCurrent = data[Object.keys(data).length - 1].weight; - var weightDelta = getWeightDelta(data); - var humidityCurrent = data[Object.keys(data).length - 1].humidity; - - document.querySelector('#weight').innerHTML = weightCurrent + ' kg'; + document.querySelector('#temperature').innerHTML = temperature + ' °C'; + document.querySelector('#weight').innerHTML = weight + ' g'; document.querySelector('#weight-delta').innerHTML = weightDelta; - document.querySelector('#humidity').innerHTML = humidityCurrent + ' %'; + document.querySelector('#humidity').innerHTML = humidity + ' %'; document.querySelector('#updated').innerHTML = measured; document.querySelector('#loading').classList.add('hide'); } @@ -207,7 +232,7 @@ async function updateCurrentData(data) { * @param {Object} data Data object from the data API * @returns {string} HTML containing the weight delta (in a fitting color) */ -function getWeightDelta(data) { +function getWeightDeltaString(data) { let timespan = document.getElementById("delta-span-input").value * 60000; // in ms if (timespan === undefined || timespan == null || timespan === 0) { timespan = 86400000; // 24h @@ -306,8 +331,10 @@ function errorHandler(scope, err) { let chartsErrorBox = document.getElementById('beelogger-charts-error-box'); chartsErrorBox.innerHTML = error.title + error.description; chartsErrorBox.classList.remove('hide'); - document.getElementById('charts').classList.add('hide'); - document.getElementById('beelogger-charts-loader').classList.add('hide'); + // document.getElementById('charts').classList.add('hide'); + document.getElementById('beelogger-preloader').classList.remove('active'); + document.getElementById('beelogger-daterange-icon').classList.remove('hide'); + break; // Something mandatory is broken, show error message across the entire screen diff --git a/public/js/charts.js b/public/js/charts.js index 6b8f43f..3f13d49 100644 --- a/public/js/charts.js +++ b/public/js/charts.js @@ -52,15 +52,16 @@ async function drawCharts(data) { infoTextElement.innerHTML = infoText; }); - document.getElementById('charts').classList.remove('hide'); + // document.getElementById('charts').classList.remove('hide'); - await drawCompareChart(data, false); + await drawCompareChart(data, window.localStorage.getItem("separate-weight") == true); await drawTempChart(data); await drawWeightChart(data); await drawDeltaChart(data, deltaGraphInterval); await drawHumidityChart(data); - document.getElementById('beelogger-charts-loader').classList.add('hide'); + document.getElementById('beelogger-daterange-icon').classList.remove('hide'); + document.getElementById('beelogger-preloader').classList.remove('active'); } /** @@ -71,7 +72,7 @@ async function drawCharts(data) { */ async function drawCompareChart(data, separateWeight) { var compareData = [ - ['Tag', 'Temperatur (°C)', 'Gewicht (kg)', 'Luftfeuchtigkeit (%)'] + ['Tag', 'Temperatur (°C)', 'Gewicht (g)', 'Luftfeuchtigkeit (%)'] ]; for (row in data) { @@ -156,7 +157,7 @@ async function drawTempChart(data) { * @param {Array} data Array containing the data records that the graph should be generated from */ async function drawWeightChart(data) { - var weightData = [['Gemessen', 'Gewicht (kg)']]; + var weightData = [['Gemessen', 'Gewicht (g)']]; for (row in data) { var measured = new Date(data[row].measured); diff --git a/requirements.txt b/requirements.txt index 113d9f1..a8501eb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,4 +10,5 @@ pyTelegramBotAPI~=4.1.1 schedule~=1.1.0 geopy~=2.2.0 requests~=2.27.1 -babel~=2.9.1 \ No newline at end of file +babel~=2.9.1 +secret_key_generator==0.0.8 \ No newline at end of file