1
0
mirror of https://github.com/beestat/app.git synced 2025-06-01 04:37:12 -04:00

Fixed #137 - If initial sync fails it never properly completes.

It will now attempt to resume the sync if it fails. This will still require a refresh on the browser or at the very least the cron job will pick up the slack.
This commit is contained in:
Jon Ziebell 2019-07-19 09:32:41 -04:00
parent 87490bd100
commit 3037b5cdb7
4 changed files with 177 additions and 26 deletions

View File

@ -66,7 +66,7 @@ class ecobee_runtime_thermostat extends cora\crud {
$thermostat = $this->api('thermostat', 'get', $thermostat_id); $thermostat = $this->api('thermostat', 'get', $thermostat_id);
if($thermostat['sync_begin'] === null) { if($thermostat['sync_begin'] !== $thermostat['first_connected']) {
$this->sync_backwards($thermostat_id); $this->sync_backwards($thermostat_id);
} else { } else {
$this->sync_forwards($thermostat_id); $this->sync_forwards($thermostat_id);
@ -87,21 +87,30 @@ class ecobee_runtime_thermostat extends cora\crud {
} }
/** /**
* Sync backwards from now until thermostat.first_connected. This should * Sync backwards. When running for the first time it will sync from now all
* only be used when syncing for the first time. * the way back to the first connected date. If it is called again it will
* check to see if a full backwards sync has already completed. If it has,
* it will throw an exception. If not, it will resume the backwards sync.
* *
* @param int $ecobee_thermostat_id * @param int $thermostat_id
*/ */
private function sync_backwards($thermostat_id) { private function sync_backwards($thermostat_id) {
$thermostat = $this->api('thermostat', 'get', $thermostat_id); $thermostat = $this->api('thermostat', 'get', $thermostat_id);
if($thermostat['sync_begin'] !== null) { if($thermostat['sync_begin'] === $thermostat['first_connected']) {
throw new \Exception('Full sync already performed; must call sync_forwards() now.'); throw new \Exception('Full sync already performed; must call sync_forwards() now.');
} }
// Sync from when the thermostat was first connected until now. if($thermostat['sync_begin'] === null) {
$sync_begin = strtotime($thermostat['first_connected']); // Sync from when the thermostat was first connected until now.
$sync_end = time(); $sync_begin = strtotime($thermostat['first_connected']);
$sync_end = time();
}
else {
// Sync from when the thermostat was first connected until sync_end.
$sync_begin = strtotime($thermostat['first_connected']);
$sync_end = strtotime($thermostat['sync_begin']);
}
$chunk_begin = $sync_end; $chunk_begin = $sync_end;
$chunk_end = $sync_end; $chunk_end = $sync_end;
@ -125,12 +134,17 @@ class ecobee_runtime_thermostat extends cora\crud {
'attributes' => [ 'attributes' => [
'thermostat_id' => $thermostat['thermostat_id'], 'thermostat_id' => $thermostat['thermostat_id'],
'sync_begin' => date('Y-m-d H:i:s', $chunk_begin), 'sync_begin' => date('Y-m-d H:i:s', $chunk_begin),
'sync_end' => date('Y-m-d H:i:s', $sync_end), 'sync_end' => date(
'Y-m-d H:i:s',
max(
$sync_end,
strtotime($thermostat['sync_end'])
)
)
] ]
] ]
); );
// Because I am doing day-level syncing this will end up fetching an // Because I am doing day-level syncing this will end up fetching an
// overlapping day of data every time. But if I properly switch this to // overlapping day of data every time. But if I properly switch this to
// interval-level syncing this should be correct or at the very least // interval-level syncing this should be correct or at the very least
@ -458,6 +472,7 @@ class ecobee_runtime_thermostat extends cora\crud {
$query = ' $query = '
select select
`ecobee_thermostat_id`, `ecobee_thermostat_id`,
`ecobee_runtime_thermostat_id`,
`timestamp`, `timestamp`,
cast(greatest(0, (cast(`compressor_heat_1` as signed) - cast(`compressor_heat_2` as signed))) as unsigned) `compressor_heat_1`, cast(greatest(0, (cast(`compressor_heat_1` as signed) - cast(`compressor_heat_2` as signed))) as unsigned) `compressor_heat_1`,

View File

@ -15,7 +15,7 @@ class user extends cora\crud {
'log_out', 'log_out',
'sync_patreon_status' 'sync_patreon_status'
], ],
'public' => [] 'public' => ['force_log_in']
]; ];
public static $converged = []; public static $converged = [];

View File

@ -61,7 +61,8 @@ beestat.component.card.recent_activity.prototype.decorate_contents_ = function(p
'lineColor': beestat.style.color.bluegray.light, 'lineColor': beestat.style.color.bluegray.light,
'min': series.x.chart_data[0], 'min': series.x.chart_data[0],
'max': series.x.chart_data[series.x.chart_data.length - 1], 'max': series.x.chart_data[series.x.chart_data.length - 1],
'minRange': 21600000, // 'minRange': 21600000,
'minRange': 21600000/8,
'tickLength': 0, 'tickLength': 0,
'gridLineWidth': 0, 'gridLineWidth': 0,
'labels': { 'labels': {
@ -383,33 +384,33 @@ beestat.component.card.recent_activity.prototype.decorate_contents_ = function(p
'data': series.compressor_cool_1.chart_data, 'data': series.compressor_cool_1.chart_data,
'yAxis': 1, 'yAxis': 1,
'marker': { 'marker': {
'enabled': false, 'enabled': true,
'states': {'hover': {'enabled': false}} // 'states': {'hover': {'enabled': false}}
}, },
'name': 'Cool', 'name': 'Cool',
'type': 'line', 'type': 'line',
'color': beestat.series.compressor_cool_1.color, 'color': beestat.series.compressor_cool_1.color,
'lineWidth': 10, // 'lineWidth': 10,
'linecap': 'square', 'linecap': 'square',
'states': {'hover': {'lineWidthPlus': 0}} // 'states': {'hover': {'lineWidthPlus': 0}}
}); });
} }
if (series.compressor_cool_2.enabled === true) { if (series.compressor_cool_2.enabled === true) {
this.chart_.options.series.push({ this.chart_.options.series.push({
'data': series.compressor_cool_2.chart_data, 'data': series.compressor_cool_2.chart_data,
'linkedTo': 'compressor_cool_1', // 'linkedTo': 'compressor_cool_1',
'yAxis': 1, 'yAxis': 1,
'marker': { 'marker': {
'enabled': false, 'enabled': true,
'states': {'hover': {'enabled': false}} // 'states': {'hover': {'enabled': false}}
}, },
'name': beestat.series.compressor_cool_2.name, 'name': beestat.series.compressor_cool_2.name,
'type': 'line', 'type': 'line',
'color': beestat.series.compressor_cool_2.color, 'color': beestat.series.compressor_cool_2.color,
'lineWidth': 10, // 'lineWidth': 10,
'linecap': 'square', 'linecap': 'square',
'states': {'hover': {'lineWidthPlus': 0}} // 'states': {'hover': {'lineWidthPlus': 0}}
}); });
} }
@ -851,13 +852,15 @@ beestat.component.card.recent_activity.prototype.get_series_ = function() {
) )
.valueOf(); .valueOf();
/* /*
* This creates a distinct object for each chunk of runtime so the total on * This creates a distinct object for each chunk of runtime so the total on
* time can be computed for any given segment. * time can be computed for any given segment.
*/ */
var durations = {}; var durations = {};
beestat.cache.ecobee_runtime_thermostat.forEach(function(ecobee_runtime_thermostat, i) { var ecobee_runtime_thermostats = this.get_adjusted_ecobee_runtime_thermostats_();
ecobee_runtime_thermostats.forEach(function(ecobee_runtime_thermostat, i) {
if (ecobee_runtime_thermostat.ecobee_thermostat_id !== thermostat.ecobee_thermostat_id) { if (ecobee_runtime_thermostat.ecobee_thermostat_id !== thermostat.ecobee_thermostat_id) {
return; return;
} }
@ -877,6 +880,8 @@ beestat.component.card.recent_activity.prototype.get_series_ = function() {
// TODO DO THIS FOR AUX // TODO DO THIS FOR AUX
// TODO DO THIS FOR COOL // TODO DO THIS FOR COOL
// ecobee_runtime_thermostat['compressor_cool_1'] += ecobee_runtime_thermostat['compressor_cool_2'];
beestat.component.card.recent_activity.optional_series.forEach(function(series_code) { beestat.component.card.recent_activity.optional_series.forEach(function(series_code) {
if (durations[series_code] === undefined) { if (durations[series_code] === undefined) {
durations[series_code] = [{'seconds': 0}]; durations[series_code] = [{'seconds': 0}];
@ -906,16 +911,17 @@ beestat.component.card.recent_activity.prototype.get_series_ = function() {
break; break;
} }
var duration = original_durations[series_code] !== undefined
? original_durations[series_code]
: ecobee_runtime_thermostat[series_code];
series[series_code].enabled = true; series[series_code].enabled = true;
series[series_code].chart_data.push([ series[series_code].chart_data.push([
x, x,
value value
]); ]);
series[series_code].data[x] = value;
var duration = original_durations[series_code] !== undefined series[series_code].data[x] = value;
? original_durations[series_code]
: ecobee_runtime_thermostat[series_code];
durations[series_code][durations[series_code].length - 1].seconds += duration; durations[series_code][durations[series_code].length - 1].seconds += duration;
// durations[series_code][durations[series_code].length - 1].seconds += ecobee_runtime_thermostat[series_code]; // durations[series_code][durations[series_code].length - 1].seconds += ecobee_runtime_thermostat[series_code];
@ -1401,3 +1407,132 @@ beestat.component.card.recent_activity.prototype.get_data_ = function() {
}) })
.send(); .send();
}; };
/**
* [get_adjusted_ecobee_runtime_thermostats_ description]
*
* @return {[type]} [description]
*/
beestat.component.card.recent_activity.prototype.get_adjusted_ecobee_runtime_thermostats_ = function() {
var ecobee_runtime_thermostats = [];
beestat.cache.ecobee_runtime_thermostat.forEach(function(ecobee_runtime_thermostat, i) {
var new_rows = {};
var directions = {};
/**
* Skip the first row as I look backwards to it to determine if runtimes
* are beginning or ending.
*
*
*
* sigh...now the issue is that I have this
* 300 fan: 300
* 600 fan: 150
* 750 fan: 0
* 900 fan: 0
*
* So the 750 fan 0 gets added, but no point is drawn there so the fan still
* appears to turn off at 600. I either need to insert a row at 749 with fan:1,
* or somehow get highcharts to put a marker on 750 because the previous value was positive.
* I think I could do if(off and previous on) value = 1
*
*/
if (i > 0 && ecobee_runtime_thermostat.ecobee_runtime_thermostat_id === 752423131) { // test end
// if (i > 0 && ecobee_runtime_thermostat.ecobee_runtime_thermostat_id === 724690669) { // test begin
// if (i > 0) {
// beestat.cache.ecobee_runtime_thermostat[i - 1].compressor_heat_1 = 0;
// ecobee_runtime_thermostat.compressor_heat_1 = 90;
// Assign the directions (begin/end) and fill in stubs for new_rows.
beestat.component.card.recent_activity.optional_series.forEach(function(series_code) {
if (
ecobee_runtime_thermostat[series_code] > 0 &&
ecobee_runtime_thermostat[series_code] < 300
) {
var new_row_timestamp_offset;
var previous_row = beestat.cache.ecobee_runtime_thermostat[i - 1];
if (previous_row[series_code] === 300) {
console.log(series_code + ' is turning off in ' + ecobee_runtime_thermostat[series_code] + 's');
directions[series_code] = 'end';
new_row_timestamp_offset = ecobee_runtime_thermostat[series_code];
} else {
console.log(series_code + ' turned on ' + ecobee_runtime_thermostat[series_code] + 's ago');
directions[series_code] = 'begin';
new_row_timestamp_offset =
(300 - ecobee_runtime_thermostat[series_code]);
}
var new_row = JSON.parse(JSON.stringify(ecobee_runtime_thermostat));
var new_row_timestamp_m = moment(ecobee_runtime_thermostat.timestamp)
.add(new_row_timestamp_offset, 'seconds');
new_row.timestamp_m = new_row_timestamp_m;
new_row.timestamp = new_row_timestamp_m.format('Y-MM-DD HH:mm:ss');
new_rows[new_row_timestamp_m.format('Y-MM-DD HH:mm:ss')] = new_row;
}
});
}
new_rows = Object.values(new_rows);
if (new_rows.length > 0) {
// Add the current row as it's easier to pretend it's new.
ecobee_runtime_thermostat.timestamp_m =
moment(ecobee_runtime_thermostat.timestamp);
new_rows.push(ecobee_runtime_thermostat);
// Sort the new rows so they can be looped over accurately.
new_rows.sort(function(a, b) {
return moment(a.timestamp).isAfter(moment(b.timestamp)) ? 1 : -1;
});
/**
* Go through each column one at a time filling in the appropriate
* values.
*/
beestat.component.card.recent_activity.optional_series.forEach(function(series_code) {
var j;
var diff;
var time_left = new_rows[0][series_code];
if (directions[series_code] === 'begin') {
for (j = new_rows.length - 1; j > 0; j--) {
diff = new_rows[j].timestamp_m.diff(
new_rows[j - 1].timestamp_m,
'seconds'
);
new_rows[j][series_code] = Math.min(time_left, diff);
time_left = Math.max(0, time_left - diff);
}
// The first new_row will always be set to 0.
new_rows[0][series_code] = 0;
} else {
// var time_left = new_rows[0][series_code];
for (j = 0; j < new_rows.length - 1; j++) {
diff = new_rows[j + 1].timestamp_m.diff(
new_rows[j].timestamp_m,
'seconds'
);
new_rows[j][series_code] = Math.min(time_left, diff);
time_left = Math.max(0, time_left - diff);
}
// The last new_row will always be set to 0.
new_rows[j][series_code] = 0;
}
});
// Add all of the new rows to the list.
new_rows.forEach(function(new_row) {
ecobee_runtime_thermostats.push(new_row);
});
console.log(ecobee_runtime_thermostat);
console.log(new_rows);
} else {
// No new rows, so just add the original row to the list.
ecobee_runtime_thermostats.push(ecobee_runtime_thermostat);
}
});
return ecobee_runtime_thermostats;
};

View File

@ -19,6 +19,7 @@ if($setting->get('environment') === 'dev' || $setting->get('environment') === 'd
echo '<script src="/js/beestat/debounce.js"></script>' . PHP_EOL; echo '<script src="/js/beestat/debounce.js"></script>' . PHP_EOL;
echo '<script src="/js/beestat/dispatcher.js"></script>' . PHP_EOL; echo '<script src="/js/beestat/dispatcher.js"></script>' . PHP_EOL;
echo '<script src="/js/beestat/cache.js"></script>' . PHP_EOL; echo '<script src="/js/beestat/cache.js"></script>' . PHP_EOL;
echo '<script src="/js/beestat/clone.js"></script>' . PHP_EOL;
echo '<script src="/js/beestat/style.js"></script>' . PHP_EOL; echo '<script src="/js/beestat/style.js"></script>' . PHP_EOL;
echo '<script src="/js/beestat/api.js"></script>' . PHP_EOL; echo '<script src="/js/beestat/api.js"></script>' . PHP_EOL;
echo '<script src="/js/beestat/error.js"></script>' . PHP_EOL; echo '<script src="/js/beestat/error.js"></script>' . PHP_EOL;