Removed temperature pages.
This commit is contained in:
parent
e4a2ed2228
commit
5413c3b433
2 changed files with 0 additions and 773 deletions
442
public/temp.php
442
public/temp.php
|
@ -1,442 +0,0 @@
|
||||||
<?php
|
|
||||||
define('FM_TEMP_KEY', 'kND861svbydCLywutu78tRmlpWdzoRLPcVZSrnxerh3KbLwfwvfvgC5hzax8gvYm');
|
|
||||||
define('FM_TEMP_INT', 10);
|
|
||||||
|
|
||||||
ini_set('display_errors', 'on');
|
|
||||||
error_reporting(-1);
|
|
||||||
|
|
||||||
date_default_timezone_set('UTC');
|
|
||||||
mb_internal_encoding('UTF-8');
|
|
||||||
|
|
||||||
try {
|
|
||||||
$pdo = new PDO('mysql:unix_socket=/var/run/mysqld/mysqld.sock;dbname=website;charset=utf8mb4', 'website', 'A3NjVvHRkHAxiYgk8MM4ZrCwrLVyPIYX', [
|
|
||||||
PDO::ATTR_CASE => PDO::CASE_NATURAL,
|
|
||||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
|
||||||
PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
|
|
||||||
PDO::ATTR_STRINGIFY_FETCHES => false,
|
|
||||||
PDO::ATTR_EMULATE_PREPARES => false,
|
|
||||||
PDO::MYSQL_ATTR_INIT_COMMAND => "
|
|
||||||
SET SESSION
|
|
||||||
sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION',
|
|
||||||
time_zone = '+00:00';
|
|
||||||
",
|
|
||||||
]);
|
|
||||||
} catch(Exception $ex) {
|
|
||||||
http_response_code(500);
|
|
||||||
echo '<h3>Unable to connect to database</h3>';
|
|
||||||
die($ex->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isset($_POST['temp']) && isset($_POST['hash']) && isset($_POST['time'])) {
|
|
||||||
$temp = (string)filter_input(INPUT_POST, 'temp');
|
|
||||||
$hash = (string)filter_input(INPUT_POST, 'hash');
|
|
||||||
$time = (string)filter_input(INPUT_POST, 'time', FILTER_SANITIZE_NUMBER_INT);
|
|
||||||
|
|
||||||
if(!hash_equals(hash_hmac('sha256', $temp . '|' . $time, FM_TEMP_KEY), $hash))
|
|
||||||
return;
|
|
||||||
|
|
||||||
$time = floor((int)json_decode($time) / FM_TEMP_INT);
|
|
||||||
if($time !== floor(time() / FM_TEMP_INT))
|
|
||||||
return;
|
|
||||||
|
|
||||||
$insert = $pdo->prepare('INSERT INTO `fm_temperature` (`temp_celcius`) VALUES (:temp)');
|
|
||||||
$insert->bindValue('temp', (string)json_decode($temp));
|
|
||||||
$insert->execute();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isset($_GET['latest'])) {
|
|
||||||
$temps = $pdo->prepare('SELECT `temp_celcius` AS `tc`, UNIX_TIMESTAMP(`temp_datetime`) AS `dt` FROM `fm_temperature` ORDER BY `temp_datetime` DESC LIMIT 1');
|
|
||||||
$temps->execute();
|
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
|
||||||
echo json_encode($temps->fetch(PDO::FETCH_ASSOC));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isset($_GET['daily'])) {
|
|
||||||
$temps = $pdo->prepare('SELECT AVG(`temp_celcius`) AS `tc`, DATE_FORMAT(MIN(`temp_datetime`), \'%H:%i\') AS `ts` FROM `fm_temperature` WHERE `temp_datetime` > NOW() - INTERVAL 1 DAY GROUP BY FLOOR(UNIX_TIMESTAMP(`temp_datetime`) / (15 * 60)) ORDER BY `temp_datetime` ASC LIMIT 96');
|
|
||||||
$temps->execute();
|
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
|
||||||
echo json_encode($temps->fetchAll(PDO::FETCH_ASSOC));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isset($_GET['weekly'])) {
|
|
||||||
$temps = $pdo->prepare('SELECT MAX(`temp_celcius`) AS `tcmax`, AVG(`temp_celcius`) AS `tcavg`, MIN(`temp_celcius`) AS `tcmin`, DATE_FORMAT(`temp_datetime`, \'%X-%V\') AS `tw` FROM `fm_temperature` WHERE `temp_datetime` > NOW() - INTERVAL 1 YEAR GROUP BY YEARWEEK(`temp_datetime`) ORDER BY `temp_datetime` ASC LIMIT 52');
|
|
||||||
$temps->execute();
|
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
|
||||||
echo json_encode($temps->fetchAll(PDO::FETCH_ASSOC));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!empty($_GET['siri'])) {
|
|
||||||
header('Content-Type: text/plain; charset=utf-8');
|
|
||||||
$temps = $pdo->prepare('SELECT `temp_celcius`, UNIX_TIMESTAMP(`temp_datetime`) AS `temp_datetime` FROM `fm_temperature` ORDER BY `temp_datetime` DESC LIMIT 1');
|
|
||||||
$temps->execute();
|
|
||||||
$temps = $temps->fetch(PDO::FETCH_ASSOC);
|
|
||||||
date_default_timezone_set('Europe/Amsterdam');
|
|
||||||
printf('It was %2$.1f°C at %1$s.', date('H:i:s', $temps['temp_datetime']), $temps['temp_celcius']);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<title>Room Temperature</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
|
|
||||||
<link href="/css/electrolize/style.css" type="text/css" rel="stylesheet"/>
|
|
||||||
<style type="text/css">
|
|
||||||
* {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
position: relative;
|
|
||||||
outline-style: none;
|
|
||||||
}
|
|
||||||
html, body {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
background-color: #111;
|
|
||||||
color: #fff;
|
|
||||||
font: 12px/20px Tahoma, Geneva, 'Dejavu Sans', Arial, Helvetica, sans-serif;
|
|
||||||
padding: 1px;
|
|
||||||
}
|
|
||||||
h2 {
|
|
||||||
font-family: 'Electrolize', Verdana, 'Dejavu Sans', Arial, Helvetica, sans-serif;
|
|
||||||
}
|
|
||||||
.current {
|
|
||||||
text-align: center;
|
|
||||||
background-color: #333;
|
|
||||||
margin: 10px;
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
.current-temp {
|
|
||||||
font-family: 'Electrolize', Verdana, 'Dejavu Sans', Arial, Helvetica, sans-serif;
|
|
||||||
font-size: 3em;
|
|
||||||
line-height: 1.2em;
|
|
||||||
}
|
|
||||||
.current-datetime {
|
|
||||||
font-size: .9em;
|
|
||||||
line-height: 1.4em;
|
|
||||||
}
|
|
||||||
.chart {
|
|
||||||
background-color: #ddd;
|
|
||||||
margin: 10px;
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 10px;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
.chart-legend {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.chart-body {
|
|
||||||
width: 100%;
|
|
||||||
height: 400px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.chart-labels {
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.legend {
|
|
||||||
display: inline-block;
|
|
||||||
text-align: left;
|
|
||||||
min-width: 100px;
|
|
||||||
}
|
|
||||||
.legend-icon {
|
|
||||||
background-color: var(--lc);
|
|
||||||
width: 10px;
|
|
||||||
height: 10px;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
.legend-name {
|
|
||||||
color: var(--lc);
|
|
||||||
font-weight: 700;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
.bars {
|
|
||||||
height: 100%;
|
|
||||||
display: inline-block;
|
|
||||||
bottom: 0;
|
|
||||||
}
|
|
||||||
.bars-bar {
|
|
||||||
width: 100%;
|
|
||||||
bottom: 0;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="main">
|
|
||||||
<div class="current">
|
|
||||||
<div class="current-temp">
|
|
||||||
<span id="-last-temp">--</span> °C
|
|
||||||
</div>
|
|
||||||
<div class="current-datetime">
|
|
||||||
<span id="-last-datetime">--:--:--</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="chart" id="-chart-hr">
|
|
||||||
<h2>15 minutely Temperature (24hr)</h2>
|
|
||||||
<p style="font-size: .8em">Add 1 or 2 hours to the displayed hour, I cannot be bothered to handle it myself.</p>
|
|
||||||
<div class="chart-body">
|
|
||||||
</div>
|
|
||||||
<div class="chart-labels" style="height: 35px;">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="chart" id="-chart-wk">
|
|
||||||
<h2>Weekly Temperature (1yr)</h2>
|
|
||||||
<div class="chart-legend">
|
|
||||||
<div class="legend" style="--lc: #800;">
|
|
||||||
<div class="legend-icon"></div>
|
|
||||||
<div class="legend-name">Maximum</div>
|
|
||||||
</div>
|
|
||||||
<div class="legend" style="--lc: #080;">
|
|
||||||
<div class="legend-icon"></div>
|
|
||||||
<div class="legend-name">Average</div>
|
|
||||||
</div>
|
|
||||||
<div class="legend" style="--lc: #008;">
|
|
||||||
<div class="legend-icon"></div>
|
|
||||||
<div class="legend-name">Minimum</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="chart-body">
|
|
||||||
</div>
|
|
||||||
<div class="chart-labels" style="height: 40px;">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script type="text/javascript">
|
|
||||||
var temp = {
|
|
||||||
lastTemp: null,
|
|
||||||
lastDateTime: null,
|
|
||||||
chartHr: null,
|
|
||||||
chartHrBody: null,
|
|
||||||
chartHrLabels: null,
|
|
||||||
chartHrBars: 24 * 60 / 15,
|
|
||||||
chartWk: null,
|
|
||||||
chartWkBody: null,
|
|
||||||
chartWkLabels: null,
|
|
||||||
chartWkBars: 52,
|
|
||||||
};
|
|
||||||
temp.weightedNumber = function(n1, n2, w) {
|
|
||||||
w = Math.min(1, Math.max(0, w));
|
|
||||||
return Math.round((n1 * w) + (n2 * (1 - w)));
|
|
||||||
};
|
|
||||||
temp.weightedColour = function(c1, c2, w) {
|
|
||||||
if(typeof c1 === 'number')
|
|
||||||
c1 = [(c1 >> 16) & 0xFF, (c1 >> 8) & 0xFF, c1 & 0xFF];
|
|
||||||
if(typeof c2 === 'number')
|
|
||||||
c2 = [(c2 >> 16) & 0xFF, (c2 >> 8) & 0xFF, c2 & 0xFF];
|
|
||||||
var rgb = [
|
|
||||||
this.weightedNumber(c1[0], c2[0], w),
|
|
||||||
this.weightedNumber(c1[1], c2[1], w),
|
|
||||||
this.weightedNumber(c1[2], c2[2], w),
|
|
||||||
];
|
|
||||||
return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
|
|
||||||
};
|
|
||||||
temp.weightedColourHex = function(c1, c2, w) {
|
|
||||||
return '#' + this.weightedColour(c1, c2, w).toString(16).padStart(6, '0');
|
|
||||||
};
|
|
||||||
temp.refreshLatest = function() {
|
|
||||||
var xhr = new XMLHttpRequest;
|
|
||||||
xhr.onload = function() {
|
|
||||||
this.updateLatest(JSON.parse(xhr.responseText));
|
|
||||||
}.bind(this);
|
|
||||||
xhr.open('GET', '/temp.php?latest');
|
|
||||||
xhr.send();
|
|
||||||
};
|
|
||||||
temp.updateLatest = function(temp) {
|
|
||||||
this.lastTemp.textContent = (parseInt(temp.tc * 10) / 10).toFixed(1).toLocaleString();
|
|
||||||
this.lastDateTime.textContent = new Date(temp.dt * 1000).toLocaleString();
|
|
||||||
};
|
|
||||||
temp.refreshHr = function() {
|
|
||||||
var xhr = new XMLHttpRequest;
|
|
||||||
xhr.onload = function() {
|
|
||||||
this.updateHr(JSON.parse(xhr.responseText));
|
|
||||||
}.bind(this);
|
|
||||||
xhr.open('GET', '/temp.php?daily');
|
|
||||||
xhr.send();
|
|
||||||
};
|
|
||||||
temp.updateHr = function(temps) {
|
|
||||||
this.chartHrBody.innerHTML = '';
|
|
||||||
this.chartHrLabels.innerHTML = '';
|
|
||||||
|
|
||||||
for(var i = 0; i < temps.length; ++i) {
|
|
||||||
var temp = temps[i],
|
|
||||||
width = (100 / (temps.length + 12)).toString() + '%';
|
|
||||||
|
|
||||||
var label = document.createElement('div'),
|
|
||||||
labelTxt = document.createElement('div');
|
|
||||||
labelTxt.textContent = temp.ts;
|
|
||||||
labelTxt.style.transform = 'rotate(270deg)';
|
|
||||||
labelTxt.style.fontSize = '.8em';
|
|
||||||
labelTxt.style.top = '15px';
|
|
||||||
label.title = temp.ts;
|
|
||||||
label.className = 'chart-body-bars bars';
|
|
||||||
label.style.width = width;
|
|
||||||
label.style.margin = '0 .5px';
|
|
||||||
label.appendChild(labelTxt);
|
|
||||||
this.chartHrLabels.appendChild(label);
|
|
||||||
|
|
||||||
var bars = document.createElement('div');
|
|
||||||
bars.className = 'chart-body-bars bars';
|
|
||||||
bars.style.width = width;
|
|
||||||
bars.style.margin = '0 .5px';
|
|
||||||
this.chartHrBody.appendChild(bars);
|
|
||||||
|
|
||||||
var bar = document.createElement('div'),
|
|
||||||
barTxt = document.createElement('div');
|
|
||||||
bar.className = 'bars-bar';
|
|
||||||
|
|
||||||
var weight = ((temp.tc - 15) / 20);
|
|
||||||
|
|
||||||
barTxt.textContent = temp.tc.toFixed(1);
|
|
||||||
barTxt.style.transform = 'rotate(270deg)';
|
|
||||||
barTxt.style.fontSize = '.8em';
|
|
||||||
barTxt.style.top = '5px';
|
|
||||||
barTxt.style.color = '#fff';
|
|
||||||
bar.appendChild(barTxt);
|
|
||||||
bar.title = temp.tc.toFixed(2) + ' °C';
|
|
||||||
bar.style.backgroundColor = this.weightedColourHex(0xFF0000, 0xFF, weight);
|
|
||||||
bar.style.overflow = 'hidden';
|
|
||||||
bar.style.height = (weight * 100).toString() + '%';
|
|
||||||
bars.appendChild(bar);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
temp.refreshWk = function() {
|
|
||||||
var xhr = new XMLHttpRequest;
|
|
||||||
xhr.onload = function() {
|
|
||||||
this.updateWk(JSON.parse(xhr.responseText));
|
|
||||||
}.bind(this);
|
|
||||||
xhr.open('GET', '/temp.php?weekly');
|
|
||||||
xhr.send();
|
|
||||||
};
|
|
||||||
temp.updateWk = function(temps) {
|
|
||||||
this.chartWkBody.innerHTML = '';
|
|
||||||
this.chartWkLabels.innerHTML = '';
|
|
||||||
|
|
||||||
for(var i = 0; i < temps.length; ++i) {
|
|
||||||
var temp = temps[i],
|
|
||||||
width = (100 / (this.chartWkBars + 3)).toString() + '%';
|
|
||||||
|
|
||||||
var label = document.createElement('div'),
|
|
||||||
labelTxt = document.createElement('div');
|
|
||||||
labelTxt.textContent = temp.tw;
|
|
||||||
labelTxt.style.transform = 'rotate(270deg)';
|
|
||||||
labelTxt.style.fontSize = '.8em';
|
|
||||||
labelTxt.style.top = '20px';
|
|
||||||
label.title = temp.tw;
|
|
||||||
label.className = 'chart-body-bars bars';
|
|
||||||
label.style.width = width;
|
|
||||||
label.style.margin = '0 .5px';
|
|
||||||
label.appendChild(labelTxt);
|
|
||||||
this.chartWkLabels.appendChild(label);
|
|
||||||
|
|
||||||
var bars = document.createElement('div');
|
|
||||||
bars.className = 'chart-body-bars bars';
|
|
||||||
bars.style.width = width;
|
|
||||||
bars.style.margin = '0 .5px';
|
|
||||||
this.chartWkBody.appendChild(bars);
|
|
||||||
|
|
||||||
var max = document.createElement('div'),
|
|
||||||
maxTxt = document.createElement('div'),
|
|
||||||
avg = document.createElement('div'),
|
|
||||||
avgTxt = document.createElement('div'),
|
|
||||||
min = document.createElement('div'),
|
|
||||||
minTxt = document.createElement('div');
|
|
||||||
max.className = avg.className = min.className = 'bars-bar';
|
|
||||||
|
|
||||||
var wMin = (temp.tcmin - 15) / 15,
|
|
||||||
wAvg = (temp.tcavg - 20) / 10,
|
|
||||||
wMax = (temp.tcmax - 20) / 15;
|
|
||||||
|
|
||||||
maxTxt.textContent = temp.tcmax.toFixed(1);
|
|
||||||
maxTxt.style.transform = 'rotate(270deg)';
|
|
||||||
maxTxt.style.fontSize = '.8em';
|
|
||||||
maxTxt.style.top = '5px';
|
|
||||||
maxTxt.style.color = '#fff';
|
|
||||||
max.appendChild(maxTxt);
|
|
||||||
max.title = temp.tcmax.toFixed(2) + ' °C';
|
|
||||||
max.style.backgroundColor = this.weightedColourHex(0xFF0000, 0x800000, wMax);
|
|
||||||
max.style.overflow = 'hidden';
|
|
||||||
max.style.height = (((temp.tcmax - 15) / 20) * 100).toString() + '%';
|
|
||||||
bars.appendChild(max);
|
|
||||||
|
|
||||||
avgTxt.textContent = temp.tcavg.toFixed(1);
|
|
||||||
avgTxt.style.transform = 'rotate(270deg)';
|
|
||||||
avgTxt.style.fontSize = '.8em';
|
|
||||||
avgTxt.style.top = '5px';
|
|
||||||
avgTxt.style.color = '#fff';
|
|
||||||
avg.appendChild(avgTxt);
|
|
||||||
avg.title = temp.tcavg.toFixed(2) + ' °C';
|
|
||||||
avg.style.backgroundColor = this.weightedColourHex(0xFF00, 0x8000, wAvg);
|
|
||||||
avg.style.overflow = 'hidden';
|
|
||||||
avg.style.height = (((temp.tcavg - 15) / 20) * 100).toString() + '%';
|
|
||||||
bars.appendChild(avg);
|
|
||||||
|
|
||||||
minTxt.textContent = temp.tcmin.toFixed(1);
|
|
||||||
minTxt.style.transform = 'rotate(270deg)';
|
|
||||||
minTxt.style.fontSize = '.8em';
|
|
||||||
minTxt.style.top = '5px';
|
|
||||||
minTxt.style.color = '#fff';
|
|
||||||
min.appendChild(minTxt);
|
|
||||||
min.title = temp.tcmin.toFixed(2) + ' °C';
|
|
||||||
min.style.backgroundColor = this.weightedColourHex(0x80, 0xFF, wMin);
|
|
||||||
min.style.overflow = 'hidden';
|
|
||||||
min.style.height = (((temp.tcmin - 15) / 20) * 100).toString() + '%';
|
|
||||||
bars.appendChild(min);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
temp.loadFake = function() {
|
|
||||||
this.updateHr(this.fakeForHourly());
|
|
||||||
this.updateWk(this.fakeForWeekly());
|
|
||||||
};
|
|
||||||
temp.fakeForHourly = function() {
|
|
||||||
var temps = [];
|
|
||||||
for(var i = 0; i < this.chartHrBars; ++i)
|
|
||||||
temps.push({ tc: (20 * ((i + 1) / this.chartHrBars)) + 15, ts: i.toString() });
|
|
||||||
return temps;
|
|
||||||
};
|
|
||||||
temp.fakeForWeekly = function() {
|
|
||||||
var wMin = (temp.tcmin - 15) / 15,
|
|
||||||
wAvg = (temp.tcavg - 20) / 10,
|
|
||||||
wMax = (temp.tcmax - 20) / 15;
|
|
||||||
var temps = [];
|
|
||||||
for(var i = 0; i < this.chartWkBars; ++i)
|
|
||||||
temps.push({
|
|
||||||
tcmax: (15 * ((i + 1) / this.chartWkBars)) + 20,
|
|
||||||
tcavg: (10 * ((i + 1) / this.chartWkBars)) + 20,
|
|
||||||
tcmin: (15 * ((i + 1) / this.chartWkBars)) + 15,
|
|
||||||
tw: i.toString(),
|
|
||||||
});
|
|
||||||
return temps;
|
|
||||||
};
|
|
||||||
window.onload = function() {
|
|
||||||
temp.lastTemp = document.getElementById('-last-temp');
|
|
||||||
temp.lastDateTime = document.getElementById('-last-datetime');
|
|
||||||
|
|
||||||
temp.chartHr = document.getElementById('-chart-hr');
|
|
||||||
temp.chartHrBody = temp.chartHr.getElementsByClassName('chart-body')[0];
|
|
||||||
temp.chartHrLabels = temp.chartHr.getElementsByClassName('chart-labels')[0];
|
|
||||||
|
|
||||||
temp.chartWk = document.getElementById('-chart-wk');
|
|
||||||
temp.chartWkBody = temp.chartWk.getElementsByClassName('chart-body')[0];
|
|
||||||
temp.chartWkLabels = temp.chartWk.getElementsByClassName('chart-labels')[0];
|
|
||||||
|
|
||||||
temp.refreshLatest();
|
|
||||||
setInterval(temp.refreshLatest.bind(temp), 5 * 60 * 1000);
|
|
||||||
|
|
||||||
temp.refreshHr();
|
|
||||||
setInterval(temp.refreshHr.bind(temp), 15 * 60 * 1000);
|
|
||||||
|
|
||||||
temp.refreshWk();
|
|
||||||
setInterval(temp.refreshWk.bind(temp), 7 * 24 * 60 * 1000);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
331
public/temp2.php
331
public/temp2.php
|
@ -1,331 +0,0 @@
|
||||||
<?php
|
|
||||||
define('FM_TEMP_KEY', 'kND861svbydCLywutu78tRmlpWdzoRLPcVZSrnxerh3KbLwfwvfvgC5hzax8gvYm');
|
|
||||||
define('FM_TEMP_INT', 10);
|
|
||||||
|
|
||||||
ini_set('display_errors', 'on');
|
|
||||||
error_reporting(-1);
|
|
||||||
|
|
||||||
date_default_timezone_set('UTC');
|
|
||||||
mb_internal_encoding('UTF-8');
|
|
||||||
|
|
||||||
try {
|
|
||||||
$pdo = new PDO('mysql:unix_socket=/var/run/mysqld/mysqld.sock;dbname=website;charset=utf8mb4', 'website', 'A3NjVvHRkHAxiYgk8MM4ZrCwrLVyPIYX', [
|
|
||||||
PDO::ATTR_CASE => PDO::CASE_NATURAL,
|
|
||||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
|
||||||
PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
|
|
||||||
PDO::ATTR_STRINGIFY_FETCHES => false,
|
|
||||||
PDO::ATTR_EMULATE_PREPARES => false,
|
|
||||||
PDO::MYSQL_ATTR_INIT_COMMAND => "
|
|
||||||
SET SESSION
|
|
||||||
sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION',
|
|
||||||
time_zone = '+00:00';
|
|
||||||
",
|
|
||||||
]);
|
|
||||||
} catch(Exception $ex) {
|
|
||||||
http_response_code(500);
|
|
||||||
echo '<h3>Unable to connect to database</h3>';
|
|
||||||
die($ex->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isset($_POST['temp']) && isset($_POST['hash']) && isset($_POST['time'])) {
|
|
||||||
$temp = (string)filter_input(INPUT_POST, 'temp');
|
|
||||||
$hash = (string)filter_input(INPUT_POST, 'hash');
|
|
||||||
$time = (string)filter_input(INPUT_POST, 'time', FILTER_SANITIZE_NUMBER_INT);
|
|
||||||
|
|
||||||
if(!hash_equals(hash_hmac('sha256', $temp . '|' . $time, FM_TEMP_KEY), $hash))
|
|
||||||
return;
|
|
||||||
|
|
||||||
$time = floor((int)json_decode($time) / FM_TEMP_INT);
|
|
||||||
if($time !== floor(time() / FM_TEMP_INT))
|
|
||||||
return;
|
|
||||||
|
|
||||||
$insert = $pdo->prepare('INSERT INTO `fm_temperature` (`temp_celcius`) VALUES (:temp)');
|
|
||||||
$insert->bindValue('temp', (string)json_decode($temp));
|
|
||||||
$insert->execute();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isset($_GET['since'])) {
|
|
||||||
$since = (int)filter_input(INPUT_GET, 'since', FILTER_SANITIZE_NUMBER_INT);
|
|
||||||
$temps = $pdo->prepare('SELECT `temp_celcius`, UNIX_TIMESTAMP(`temp_datetime`) AS `temp_datetime` FROM `fm_temperature` WHERE `temp_datetime` > FROM_UNIXTIME(:since) AND `temp_datetime` > NOW() - INTERVAL 1 DAY ORDER BY `temp_datetime` ASC LIMIT 288');
|
|
||||||
$temps->bindValue('since', $since);
|
|
||||||
$temps->execute();
|
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
|
||||||
echo json_encode($temps->fetchAll(PDO::FETCH_ASSOC));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isset($_GET['since_3mo'])) {
|
|
||||||
$since = (int)filter_input(INPUT_GET, 'since_3mo', FILTER_SANITIZE_NUMBER_INT);
|
|
||||||
$temps = $pdo->prepare('SELECT MAX(`temp_celcius`) AS `temp_celcius_max`, AVG(`temp_celcius`) AS `temp_celcius_avg`, MIN(`temp_celcius`) AS `temp_celcius_min`, UNIX_TIMESTAMP(DATE(`temp_datetime`)) AS `temp_datetime` FROM `fm_temperature` WHERE `temp_datetime` > DATE(FROM_UNIXTIME(:since)) AND `temp_datetime` > NOW() - INTERVAL 3 MONTH GROUP BY DATE(`temp_datetime`) ORDER BY `temp_datetime` ASC LIMIT 92');
|
|
||||||
$temps->bindValue('since', $since);
|
|
||||||
$temps->execute();
|
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
|
||||||
echo json_encode($temps->fetchAll(PDO::FETCH_ASSOC));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isset($_GET['since_6mo'])) {
|
|
||||||
$since = (int)filter_input(INPUT_GET, 'since_6mo', FILTER_SANITIZE_NUMBER_INT);
|
|
||||||
$temps = $pdo->prepare('SELECT MAX(`temp_celcius`) AS `temp_celcius_max`, AVG(`temp_celcius`) AS `temp_celcius_avg`, MIN(`temp_celcius`) AS `temp_celcius_min`, UNIX_TIMESTAMP(DATE(`temp_datetime`)) AS `temp_datetime` FROM `fm_temperature` WHERE `temp_datetime` > DATE(FROM_UNIXTIME(:since)) AND `temp_datetime` > NOW() - INTERVAL 6 MONTH GROUP BY DATE(`temp_datetime`) ORDER BY `temp_datetime` ASC LIMIT 92');
|
|
||||||
$temps->bindValue('since', $since);
|
|
||||||
$temps->execute();
|
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
|
||||||
echo json_encode($temps->fetchAll(PDO::FETCH_ASSOC));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!empty($_GET['siri'])) {
|
|
||||||
header('Content-Type: text/plain; charset=utf-8');
|
|
||||||
$temps = $pdo->prepare('SELECT `temp_celcius`, UNIX_TIMESTAMP(`temp_datetime`) AS `temp_datetime` FROM `fm_temperature` ORDER BY `temp_datetime` DESC LIMIT 1');
|
|
||||||
$temps->execute();
|
|
||||||
$temps = $temps->fetch(PDO::FETCH_ASSOC);
|
|
||||||
date_default_timezone_set('Europe/Amsterdam');
|
|
||||||
printf('It was %2$.1f°C at %1$s.', date('H:i:s', $temps['temp_datetime']), $temps['temp_celcius']);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<title>Room Temperature</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
|
|
||||||
<link href="/css/electrolize/style.css" type="text/css" rel="stylesheet"/>
|
|
||||||
<style type="text/css">
|
|
||||||
* {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
position: relative;
|
|
||||||
outline-style: none;
|
|
||||||
}
|
|
||||||
html, body {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
background-color: #111;
|
|
||||||
color: #fff;
|
|
||||||
font: 12px/20px Tahoma, Geneva, 'Dejavu Sans', Arial, Helvetica, sans-serif;
|
|
||||||
padding: 1px;
|
|
||||||
}
|
|
||||||
.current {
|
|
||||||
text-align: center;
|
|
||||||
background-color: #333;
|
|
||||||
margin: 10px;
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
.current-temp {
|
|
||||||
font-family: 'Electrolize', Verdana, 'Dejavu Sans', Arial, Helvetica, sans-serif;
|
|
||||||
font-size: 3em;
|
|
||||||
line-height: 1.2em;
|
|
||||||
}
|
|
||||||
.current-datetime {
|
|
||||||
font-size: .9em;
|
|
||||||
line-height: 1.4em;
|
|
||||||
}
|
|
||||||
.chart {
|
|
||||||
background-color: #ddd;
|
|
||||||
margin: 10px;
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="main">
|
|
||||||
<div class="current">
|
|
||||||
<div class="current-temp">
|
|
||||||
<span id="-last-temp">--</span> °C
|
|
||||||
</div>
|
|
||||||
<div class="current-datetime">
|
|
||||||
<span id="-last-datetime">--:--:--</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="chart">
|
|
||||||
<canvas id="-chart" width="400" height="170"></canvas>
|
|
||||||
</div>
|
|
||||||
<div class="chart">
|
|
||||||
<canvas id="-chart-mo" width="400" height="170"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/chart.js@3.3.2/dist/chart.min.js"></script>
|
|
||||||
<script type="text/javascript">
|
|
||||||
var temp = {
|
|
||||||
last: 0,
|
|
||||||
lastMo: 0,
|
|
||||||
history: [],
|
|
||||||
historyMo: [],
|
|
||||||
lastTemp: null,
|
|
||||||
lastDateTime: null,
|
|
||||||
chart: null,
|
|
||||||
chartMo: null,
|
|
||||||
};
|
|
||||||
temp.getLastTemperature = function() {
|
|
||||||
if(this.history.length === 0)
|
|
||||||
return {temp_datetime: 0, temp_celcius: 0};
|
|
||||||
return this.history[this.history.length - 1];
|
|
||||||
};
|
|
||||||
temp.refresh = function() {
|
|
||||||
var xhr = new XMLHttpRequest;
|
|
||||||
xhr.onload = function() {
|
|
||||||
var temps = JSON.parse(xhr.responseText);
|
|
||||||
for(var i = 0; i < temps.length; ++i) {
|
|
||||||
var temp = temps[i];
|
|
||||||
this.last = temp.temp_datetime;
|
|
||||||
this.history.push(temp);
|
|
||||||
}
|
|
||||||
this.refreshUI();
|
|
||||||
}.bind(this);
|
|
||||||
xhr.open('GET', '/temp2.php?since=' + encodeURIComponent(parseInt(this.last).toString()));
|
|
||||||
xhr.send();
|
|
||||||
};
|
|
||||||
temp.refreshUI = function() {
|
|
||||||
var temp = this.getLastTemperature();
|
|
||||||
this.lastTemp.textContent = (parseInt(temp.temp_celcius * 10) / 10).toFixed(1).toLocaleString();
|
|
||||||
this.lastDateTime.textContent = new Date(temp.temp_datetime * 1000).toLocaleString();
|
|
||||||
|
|
||||||
var take = Math.min(288, this.history.length),
|
|
||||||
dataset = this.chart.data.datasets[0];
|
|
||||||
this.chart.data.labels = [];
|
|
||||||
dataset.data = [];
|
|
||||||
for(var i = this.history.length - take; i < this.history.length; ++i) {
|
|
||||||
var temp = this.history[i];
|
|
||||||
this.chart.data.labels.push(new Date(temp.temp_datetime * 1000).toLocaleString());
|
|
||||||
dataset.data.push(temp.temp_celcius);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.chart.update();
|
|
||||||
};
|
|
||||||
temp.refreshMo = function() {
|
|
||||||
var xhr = new XMLHttpRequest;
|
|
||||||
xhr.onload = function() {
|
|
||||||
var temps = JSON.parse(xhr.responseText);
|
|
||||||
for(var i = 0; i < temps.length; ++i) {
|
|
||||||
var temp = temps[i];
|
|
||||||
this.lastMo = temp.temp_datetime;
|
|
||||||
this.historyMo.push(temp);
|
|
||||||
}
|
|
||||||
this.refreshUIMo();
|
|
||||||
}.bind(this);
|
|
||||||
xhr.open('GET', '/temp2.php?since_6mo=' + encodeURIComponent(parseInt(this.lastMo).toString()));
|
|
||||||
xhr.send();
|
|
||||||
};
|
|
||||||
temp.refreshUIMo = function() {
|
|
||||||
var take = Math.min(92, this.historyMo.length),
|
|
||||||
datasetMax = this.chartMo.data.datasets[0],
|
|
||||||
datasetAvg = this.chartMo.data.datasets[1],
|
|
||||||
datasetMin = this.chartMo.data.datasets[2];
|
|
||||||
this.chart.data.labels = [];
|
|
||||||
datasetMax.data = [];
|
|
||||||
datasetAvg.data = [];
|
|
||||||
datasetMin.data = [];
|
|
||||||
for(var i = this.historyMo.length - take; i < this.historyMo.length; ++i) {
|
|
||||||
var temp = this.historyMo[i];
|
|
||||||
this.chartMo.data.labels.push(new Date(temp.temp_datetime * 1000).toDateString());
|
|
||||||
datasetMax.data.push(temp.temp_celcius_max);
|
|
||||||
datasetAvg.data.push(temp.temp_celcius_avg);
|
|
||||||
datasetMin.data.push(temp.temp_celcius_min);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.chartMo.update();
|
|
||||||
};
|
|
||||||
window.onload = function() {
|
|
||||||
temp.lastTemp = document.getElementById('-last-temp');
|
|
||||||
temp.lastDateTime = document.getElementById('-last-datetime');
|
|
||||||
|
|
||||||
var ctx = document.getElementById('-chart').getContext('2d');
|
|
||||||
temp.chart = new Chart(ctx, {
|
|
||||||
type: 'line',
|
|
||||||
data: {
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
label: 'Temperature',
|
|
||||||
data: [],
|
|
||||||
borderColor: '#111',
|
|
||||||
backgroundColor: '#222',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
plugins: {
|
|
||||||
legend: {
|
|
||||||
position: 'top',
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
display: true,
|
|
||||||
text: 'Temperature History',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
scales: {
|
|
||||||
y: {
|
|
||||||
suggestedMax: 34,
|
|
||||||
suggestedMin: 20,
|
|
||||||
ticks: {
|
|
||||||
stepSize: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
temp.refresh();
|
|
||||||
setInterval(temp.refresh.bind(temp), 5 * 60 * 1000);
|
|
||||||
|
|
||||||
var ctxMo = document.getElementById('-chart-mo').getContext('2d');
|
|
||||||
temp.chartMo = new Chart(ctxMo, {
|
|
||||||
type: 'line',
|
|
||||||
data: {
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
label: 'Maximum Temperature',
|
|
||||||
data: [],
|
|
||||||
borderColor: '#400',
|
|
||||||
backgroundColor: '#800',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Average Temperature',
|
|
||||||
data: [],
|
|
||||||
borderColor: '#040',
|
|
||||||
backgroundColor: '#080',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Minimum Temperature',
|
|
||||||
data: [],
|
|
||||||
borderColor: '#004',
|
|
||||||
backgroundColor: '#008',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
plugins: {
|
|
||||||
legend: {
|
|
||||||
position: 'top',
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
display: true,
|
|
||||||
text: 'Daily Temperature (6 months)',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
scales: {
|
|
||||||
y: {
|
|
||||||
suggestedMax: 34,
|
|
||||||
suggestedMin: 20,
|
|
||||||
ticks: {
|
|
||||||
stepSize: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
temp.refreshMo();
|
|
||||||
setInterval(temp.refreshMo.bind(temp), 31 * 24 * 60 * 1000);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
Loading…
Reference in a new issue