mirror of
https://github.com/beestat/app.git
synced 2025-05-31 20:26:32 -04:00
Added HVAC runtime to 3d visualizer
This commit is contained in:
parent
3edda2311b
commit
79667068d4
@ -282,16 +282,17 @@ input[type=range]{
|
|||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
background:transparent;
|
background:transparent;
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
|
--background: #37474f;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type=range]::-webkit-slider-runnable-track {
|
input[type=range]::-webkit-slider-runnable-track {
|
||||||
background: #37474f;
|
background: var(--background);
|
||||||
height: 5px;
|
height: 5px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type=range]::-moz-range-track {
|
input[type=range]::-moz-range-track {
|
||||||
background: #37474f;
|
background: var(--background);
|
||||||
height: 5px;
|
height: 5px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
@ -578,7 +578,7 @@ beestat.component.card.floor_plan_editor.prototype.decorate_info_pane_room_ = fu
|
|||||||
const sensors = {};
|
const sensors = {};
|
||||||
Object.values(beestat.cache.thermostat).forEach(function(thermostat) {
|
Object.values(beestat.cache.thermostat).forEach(function(thermostat) {
|
||||||
const thermostat_sensors = Object.values(beestat.cache.sensor).filter(function(sensor) {
|
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) {
|
.sort(function(a, b) {
|
||||||
return a.name.localeCompare(b.name, 'en', {'sensitivity': 'base'});
|
return a.name.localeCompare(b.name, 'en', {'sensitivity': 'base'});
|
||||||
|
@ -340,6 +340,10 @@ beestat.component.card.three_d.prototype.decorate_drawing_pane_ = function(paren
|
|||||||
this.get_data_()
|
this.get_data_()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.scene_.addEventListener('change_active_room', function() {
|
||||||
|
self.update_hud_();
|
||||||
|
});
|
||||||
|
|
||||||
// Set the initial date.
|
// Set the initial date.
|
||||||
// if (this.has_data_() === true) {
|
// if (this.has_data_() === true) {
|
||||||
this.update_scene_();
|
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) {
|
beestat.component.card.three_d.prototype.decorate_controls_ = function(parent) {
|
||||||
const self = this;
|
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) {
|
if (parent !== undefined) {
|
||||||
this.controls_container_ = parent;
|
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 range = new beestat.component.input.range();
|
||||||
const time_container = document.createElement('div');
|
const time_container = document.createElement('div');
|
||||||
|
|
||||||
|
range.set_background(this.get_chart_gradient_(thermostat_ids));
|
||||||
|
|
||||||
const container = document.createElement('div');
|
const container = document.createElement('div');
|
||||||
Object.assign(container.style, {
|
Object.assign(container.style, {
|
||||||
'display': 'flex',
|
'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.
|
* Watermark.
|
||||||
*
|
*
|
||||||
@ -592,7 +713,7 @@ beestat.component.card.three_d.prototype.decorate_toolbar_ = function(parent) {
|
|||||||
// Add room
|
// Add room
|
||||||
tile_group.add_tile(new beestat.component.tile()
|
tile_group.add_tile(new beestat.component.tile()
|
||||||
.set_icon('label_off')
|
.set_icon('label_off')
|
||||||
.set_title('Labels')
|
.set_title('Toggle Labels')
|
||||||
.set_text_color(beestat.style.color.gray.light)
|
.set_text_color(beestat.style.color.gray.light)
|
||||||
.set_background_color(beestat.style.color.bluegray.base)
|
.set_background_color(beestat.style.color.bluegray.base)
|
||||||
.set_background_hover_color(beestat.style.color.bluegray.light)
|
.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
|
// Add room
|
||||||
tile_group.add_tile(new beestat.component.tile()
|
tile_group.add_tile(new beestat.component.tile()
|
||||||
.set_icon('restart_off')
|
.set_icon('restart_off')
|
||||||
.set_title('Auto-Rotate')
|
.set_title('Toggle Auto-Rotate')
|
||||||
.set_text_color(beestat.style.color.gray.light)
|
.set_text_color(beestat.style.color.gray.light)
|
||||||
.set_background_color(beestat.style.color.bluegray.base)
|
.set_background_color(beestat.style.color.bluegray.base)
|
||||||
.set_background_hover_color(beestat.style.color.bluegray.light)
|
.set_background_hover_color(beestat.style.color.bluegray.light)
|
||||||
|
@ -79,3 +79,16 @@ beestat.component.input.range.prototype.set_max = function(max) {
|
|||||||
|
|
||||||
return this;
|
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;
|
||||||
|
};
|
||||||
|
@ -223,12 +223,8 @@ beestat.component.scene.prototype.mouseup_handler_ = function() {
|
|||||||
window.removeEventListener('touchend', this.mouseup_handler_);
|
window.removeEventListener('touchend', this.mouseup_handler_);
|
||||||
|
|
||||||
if (this.dragged_ === false) {
|
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.active_mesh_ = this.intersected_mesh_;
|
||||||
|
this.dispatchEvent('change_active_room');
|
||||||
this.update_();
|
this.update_();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -364,14 +360,14 @@ beestat.component.scene.prototype.update_ = function() {
|
|||||||
// Set the color of each room
|
// Set the color of each room
|
||||||
floor_plan.data.groups.forEach(function(group) {
|
floor_plan.data.groups.forEach(function(group) {
|
||||||
group.rooms.forEach(function(room) {
|
group.rooms.forEach(function(room) {
|
||||||
const value_sprite = self.rooms_[room.room_id].userData.sprites.value;
|
const value_sprite = self.meshes_[room.room_id].userData.sprites.value;
|
||||||
const icon_sprite = self.rooms_[room.room_id].userData.sprites.icon;
|
const icon_sprite = self.meshes_[room.room_id].userData.sprites.icon;
|
||||||
|
|
||||||
// Room outline
|
// Room outline
|
||||||
if (self.rooms_[room.room_id] === self.active_mesh_) {
|
if (self.meshes_[room.room_id] === self.active_mesh_) {
|
||||||
self.rooms_[room.room_id].userData.outline.visible = true;
|
self.meshes_[room.room_id].userData.outline.visible = true;
|
||||||
} else {
|
} else {
|
||||||
self.rooms_[room.room_id].userData.outline.visible = false;
|
self.meshes_[room.room_id].userData.outline.visible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let color;
|
let color;
|
||||||
@ -458,7 +454,7 @@ beestat.component.scene.prototype.update_ = function() {
|
|||||||
// Labels
|
// Labels
|
||||||
if (
|
if (
|
||||||
self.labels_ === true ||
|
self.labels_ === true ||
|
||||||
self.rooms_[room.room_id] === self.active_mesh_
|
self.meshes_[room.room_id] === self.active_mesh_
|
||||||
) {
|
) {
|
||||||
switch (self.data_type_) {
|
switch (self.data_type_) {
|
||||||
case 'temperature':
|
case 'temperature':
|
||||||
@ -494,7 +490,7 @@ beestat.component.scene.prototype.update_ = function() {
|
|||||||
icon_sprite.material = self.get_blank_label_material_();
|
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);
|
mesh.translateY(room.y);
|
||||||
|
|
||||||
// Store a reference to the mesh representing each room.
|
// Store a reference to the mesh representing each room.
|
||||||
if (this.rooms_ === undefined) {
|
if (this.meshes_ === undefined) {
|
||||||
this.rooms_ = {};
|
this.meshes_ = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Do I need both these?
|
// Allow me to go from room -> mesh and mesh -> room
|
||||||
this.rooms_[room.room_id] = mesh;
|
this.meshes_[room.room_id] = mesh;
|
||||||
// mesh.userData.room_id = room.room_id;
|
// mesh.userData.room_id = room.room_id;
|
||||||
|
mesh.userData.room = room;
|
||||||
|
|
||||||
layer.add(mesh);
|
layer.add(mesh);
|
||||||
|
|
||||||
@ -982,3 +979,16 @@ beestat.component.scene.prototype.dispose = function() {
|
|||||||
window.cancelAnimationFrame(this.animation_frame_);
|
window.cancelAnimationFrame(this.animation_frame_);
|
||||||
beestat.component.prototype.dispose.apply(this, arguments);
|
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;
|
||||||
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user