2021-07-07 01:13:50 +00:00
< ? php
define ( 'FM_TEMP_KEY' , 'kND861svbydCLywutu78tRmlpWdzoRLPcVZSrnxerh3KbLwfwvfvgC5hzax8gvYm' );
define ( 'FM_TEMP_INT' , 10 );
ini_set ( 'display_errors' , 'on' );
error_reporting ( - 1 );
2022-02-04 04:25:57 +00:00
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 ());
}
2021-07-07 01:13:50 +00:00
if ( isset ( $_POST [ 'temp' ]) && isset ( $_POST [ 'hash' ]) && isset ( $_POST [ 'time' ])) {
2022-02-04 20:30:52 +00:00
$temp = ( string ) filter_input ( INPUT_POST , 'temp' );
$hash = ( string ) filter_input ( INPUT_POST , 'hash' );
2021-07-07 01:13:50 +00:00
$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 ;
}
2022-08-26 01:26:00 +00:00
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' );
2021-07-07 01:13:50 +00:00
$temps -> execute ();
header ( 'Content-Type: application/json; charset=utf-8' );
2022-08-26 01:26:00 +00:00
echo json_encode ( $temps -> fetch ( PDO :: FETCH_ASSOC ));
2021-07-07 01:13:50 +00:00
return ;
}
2022-08-26 01:26:00 +00:00
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' );
2022-02-04 04:25:57 +00:00
$temps -> execute ();
header ( 'Content-Type: application/json; charset=utf-8' );
echo json_encode ( $temps -> fetchAll ( PDO :: FETCH_ASSOC ));
return ;
}
2022-08-26 01:26:00 +00:00
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' );
2022-02-04 04:25:57 +00:00
$temps -> execute ();
header ( 'Content-Type: application/json; charset=utf-8' );
echo json_encode ( $temps -> fetchAll ( PDO :: FETCH_ASSOC ));
return ;
}
2021-07-07 01:13:50 +00:00
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 );
2022-02-04 04:25:57 +00:00
date_default_timezone_set ( 'Europe/Amsterdam' );
2021-07-07 01:13:50 +00:00
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 : 12 px / 20 px Tahoma , Geneva , 'Dejavu Sans' , Arial , Helvetica , sans - serif ;
padding : 1 px ;
}
2022-08-26 01:26:00 +00:00
h2 {
font - family : 'Electrolize' , Verdana , 'Dejavu Sans' , Arial , Helvetica , sans - serif ;
}
2021-07-07 01:13:50 +00:00
. current {
text - align : center ;
background - color : #333;
margin : 10 px ;
padding : 10 px ;
border - radius : 10 px ;
}
. current - temp {
font - family : 'Electrolize' , Verdana , 'Dejavu Sans' , Arial , Helvetica , sans - serif ;
font - size : 3 em ;
line - height : 1.2 em ;
}
. current - datetime {
font - size : . 9 em ;
line - height : 1.4 em ;
}
. chart {
background - color : #ddd;
margin : 10 px ;
padding : 10 px ;
border - radius : 10 px ;
2022-08-26 01:26:00 +00:00
color : #666;
}
. chart - legend {
text - align : center ;
}
. chart - body {
width : 100 % ;
height : 400 px ;
text - align : center ;
}
. chart - labels {
width : 100 % ;
text - align : center ;
}
. legend {
display : inline - block ;
text - align : left ;
min - width : 100 px ;
}
. legend - icon {
background - color : var ( -- lc );
width : 10 px ;
height : 10 px ;
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 ;
2021-07-07 01:13:50 +00:00
}
</ 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 >
2022-08-26 01:26:00 +00:00
< div class = " chart " id = " -chart-hr " >
< h2 > 15 minutely Temperature ( 24 hr ) </ 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 >
2021-07-07 01:13:50 +00:00
</ div >
2022-08-26 01:26:00 +00:00
< div class = " chart " id = " -chart-wk " >
< h2 > Weekly Temperature ( 1 yr ) </ 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 >
2022-02-04 04:25:57 +00:00
</ div >
2021-07-07 01:13:50 +00:00
</ div >
< script type = " text/javascript " >
var temp = {
lastTemp : null ,
lastDateTime : null ,
2022-08-26 01:26:00 +00:00
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 ];
2021-07-07 01:13:50 +00:00
};
2022-08-26 01:26:00 +00:00
temp . weightedColourHex = function ( c1 , c2 , w ) {
return '#' + this . weightedColour ( c1 , c2 , w ) . toString ( 16 ) . padStart ( 6 , '0' );
2021-07-07 01:13:50 +00:00
};
2022-08-26 01:26:00 +00:00
temp . refreshLatest = function () {
2021-07-07 01:13:50 +00:00
var xhr = new XMLHttpRequest ;
xhr . onload = function () {
2022-08-26 01:26:00 +00:00
this . updateLatest ( JSON . parse ( xhr . responseText ));
2021-07-07 01:13:50 +00:00
} . bind ( this );
2022-08-26 01:26:00 +00:00
xhr . open ( 'GET' , '/temp.php?latest' );
2021-07-07 01:13:50 +00:00
xhr . send ();
};
2022-08-26 01:26:00 +00:00
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 = '' ;
2021-07-07 01:13:50 +00:00
2022-08-26 01:26:00 +00:00
for ( var i = 0 ; i < temps . length ; ++ i ) {
var temp = temps [ i ],
width = ( 100 / ( temps . length + 12 )) . toString () + '%' ;
2021-07-07 01:13:50 +00:00
2022-08-26 01:26:00 +00:00
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 );
}
2021-07-07 01:13:50 +00:00
};
2022-08-26 01:26:00 +00:00
temp . refreshWk = function () {
2022-02-04 04:25:57 +00:00
var xhr = new XMLHttpRequest ;
xhr . onload = function () {
2022-08-26 01:26:00 +00:00
this . updateWk ( JSON . parse ( xhr . responseText ));
2022-02-04 04:25:57 +00:00
} . bind ( this );
2022-08-26 01:26:00 +00:00
xhr . open ( 'GET' , '/temp.php?weekly' );
2022-02-04 04:25:57 +00:00
xhr . send ();
};
2022-08-26 01:26:00 +00:00
temp . updateWk = function ( temps ) {
this . chartWkBody . innerHTML = '' ;
this . chartWkLabels . innerHTML = '' ;
2022-02-04 04:25:57 +00:00
2022-08-26 01:26:00 +00:00
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 ;
2022-02-04 04:25:57 +00:00
};
2021-07-07 01:13:50 +00:00
window . onload = function () {
temp . lastTemp = document . getElementById ( '-last-temp' );
temp . lastDateTime = document . getElementById ( '-last-datetime' );
2022-08-26 01:26:00 +00:00
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 ];
2021-07-07 01:13:50 +00:00
2022-08-26 01:26:00 +00:00
temp . refreshLatest ();
setInterval ( temp . refreshLatest . bind ( temp ), 5 * 60 * 1000 );
2022-02-04 04:25:57 +00:00
2022-08-26 01:26:00 +00:00
temp . refreshHr ();
setInterval ( temp . refreshHr . bind ( temp ), 15 * 60 * 1000 );
2022-02-04 04:25:57 +00:00
2022-08-26 01:26:00 +00:00
temp . refreshWk ();
setInterval ( temp . refreshWk . bind ( temp ), 7 * 24 * 60 * 1000 );
2021-07-07 01:13:50 +00:00
};
</ script >
</ body >
2022-08-26 01:26:00 +00:00
</ html >