У меня бывают скачки напряжения и я хочу сделать оповещения в телегу когда напряжение выходит за пределы и когда возвращается.
По-быстрому сделал вот так
var L1 = "wb-map3et_145/Urms L1";
var L2 = "wb-map3et_145/Urms L2";
var L3 = "wb-map3et_145/Urms L3";
VoltageTopics = [L1, L2, L3];
VoltageNames = ["L1", "L2", "L3"];
defineRule("VoltageNotifications", {
whenChanged: VoltageTopics,
then: function (newValue, devName, cellName) {
var index = VoltageTopics.indexOf(devName + '/' + cellName);
if (newValue > 240) { SendTelegramMsg( 'Напряжение на фазе ' + VoltageNames[index] + ' в Южном выше нормы. U = ' + dev[VoltageTopics[index]] + 'В'); }
if (newValue < 200) { SendTelegramMsg( 'Напряжение на фазе ' + VoltageNames[index] + ' в Южном ниже нормы. U = ' + dev[VoltageTopics[index]] + 'В'); }
if ( 201.999 < newValue && newValue < 239.999) { SendTelegramMsg( 'Напряжение на фазе ' + VoltageNames[index] + ' в Южном вернулось в норму. U = ' + dev[VoltageTopics[index]] + 'В'); }
}
});
Но оно несколько раз в минуту шлёт сообщения, когда напряжение по каждому случаю IF, а я хотел только одно сообщение когда напряжение вышло за предел и потом одно сообщение когда напряжение вернулось в диапазон.
Как это сделать?
В третьем if каждое логическое условие поместите в свои скобки ((201.999 < newValue) && (newValue < 239.999))
В условиях предупреждения выхода из пределов добавьте условие, что старое значение (oldValue) находилось в пределах. В условии возвращения в пределы добавьте условие, что старое значение было вне пределов.
Поскольку в параметрах функции нет oldValue (и очень жаль!), предлагаю сделать virtualDevice, в которое записывать текущее напряжение после проверок всех условий. Тогда при следующей проверке там окажется прежнее напряжение, то, что нам надо.
Если у вас напряжение склонно “дребезжать” вокруг одного из пределов, вы будете получать сообщения очень часто. Можно разнести пределы выхода из границ и возврата в границы - гистерезис.
Добрый день!
Чтобы избежать отправки множества сообщений при каждом изменении напряжения, можно добавить флаги для каждой фазы, которые будут отслеживать, было ли уже отправлено сообщение о выходе напряжения за пределы или о его возвращении в норму. Таким образом, скрипт будет отправлять сообщения только при смене состояния.
Однако, из практики мониторинга, целесообразно реализовать отправку сообщений раз в определённое количество минут, чтобы уведомления бросались в глаза сильнее, но при этом не было чрезмерного спама.
Это мне не нужно. Если надо я могу графики в веб интерфейсе посмотреть. Мне скорее нужна выписка, что напряжение было выше нормы с хх:хх по уу:уу.
И потом все эти отрезки времени за месяц сложить.
вот так?
Сначала сравниваем значение текущего напряжения с предыдущим, а потом записываем текущее в ячейку и при следующей проверке оно уже будет предыдущим.
Получается только при первой проверке в ячейке VirtualDevice будет пусто, но это один раз не страшно. Всего одно дополнительное сообщение.
var L1 = "wb-map3et_145/Urms L1";
var L2 = "wb-map3et_145/Urms L2";
var L3 = "wb-map3et_145/Urms L3";
VoltageTopics = [L1, L2, L3];
VoltageNames = ["L1", "L2", "L3"];
oldTopics = ['Voltage/L1', 'Voltage/L2', 'Voltage/L3'];
defineVirtualDevice("Voltage", {
title: "Напряжение",
cells: {
L1: {
title: "L1",
type: "value",
value: "",
units: "В",
precision: 2,
},
L2: {
title: "L2",
type: "value",
value: "",
units: "В",
precision: 2,
},
L3: {
title: "L3",
type: "value",
value: "",
units: "В",
precision: 2,
}
}
});
defineRule("VoltageNotifications", {
whenChanged: VoltageTopics,
then: function (newValue, devName, cellName) {
var index = VoltageTopics.indexOf(devName + '/' + cellName);
if ( (newValue >= 240) && (200 < oldTopics[index]) && (oldTopics[index] < 240) ) {
SendTelegramMsg( 'Напряжение на фазе ' + VoltageNames[index] + ' в Южном выше нормы. U = ' + dev[VoltageTopics[index]] + 'В');
}
if ( (newValue <= 200) && (200 < oldTopics[index]) && (oldTopics[index] < 240) ) {
SendTelegramMsg( 'Напряжение на фазе ' + VoltageNames[index] + ' в Южном ниже нормы. U = ' + dev[VoltageTopics[index]] + 'В');
}
if ( (200 < newValue) && (newValue < 240) && (oldTopics[index] <= 200) && (240 <= oldTopics[index]) ) {
SendTelegramMsg( 'Напряжение на фазе ' + VoltageNames[index] + ' в Южном вернулось в норму. U = ' + dev[VoltageTopics[index]] + 'В');
}
dev[ oldTopics[index] ] = newValue; // запись напряжения в ячейку виртуального устройства
}
});
Да, ваш код должен работать.
Остались ли еще вопросы?
Нет я заметил логическую ошибку в условии.
Вот это непонятно как будет работать, т.к. старое значение сначала должно быть меньше 200, а потом меньше 240
if ( (newValue <= 200) && (200 < oldTopics[index]) && (oldTopics[index] < 240) )
А мне надо чтобы оно было либо меньше 200, либо больше 240
Вот так?
if ( (200 < newValue) && (newValue < 240) && ( (oldTopics[index] <= 200) || (240 >= oldTopics[index]) ) )
Теперь вторая часть задачи: как зафиксировать промежуток времени между сообщением о выходе напряжения за пределы 200…240В и сообщением о возвращении его в норму?
Рекомендую ознакомится с данными примерами правил.
Тут ничего полезного нет.
Я сделал вот так
var L1 = "wb-map3et_145/Urms L1";
var L2 = "wb-map3et_145/Urms L2";
var L3 = "wb-map3et_145/Urms L3";
VoltageTopics = [L1, L2, L3];
VoltageNames = ["L1", "L2", "L3"];
oldTopics = ['oldVoltage/L1', 'oldVoltage/L2', 'oldVoltage/L3'];
defineVirtualDevice("oldVoltage", {
title: "Напряжение OLD",
cells: {
L1: {
title: "L1",
type: "value",
value: "",
units: "В",
precision: 2,
},
L2: {
title: "L2",
type: "value",
value: "",
units: "В",
precision: 2,
},
L3: {
title: "L3",
type: "value",
value: "",
units: "В",
precision: 2,
},
date: {
title: "date",
type: "value",
value: "",
units: "ms",
precision: 0,
}
}
});
defineRule("VoltageNotifications", {
whenChanged: VoltageTopics,
then: function (newValue, devName, cellName) {
var index = VoltageTopics.indexOf(devName + '/' + cellName);
if ( (newValue >= 240) && (200 < oldTopics[index]) && (oldTopics[index] < 240) ) {
SendTelegramMsg( 'Напряжение на фазе ' + VoltageNames[index] + ' в Южном выше нормы. U = ' + dev[VoltageTopics[index]] + 'В');
dev['oldVoltage/date'] = new Date(); // записываем время, когда напряжение стало выше 240
}
if ( (newValue <= 200) && (200 < oldTopics[index]) && (oldTopics[index] < 240) ) {
SendTelegramMsg( 'Напряжение на фазе ' + VoltageNames[index] + ' в Южном ниже нормы. U = ' + dev[VoltageTopics[index]] + 'В');
dev['oldVoltage/date'] = new Date(); // записываем время, когда напряжение стало ниже 200
}
if ( (200 < newValue) && (newValue < 240) && ( (oldTopics[index] <= 200) || (240 >= oldTopics[index]) ) ) {
timeDifference = ( new Date() - dev['oldVoltage/date'] ) / (1000*60); // Время отсутствия должного напряжения в минутах
SendTelegramMsg( 'Напряжение на фазе ' + VoltageNames[index] + ' в Южном вернулось в норму. U = ' + dev[VoltageTopics[index]] + 'В. Время отсутствия должного напряжения ' + timeDifference + ' минут.');
}
dev[ oldTopics[index] ] = newValue; // запись напряжения в ячейку виртуального устройства
}
});
Ошибок вроде нет синтаксических, надеюсь, все будет работать корректно.
Могу ли я еще чем-то помочь?
Не работает. Прямо сейчас на одной фазе 245В, а в телеге ни одного сообщения
Добрый день, вот пример
Немного конечно больше пишет в логи, но достаточно наглядно отображает.
// Установим диапазон напряжения
var voltage_min = 215; // 220 - 5
var voltage_max = 225; // 220 + 5
var voltage_exceeded = false; // Флаг для контроля выхода за пределы
// Лог при запуске скрипта
log("Скрипт для мониторинга напряжения запущен.");
// Функция для отправки сообщений в Telegram
function sendTelegramMessage(message) {
var token = "ВАШ_TG_BOT_TOKEN"; // Токен вашего Telegram бота
var chat_id = "ВАШ_CHAT_ID"; // Ваш чат или ID пользователя
var url = "https://api.telegram.org/bot" + token + "/sendMessage?chat_id=" + chat_id + "&text=" + encodeURIComponent(message);
runShellCommand("curl -s -X POST " + url);
log("Отправлено сообщение в Telegram: " + message); // Лог отправки сообщения
}
// Следим за изменением напряжения
defineRule("voltage_check", {
whenChanged: "wb-map6s_134/Urms", // Топик с данными напряжения
then: function (newValue, devName, cellName) {
var voltage = parseFloat(newValue);
// Логируем текущее значение напряжения
log("Текущее напряжение: " + voltage + " В");
// Если напряжение вышло за пределы диапазона и еще не было оповещения
if ((voltage < voltage_min || voltage > voltage_max) && !voltage_exceeded) {
var message = "Напряжение вышло за пределы: " + voltage + " В";
sendTelegramMessage(message);
log(message); // Логируем событие
voltage_exceeded = true;
}
// Если напряжение вернулось в норму
if (voltage >= voltage_min && voltage <= voltage_max && voltage_exceeded) {
var message = " Напряжение вернулось в норму: " + voltage + " В";
sendTelegramMessage(message);
log(message); // Логируем событие
voltage_exceeded = false;
}
}
});
1 лайк
Теперь работает, но это только для одной фазы пример. Я доработал его под 3 фазы.
var voltage_min = 200;
var voltage_max = 240;
var L1 = "wb-map3et_145/Urms L1";
var L2 = "wb-map3et_145/Urms L2";
var L3 = "wb-map3et_145/Urms L3";
log("Скрипт для мониторинга напряжения запущен.");
VoltageTopics = [L1, L2, L3];
VoltageNames = ["L1", "L2", "L3"];
VoltageExceeded = [false, false, false]; // Флаг для контроля выхода за пределы. Становится true при отправке сообщения о выходе напряжение за пределы нормы.
// Следим за изменением напряжения
defineRule("VoltageNotifications", {
whenChanged: VoltageTopics, // Топики с данными напряжения
then: function (newValue, devName, cellName) {
var voltage = parseFloat(newValue); // на всякий случай, если в newValue передаётся строка 220В, то parseFloat прочитает из строки только число 220
var index = VoltageTopics.indexOf(devName + '/' + cellName);
// Логируем текущее значение напряжения
log("Текущее напряжение: " + VoltageNames[index] + ' = ' + voltage + " В");
// Если напряжение вышло за пределы диапазона и еще не было оповещения
if ( (voltage < voltage_min || voltage > voltage_max) && !VoltageExceeded[index]) {
var message = 'Напряжение в Южном вышло за пределы: ' + VoltageNames[index] + ' = ' + voltage + ' В';
SendTelegramMsg(message);
log(message); // Логируем событие
VoltageExceeded[index] = true;
log(VoltageExceeded[index]); // Логируем событие
}
// Если напряжение вернулось в норму
if (voltage >= voltage_min && voltage <= voltage_max && VoltageExceeded[index]) {
var message = 'Напряжение в Южном вернулось в норму: ' + VoltageNames[index] + ' = ' + voltage + ' В';
SendTelegramMsg(message);
log(message); // Логируем событие
VoltageExceeded[index] = false;
log(VoltageExceeded[index]); // Логируем событие
}
}
});
Дальше я хотел вычислять время отсутствия нормального напряжения. Внутри первого IF вставляю
var voltageExceededDate = new Date();
а внутрь второго
var voltageReturnDate = new Date();
var noVoltagePeriod = (voltageReturnDate - voltageExceededDate) / (1000*60);
Но почему-то в отличии от Javascript тут время выводится не в миллисекунах и поэтому над ним невозможно совершать математические действия.
voltageExceededDate: 2024-09-10 18:10:29.912+03:00
voltageReturnDate: 2024-09-10 18:10:35.908+03:00
noVoltagePeriod: NaN
Что делать?
Добрый день, ниже несколько обновил свой скрипт.
// Установим диапазон напряжения
var voltage_min = 210;
var voltage_max = 230;
var voltage_exceeded = false; // Флаг для контроля выхода за пределы
var exceeded_start_time = null; // Время выхода напряжения за пределы
// Лог при запуске скрипта
log("Скрипт для мониторинга напряжения запущен.");
// Настройка токена и ID чата
var telegram_bot_token = "token"; // Токен вашего Telegram бота
var telegram_chat_id = chat_id; // ID чата или пользователя
// Функция для отправки сообщений в Telegram
function sendTelegramMessage(message) {
var command = 'curl -s -X POST https://api.telegram.org/bot' + telegram_bot_token + '/sendMessage -d chat_id=' + telegram_chat_id + ' -d text="' + encodeURIComponent(message) + '"';
runShellCommand(command, {
captureOutput: true,
exitCallback: function (exitCode, stdout, stderr) {
log("Telegram сообщение отправлено: " + message + ". Код выхода: " + exitCode);
if (stderr) {
log("Ошибка отправки в Telegram: " + stderr);
}
}
});
}
// Следим за изменением напряжения
defineRule("voltage_check", {
whenChanged: "wb-map6s_134/Urms", // Топик с данными напряжения
then: function (newValue, devName, cellName) {
var voltage = parseFloat(newValue);
// Логируем текущее значение напряжения
log("Текущее напряжение: " + voltage + " В");
// Если напряжение вышло за пределы диапазона и еще не было оповещения
if ((voltage < voltage_min || voltage > voltage_max) && !voltage_exceeded) {
var message = "⚠️ Напряжение вышло за пределы: " + voltage + " В";
sendTelegramMessage(message);
log(message); // Логируем событие
voltage_exceeded = true;
exceeded_start_time = new Date(); // Запоминаем время выхода за пределы
}
// Если напряжение вернулось в норму
if (voltage >= voltage_min && voltage <= voltage_max && voltage_exceeded) {
var exceeded_end_time = new Date(); // Время возвращения в норму
var duration = (exceeded_end_time - exceeded_start_time) / 1000; // Продолжительность в секундах
var message = "✅ Напряжение вернулось в норму: " + voltage + " В. " +
"Напряжение было вне диапазона в течение " + duration + " секунд.";
sendTelegramMessage(message);
log(message); // Логируем событие
// Сбрасываем флаг и время
voltage_exceeded = false;
exceeded_start_time = null;
}
}
});
Блин работает. Вчера точно так же делал и new Date()
и new Date(milliseconds)
пробовал, но не получалось.