161 lines
6.9 KiB
JavaScript
161 lines
6.9 KiB
JavaScript
// скрипт страницы index, на которой отображаются графики
|
||
|
||
// интервал обновления статуса в миллисекундах
|
||
const RELOAD_STATS_INTERVAL = 10000
|
||
|
||
// интервал обновления графика - 1% показываемого времени (2 недели)
|
||
// const RELOAD_CHART_INTERVAL = (3600 * 1000 * 24 * 14) / 100
|
||
// const RELOAD_CHART_INTERVAL = (3600 * 1000 * 24) / 100
|
||
const RELOAD_CHART_INTERVAL = 30000
|
||
|
||
const DATETIME_FORMAT = "DD MMM YYYY HH:mm:ss"
|
||
|
||
function unpackBits(num, desc) {
|
||
let out = ""
|
||
for (let i = 0; i < desc.length; i++) {
|
||
if (desc[i] !== null) {
|
||
if ((num & (1 << i)) !== 0) {
|
||
// бит установлен
|
||
if (out.length === 0) {
|
||
out = desc[i]
|
||
} else {
|
||
out += " + "
|
||
out += desc[i]
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return out
|
||
}
|
||
|
||
/**
|
||
* Функция для линейной аппроксимации набора точек. Для заданных точек находит коэфицент a из уравнения y=ax+b.
|
||
* Уравнение подбирается при помощи метода наименьших квадратов.
|
||
* @param dataset набор точек в виде [[timestamp, val], [timestamp, val], ...], где timestamp - значение по X, val - значение по Y
|
||
* @returns {number}, коэфицент a
|
||
*/
|
||
function approximateWithTimestamps(dataset) {
|
||
|
||
// для точных расчетов нужно сместить timestamp
|
||
const timestamp_offset = dataset[0][0]
|
||
|
||
// сумма (x[i] * y[i])
|
||
let sum_x_mul_y = 0
|
||
for (let i = 0; i < dataset.length; i++) {
|
||
sum_x_mul_y += (dataset[i][0] - timestamp_offset) * dataset[i][1]
|
||
}
|
||
|
||
// сумма всех x[i]
|
||
let sum_x = 0;
|
||
for (let i = 0; i < dataset.length; i++) {
|
||
sum_x += dataset[i][0] - timestamp_offset
|
||
}
|
||
|
||
// сумма всех y[i]
|
||
let sum_y = 0;
|
||
for (let i = 0; i < dataset.length; i++) {
|
||
sum_y += dataset[i][1]
|
||
}
|
||
|
||
// сумма всех x[i]^2
|
||
let sum_x_mul_x = 0;
|
||
for (let i = 0; i < dataset.length; i++) {
|
||
sum_x_mul_x += Math.pow(dataset[i][0] - timestamp_offset, 2)
|
||
}
|
||
|
||
// вычисление коэфицента a из формулы y=ax+b
|
||
// нам нужен только он
|
||
return (dataset.length * sum_x_mul_y - sum_x * sum_y) / (sum_x_mul_x - Math.pow(sum_x, 2))
|
||
}
|
||
|
||
async function makeRequest(url) {
|
||
let response = await fetch(url)
|
||
if (response.status !== 200) {
|
||
console.log('fetch(' + url + ') failed. Status Code: ' + response.status);
|
||
return null;
|
||
}
|
||
return await response.json()
|
||
}
|
||
|
||
async function loadAllData() {
|
||
return await makeRequest('/fetch/all')
|
||
}
|
||
|
||
async function loadChartData() {
|
||
return (await makeRequest('/fetch/tank-chart'))['tank_chart']
|
||
}
|
||
|
||
async function loadLastUpdates() {
|
||
return (await makeRequest('/fetch/stats'))['stats']
|
||
}
|
||
|
||
async function updateStatus() {
|
||
let dataset = await loadLastUpdates()
|
||
|
||
// последнее обновление
|
||
document.getElementById("tank-last-update").innerHTML = moment(new Date(dataset['tank']['last_update'] * 1000)).format(DATETIME_FORMAT)
|
||
document.getElementById("pump-last-update").innerHTML = moment(new Date(dataset['pump']['last_update'] * 1000)).format(DATETIME_FORMAT)
|
||
|
||
//<p>Уровень воды <span id="tank-level-dir"></span></p>
|
||
const last_radar_values = dataset['tank']['last_radar_values']
|
||
if (last_radar_values.length === 0) {
|
||
document.getElementById("tank-level-dir").innerHTML = "(?)";
|
||
} else {
|
||
document.getElementById("tank-level-dir").innerHTML = approximateWithTimestamps(last_radar_values) < 0 ? '↘' : '↗';
|
||
}
|
||
|
||
//<p>Текущий уровень воды: <span id="tank-level-now"></span>%</p>
|
||
document.getElementById("tank-level-now").innerHTML = dataset['tank']['last_percentage']
|
||
|
||
//<p>Текущее значение с радара: <span id="tank-raw-now"></span></p>
|
||
document.getElementById("tank-raw-now").innerHTML = dataset['tank']['last_radar']
|
||
|
||
//<p>Статус: <span id="tank-status"></span></p>
|
||
const shur_status_bits = ['нужна вода', 'поплавок нижний', 'поплавок верхний', 'поплавок аварийный']
|
||
document.getElementById("tank-status").innerHTML = unpackBits(dataset['tank']['status_reg'], shur_status_bits) + " (" + dataset['tank']['status_reg'] + ")";
|
||
|
||
//<p>Частота ПЧ: <span id="pump-vfd-freq"></span>Гц</p>
|
||
document.getElementById("pump-vfd-freq").innerHTML = dataset['pump']['vfd_freq']
|
||
|
||
//<p>Ток ПЧ: <span id="pump-vfd-curr"></span>А</p>
|
||
document.getElementById("pump-vfd-curr").innerHTML = dataset['pump']['vfd_curr']
|
||
|
||
//<p>Ошибка ПЧ: <span id="pump-vfd-error"></span></p>
|
||
document.getElementById("pump-vfd-error").innerHTML = dataset['pump']['vfd_err']
|
||
|
||
//<p>Регистр аварий: <span id="pump-alarms"></span></p>
|
||
document.getElementById("pump-alarms").innerHTML = dataset['pump']['alarms']
|
||
|
||
//<p>Состояние КА: <span id="pump-stage"></span></p>
|
||
document.getElementById("pump-stage").innerHTML = dataset['pump']['pump_stage']
|
||
|
||
//<p>Текущий расход: <span id="pump-flow-meter"></span>м³</p>
|
||
document.getElementById("pump-flow-meter").innerHTML = dataset['pump']['flow_meter']
|
||
|
||
}
|
||
// состояния конченого автомата
|
||
// $states = [
|
||
// 0 => "отключен",
|
||
// 2 => "инициализация: установка задвижек в начальное состояние",
|
||
// 21 => "инициализация: закрытие задвижек 23.5 и 23.6",
|
||
// 31 => "инициализация: открытие задвижек 23.5 и 23.6",
|
||
// 99 => "<span class=\"value-bad\">авария</span>",
|
||
//
|
||
// 100 => "ожидание сигнала на перекачку воды",
|
||
//
|
||
// 102 => "запуск: открытие задвижки 23.6",
|
||
// 110 => "запуск: ожидание сигнала от датчика уровня поз.36",
|
||
// 121 => "запуск: открытие задвижек насоса",
|
||
// 131 => "запуск: закрытие задвижки 23.6",
|
||
// 141 => "запуск: пуск ПЧ",
|
||
//
|
||
// 200 => "<span class=\"value-good\">работает</span>",
|
||
//
|
||
// 202 => "остановка: закрытие задвижек 23.3 и 23.4",
|
||
// 211 => "остановка: ожидание остановки ПЧ",
|
||
// 221 => "остановка: перевод запорной арматуры в исходное состояние",
|
||
// 231 => "остановка: работа компрессора",
|
||
// 235 => "остановка: сброс конденсата клапанами 25.*"
|
||
// ];
|