mirror of
https://github.com/beestat/app.git
synced 2025-05-24 02:14:03 -04:00
Enabled metrics and new profiles for early access
This commit is contained in:
parent
154af5d89f
commit
8b57cfc227
@ -29,7 +29,7 @@ class thermostat_group extends cora\crud {
|
||||
'generate_profile' => 604800, // 7 Days
|
||||
'generate_profiles' => 604800, // 7 Days
|
||||
'get_scores' => 604800, // 7 Days
|
||||
'get_metrics' => 604800 // 7 Days
|
||||
// 'get_metrics' => 604800 // 7 Days
|
||||
];
|
||||
|
||||
/**
|
||||
@ -565,7 +565,8 @@ class thermostat_group extends cora\crud {
|
||||
|
||||
$metric_codes = [
|
||||
'setpoint_heat',
|
||||
'setpoint_cool'
|
||||
'setpoint_cool',
|
||||
'runtime_per_heating_degree_day'
|
||||
];
|
||||
|
||||
$metrics = [];
|
||||
@ -636,6 +637,25 @@ class thermostat_group extends cora\crud {
|
||||
$metrics['setpoint_cool']['histogram'][$setpoint_cool]++;
|
||||
$metrics['setpoint_cool']['values'][] = $setpoint_cool;
|
||||
}
|
||||
|
||||
// runtime_per_heating_degree_day
|
||||
if(
|
||||
isset($other_thermostat_group['profile']) === true &&
|
||||
isset($other_thermostat_group['profile']['runtime']) == true &&
|
||||
$other_thermostat_group['profile']['runtime']['heat_1'] !== null &&
|
||||
isset($other_thermostat_group['profile']['degree_days']) === true &&
|
||||
$other_thermostat_group['profile']['degree_days']['heat'] !== null
|
||||
) {
|
||||
$runtime_per_heating_degree_day = round(
|
||||
$other_thermostat_group['profile']['runtime']['heat_1'] / $other_thermostat_group['profile']['degree_days']['heat'],
|
||||
1
|
||||
);
|
||||
if(isset($metrics['runtime_per_heating_degree_day']['histogram'][(string)$runtime_per_heating_degree_day]) === false) {
|
||||
$metrics['runtime_per_heating_degree_day']['histogram'][(string)$runtime_per_heating_degree_day] = 0;
|
||||
}
|
||||
$metrics['runtime_per_heating_degree_day']['histogram'][(string)$runtime_per_heating_degree_day]++;
|
||||
$metrics['runtime_per_heating_degree_day']['values'][] = $runtime_per_heating_degree_day;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -656,6 +676,13 @@ class thermostat_group extends cora\crud {
|
||||
$metrics['setpoint_cool']['median'] = array_median($metrics['setpoint_cool']['values']);
|
||||
unset($metrics['setpoint_cool']['values']);
|
||||
|
||||
// runtime_per_heating_degree_day
|
||||
$metrics['runtime_per_heating_degree_day']['standard_deviation'] = round($this->standard_deviation(
|
||||
$metrics['runtime_per_heating_degree_day']['values']
|
||||
), 2);
|
||||
$metrics['runtime_per_heating_degree_day']['median'] = array_median($metrics['runtime_per_heating_degree_day']['values']);
|
||||
unset($metrics['runtime_per_heating_degree_day']['values']);
|
||||
|
||||
return $metrics;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
beestat.home_comparisons = {};
|
||||
beestat.comparisons = {};
|
||||
|
||||
/**
|
||||
* Fire off an API call to get the comparison scores using the currently
|
||||
@ -14,7 +14,7 @@ beestat.home_comparisons = {};
|
||||
* @param {Function} callback Optional callback to fire when the API call
|
||||
* completes.
|
||||
*/
|
||||
beestat.home_comparisons.get_comparison_scores = function(callback) {
|
||||
beestat.comparisons.get_comparison_scores = function(callback) {
|
||||
var types = [
|
||||
'heat',
|
||||
'cool',
|
||||
@ -29,15 +29,26 @@ beestat.home_comparisons.get_comparison_scores = function(callback) {
|
||||
'get_scores',
|
||||
{
|
||||
'type': type,
|
||||
'attributes': beestat.home_comparisons.get_comparison_attributes(type)
|
||||
'attributes': beestat.comparisons.get_comparison_attributes(type)
|
||||
},
|
||||
type
|
||||
'score_' + type
|
||||
);
|
||||
});
|
||||
|
||||
api.add_call(
|
||||
'thermostat_group',
|
||||
'get_metrics',
|
||||
{
|
||||
'attributes': beestat.comparisons.get_comparison_attributes('resist') // todo
|
||||
},
|
||||
'metrics'
|
||||
);
|
||||
|
||||
api.set_callback(function(data) {
|
||||
beestat.cache.set('data.metrics', data.metrics);
|
||||
|
||||
types.forEach(function(type) {
|
||||
beestat.cache.set('data.comparison_scores_' + type, data[type]);
|
||||
beestat.cache.set('data.comparison_scores_' + type, data['score_' + type]);
|
||||
});
|
||||
|
||||
if (callback !== undefined) {
|
||||
@ -56,7 +67,7 @@ beestat.home_comparisons.get_comparison_scores = function(callback) {
|
||||
*
|
||||
* @return {Object} The comparison attributes.
|
||||
*/
|
||||
beestat.home_comparisons.get_comparison_attributes = function(type) {
|
||||
beestat.comparisons.get_comparison_attributes = function(type) {
|
||||
var thermostat = beestat.cache.thermostat[beestat.setting('thermostat_id')];
|
||||
var thermostat_group =
|
||||
beestat.cache.thermostat_group[thermostat.thermostat_group_id];
|
@ -298,3 +298,34 @@ beestat.series.indoor_resist_delta = {
|
||||
'color': beestat.style.color.gray.dark
|
||||
};
|
||||
beestat.series.indoor_resist_delta_raw = beestat.series.indoor_resist_delta;
|
||||
|
||||
// Temperature Profiles New
|
||||
beestat.series.indoor_heat_1_delta = {
|
||||
'name': 'Indoor Heat 1 Δ',
|
||||
'color': beestat.series.compressor_heat_1.color
|
||||
};
|
||||
beestat.series.indoor_heat_1_delta_raw = beestat.series.indoor_heat_1_delta;
|
||||
|
||||
beestat.series.indoor_heat_2_delta = {
|
||||
'name': 'Indoor Heat 2 Δ',
|
||||
'color': beestat.series.compressor_heat_2.color
|
||||
};
|
||||
beestat.series.indoor_heat_2_delta_raw = beestat.series.indoor_heat_2_delta;
|
||||
|
||||
beestat.series.indoor_cool_1_delta = {
|
||||
'name': 'Indoor Cool 1 Δ',
|
||||
'color': beestat.series.compressor_cool_1.color
|
||||
};
|
||||
beestat.series.indoor_cool_1_delta_raw = beestat.series.indoor_cool_1_delta;
|
||||
|
||||
beestat.series.indoor_cool_2_delta = {
|
||||
'name': 'Indoor Cool 2 Δ',
|
||||
'color': beestat.series.compressor_cool_2.color
|
||||
};
|
||||
beestat.series.indoor_cool_2_delta_raw = beestat.series.indoor_cool_2_delta;
|
||||
|
||||
beestat.series.indoor_resist_delta = {
|
||||
'name': 'Indoor Δ',
|
||||
'color': beestat.style.color.gray.dark
|
||||
};
|
||||
beestat.series.indoor_resist_delta_raw = beestat.series.indoor_resist_delta;
|
||||
|
@ -32,8 +32,7 @@ beestat.user.has_early_access = function() {
|
||||
return user.user_id === 1 ||
|
||||
(
|
||||
user.patreon_status !== null &&
|
||||
user.patreon_status.patron_status === 'active_patron' &&
|
||||
user.patreon_status.currently_entitled_amount_cents >= 500
|
||||
user.patreon_status.patron_status === 'active_patron'
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,28 +0,0 @@
|
||||
/**
|
||||
* Possible issue with your comparison.
|
||||
*/
|
||||
beestat.component.card.comparison_issue = function() {
|
||||
beestat.component.card.apply(this, arguments);
|
||||
};
|
||||
beestat.extend(beestat.component.card.comparison_issue, beestat.component.card);
|
||||
|
||||
/**
|
||||
* Decorate
|
||||
*
|
||||
* @param {rocket.Elements} parent
|
||||
*/
|
||||
beestat.component.card.comparison_issue.prototype.decorate_contents_ = function(parent) {
|
||||
parent.style('background', beestat.style.color.red.dark);
|
||||
parent.appendChild($.createElement('p').innerText('Notice how one or more of the lines below slopes down or is very flat? The expectation is that these slope upwards. This may affect the accuracy of your scores.'));
|
||||
parent.appendChild($.createElement('p').innerText('I\'ll be investigating these situations and improving the algorithm as much as possible to provide as accurate results as I can. Thank you!'));
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the title of the card.
|
||||
*
|
||||
* @return {string} The title of the card.
|
||||
*/
|
||||
beestat.component.card.comparison_issue.prototype.get_title_ = function() {
|
||||
return 'Possible issue with your temperature profiles!';
|
||||
};
|
||||
|
@ -51,24 +51,24 @@ beestat.component.card.comparison_settings.prototype.decorate_contents_ = functi
|
||||
* If the data is available, then get the data if we don't already have it
|
||||
* loaded. If the data is not available, poll until it becomes available.
|
||||
*/
|
||||
if (thermostat_group.temperature_profile === null) {
|
||||
if (thermostat_group.profile === null) {
|
||||
// This will show the loading screen.
|
||||
self.data_available_();
|
||||
|
||||
var poll_interval = 10000;
|
||||
|
||||
beestat.add_poll_interval(poll_interval);
|
||||
beestat.dispatcher.addEventListener('poll.home_comparisons_load', function() {
|
||||
beestat.dispatcher.addEventListener('poll.comparisons_load', function() {
|
||||
if (self.data_available_() === true) {
|
||||
beestat.remove_poll_interval(poll_interval);
|
||||
beestat.dispatcher.removeEventListener('poll.home_comparisons_load');
|
||||
beestat.dispatcher.removeEventListener('poll.comparisons_load');
|
||||
|
||||
new beestat.api()
|
||||
.add_call(
|
||||
'thermostat_group',
|
||||
'generate_temperature_profiles',
|
||||
'generate_profiles',
|
||||
{},
|
||||
'generate_temperature_profiles'
|
||||
'generate_profiles'
|
||||
)
|
||||
.add_call(
|
||||
'thermostat_group',
|
||||
@ -78,7 +78,7 @@ beestat.component.card.comparison_settings.prototype.decorate_contents_ = functi
|
||||
)
|
||||
.set_callback(function(response) {
|
||||
beestat.cache.set('thermostat_group', response.thermostat_group);
|
||||
(new beestat.layer.home_comparisons()).render();
|
||||
(new beestat.layer.comparisons()).render();
|
||||
})
|
||||
.send();
|
||||
}
|
||||
@ -127,7 +127,7 @@ beestat.component.card.comparison_settings.prototype.decorate_region_ = function
|
||||
// Open up the loading window.
|
||||
self.show_loading_('Calculating Score for ' + region + ' region');
|
||||
|
||||
beestat.home_comparisons.get_comparison_scores(function() {
|
||||
beestat.comparisons.get_comparison_scores(function() {
|
||||
// Rerender to get rid of the loader.
|
||||
self.rerender();
|
||||
});
|
||||
@ -200,7 +200,7 @@ beestat.component.card.comparison_settings.prototype.decorate_property_ = functi
|
||||
// Open up the loading window.
|
||||
self.show_loading_('Calculating Score for ' + property_type.text);
|
||||
|
||||
beestat.home_comparisons.get_comparison_scores(function() {
|
||||
beestat.comparisons.get_comparison_scores(function() {
|
||||
// Rerender to get rid of the loader.
|
||||
self.rerender();
|
||||
});
|
||||
|
27
js/component/card/early_access.js
Normal file
27
js/component/card/early_access.js
Normal file
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Early access
|
||||
*/
|
||||
beestat.component.card.early_access = function() {
|
||||
beestat.component.card.apply(this, arguments);
|
||||
};
|
||||
beestat.extend(beestat.component.card.early_access, beestat.component.card);
|
||||
|
||||
/**
|
||||
* Decorate
|
||||
*
|
||||
* @param {rocket.Elements} parent
|
||||
*/
|
||||
beestat.component.card.early_access.prototype.decorate_contents_ = function(parent) {
|
||||
parent.style('background', beestat.style.color.green.base);
|
||||
parent.appendChild($.createElement('p').innerText('Experimental early access features below! ⤵'));
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the title of the card.
|
||||
*
|
||||
* @return {string} The title of the card.
|
||||
*/
|
||||
// beestat.component.card.early_access.prototype.get_title_ = function() {
|
||||
// return 'Possible issue with your temperature profiles!';
|
||||
// };
|
||||
|
84
js/component/card/metrics.js
Normal file
84
js/component/card/metrics.js
Normal file
@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Metrics card.
|
||||
*/
|
||||
beestat.component.card.metrics = function(thermostat_group_id) {
|
||||
this.thermostat_group_id_ = thermostat_group_id;
|
||||
|
||||
var self = this;
|
||||
|
||||
/*
|
||||
* Debounce so that multiple setting changes don't re-trigger the same
|
||||
* event. This fires on the trailing edge so that all changes are accounted
|
||||
* for when rerendering.
|
||||
*/
|
||||
var data_change_function = beestat.debounce(function() {
|
||||
self.rerender();
|
||||
}, 10);
|
||||
|
||||
beestat.dispatcher.addEventListener(
|
||||
'cache.data.metrics',
|
||||
data_change_function
|
||||
);
|
||||
|
||||
beestat.component.card.apply(this, arguments);
|
||||
|
||||
// this.layer_.register_loader(beestat.comparisons.get_comparison_metricss);
|
||||
};
|
||||
beestat.extend(beestat.component.card.metrics, beestat.component.card);
|
||||
|
||||
/**
|
||||
* Decorate
|
||||
*
|
||||
* @param {rocket.Elements} parent
|
||||
*/
|
||||
beestat.component.card.metrics.prototype.decorate_contents_ = function(parent) {
|
||||
var self = this;
|
||||
|
||||
var metrics = [
|
||||
'setpoint_heat',
|
||||
'setpoint_cool',
|
||||
// 'runtime_per_heating_degree_day'
|
||||
];
|
||||
|
||||
// Decorate the metrics
|
||||
var metric_container = $.createElement('div')
|
||||
.style({
|
||||
'display': 'grid',
|
||||
// 'grid-template-columns': 'repeat(auto-fit, minmax(160px, 1fr))',
|
||||
'grid-template-columns': '1fr 1fr 1fr',
|
||||
'margin': '0 0 ' + beestat.style.size.gutter + 'px -' + beestat.style.size.gutter + 'px'
|
||||
});
|
||||
parent.appendChild(metric_container);
|
||||
|
||||
metrics.forEach(function(metric) {
|
||||
var div = $.createElement('div')
|
||||
.style({
|
||||
'padding': beestat.style.size.gutter + 'px 0 0 ' + beestat.style.size.gutter + 'px'
|
||||
});
|
||||
metric_container.appendChild(div);
|
||||
|
||||
(new beestat.component.metric[metric](self.thermostat_group_id_)).render(div);
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the title of the card.
|
||||
*
|
||||
* @return {string} The title of the card.
|
||||
*/
|
||||
beestat.component.card.metrics.prototype.get_title_ = function() {
|
||||
return 'Metrics';
|
||||
};
|
||||
|
||||
/**
|
||||
* Decorate the menu.
|
||||
*
|
||||
* @param {rocket.Elements} parent
|
||||
*/
|
||||
/*beestat.component.card.my_home.prototype.decorate_top_right_ = function(parent) {
|
||||
|
||||
};*/
|
@ -20,7 +20,7 @@ beestat.component.card.score = function() {
|
||||
|
||||
beestat.component.card.apply(this, arguments);
|
||||
|
||||
this.layer_.register_loader(beestat.home_comparisons.get_comparison_scores);
|
||||
this.layer_.register_loader(beestat.comparisons.get_comparison_scores);
|
||||
};
|
||||
beestat.extend(beestat.component.card.score, beestat.component.card);
|
||||
|
||||
|
237
js/component/card/temperature_profiles_new.js
Normal file
237
js/component/card/temperature_profiles_new.js
Normal file
@ -0,0 +1,237 @@
|
||||
/**
|
||||
* Temperature profiles.
|
||||
*
|
||||
* @param {number} thermostat_group_id The thermostat_group_id this card is
|
||||
* displaying data for.
|
||||
*/
|
||||
beestat.component.card.temperature_profiles_new = function(thermostat_group_id) {
|
||||
this.thermostat_group_id_ = thermostat_group_id;
|
||||
|
||||
beestat.component.card.apply(this, arguments);
|
||||
};
|
||||
beestat.extend(beestat.component.card.temperature_profiles_new, beestat.component.card);
|
||||
|
||||
/**
|
||||
* Decorate card.
|
||||
*
|
||||
* @param {rocket.Elements} parent
|
||||
*/
|
||||
beestat.component.card.temperature_profiles_new.prototype.decorate_contents_ = function(parent) {
|
||||
var data = this.get_data_();
|
||||
this.chart_ = new beestat.component.chart.temperature_profiles_new(data);
|
||||
this.chart_.render(parent);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all of the series data.
|
||||
*
|
||||
* @return {object} The series data.
|
||||
*/
|
||||
beestat.component.card.temperature_profiles_new.prototype.get_data_ = function() {
|
||||
var thermostat_group = beestat.cache.thermostat_group[
|
||||
this.thermostat_group_id_
|
||||
];
|
||||
|
||||
var data = {
|
||||
'x': [],
|
||||
'series': {},
|
||||
'metadata': {
|
||||
'series': {},
|
||||
'chart': {
|
||||
'title': this.get_title_(),
|
||||
'subtitle': this.get_subtitle_(),
|
||||
'outdoor_temperature': beestat.temperature({
|
||||
'temperature': (thermostat_group.weather.temperature / 10),
|
||||
'round': 0
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (
|
||||
thermostat_group.profile === null
|
||||
) {
|
||||
this.chart_.render(parent);
|
||||
this.show_loading_('Calculating');
|
||||
} else {
|
||||
// Global x range.
|
||||
var x_min = Infinity;
|
||||
var x_max = -Infinity;
|
||||
|
||||
var y_min = Infinity;
|
||||
var y_max = -Infinity;
|
||||
for (var type in thermostat_group.profile.temperature) {
|
||||
// Cloned because I mutate this data for temperature conversions.
|
||||
var profile = beestat.clone(
|
||||
thermostat_group.profile.temperature[type]
|
||||
);
|
||||
|
||||
if (profile !== null) {
|
||||
// Convert the data to Celsius if necessary
|
||||
var deltas_converted = {};
|
||||
for (var key in profile.deltas) {
|
||||
deltas_converted[beestat.temperature({'temperature': key})] =
|
||||
beestat.temperature({
|
||||
'temperature': (profile.deltas[key]),
|
||||
'delta': true,
|
||||
'round': 3
|
||||
});
|
||||
}
|
||||
|
||||
profile.deltas = deltas_converted;
|
||||
var linear_trendline = this.get_linear_trendline_(profile.deltas);
|
||||
|
||||
var min_max_keys = Object.keys(profile.deltas);
|
||||
|
||||
// This specific trendline x range.
|
||||
var this_x_min = Math.min.apply(null, min_max_keys);
|
||||
var this_x_max = Math.max.apply(null, min_max_keys);
|
||||
|
||||
// Global x range.
|
||||
x_min = Math.min(x_min, this_x_min);
|
||||
x_max = Math.max(x_max, this_x_max);
|
||||
|
||||
data.series['trendline_' + type] = [];
|
||||
data.series['raw_' + type] = [];
|
||||
|
||||
/**
|
||||
* Data is stored internally as °F with 1 value per degree. That data
|
||||
* gets converted to °C which then requires additional precision
|
||||
* (increment).
|
||||
*
|
||||
* The additional precision introduces floating point error, so
|
||||
* convert the x value to a fixed string.
|
||||
*
|
||||
* The string then needs converted to a number for highcharts, so
|
||||
* later on use parseFloat to get back to that.
|
||||
*
|
||||
* Stupid Celsius.
|
||||
*/
|
||||
var increment;
|
||||
var fixed;
|
||||
if (beestat.setting('temperature_unit') === '°F') {
|
||||
increment = 1;
|
||||
fixed = 0;
|
||||
} else {
|
||||
increment = 0.1;
|
||||
fixed = 1;
|
||||
}
|
||||
for (var x = this_x_min; x <= this_x_max; x += increment) {
|
||||
var x_fixed = x.toFixed(fixed);
|
||||
var y = (linear_trendline.slope * x_fixed) +
|
||||
linear_trendline.intercept;
|
||||
|
||||
data.series['trendline_' + type].push([
|
||||
parseFloat(x_fixed),
|
||||
y
|
||||
]);
|
||||
if (profile.deltas[x_fixed] !== undefined) {
|
||||
data.series['raw_' + type].push([
|
||||
parseFloat(x_fixed),
|
||||
profile.deltas[x_fixed]
|
||||
]);
|
||||
y_min = Math.min(y_min, profile.deltas[x_fixed]);
|
||||
y_max = Math.max(y_max, profile.deltas[x_fixed]);
|
||||
}
|
||||
|
||||
data.metadata.chart.y_min = y_min;
|
||||
data.metadata.chart.y_max = y_max;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a linear trendline from a set of data.
|
||||
*
|
||||
* @param {Object} data The data; at least two points required.
|
||||
*
|
||||
* @return {Object} The slope and intercept of the trendline.
|
||||
*/
|
||||
beestat.component.card.temperature_profiles_new.prototype.get_linear_trendline_ = function(data) {
|
||||
// Requires at least two points.
|
||||
if (Object.keys(data).length < 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var sum_x = 0;
|
||||
var sum_y = 0;
|
||||
var sum_xy = 0;
|
||||
var sum_x_squared = 0;
|
||||
var n = 0;
|
||||
|
||||
for (var x in data) {
|
||||
x = parseFloat(x);
|
||||
var y = parseFloat(data[x]);
|
||||
|
||||
sum_x += x;
|
||||
sum_y += y;
|
||||
sum_xy += (x * y);
|
||||
sum_x_squared += Math.pow(x, 2);
|
||||
n++;
|
||||
}
|
||||
|
||||
var slope = ((n * sum_xy) - (sum_x * sum_y)) /
|
||||
((n * sum_x_squared) - (Math.pow(sum_x, 2)));
|
||||
var intercept = ((sum_y) - (slope * sum_x)) / (n);
|
||||
|
||||
return {
|
||||
'slope': slope,
|
||||
'intercept': intercept
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the title of the card.
|
||||
*
|
||||
* @return {string} The title.
|
||||
*/
|
||||
beestat.component.card.temperature_profiles_new.prototype.get_title_ = function() {
|
||||
return 'Temperature Profiles';
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the subtitle of the card.
|
||||
*
|
||||
* @return {string} The subtitle.
|
||||
*/
|
||||
beestat.component.card.temperature_profiles_new.prototype.get_subtitle_ = function() {
|
||||
var thermostat = beestat.cache.thermostat[beestat.setting('thermostat_id')];
|
||||
var thermostat_group = beestat.cache.thermostat_group[
|
||||
thermostat.thermostat_group_id
|
||||
];
|
||||
|
||||
var generated_at_m = moment(
|
||||
thermostat_group.profile.metadata.generated_at
|
||||
);
|
||||
|
||||
return 'Generated ' + generated_at_m.format('MMM Do @ h a') + ' (updated weekly)';
|
||||
};
|
||||
|
||||
/**
|
||||
* Decorate the menu.
|
||||
*
|
||||
* @param {rocket.Elements} parent
|
||||
*/
|
||||
beestat.component.card.temperature_profiles_new.prototype.decorate_top_right_ = function(parent) {
|
||||
var self = this;
|
||||
|
||||
var menu = (new beestat.component.menu()).render(parent);
|
||||
|
||||
menu.add_menu_item(new beestat.component.menu_item()
|
||||
.set_text('Download Chart')
|
||||
.set_icon('download')
|
||||
.set_callback(function() {
|
||||
self.chart_.export();
|
||||
}));
|
||||
|
||||
menu.add_menu_item(new beestat.component.menu_item()
|
||||
.set_text('Help')
|
||||
.set_icon('help_circle')
|
||||
.set_callback(function() {
|
||||
window.open('https://doc.beestat.io/9c0fba6793dd4bc68f798c1516f0ea25');
|
||||
}));
|
||||
};
|
346
js/component/chart/temperature_profiles_new.js
Normal file
346
js/component/chart/temperature_profiles_new.js
Normal file
@ -0,0 +1,346 @@
|
||||
/**
|
||||
* Temperature profiles chart.
|
||||
*
|
||||
* @param {object} data The chart data.
|
||||
*/
|
||||
beestat.component.chart.temperature_profiles_new = function(data) {
|
||||
this.data_ = data;
|
||||
|
||||
beestat.component.chart.apply(this, arguments);
|
||||
};
|
||||
beestat.extend(beestat.component.chart.temperature_profiles_new, beestat.component.chart);
|
||||
|
||||
/**
|
||||
* Override for get_options_xAxis_labels_formatter_.
|
||||
*
|
||||
* @return {Function} xAxis labels formatter.
|
||||
*/
|
||||
beestat.component.chart.temperature_profiles_new.prototype.get_options_xAxis_labels_formatter_ = function() {
|
||||
return function() {
|
||||
return this.value + beestat.setting('temperature_unit');
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Override for get_options_series_.
|
||||
*
|
||||
* @return {Array} All of the series to display on the chart.
|
||||
*/
|
||||
beestat.component.chart.temperature_profiles_new.prototype.get_options_series_ = function() {
|
||||
var series = [];
|
||||
|
||||
// Trendline data
|
||||
series.push({
|
||||
'data': this.data_.series.trendline_heat_1,
|
||||
'name': 'indoor_heat_1_delta',
|
||||
'color': beestat.series.indoor_heat_1_delta.color,
|
||||
'marker': {
|
||||
'enabled': false,
|
||||
'states': {'hover': {'enabled': false}}
|
||||
},
|
||||
'type': 'line',
|
||||
'lineWidth': 2,
|
||||
'states': {'hover': {'lineWidthPlus': 0}}
|
||||
});
|
||||
|
||||
// Trendline data
|
||||
series.push({
|
||||
'data': this.data_.series.trendline_heat_2,
|
||||
'name': 'indoor_heat_2_delta',
|
||||
'color': beestat.series.indoor_heat_2_delta.color,
|
||||
'marker': {
|
||||
'enabled': false,
|
||||
'states': {'hover': {'enabled': false}}
|
||||
},
|
||||
'type': 'line',
|
||||
'lineWidth': 2,
|
||||
'states': {'hover': {'lineWidthPlus': 0}}
|
||||
});
|
||||
|
||||
// Trendline data
|
||||
series.push({
|
||||
'data': this.data_.series.trendline_cool_1,
|
||||
'name': 'indoor_cool_1_delta',
|
||||
'color': beestat.series.indoor_cool_1_delta.color,
|
||||
'marker': {
|
||||
'enabled': false,
|
||||
'states': {'hover': {'enabled': false}}
|
||||
},
|
||||
'type': 'line',
|
||||
'lineWidth': 2,
|
||||
'states': {'hover': {'lineWidthPlus': 0}}
|
||||
});
|
||||
|
||||
// Trendline data
|
||||
series.push({
|
||||
'data': this.data_.series.trendline_cool_2,
|
||||
'name': 'indoor_cool_2_delta',
|
||||
'color': beestat.series.indoor_cool_2_delta.color,
|
||||
'marker': {
|
||||
'enabled': false,
|
||||
'states': {'hover': {'enabled': false}}
|
||||
},
|
||||
'type': 'line',
|
||||
'lineWidth': 2,
|
||||
'states': {'hover': {'lineWidthPlus': 0}}
|
||||
});
|
||||
|
||||
// Trendline data
|
||||
series.push({
|
||||
'data': this.data_.series.trendline_resist,
|
||||
'name': 'indoor_resist_delta',
|
||||
'color': beestat.series.indoor_resist_delta.color,
|
||||
'marker': {
|
||||
'enabled': false,
|
||||
'states': {'hover': {'enabled': false}}
|
||||
},
|
||||
'type': 'line',
|
||||
'lineWidth': 2,
|
||||
'states': {'hover': {'lineWidthPlus': 0}}
|
||||
});
|
||||
|
||||
// Raw data
|
||||
series.push({
|
||||
'data': this.data_.series.raw_heat_1,
|
||||
'name': 'indoor_heat_1_delta_raw',
|
||||
'color': beestat.series.indoor_heat_1_delta_raw.color,
|
||||
'dashStyle': 'ShortDot',
|
||||
'marker': {
|
||||
'enabled': false,
|
||||
'states': {'hover': {'enabled': false}}
|
||||
},
|
||||
'type': 'spline',
|
||||
'lineWidth': 1,
|
||||
'states': {'hover': {'lineWidthPlus': 0}}
|
||||
});
|
||||
|
||||
// Raw data
|
||||
series.push({
|
||||
'data': this.data_.series.raw_heat_2,
|
||||
'name': 'indoor_heat_2_delta_raw',
|
||||
'color': beestat.series.indoor_heat_2_delta_raw.color,
|
||||
'dashStyle': 'ShortDot',
|
||||
'marker': {
|
||||
'enabled': false,
|
||||
'states': {'hover': {'enabled': false}}
|
||||
},
|
||||
'type': 'spline',
|
||||
'lineWidth': 1,
|
||||
'states': {'hover': {'lineWidthPlus': 0}}
|
||||
});
|
||||
|
||||
// Raw data
|
||||
series.push({
|
||||
'data': this.data_.series.raw_cool_1,
|
||||
'name': 'indoor_cool_1_delta_raw',
|
||||
'color': beestat.series.indoor_cool_1_delta_raw.color,
|
||||
'dashStyle': 'ShortDot',
|
||||
'marker': {
|
||||
'enabled': false,
|
||||
'states': {'hover': {'enabled': false}}
|
||||
},
|
||||
'type': 'spline',
|
||||
'lineWidth': 1,
|
||||
'states': {'hover': {'lineWidthPlus': 0}}
|
||||
});
|
||||
|
||||
// Raw data
|
||||
series.push({
|
||||
'data': this.data_.series.raw_cool_2,
|
||||
'name': 'indoor_cool_2_delta_raw',
|
||||
'color': beestat.series.indoor_cool_2_delta_raw.color,
|
||||
'dashStyle': 'ShortDot',
|
||||
'marker': {
|
||||
'enabled': false,
|
||||
'states': {'hover': {'enabled': false}}
|
||||
},
|
||||
'type': 'spline',
|
||||
'lineWidth': 1,
|
||||
'states': {'hover': {'lineWidthPlus': 0}}
|
||||
});
|
||||
|
||||
// Raw data
|
||||
series.push({
|
||||
'data': this.data_.series.raw_resist,
|
||||
'name': 'indoor_resist_delta_raw',
|
||||
'color': beestat.series.indoor_resist_delta_raw.color,
|
||||
'dashStyle': 'ShortDot',
|
||||
'marker': {
|
||||
'enabled': false,
|
||||
'states': {'hover': {'enabled': false}}
|
||||
},
|
||||
'type': 'spline',
|
||||
'lineWidth': 1,
|
||||
'states': {'hover': {'lineWidthPlus': 0}}
|
||||
});
|
||||
|
||||
return series;
|
||||
};
|
||||
|
||||
/**
|
||||
* Override for get_options_yAxis_.
|
||||
*
|
||||
* @return {Array} The y-axis options.
|
||||
*/
|
||||
beestat.component.chart.temperature_profiles_new.prototype.get_options_yAxis_ = function() {
|
||||
var absolute_y_max = Math.max(
|
||||
Math.abs(this.data_.metadata.chart.y_min),
|
||||
Math.abs(this.data_.metadata.chart.y_max)
|
||||
);
|
||||
|
||||
var y_min = absolute_y_max * -1;
|
||||
var y_max = absolute_y_max;
|
||||
|
||||
return [
|
||||
{
|
||||
'alignTicks': false,
|
||||
'gridLineColor': beestat.style.color.bluegray.light,
|
||||
'gridLineDashStyle': 'longdash',
|
||||
'title': {'text': null},
|
||||
'labels': {
|
||||
'style': {'color': beestat.style.color.gray.base},
|
||||
'formatter': function() {
|
||||
return this.value + beestat.setting('temperature_unit');
|
||||
}
|
||||
},
|
||||
'min': y_min,
|
||||
'max': y_max,
|
||||
'plotLines': [
|
||||
{
|
||||
'color': beestat.style.color.bluegray.light,
|
||||
'dashStyle': 'solid',
|
||||
'width': 3,
|
||||
'value': 0,
|
||||
'zIndex': 1
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
* Override for get_options_tooltip_formatter_.
|
||||
*
|
||||
* @return {Function} The tooltip formatter.
|
||||
*/
|
||||
beestat.component.chart.temperature_profiles_new.prototype.get_options_tooltip_formatter_ = function() {
|
||||
var self = this;
|
||||
|
||||
return function() {
|
||||
var sections = [];
|
||||
var section = [];
|
||||
this.points.forEach(function(point) {
|
||||
var series = point.series;
|
||||
|
||||
var value = beestat.temperature({
|
||||
'temperature': point.y,
|
||||
'units': true,
|
||||
'convert': false,
|
||||
'delta': true,
|
||||
'type': 'string'
|
||||
}) + ' / h';
|
||||
|
||||
if (series.name.indexOf('raw') === -1) {
|
||||
section.push({
|
||||
'label': beestat.series[series.name].name,
|
||||
'value': value,
|
||||
'color': series.color
|
||||
});
|
||||
}
|
||||
});
|
||||
sections.push(section);
|
||||
|
||||
return self.tooltip_formatter_helper_(
|
||||
'Outdoor Temp: ' +
|
||||
beestat.temperature({
|
||||
'temperature': this.x,
|
||||
'round': 0,
|
||||
'units': true,
|
||||
'convert': false
|
||||
}),
|
||||
sections
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Override for get_options_chart_zoomType_.
|
||||
*
|
||||
* @return {string} The zoom type.
|
||||
*/
|
||||
beestat.component.chart.temperature_profiles_new.prototype.get_options_chart_zoomType_ = function() {
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Override for get_options_legend_.
|
||||
*
|
||||
* @return {object} The legend options.
|
||||
*/
|
||||
beestat.component.chart.temperature_profiles_new.prototype.get_options_legend_ = function() {
|
||||
return {
|
||||
'enabled': false
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Override for get_options_xAxis_.
|
||||
*
|
||||
* @return {object} The xAxis options.
|
||||
*/
|
||||
beestat.component.chart.temperature_profiles_new.prototype.get_options_xAxis_ = function() {
|
||||
return {
|
||||
'lineWidth': 0,
|
||||
'tickLength': 0,
|
||||
'tickInterval': 5,
|
||||
'gridLineWidth': 1,
|
||||
'gridLineColor': beestat.style.color.bluegray.light,
|
||||
'gridLineDashStyle': 'longdash',
|
||||
'labels': {
|
||||
'style': {
|
||||
'color': beestat.style.color.gray.base
|
||||
},
|
||||
'formatter': this.get_options_xAxis_labels_formatter_()
|
||||
},
|
||||
'crosshair': this.get_options_xAxis_crosshair_(),
|
||||
'plotLines': [
|
||||
{
|
||||
'color': beestat.series.outdoor_temperature.color,
|
||||
'dashStyle': 'ShortDash',
|
||||
'width': 1,
|
||||
'label': {
|
||||
'style': {
|
||||
'color': beestat.series.outdoor_temperature.color
|
||||
},
|
||||
'useHTML': true,
|
||||
'text': 'Now: ' + beestat.temperature({
|
||||
'temperature': this.data_.metadata.chart.outdoor_temperature,
|
||||
'convert': false,
|
||||
'units': true,
|
||||
'round': 0
|
||||
})
|
||||
},
|
||||
'value': this.data_.metadata.chart.outdoor_temperature,
|
||||
'zIndex': 2
|
||||
}
|
||||
]
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Override for get_options_chart_height_.
|
||||
*
|
||||
* @return {number} The height of the chart.
|
||||
*/
|
||||
beestat.component.chart.temperature_profiles_new.prototype.get_options_chart_height_ = function() {
|
||||
return 300;
|
||||
};
|
||||
|
||||
/**
|
||||
* Override for get_options_plotOptions_series_connectNulls_.
|
||||
*
|
||||
* @return {boolean} Whether or not to connect nulls.
|
||||
*/
|
||||
beestat.component.chart.temperature_profiles_new.prototype.get_options_plotOptions_series_connectNulls_ = function() {
|
||||
return true;
|
||||
};
|
@ -38,7 +38,7 @@ beestat.component.header.prototype.decorate_ = function(parent) {
|
||||
'icon': 'signal_variant'
|
||||
},
|
||||
{
|
||||
'layer': 'home_comparisons',
|
||||
'layer': 'comparisons',
|
||||
'text': 'Comparisons',
|
||||
'icon': 'home_group'
|
||||
}
|
||||
|
137
js/component/metric.js
Normal file
137
js/component/metric.js
Normal file
@ -0,0 +1,137 @@
|
||||
/**
|
||||
* Generic customizable metric.
|
||||
*/
|
||||
beestat.component.metric = function() {
|
||||
beestat.component.apply(this, arguments);
|
||||
};
|
||||
beestat.extend(beestat.component.metric, beestat.component);
|
||||
|
||||
beestat.component.metric.prototype.rerender_on_breakpoint_ = false;
|
||||
|
||||
/**
|
||||
* Decorate
|
||||
*
|
||||
* @param {rocket.Elements} parent
|
||||
*/
|
||||
beestat.component.metric.prototype.decorate_ = function(parent) {
|
||||
if (beestat.cache.data.metrics === undefined) { // todo
|
||||
parent.appendChild($.createElement('div').innerText('Loading...'));
|
||||
return;
|
||||
}
|
||||
|
||||
var outer_container = $.createElement('div').style({
|
||||
'background': beestat.style.color.bluegray.dark,
|
||||
'padding': (beestat.style.size.gutter / 2)
|
||||
});
|
||||
|
||||
outer_container.appendChild(
|
||||
$.createElement('div').innerText(this.get_title_())
|
||||
);
|
||||
|
||||
var inner_container = $.createElement('div').style({
|
||||
'position': 'relative',
|
||||
'margin-top': '50px',
|
||||
'margin-bottom': '20px',
|
||||
'margin-left': '25px'
|
||||
});
|
||||
|
||||
var icon = $.createElement('div').style({
|
||||
'position': 'absolute',
|
||||
'top': '-12px',
|
||||
'left': '-28px'
|
||||
});
|
||||
|
||||
(new beestat.component.icon(this.get_icon_()))
|
||||
.set_color(this.get_color_())
|
||||
.render(icon);
|
||||
|
||||
var line = $.createElement('div').style({
|
||||
'background': this.get_color_(),
|
||||
'height': '5px',
|
||||
'border-radius': '5px'
|
||||
});
|
||||
|
||||
var min = $.createElement('div')
|
||||
.innerText(this.get_min_(true))
|
||||
.style({
|
||||
'position': 'absolute',
|
||||
'top': '10px',
|
||||
'left': '0px'
|
||||
});
|
||||
|
||||
var max = $.createElement('div')
|
||||
.innerText(this.get_max_(true))
|
||||
.style({
|
||||
'position': 'absolute',
|
||||
'top': '10px',
|
||||
'right': '0px'
|
||||
});
|
||||
|
||||
var label = $.createElement('div')
|
||||
.innerText(this.get_value_())
|
||||
.style({
|
||||
'position': 'absolute',
|
||||
'top': '-25px',
|
||||
'left': this.get_marker_position_() + '%',
|
||||
'width': '100px',
|
||||
'text-align': 'center',
|
||||
'margin-left': '-50px',
|
||||
'font-weight': beestat.style.font_weight.bold
|
||||
});
|
||||
|
||||
var circle = $.createElement('div').style({
|
||||
'background': this.get_color_(),
|
||||
'position': 'absolute',
|
||||
'top': '-4px',
|
||||
'left': this.get_marker_position_() + '%',
|
||||
'margin-left': '-7px',
|
||||
'width': '14px',
|
||||
'height': '14px',
|
||||
'border-radius': '50%'
|
||||
});
|
||||
|
||||
var chart = $.createElement('div').style({
|
||||
'position': 'absolute',
|
||||
'top': '-40px',
|
||||
'left': '0px',
|
||||
'width': '100%',
|
||||
'height': '40px'
|
||||
});
|
||||
|
||||
var histogram = this.get_histogram_();
|
||||
var histogram_max = this.get_histogram_max_();
|
||||
var column_width = (100 / histogram.length) + '%';
|
||||
histogram.forEach(function(data) {
|
||||
var column = $.createElement('div').style({
|
||||
'display': 'inline-block',
|
||||
'background': 'rgba(255, 255, 255, 0.1)',
|
||||
'width': column_width,
|
||||
'height': (data.count / histogram_max * 100) + '%'
|
||||
});
|
||||
chart.appendChild(column);
|
||||
});
|
||||
|
||||
inner_container.appendChild(icon);
|
||||
inner_container.appendChild(line);
|
||||
inner_container.appendChild(min);
|
||||
inner_container.appendChild(max);
|
||||
inner_container.appendChild(label);
|
||||
inner_container.appendChild(circle);
|
||||
inner_container.appendChild(chart);
|
||||
|
||||
outer_container.appendChild(inner_container);
|
||||
|
||||
parent.appendChild(outer_container);
|
||||
};
|
||||
|
||||
beestat.component.metric.prototype.get_marker_position_ = function() {
|
||||
return 100 * (this.get_value_() - this.get_min_()) / (this.get_max_() - this.get_min_());
|
||||
};
|
||||
|
||||
beestat.component.metric.prototype.get_histogram_max_ = function() {
|
||||
var max = -Infinity;
|
||||
this.get_histogram_().forEach(function(data) {
|
||||
max = Math.max(max, data.count);
|
||||
});
|
||||
return max;
|
||||
};
|
98
js/component/metric/runtime_per_heating_degree_day.js
Normal file
98
js/component/metric/runtime_per_heating_degree_day.js
Normal file
@ -0,0 +1,98 @@
|
||||
/**
|
||||
* Runtime per heating degree day metric.
|
||||
*
|
||||
* @param {number} thermostat_group_id The thermostat group.
|
||||
*/
|
||||
beestat.component.metric.runtime_per_heating_degree_day = function(thermostat_group_id) {
|
||||
this.thermostat_group_id_ = thermostat_group_id;
|
||||
|
||||
beestat.component.metric.apply(this, arguments);
|
||||
};
|
||||
beestat.extend(beestat.component.metric.runtime_per_heating_degree_day, beestat.component.metric);
|
||||
|
||||
beestat.component.metric.runtime_per_heating_degree_day.prototype.rerender_on_breakpoint_ = false;
|
||||
|
||||
/**
|
||||
* Get the title of this metric.
|
||||
*
|
||||
* @return {string} The title of this metric.
|
||||
*/
|
||||
beestat.component.metric.runtime_per_heating_degree_day.prototype.get_title_ = function() {
|
||||
return 'Runtime / HDD';
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the icon of this metric.
|
||||
*
|
||||
* @return {string} The icon of this metric.
|
||||
*/
|
||||
beestat.component.metric.runtime_per_heating_degree_day.prototype.get_icon_ = function() {
|
||||
return 'fire';
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the color of this metric.
|
||||
*
|
||||
* @return {string} The color of this metric.
|
||||
*/
|
||||
beestat.component.metric.runtime_per_heating_degree_day.prototype.get_color_ = function() {
|
||||
return beestat.series.compressor_heat_1.color;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the minimum value of this metric (within two standard deviations).
|
||||
*
|
||||
* @return {mixed} The minimum value of this metric.
|
||||
*/
|
||||
beestat.component.metric.runtime_per_heating_degree_day.prototype.get_min_ = function() {
|
||||
var standard_deviation =
|
||||
beestat.cache.data.metrics.runtime_per_heating_degree_day.standard_deviation;
|
||||
return (beestat.cache.data.metrics.runtime_per_heating_degree_day.median - (standard_deviation * 2)).toFixed(1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the maximum value of this metric (within two standard deviations).
|
||||
*
|
||||
* @return {mixed} The maximum value of this metric.
|
||||
*/
|
||||
beestat.component.metric.runtime_per_heating_degree_day.prototype.get_max_ = function() {
|
||||
var standard_deviation =
|
||||
beestat.cache.data.metrics.runtime_per_heating_degree_day.standard_deviation;
|
||||
return (beestat.cache.data.metrics.runtime_per_heating_degree_day.median + (standard_deviation * 2)).toFixed(1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the value of this metric.
|
||||
*
|
||||
* @return {mixed} The value of this metric.
|
||||
*/
|
||||
beestat.component.metric.runtime_per_heating_degree_day.prototype.get_value_ = function() {
|
||||
var thermostat_group = beestat.cache.thermostat_group[
|
||||
this.thermostat_group_id_
|
||||
];
|
||||
// todo: store this explicitly on the profile so it doesn't have to be calculated in JS?
|
||||
return (thermostat_group.profile.runtime.heat_1 /
|
||||
thermostat_group.profile.degree_days.heat).toFixed(1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a histogram between the min and max values of this metric.
|
||||
*
|
||||
* @return {array} The histogram.
|
||||
*/
|
||||
beestat.component.metric.runtime_per_heating_degree_day.prototype.get_histogram_ = function() {
|
||||
var histogram = [];
|
||||
for (var value in beestat.cache.data.metrics.runtime_per_heating_degree_day.histogram) {
|
||||
if (
|
||||
value >= this.get_min_() &&
|
||||
value <= this.get_max_()
|
||||
) {
|
||||
var count = beestat.cache.data.metrics.runtime_per_heating_degree_day.histogram[value];
|
||||
histogram.push({
|
||||
'value': value,
|
||||
'count': count
|
||||
});
|
||||
}
|
||||
}
|
||||
return histogram;
|
||||
};
|
119
js/component/metric/setpoint_cool.js
Normal file
119
js/component/metric/setpoint_cool.js
Normal file
@ -0,0 +1,119 @@
|
||||
/**
|
||||
* Cool setpoint metric.
|
||||
*
|
||||
* @param {number} thermostat_group_id The thermostat group.
|
||||
*/
|
||||
beestat.component.metric.setpoint_cool = function(thermostat_group_id) {
|
||||
this.thermostat_group_id_ = thermostat_group_id;
|
||||
|
||||
beestat.component.metric.apply(this, arguments);
|
||||
};
|
||||
beestat.extend(beestat.component.metric.setpoint_cool, beestat.component.metric);
|
||||
|
||||
beestat.component.metric.setpoint_cool.prototype.rerender_on_breakpoint_ = false;
|
||||
|
||||
/**
|
||||
* Get the title of this metric.
|
||||
*
|
||||
* @return {string} The title of this metric.
|
||||
*/
|
||||
beestat.component.metric.setpoint_cool.prototype.get_title_ = function() {
|
||||
return 'Cool Setpoint';
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the icon of this metric.
|
||||
*
|
||||
* @return {string} The icon of this metric.
|
||||
*/
|
||||
beestat.component.metric.setpoint_cool.prototype.get_icon_ = function() {
|
||||
return 'snowflake';
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the color of this metric.
|
||||
*
|
||||
* @return {string} The color of this metric.
|
||||
*/
|
||||
beestat.component.metric.setpoint_cool.prototype.get_color_ = function() {
|
||||
return beestat.series.compressor_cool_1.color;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the minimum value of this metric (within two standard deviations).
|
||||
*
|
||||
* @param {boolean} units Whether or not to return a numerical value or a
|
||||
* string with units.
|
||||
*
|
||||
* @return {mixed} The minimum value of this metric.
|
||||
*/
|
||||
beestat.component.metric.setpoint_cool.prototype.get_min_ = function(units) {
|
||||
var standard_deviation =
|
||||
beestat.cache.data.metrics.setpoint_cool.standard_deviation;
|
||||
return beestat.temperature({
|
||||
'temperature': beestat.cache.data.metrics.setpoint_cool.median - (standard_deviation * 2),
|
||||
'round': 0,
|
||||
'units': units
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the maximum value of this metric (within two standard deviations).
|
||||
*
|
||||
* @param {boolean} units Whether or not to return a numerical value or a
|
||||
* string with units.
|
||||
*
|
||||
* @return {mixed} The maximum value of this metric.
|
||||
*/
|
||||
beestat.component.metric.setpoint_cool.prototype.get_max_ = function(units) {
|
||||
var standard_deviation =
|
||||
beestat.cache.data.metrics.setpoint_cool.standard_deviation;
|
||||
return beestat.temperature({
|
||||
'temperature': beestat.cache.data.metrics.setpoint_cool.median + (standard_deviation * 2),
|
||||
'round': 0,
|
||||
'units': units
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the value of this metric.
|
||||
*
|
||||
* @param {boolean} units Whether or not to return a numerical value or a
|
||||
* string with units.
|
||||
*
|
||||
* @return {mixed} The value of this metric.
|
||||
*/
|
||||
beestat.component.metric.setpoint_cool.prototype.get_value_ = function(units) {
|
||||
var thermostat_group = beestat.cache.thermostat_group[
|
||||
this.thermostat_group_id_
|
||||
];
|
||||
return beestat.temperature({
|
||||
'temperature': thermostat_group.profile.setpoint.cool,
|
||||
'units': units
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a histogram between the min and max values of this metric.
|
||||
*
|
||||
* @param {boolean} units Whether or not to return a numerical value or a
|
||||
* string with units.
|
||||
*
|
||||
* @return {array} The histogram.
|
||||
*/
|
||||
beestat.component.metric.setpoint_cool.prototype.get_histogram_ = function(units) {
|
||||
var histogram = [];
|
||||
for (var temperature in beestat.cache.data.metrics.setpoint_cool.histogram) {
|
||||
if (
|
||||
temperature >= this.get_min_(units) &&
|
||||
temperature <= this.get_max_(units)
|
||||
) {
|
||||
var count = beestat.cache.data.metrics.setpoint_cool.histogram[temperature];
|
||||
histogram.push({
|
||||
'value': beestat.temperature(temperature),
|
||||
'count': count
|
||||
});
|
||||
}
|
||||
}
|
||||
return histogram;
|
||||
};
|
119
js/component/metric/setpoint_heat.js
Normal file
119
js/component/metric/setpoint_heat.js
Normal file
@ -0,0 +1,119 @@
|
||||
/**
|
||||
* Heat setpoint metric.
|
||||
*
|
||||
* @param {number} thermostat_group_id The thermostat group.
|
||||
*/
|
||||
beestat.component.metric.setpoint_heat = function(thermostat_group_id) {
|
||||
this.thermostat_group_id_ = thermostat_group_id;
|
||||
|
||||
beestat.component.metric.apply(this, arguments);
|
||||
};
|
||||
beestat.extend(beestat.component.metric.setpoint_heat, beestat.component.metric);
|
||||
|
||||
beestat.component.metric.setpoint_heat.prototype.rerender_on_breakpoint_ = false;
|
||||
|
||||
/**
|
||||
* Get the title of this metric.
|
||||
*
|
||||
* @return {string} The title of this metric.
|
||||
*/
|
||||
beestat.component.metric.setpoint_heat.prototype.get_title_ = function() {
|
||||
return 'Heat Setpoint';
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the icon of this metric.
|
||||
*
|
||||
* @return {string} The icon of this metric.
|
||||
*/
|
||||
beestat.component.metric.setpoint_heat.prototype.get_icon_ = function() {
|
||||
return 'fire';
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the color of this metric.
|
||||
*
|
||||
* @return {string} The color of this metric.
|
||||
*/
|
||||
beestat.component.metric.setpoint_heat.prototype.get_color_ = function() {
|
||||
return beestat.series.compressor_heat_1.color;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the minimum value of this metric (within two standard deviations).
|
||||
*
|
||||
* @param {boolean} units Whether or not to return a numerical value or a
|
||||
* string with units.
|
||||
*
|
||||
* @return {mixed} The minimum value of this metric.
|
||||
*/
|
||||
beestat.component.metric.setpoint_heat.prototype.get_min_ = function(units) {
|
||||
var standard_deviation =
|
||||
beestat.cache.data.metrics.setpoint_heat.standard_deviation;
|
||||
return beestat.temperature({
|
||||
'temperature': beestat.cache.data.metrics.setpoint_heat.median - (standard_deviation * 2),
|
||||
'round': 0,
|
||||
'units': units
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the maximum value of this metric (within two standard deviations).
|
||||
*
|
||||
* @param {boolean} units Whether or not to return a numerical value or a
|
||||
* string with units.
|
||||
*
|
||||
* @return {mixed} The maximum value of this metric.
|
||||
*/
|
||||
beestat.component.metric.setpoint_heat.prototype.get_max_ = function(units) {
|
||||
var standard_deviation =
|
||||
beestat.cache.data.metrics.setpoint_heat.standard_deviation;
|
||||
return beestat.temperature({
|
||||
'temperature': beestat.cache.data.metrics.setpoint_heat.median + (standard_deviation * 2),
|
||||
'round': 0,
|
||||
'units': units
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the value of this metric.
|
||||
*
|
||||
* @param {boolean} units Whether or not to return a numerical value or a
|
||||
* string with units.
|
||||
*
|
||||
* @return {mixed} The value of this metric.
|
||||
*/
|
||||
beestat.component.metric.setpoint_heat.prototype.get_value_ = function(units) {
|
||||
var thermostat_group = beestat.cache.thermostat_group[
|
||||
this.thermostat_group_id_
|
||||
];
|
||||
return beestat.temperature({
|
||||
'temperature': thermostat_group.profile.setpoint.heat,
|
||||
'units': units
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a histogram between the min and max values of this metric.
|
||||
*
|
||||
* @param {boolean} units Whether or not to return a numerical value or a
|
||||
* string with units.
|
||||
*
|
||||
* @return {array} The histogram.
|
||||
*/
|
||||
beestat.component.metric.setpoint_heat.prototype.get_histogram_ = function(units) {
|
||||
var histogram = [];
|
||||
for (var temperature in beestat.cache.data.metrics.setpoint_heat.histogram) {
|
||||
if (
|
||||
temperature >= this.get_min_(units) &&
|
||||
temperature <= this.get_max_(units)
|
||||
) {
|
||||
var count = beestat.cache.data.metrics.setpoint_heat.histogram[temperature];
|
||||
histogram.push({
|
||||
'value': beestat.temperature(temperature),
|
||||
'count': count
|
||||
});
|
||||
}
|
||||
}
|
||||
return histogram;
|
||||
};
|
@ -148,7 +148,7 @@ beestat.component.modal.change_system_type.prototype.get_buttons_ = function() {
|
||||
|
||||
// Re-run comparison scores as they are invalid for the new system
|
||||
// type.
|
||||
beestat.home_comparisons.get_comparison_scores();
|
||||
beestat.comparisons.get_comparison_scores();
|
||||
|
||||
// Close the modal.
|
||||
self.dispose();
|
||||
|
13
js/js.php
13
js/js.php
@ -27,7 +27,7 @@ if($setting->get('environment') === 'dev' || $setting->get('environment') === 'd
|
||||
echo '<script src="/js/beestat/time.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/beestat/setting.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/beestat/poll.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/beestat/home_comparisons.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/beestat/comparisons.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/beestat/highcharts.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/beestat/get_sync_progress.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/beestat/user.js"></script>' . PHP_EOL;
|
||||
@ -40,7 +40,7 @@ if($setting->get('environment') === 'dev' || $setting->get('environment') === 'd
|
||||
echo '<script src="/js/layer.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/layer/load.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/layer/dashboard.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/layer/home_comparisons.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/layer/comparisons.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/layer/sensors.js"></script>' . PHP_EOL;
|
||||
|
||||
// Component
|
||||
@ -51,7 +51,7 @@ if($setting->get('environment') === 'dev' || $setting->get('environment') === 'd
|
||||
echo '<script src="/js/component/card/runtime_thermostat_summary.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/card/alerts.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/card/comparison_settings.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/card/comparison_issue.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/card/early_access.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/card/demo.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/card/footer.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/card/my_home.js"></script>' . PHP_EOL;
|
||||
@ -65,9 +65,12 @@ if($setting->get('environment') === 'dev' || $setting->get('environment') === 'd
|
||||
echo '<script src="/js/component/card/sensors.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/card/system.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/card/temperature_profiles.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/card/temperature_profiles_new.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/card/metrics.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/chart.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/chart/runtime_thermostat_summary.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/chart/temperature_profiles.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/chart/temperature_profiles_new.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/chart/runtime_thermostat_detail_temperature.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/chart/runtime_thermostat_detail_equipment.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/chart/runtime_sensor_detail_temperature.js"></script>' . PHP_EOL;
|
||||
@ -98,6 +101,10 @@ if($setting->get('environment') === 'dev' || $setting->get('environment') === 'd
|
||||
echo '<script src="/js/component/button.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/button_group.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/title.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/metric.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/metric/setpoint_heat.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/metric/setpoint_cool.js"></script>' . PHP_EOL;
|
||||
echo '<script src="/js/component/metric/runtime_per_heating_degree_day.js"></script>' . PHP_EOL;
|
||||
}
|
||||
else {
|
||||
echo '<script src="/js/beestat.js?' . $setting->get('commit') . '"></script>' . PHP_EOL;
|
||||
|
@ -1,100 +1,103 @@
|
||||
/**
|
||||
* Home comparisons layer.
|
||||
*/
|
||||
beestat.layer.home_comparisons = function() {
|
||||
beestat.layer.apply(this, arguments);
|
||||
};
|
||||
beestat.extend(beestat.layer.home_comparisons, beestat.layer);
|
||||
|
||||
beestat.layer.home_comparisons.prototype.decorate_ = function(parent) {
|
||||
/*
|
||||
* Set the overflow on the body so the scrollbar is always present so
|
||||
* highcharts graphs render properly.
|
||||
*/
|
||||
$('body').style({
|
||||
'overflow-y': 'scroll',
|
||||
'background': beestat.style.color.bluegray.light,
|
||||
'padding': '0 ' + beestat.style.size.gutter + 'px'
|
||||
});
|
||||
|
||||
(new beestat.component.header('home_comparisons')).render(parent);
|
||||
|
||||
var thermostat = beestat.cache.thermostat[beestat.setting('thermostat_id')];
|
||||
var thermostat_group = beestat.cache.thermostat_group[thermostat.thermostat_group_id];
|
||||
|
||||
// All the cards
|
||||
var cards = [];
|
||||
|
||||
if (window.is_demo === true) {
|
||||
cards.push([
|
||||
{
|
||||
'card': new beestat.component.card.demo(),
|
||||
'size': 12
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
cards.push([
|
||||
{
|
||||
'card': new beestat.component.card.comparison_settings(),
|
||||
'size': 6
|
||||
},
|
||||
{
|
||||
'card': new beestat.component.card.my_home(),
|
||||
'size': 6
|
||||
}
|
||||
]);
|
||||
|
||||
// Scores and graph
|
||||
if (thermostat_group.temperature_profile !== null) {
|
||||
cards.push([
|
||||
{
|
||||
'card': new beestat.component.card.score.heat(),
|
||||
'size': 4
|
||||
},
|
||||
{
|
||||
'card': new beestat.component.card.score.cool(),
|
||||
'size': 4
|
||||
},
|
||||
{
|
||||
'card': new beestat.component.card.score.resist(),
|
||||
'size': 4
|
||||
}
|
||||
]);
|
||||
|
||||
if (
|
||||
(
|
||||
thermostat_group.temperature_profile.heat !== undefined &&
|
||||
thermostat_group.temperature_profile.heat.linear_trendline.slope < 0
|
||||
) ||
|
||||
(
|
||||
thermostat_group.temperature_profile.cool !== undefined &&
|
||||
thermostat_group.temperature_profile.cool.linear_trendline.slope < 0
|
||||
)
|
||||
) {
|
||||
cards.push([
|
||||
{
|
||||
'card': new beestat.component.card.comparison_issue(),
|
||||
'size': 12
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
cards.push([
|
||||
{
|
||||
'card': new beestat.component.card.temperature_profiles(thermostat_group.thermostat_group_id),
|
||||
'size': 12
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
// Footer
|
||||
cards.push([
|
||||
{
|
||||
'card': new beestat.component.card.footer(),
|
||||
'size': 12
|
||||
}
|
||||
]);
|
||||
|
||||
(new beestat.component.layout(cards)).render(parent);
|
||||
};
|
||||
/**
|
||||
* Home comparisons layer.
|
||||
*/
|
||||
beestat.layer.comparisons = function() {
|
||||
beestat.layer.apply(this, arguments);
|
||||
};
|
||||
beestat.extend(beestat.layer.comparisons, beestat.layer);
|
||||
|
||||
beestat.layer.comparisons.prototype.decorate_ = function(parent) {
|
||||
/*
|
||||
* Set the overflow on the body so the scrollbar is always present so
|
||||
* highcharts graphs render properly.
|
||||
*/
|
||||
$('body').style({
|
||||
'overflow-y': 'scroll',
|
||||
'background': beestat.style.color.bluegray.light,
|
||||
'padding': '0 ' + beestat.style.size.gutter + 'px'
|
||||
});
|
||||
|
||||
(new beestat.component.header('comparisons')).render(parent);
|
||||
|
||||
var thermostat = beestat.cache.thermostat[beestat.setting('thermostat_id')];
|
||||
var thermostat_group = beestat.cache.thermostat_group[thermostat.thermostat_group_id];
|
||||
|
||||
// All the cards
|
||||
var cards = [];
|
||||
|
||||
if (window.is_demo === true) {
|
||||
cards.push([
|
||||
{
|
||||
'card': new beestat.component.card.demo(),
|
||||
'size': 12
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
cards.push([
|
||||
{
|
||||
'card': new beestat.component.card.comparison_settings(),
|
||||
'size': 6
|
||||
},
|
||||
{
|
||||
'card': new beestat.component.card.my_home(),
|
||||
'size': 6
|
||||
}
|
||||
]);
|
||||
|
||||
// Scores and graph
|
||||
if (thermostat_group.profile !== null) {
|
||||
cards.push([
|
||||
{
|
||||
'card': new beestat.component.card.score.heat(),
|
||||
'size': 4
|
||||
},
|
||||
{
|
||||
'card': new beestat.component.card.score.cool(),
|
||||
'size': 4
|
||||
},
|
||||
{
|
||||
'card': new beestat.component.card.score.resist(),
|
||||
'size': 4
|
||||
}
|
||||
]);
|
||||
|
||||
cards.push([
|
||||
{
|
||||
'card': new beestat.component.card.temperature_profiles(thermostat_group.thermostat_group_id),
|
||||
'size': 12
|
||||
}
|
||||
]);
|
||||
|
||||
if (beestat.user.has_early_access() === true) {
|
||||
cards.push([
|
||||
{
|
||||
'card': new beestat.component.card.early_access(),
|
||||
'size': 12
|
||||
}
|
||||
]);
|
||||
cards.push([
|
||||
{
|
||||
'card': new beestat.component.card.metrics(thermostat_group.thermostat_group_id),
|
||||
'size': 12
|
||||
}
|
||||
]);
|
||||
cards.push([
|
||||
{
|
||||
'card': new beestat.component.card.temperature_profiles_new(thermostat_group.thermostat_group_id),
|
||||
'size': 12
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// Footer
|
||||
cards.push([
|
||||
{
|
||||
'card': new beestat.component.card.footer(),
|
||||
'size': 12
|
||||
}
|
||||
]);
|
||||
|
||||
(new beestat.component.layout(cards)).render(parent);
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user