Archived
1
0

Support for many thermostats

Uses the device ID to support several thermostats. Pretty simple - only
setup is now an array of devices, now a single device. However, many
changes follow...
This commit is contained in:
dorfl68
2016-01-19 22:29:04 -05:00
parent f9b7276cb6
commit 9a4f57b5bb
14 changed files with 568 additions and 469 deletions

94
calc_delay.php Normal file
View File

@@ -0,0 +1,94 @@
<?php
include('settings/globals.php');
if(in_array(THERMOSTAT_TYPE,$valid_thermostats)){
require('thermostats/'.THERMOSTAT_TYPE.'/scrape.php');
require('thermostats/'.THERMOSTAT_TYPE.'/logininfo.php');
} else{
die("Invalid THERMOSTAT_TYPE set in settings/globals.php");
}
$d = $device_array[$_GET['id']]; // device ID we are calculating this for
include('settings/globals.php');
header('Content-Type: application/json');
$conn = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
// Check connection
if (!$conn) {
die("Connection failed: " . mysqli_connect_error());
}
$sql = 'SELECT UNIX_TIMESTAMP(date),dispTemperature,weatherTemperature,heatSetPoint,systemSwitchPosition from stat WHERE deviceID=' . $d; // note filter for ID
$result = $conn->query($sql);
if (!$result) {
printf("Errormessage: %s\n", $conn->error);
}
$rows = array();
while($r = mysqli_fetch_assoc($result)) {
$r['date'] = $r['UNIX_TIMESTAMP(date)'];
unset($r['UNIX_TIMESTAMP(date)']);
$rows[] = $r;
}
// print("<pre>");
// print_r($rows);
$startTime = -1;
$startTemp = NULL;
$startSetPoint = NULL;
$targetSetPoint = NULL;
$heat_up = NULL;
$heat_down = NULL;
$cool_up = NULL;
$cool_down = NULL;
$type = NULL;
for($i = 1; $i < count($rows); $i++){
$now = $rows[$i];
$last= $rows[$i-1];
// echo $startTime;
// print_r($now);
if($startTime == -1){
// echo "no start <br/>";
if($now['heatSetPoint'] <> $last['heatSetPoint']){
//Down!
// echo "down<br/>";
$startTime = $now['date'];
$startTemp = $now['dispTemperature'];
$startSetPoint = $last['heatSetPoint'];
$targetSetPoint = $now['heatSetPoint'];
if($now['heatSetPoint'] > $last['heatSetPoint']){
$type = "up";
} else {
$type = "down";
}
}
} else{
//looking for end
// echo "yes start <br/>";
if($now['dispTemperature'] == $targetSetPoint || $now['heatSetPoint'] <> $targetSetPoint){
$changeTime = ($now['date']-$startTime)/60;
$changeTemp = abs($startTemp - $now['dispTemperature']);
$outside = $now['weatherTemperature'];
$minperdeg = $changeTime/$changeTemp;
if($type == "up"){
$heat_up[] = [$minperdeg,intval($outside)];
} else{
$heat_down[] = [$minperdeg,intval($outside)];
}
$startTime = -1;
}
}
}
$return = [$heat_up, $heat_down];
print json_encode($return);
$conn->close();
?>

View File

@@ -2,14 +2,19 @@
include('settings/globals.php'); include('settings/globals.php');
$valid_thermostats = ["honeywell"];
if(in_array(THERMOSTAT_TYPE,$valid_thermostats)){ if(in_array(THERMOSTAT_TYPE,$valid_thermostats)){
require('thermostats/'.THERMOSTAT_TYPE.'/scrape.php'); require('thermostats/'.THERMOSTAT_TYPE.'/scrape.php');
require('thermostats/'.THERMOSTAT_TYPE.'/logininfo.php');
} else{ } else{
die("Invalid THERMOSTAT_TYPE set in settings/globals.php"); die("Invalid THERMOSTAT_TYPE set in settings/globals.php");
} }
$data = getCurrentInfo();
// dorfl added simple loop
for ($i = 0; $i <enumerate_thermostats(); $i++) { // all thermostats
$data = getCurrentInfo($i); // changed info!
$conn = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME); $conn = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
// Check connection // Check connection
@@ -37,6 +42,7 @@ echo $result;
if (!$result) { if (!$result) {
printf("Errormessage: %s\n", $conn->error); printf("Errormessage: %s\n", $conn->error);
} }
} // end for thermostats
$conn->close(); $conn->close();

View File

@@ -1,12 +1,28 @@
<?php <?php
$q = ''; $q = '';
$device_index = '';
include('settings/globals.php');
if(in_array(THERMOSTAT_TYPE,$valid_thermostats)){
require('thermostats/'.THERMOSTAT_TYPE.'/scrape.php');
require('thermostats/'.THERMOSTAT_TYPE.'/logininfo.php');
} else{
die("Invalid THERMOSTAT_TYPE set in settings/globals.php");
}
if(isset($_GET)){ if(isset($_GET)){
if(isset($_GET['q'])){ if(isset($_GET['q'])){
$q = $_GET['q']; $q = $_GET['q'];
if(isset($_GET['id'])){
$d = $device_array[$_GET['id']];
//$d="1488017";
header('Content-Type: application/json'); header('Content-Type: application/json');
include('settings/globals.php');
$conn = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME); $conn = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
// Check connection // Check connection
if (!$conn) { if (!$conn) {
@@ -33,7 +49,7 @@ if(isset($_GET)){
die("No query"); die("No query");
} }
$sql = $sql . " WHERE deviceID=" . $d;
$result = $conn->query($sql); $result = $conn->query($sql);
if (!$result) { if (!$result) {
printf("Errormessage: %s\n", $conn->error); printf("Errormessage: %s\n", $conn->error);
@@ -48,7 +64,7 @@ if(isset($_GET)){
$conn->close(); $conn->close();
}
} }
} }

View File

@@ -1,123 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Stat delay</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.5.0/bootstrap-table.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<script src="http://code.highcharts.com/highcharts.js"></script>
<script src="http://code.highcharts.com/modules/exporting.js"></script>
<script type="text/javascript">
$(function () {
console.log('load');
var seriesOptions = [];
var createChart = function(){
console.log('create');
$('#container').highcharts({
chart: {
type: 'scatter',
zoomType: 'xy'
},
title: {
text: 'Time to heat or cool vs outside temperature'
},
subtitle: {
text: 'Because science'
},
xAxis: {
title: {
enabled: true,
text: 'Minutes per degree change'
},
startOnTick: true,
endOnTick: true,
showLastLabel: true
},
yAxis: {
title: {
text: 'Outside temp'
}
},
legend: {
layout: 'vertical',
align: 'left',
verticalAlign: 'top',
x: 100,
y: 70,
floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.legendBackgroundColor) || '#FFFFFF',
borderWidth: 1
},
plotOptions: {
scatter: {
marker: {
radius: 5,
states: {
hover: {
enabled: true,
lineColor: 'rgb(100,100,100)'
}
}
},
states: {
hover: {
marker: {
enabled: false
}
}
},
tooltip: {
headerFormat: '<b>{series.name}</b><br>',
pointFormat: '{point.x} min per degree, {point.y} degrees'
}
}
},
series: seriesOptions,
});
}
$.getJSON('delay.php', function (data) {
console.log("data");
seriesOptions[0] = {
name: "Heat, Heating",
data: data[0]
};
seriesOptions[1] = {
name: "Heat, down",
data: data[1]
};
createChart();
});
});
</script>
<body>
<!-- Fixed navbar -->
<nav class="navbar navbar-inverse">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="#">Stat stats</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a href="index.html">Home</a></li>
<li><a href="graph.html">Graph</a></li>
<li class="active"><a href="delay.html">Delay</a></li>
</ul>
</div><!--/.nav-collapse -->
</div>
</nav>
<div id="container" style="min-width: 310px; height: 400px; max-width: 800px; margin: 0 auto"></div>
</body></html>

205
delay.php
View File

@@ -1,82 +1,141 @@
<!DOCTYPE html>
<html lang="en">
<?php <?php
include('settings/globals.php'); include('settings/globals.php');
header('Content-Type: application/json');
$conn = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
// Check connection
if (!$conn) {
die("Connection failed: " . mysqli_connect_error());
}
$sql = 'SELECT UNIX_TIMESTAMP(date),dispTemperature,weatherTemperature,heatSetPoint,systemSwitchPosition from stat';
$result = $conn->query($sql); $valid_thermostats = ["honeywell"];
if (!$result) {
printf("Errormessage: %s\n", $conn->error);
}
$rows = array();
while($r = mysqli_fetch_assoc($result)) {
$r['date'] = $r['UNIX_TIMESTAMP(date)'];
unset($r['UNIX_TIMESTAMP(date)']);
$rows[] = $r;
}
// print("<pre>");
// print_r($rows);
$startTime = -1;
$startTemp = NULL;
$startSetPoint = NULL;
$targetSetPoint = NULL;
$heat_up = NULL; if(in_array(THERMOSTAT_TYPE,$valid_thermostats)){
$heat_down = NULL; require('thermostats/'.THERMOSTAT_TYPE.'/scrape.php');
$cool_up = NULL; require('thermostats/'.THERMOSTAT_TYPE.'/logininfo.php');
$cool_down = NULL;
$type = NULL;
for($i = 1; $i < count($rows); $i++){
$now = $rows[$i];
$last= $rows[$i-1];
// echo $startTime;
// print_r($now);
if($startTime == -1){
// echo "no start <br/>";
if($now['heatSetPoint'] <> $last['heatSetPoint']){
//Down!
// echo "down<br/>";
$startTime = $now['date'];
$startTemp = $now['dispTemperature'];
$startSetPoint = $last['heatSetPoint'];
$targetSetPoint = $now['heatSetPoint'];
if($now['heatSetPoint'] > $last['heatSetPoint']){
$type = "up";
} else{ } else{
$type = "down"; die("Invalid THERMOSTAT_TYPE set in settings/globals.php");
}
}
} else{
//looking for end
// echo "yes start <br/>";
if($now['dispTemperature'] == $targetSetPoint || $now['heatSetPoint'] <> $targetSetPoint){
$changeTime = ($now['date']-$startTime)/60;
$changeTemp = abs($startTemp - $now['dispTemperature']);
$outside = $now['weatherTemperature'];
$minperdeg = $changeTime/$changeTemp;
if($type == "up"){
$heat_up[] = [$minperdeg,intval($outside)];
} else{
$heat_down[] = [$minperdeg,intval($outside)];
} }
$startTime = -1; $id = $_GET['id']; // device ID
}
}
}
$return = [$heat_up, $heat_down];
print json_encode($return);
$conn->close();
?> ?>
<head>
<title>Stat delay</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.5.0/bootstrap-table.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<script src="http://code.highcharts.com/highcharts.js"></script>
<script src="http://code.highcharts.com/modules/exporting.js"></script>
<script type="text/javascript">
$(function () {
console.log('load');
var seriesOptions = [];
var createChart = function(){
console.log('create');
$('#container').highcharts({
chart: {
type: 'scatter',
zoomType: 'xy'
},
title: {
text: 'Time to heat or cool vs outside temperature'
},
subtitle: {
text: 'Because science'
},
xAxis: {
title: {
enabled: true,
text: 'Minutes per degree change'
},
startOnTick: true,
endOnTick: true,
showLastLabel: true
},
yAxis: {
title: {
text: 'Outside temp'
}
},
legend: {
layout: 'vertical',
align: 'left',
verticalAlign: 'top',
x: 100,
y: 70,
floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.legendBackgroundColor) || '#FFFFFF',
borderWidth: 1
},
plotOptions: {
scatter: {
marker: {
radius: 5,
states: {
hover: {
enabled: true,
lineColor: 'rgb(100,100,100)'
}
}
},
states: {
hover: {
marker: {
enabled: false
}
}
},
tooltip: {
headerFormat: '<b>{series.name}</b><br>',
pointFormat: '{point.x} min per degree, {point.y} degrees'
}
}
},
series: seriesOptions,
});
}
$.getJSON('calc_delay.php?id=<?php echo $id ?>', function (data) {
console.log("data");
seriesOptions[0] = {
name: "Heat, Heating",
data: data[0]
};
seriesOptions[1] = {
name: "Heat, down",
data: data[1]
};
createChart();
});
});
</script>
<body>
<?php
// navbar
include('navbar.php');
?>
<h1>
<?php
// title!
echo $device_name_array[$id];
?>
</h1>
<div id="container" style="min-width: 310px; height: 400px; max-width: 800px; margin: 0 auto"></div>
</body></html>

57
getdata.php Normal file
View File

@@ -0,0 +1,57 @@
<?php
$q = '';
if(isset($_GET)){
if(isset($_GET['q'])){
$q = $_GET['q'];
$d = 1488017; // device ID number
header('Content-Type: application/json');
include('settings/globals.php');
$conn = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
// Check connection
if (!$conn) {
die("Connection failed: " . mysqli_connect_error());
}
$sql = '';
switch($q){
case "inside":
$sql = "SELECT UNIX_TIMESTAMP(date),dispTemperature from stat";
break;
case 'outside':
$sql = "SELECT UNIX_TIMESTAMP(date),weatherTemperature from stat";
break;
case 'set_heat':
$sql = "SELECT UNIX_TIMESTAMP(date),heatSetpoint from stat";
break;
case 'set_cool':
$sql = "SELECT UNIX_TIMESTAMP(date),coolSetpoint from stat";
break;
case 'humidity':
$sql = "SELECT UNIX_TIMESTAMP(date),weatherHumidity from stat";
break;
default:
die("No query");
}
$sql = $sql . " WHERE deviceID=" . $d;
$result = $conn->query($sql);
echo $sql;
$rows = array();
while($r = mysqli_fetch_assoc($result)) {
$row = array_map('floatval',array_values($r));
$row[0] = $row[0]*1000;
$rows[] = $row;
echo $row[1];
}
$conn->close();
}
}
?>

View File

@@ -1,7 +1,18 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<?php
include('settings/globals.php');
if(in_array(THERMOSTAT_TYPE,$valid_thermostats)){
require('thermostats/'.THERMOSTAT_TYPE.'/scrape.php');
require('thermostats/'.THERMOSTAT_TYPE.'/logininfo.php');
} else{
die("Invalid THERMOSTAT_TYPE set in settings/globals.php");
}
$id = $_GET['id']; //id # of thermostat
?>
<head> <head>
<title>Stat tracker</title> <title> Household Temperature Tracker</title>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"> <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
@@ -65,7 +76,7 @@
}; };
$.each(names, function (i, name) { $.each(names, function (i, name) {
$.getJSON('db-get.php?q='+name, function (data) { $.getJSON('db-get.php?id=<?php echo $id ?>&q='+name, function (data) {
seriesOptions[i] = { seriesOptions[i] = {
name: name, name: name,
@@ -83,24 +94,18 @@
</script> </script>
</head> </head>
<body> <body>
<!-- Fixed navbar --> <?php
<nav class="navbar navbar-inverse"> // navbar
<div class="container"> include('navbar.php');
<div class="navbar-header"> ?>
<a class="navbar-brand" href="#">Stat stats</a> <h1>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a href="index.html">Home</a></li>
<li class="active"><a href="graph.html">Graph</a></li>
<li><a href="delay.html">Delay</a></li>
</ul>
</div><!--/.nav-collapse -->
</div>
</nav>
<div id="container" style="height: 400px; min-width: 310px"></div>
<?php
// title!
echo $device_name_array[$id];
?>
</h1>
<div id="container" style="height: 600px; min-width: 310px"></div>
</body> </body>

View File

@@ -1,50 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>Stat stat</title>
<!-- Bootstrap -->
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<!-- Fixed navbar -->
<nav class="navbar navbar-inverse">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="#">Stat stat</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="index.htmll=">Home</a></li>
<li><a href="graph.html">Graph</a></li>
<li><a href="delay.html">Delay</a></li>
</ul>
</div><!--/.nav-collapse -->
</div>
</nav>
<div class="container" role="main">
<h1>Honeywell Thermostat tracker</h1>
<a href="graph.html"><button type="button" class="btn btn-lg btn-default">Graph</button></a>
<a href="delay.html"><button type="button" class="btn btn-lg btn-default">Delay</button></a>
</div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
</body>
</html>

3
index.php Normal file
View File

@@ -0,0 +1,3 @@
<?php
header('Location: graph.php?id=0');
?>

48
navbar.php Normal file
View File

@@ -0,0 +1,48 @@
<!-- Fixed navbar -->
<nav class="navbar navbar-inverse">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="#">Household Temperature Tracker</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="index.php">Home</a></li>
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">Graph
<span class="caret"></span></a>
<ul class="dropdown-menu">
<?php
// create drop-down entries
for ($i = 0; $i <enumerate_thermostats(); $i++) {
echo '<li><a href="graph.php?id=';
echo $i;
echo '">';
echo $device_name_array[$i];
echo '</a></li>';
}

View File

@@ -1,9 +1,11 @@
<?php <?php
define('DB_HOST',''); define('DB_HOST','localhost'); // define sql host
define('DB_NAME', ''); define('DB_NAME', 'database'); // sql database
define('DB_USER', ''); define('DB_USER', 'user'); // sql database user
define('DB_PASSWORD', ''); define('DB_PASSWORD', 'pw'); // guess what
// THERMOSTAT_TYPE needs to match the directory name of the thermostat plugin you are using. // THERMOSTAT_TYPE needs to match the directory name of the thermostat plugin you are using.
define('THERMOSTAT_TYPE',''); define('THERMOSTAT_TYPE','honeywell'); // only honeywell supported at this poing
$valid_thermostats = ["honeywell"]; // this should really be somewhere else but here it works right now
?> ?>

View File

@@ -1,6 +1,12 @@
<?php <?php
//Total Connect info //Total Connect info
$username=""; //
$password=""; $username="user@whatever.com"; // username as used with Honeywell
$device_number = ""; $password="mypassword"; // password as used with Honeywell
// device array - cannot be zero entries
$device_array = array("1234567","1234568","1234569 "); // from https://mytotalconnectcomfort.com/portal/Device/Control/[devicenumber to use here]?[ignore all that follows]
$device_name_array = array("Kitchen","Dining","Upstairs"); // we could probably pull the names from the page but easier this way
?> ?>

View File

@@ -123,7 +123,7 @@ function getStatus($device){
} }
} }
curl_close($ch);
return $data; return $data;
@@ -139,46 +139,22 @@ function cleanCookies(){
curl_close($ch); curl_close($ch);
} }
function add_data($data){
include('globals.php');
$conn = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME); Function enumerate_thermostats(){ // counts number of thermostats in array. Could probably move somewhere else
// Check connection require('logininfo.php');
if (!$conn) { $count = count($device_array);
die("Connection failed: " . mysqli_connect_error()); return $count;
} }
$good_columns = array("coolLowerSetpLimit","coolNextPeriod","coolSetpoint","coolUpperSetptLimit","deviceID","dispTemperature","displayedUnits","heatLowerSetptLimit","heatNextPeriod","heatSetpoint","heatUpperSetptLimit","isInVacationHoldMode","schedCoolSp","schedHeatSp","scheduleCapable","statusCool","statusHeat","systemSwitchPosition","weatherHumidity","weatherPhrase","weatherTemperature"); function getCurrentInfo($d){ // gets the current info for the thermostat with the id $d
$clean_data = array(); require('logininfo.php');
foreach($good_columns as $col){
$clean_data[$col] = $data[$col];
}
//$clean_data['weatherPhrase'] = $conn->real_escape_string($clean_data['weatherPhrase']);
$columns = implode(", ",array_keys($clean_data));
$values = implode(", ", array_values($clean_data));
$sql = "INSERT INTO `stat`(".$columns.") VALUES (".$values.")";
$result = $conn->query($sql);
echo $sql;
echo "\n";
echo $result;
if (!$result) {
printf("Errormessage: %s\n", $conn->error);
}
$conn->close();
}
function getCurrentInfo(){
require_once('logininfo.php');
login($username, $password); login($username, $password);
$data = getStatus($device_number); $data = getStatus($device_array[$d]);
return $data; return $data;
} }
?> ?>