1
0
mirror of https://github.com/beestat/app.git synced 2025-05-24 02:14:03 -04:00

Added HVAC runtime to 3d visualizer

This commit is contained in:
Jon Ziebell 2022-09-09 14:54:36 -04:00
parent 3edda2311b
commit 79667068d4
5 changed files with 166 additions and 21 deletions

View File

@ -282,16 +282,17 @@ input[type=range]{
-webkit-appearance: none;
background:transparent;
margin-top: 5px;
--background: #37474f;
}
input[type=range]::-webkit-slider-runnable-track {
background: #37474f;
background: var(--background);
height: 5px;
border-radius: 5px;
}
input[type=range]::-moz-range-track {
background: #37474f;
background: var(--background);
height: 5px;
border-radius: 5px;
}

View File

@ -578,7 +578,7 @@ beestat.component.card.floor_plan_editor.prototype.decorate_info_pane_room_ = fu
const sensors = {};
Object.values(beestat.cache.thermostat).forEach(function(thermostat) {
const thermostat_sensors = Object.values(beestat.cache.sensor).filter(function(sensor) {
return sensor.thermostat_id === self.thermostat_id_;
return sensor.thermostat_id === thermostat.thermostat_id;
})
.sort(function(a, b) {
return a.name.localeCompare(b.name, 'en', {'sensitivity': 'base'});

View File

@ -340,6 +340,10 @@ beestat.component.card.three_d.prototype.decorate_drawing_pane_ = function(paren
this.get_data_()
);
this.scene_.addEventListener('change_active_room', function() {
self.update_hud_();
});
// Set the initial date.
// if (this.has_data_() === true) {
this.update_scene_();
@ -428,6 +432,19 @@ beestat.component.card.three_d.prototype.decorate_drawing_pane_ = function(paren
beestat.component.card.three_d.prototype.decorate_controls_ = function(parent) {
const self = this;
const active_room = this.scene_.get_active_room_();
let thermostat_ids;
if (
active_room !== null &&
active_room.sensor_id !== undefined
) {
thermostat_ids = [beestat.cache.sensor[active_room.sensor_id].thermostat_id];
} else {
thermostat_ids = Object.keys(
beestat.floor_plan.get_thermostat_ids_map(this.floor_plan_id_)
);
}
if (parent !== undefined) {
this.controls_container_ = parent;
}
@ -441,6 +458,8 @@ beestat.component.card.three_d.prototype.decorate_controls_ = function(parent) {
const range = new beestat.component.input.range();
const time_container = document.createElement('div');
range.set_background(this.get_chart_gradient_(thermostat_ids));
const container = document.createElement('div');
Object.assign(container.style, {
'display': 'flex',
@ -555,6 +574,108 @@ beestat.component.card.three_d.prototype.decorate_controls_ = function(parent) {
});
};
/**
* Get a CSS linear gradient style that represents the runtime chart.
*
* @param {array} thermostat_ids Which thermostat_ids to include data from.
*
* @return {string}
*/
beestat.component.card.three_d.prototype.get_chart_gradient_ = function(thermostat_ids) {
const data = this.get_data_();
const background_color_rgb = beestat.style.hex_to_rgb(beestat.style.color.bluegray.base);
const background_color = 'rgba(' + background_color_rgb.r + ',' + background_color_rgb.g + ',' + background_color_rgb.b + ',1)';
let current_color = background_color;
const gradient = [
{
'color': current_color,
'position': 0
}
];
const date_m = moment();
for (let i = 0; i < 287; i++) {
const minute_of_day = i * 5;
date_m.hours(Math.floor(minute_of_day / 60));
date_m.minutes(Math.floor(minute_of_day % 60));
const time = date_m.format('HH:mm');
let red = 0;
let green = 0;
let blue = 0;
let alpha = 0;
let count = 0;
let this_color = background_color;
[
'fan',
'compressor_heat_1',
'compressor_heat_2',
'auxiliary_heat_1',
'auxiliary_heat_2',
'compressor_cool_1',
'compressor_cool_2'
].forEach(function(series_code) {
thermostat_ids.forEach(function(thermostat_id) {
if (
data.series[series_code][thermostat_id] !== undefined &&
data.series[series_code][thermostat_id][time] !== undefined &&
data.series[series_code][thermostat_id][time] > 0
) {
// Only resets these if there is data to override it.
if (count > 0) {
red = 0;
green = 0;
blue = 0;
alpha = 0;
count = 0;
}
const color = beestat.style.hex_to_rgb(beestat.series[series_code].color);
red += color.r;
green += color.g;
blue += color.b;
alpha += data.series[series_code][thermostat_id][time] / thermostat_ids.length;
count++;
}
});
let rgb;
if (count > 0) {
rgb = {
'r': red / count,
'g': green / count,
'b': blue / count
};
alpha /= count;
this_color = 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + alpha + ')';
} else {
this_color = background_color;
}
});
if (this_color !== current_color) {
gradient.push({
'color': this_color,
'position': Math.round(i / 288 * 100 * 10) / 10
});
current_color = this_color;
}
}
let gradient_string = ['90deg'];
for (let i = 0; i < gradient.length; i++) {
const start = gradient[i].position + '%';
const end = gradient[i + 1] !== undefined ? gradient[i + 1].position + '%' : '100%';
gradient_string.push(gradient[i].color + ' ' + start + ' ' + end);
}
return 'linear-gradient(' + gradient_string.join(', ') + ')';
};
/**
* Watermark.
*
@ -592,7 +713,7 @@ beestat.component.card.three_d.prototype.decorate_toolbar_ = function(parent) {
// Add room
tile_group.add_tile(new beestat.component.tile()
.set_icon('label_off')
.set_title('Labels')
.set_title('Toggle Labels')
.set_text_color(beestat.style.color.gray.light)
.set_background_color(beestat.style.color.bluegray.base)
.set_background_hover_color(beestat.style.color.bluegray.light)
@ -611,7 +732,7 @@ beestat.component.card.three_d.prototype.decorate_toolbar_ = function(parent) {
// Add room
tile_group.add_tile(new beestat.component.tile()
.set_icon('restart_off')
.set_title('Auto-Rotate')
.set_title('Toggle Auto-Rotate')
.set_text_color(beestat.style.color.gray.light)
.set_background_color(beestat.style.color.bluegray.base)
.set_background_hover_color(beestat.style.color.bluegray.light)

View File

@ -79,3 +79,16 @@ beestat.component.input.range.prototype.set_max = function(max) {
return this;
};
/**
* Set the background value of the range input.
*
* @param {string} background
*
* @return {beestat.component.input.range} This.
*/
beestat.component.input.range.prototype.set_background = function(background) {
this.input_.style.setProperty('--background', background);
return this;
};

View File

@ -223,12 +223,8 @@ beestat.component.scene.prototype.mouseup_handler_ = function() {
window.removeEventListener('touchend', this.mouseup_handler_);
if (this.dragged_ === false) {
// Clear any active state
// if (this.active_mesh_ !== undefined) {
// this.active_mesh_.userData.outline.visible = false;
// }
this.active_mesh_ = this.intersected_mesh_;
this.dispatchEvent('change_active_room');
this.update_();
}
};
@ -364,14 +360,14 @@ beestat.component.scene.prototype.update_ = function() {
// Set the color of each room
floor_plan.data.groups.forEach(function(group) {
group.rooms.forEach(function(room) {
const value_sprite = self.rooms_[room.room_id].userData.sprites.value;
const icon_sprite = self.rooms_[room.room_id].userData.sprites.icon;
const value_sprite = self.meshes_[room.room_id].userData.sprites.value;
const icon_sprite = self.meshes_[room.room_id].userData.sprites.icon;
// Room outline
if (self.rooms_[room.room_id] === self.active_mesh_) {
self.rooms_[room.room_id].userData.outline.visible = true;
if (self.meshes_[room.room_id] === self.active_mesh_) {
self.meshes_[room.room_id].userData.outline.visible = true;
} else {
self.rooms_[room.room_id].userData.outline.visible = false;
self.meshes_[room.room_id].userData.outline.visible = false;
}
let color;
@ -458,7 +454,7 @@ beestat.component.scene.prototype.update_ = function() {
// Labels
if (
self.labels_ === true ||
self.rooms_[room.room_id] === self.active_mesh_
self.meshes_[room.room_id] === self.active_mesh_
) {
switch (self.data_type_) {
case 'temperature':
@ -494,7 +490,7 @@ beestat.component.scene.prototype.update_ = function() {
icon_sprite.material = self.get_blank_label_material_();
}
self.rooms_[room.room_id].material.color.setHex(color.replace('#', '0x'));
self.meshes_[room.room_id].material.color.setHex(color.replace('#', '0x'));
});
});
@ -568,13 +564,14 @@ beestat.component.scene.prototype.add_room_ = function(layer, group, room) {
mesh.translateY(room.y);
// Store a reference to the mesh representing each room.
if (this.rooms_ === undefined) {
this.rooms_ = {};
if (this.meshes_ === undefined) {
this.meshes_ = {};
}
// TODO Do I need both these?
this.rooms_[room.room_id] = mesh;
// Allow me to go from room -> mesh and mesh -> room
this.meshes_[room.room_id] = mesh;
// mesh.userData.room_id = room.room_id;
mesh.userData.room = room;
layer.add(mesh);
@ -982,3 +979,16 @@ beestat.component.scene.prototype.dispose = function() {
window.cancelAnimationFrame(this.animation_frame_);
beestat.component.prototype.dispose.apply(this, arguments);
};
/**
* Get the currently active room.
*
* @return {object}
*/
beestat.component.scene.prototype.get_active_room_ = function() {
if (this.active_mesh_ !== undefined) {
return this.active_mesh_.userData.room;
}
return null;
};