Вот скрипт на котором “упали“
// ==================================================
// Скрипт: управление вентиляторами в 2 теплицах
// С задержкой 0.5 сек для обеих теплиц
// ==================================================
// ------------------- НАСТРОЙКИ ГРУППЫ 1 (Теплица 1 - 11 реле) -------------------
var BUTTON_ALL_1 = "wb-mr6c_151/Input 1";
var BUTTON_AUTO_1 = "wb-mr6c_151/Input 2";
var auto_relay_on_1 = "wb-mr6c_151/K5";
var auto_relay_off_1 = "wb-mr6c_151/K4";
// 11 отдельных реле - теплица 1
var RELAYS_GROUP_1 = [
"wb-mr6cu_231/K1", "wb-mr6cu_231/K2", "wb-mr6cu_231/K3", "wb-mr6cu_231/K4",
"wb-mr6cu_231/K5", "wb-mr6cu_231/K6", "wb-mr6cu_233/K1", "wb-mr6cu_233/K2",
"wb-mr6cu_233/K3", "wb-mr6cu_233/K4", "wb-mr6cu_233/K5"
];
// ------------------- ДАТЧИКИ ТЕПЛИЦЫ 1 -------------------
var TEMP_TOP_1_1 = "wb-msw-v4_203/Temperature";
var TEMP_TOP_1_2 = "wb-msw-v4_207/Temperature";
var HUM_TOP_1_1 = "wb-msw-v4_203/Humidity";
var HUM_TOP_1_2 = "wb-msw-v4_207/Humidity";
var TEMP_BOTTOM_1_1 = "wb-m1w2_93/External Sensor 1";
var TEMP_BOTTOM_1_2 = "wb-m1w2_95/External Sensor 1";
// ------------------- НАСТРОЙКИ ГРУППЫ 2 (Теплица 2 - 10 реле) -------------------
var BUTTON_ALL_2 = "wb-mr6c_152/Input 1";
var BUTTON_AUTO_2 = "wb-mr6c_152/Input 2";
var auto_relay_on_2 = "wb-mr6c_152/K5";
var auto_relay_off_2 = "wb-mr6c_152/K4";
// 10 отдельных реле - теплица 2
var RELAYS_GROUP_2 = [
"wb-mr6cu_176/K1", "wb-mr6cu_176/K2", "wb-mr6cu_176/K3", "wb-mr6cu_176/K4",
"wb-mr6cu_176/K5", "wb-mr6cu_176/K6", "wb-mr6cu_43/K1", "wb-mr6cu_43/K2",
"wb-mr6cu_43/K3", "wb-mr6cu_43/K4"
];
// ------------------- ДАТЧИКИ ТЕПЛИЦЫ 2 -------------------
var TEMP_TOP_2_1 = "wb-msw-v4_193/Temperature";
var TEMP_TOP_2_2 = "wb-msw-v4_183/Temperature";
var HUM_TOP_2_1 = "wb-msw-v4_193/Humidity";
var HUM_TOP_2_2 = "wb-msw-v4_183/Humidity";
var TEMP_BOTTOM_2_1 = "wb-m1w2_101/External Sensor 1";
var TEMP_BOTTOM_2_2 = "wb-m1w2_92/External Sensor 1";
// ------------------- ПАРАМЕТРЫ -------------------
var DELAY_BETWEEN_RELAYS = 500; // Задержка 0.5 секунды (в миллисекундах)
// ------------------- ВИРТУАЛЬНЫЕ УСТРОЙСТВА -------------------
var VIRTUAL_DEV_1 = "greenhouse_1";
var VIRTUAL_DEV_2 = "greenhouse_2";
defineVirtualDevice(VIRTUAL_DEV_1, {
title: "Теплица 1 - Управление и мониторинг",
cells: {
all_on: { type: "switch", value: false, title: "ВКЛ/ВЫКЛ вентиляции" },
auto: { type: "switch", value: false, title: "Авторежим" },
auto_led: { type: "switch", value: false, readonly: true, title: "Авто режим" },
manual_led: { type: "switch", value: true, readonly: true, title: "Ручной режим" },
progress: { type: "value", value: 0, unit: "%", title: "Выполнение", readonly: true },
temp_top_avg: { type: "value", value: 0, unit: "°C", title: "Температура сверху (ср.)", readonly: true },
temp_top_1: { type: "value", value: 0, unit: "°C", title: "Температура сверху 1", readonly: true },
temp_top_2: { type: "value", value: 0, unit: "°C", title: "Температура сверху 2", readonly: true },
hum_top_avg: { type: "value", value: 0, unit: "%", title: "Влажность сверху (ср.)", readonly: true },
hum_top_1: { type: "value", value: 0, unit: "%", title: "Влажность сверху 1", readonly: true },
hum_top_2: { type: "value", value: 0, unit: "%", title: "Влажность сверху 2", readonly: true },
temp_bottom_avg: { type: "value", value: 0, unit: "°C", title: "Температура снизу (ср.)", readonly: true },
temp_bottom_1: { type: "value", value: 0, unit: "°C", title: "Температура снизу 1", readonly: true },
temp_bottom_2: { type: "value", value: 0, unit: "°C", title: "Температура снизу 2", readonly: true }
}
});
defineVirtualDevice(VIRTUAL_DEV_2, {
title: "Теплица 2 - Управление и мониторинг",
cells: {
all_on: { type: "switch", value: false, title: "ВКЛ/ВЫКЛ вентиляции" },
auto: { type: "switch", value: false, title: "Авторежим" },
auto_led: { type: "switch", value: false, readonly: true, title: "Авто режим" },
manual_led: { type: "switch", value: true, readonly: true, title: "Ручной режим" },
progress: { type: "value", value: 0, unit: "%", title: "Выполнение", readonly: true },
temp_top_avg: { type: "value", value: 0, unit: "°C", title: "Температура сверху (ср.)", readonly: true },
temp_top_1: { type: "value", value: 0, unit: "°C", title: "Температура сверху 1", readonly: true },
temp_top_2: { type: "value", value: 0, unit: "°C", title: "Температура сверху 2", readonly: true },
hum_top_avg: { type: "value", value: 0, unit: "%", title: "Влажность сверху (ср.)", readonly: true },
hum_top_1: { type: "value", value: 0, unit: "%", title: "Влажность сверху 1", readonly: true },
hum_top_2: { type: "value", value: 0, unit: "%", title: "Влажность сверху 2", readonly: true },
temp_bottom_avg: { type: "value", value: 0, unit: "°C", title: "Температура снизу (ср.)", readonly: true },
temp_bottom_1: { type: "value", value: 0, unit: "°C", title: "Температура снизу 1", readonly: true },
temp_bottom_2: { type: "value", value: 0, unit: "°C", title: "Температура снизу 2", readonly: true }
}
});
// ------------------- ПЕРЕМЕННЫЕ ДЛЯ УПРАВЛЕНИЯ -------------------
var activeOperation = {
1: false,
2: false
};
// ------------------- ФУНКЦИИ -------------------
function toNumber(val) {
var num = parseFloat(val);
return isNaN(num) ? 0 : num;
}
function toBool(val) {
return val === true || val === 1 || val === "1";
}
function roundToHundredths(value) {
return Math.round(value * 100) / 100;
}
function calculateAverage(values) {
var sum = 0;
var count = 0;
for (var i = 0; i < values.length; i++) {
var val = toNumber(values[i]);
if (val !== 0) {
sum += val;
count++;
}
}
return count > 0 ? roundToHundredths(sum / count) : 0;
}
// ------------------- ОБНОВЛЕНИЕ ДАТЧИКОВ -------------------
function updateSensors(greenhouseId) {
if (greenhouseId === 1) {
var tempTop1 = dev[TEMP_TOP_1_1];
var tempTop2 = dev[TEMP_TOP_1_2];
var humTop1 = dev[HUM_TOP_1_1];
var humTop2 = dev[HUM_TOP_1_2];
var tempBottom1 = dev[TEMP_BOTTOM_1_1];
var tempBottom2 = dev[TEMP_BOTTOM_1_2];
dev[VIRTUAL_DEV_1 + "/temp_top_1"] = roundToHundredths(toNumber(tempTop1));
dev[VIRTUAL_DEV_1 + "/temp_top_2"] = roundToHundredths(toNumber(tempTop2));
dev[VIRTUAL_DEV_1 + "/hum_top_1"] = roundToHundredths(toNumber(humTop1));
dev[VIRTUAL_DEV_1 + "/hum_top_2"] = roundToHundredths(toNumber(humTop2));
dev[VIRTUAL_DEV_1 + "/temp_bottom_1"] = roundToHundredths(toNumber(tempBottom1));
dev[VIRTUAL_DEV_1 + "/temp_bottom_2"] = roundToHundredths(toNumber(tempBottom2));
dev[VIRTUAL_DEV_1 + "/temp_top_avg"] = calculateAverage([tempTop1, tempTop2]);
dev[VIRTUAL_DEV_1 + "/hum_top_avg"] = calculateAverage([humTop1, humTop2]);
dev[VIRTUAL_DEV_1 + "/temp_bottom_avg"] = calculateAverage([tempBottom1, tempBottom2]);
} else if (greenhouseId === 2) {
var tempTop1 = dev[TEMP_TOP_2_1];
var tempTop2 = dev[TEMP_TOP_2_2];
var humTop1 = dev[HUM_TOP_2_1];
var humTop2 = dev[HUM_TOP_2_2];
var tempBottom1 = dev[TEMP_BOTTOM_2_1];
var tempBottom2 = dev[TEMP_BOTTOM_2_2];
dev[VIRTUAL_DEV_2 + "/temp_top_1"] = roundToHundredths(toNumber(tempTop1));
dev[VIRTUAL_DEV_2 + "/temp_top_2"] = roundToHundredths(toNumber(tempTop2));
dev[VIRTUAL_DEV_2 + "/hum_top_1"] = roundToHundredths(toNumber(humTop1));
dev[VIRTUAL_DEV_2 + "/hum_top_2"] = roundToHundredths(toNumber(humTop2));
dev[VIRTUAL_DEV_2 + "/temp_bottom_1"] = roundToHundredths(toNumber(tempBottom1));
dev[VIRTUAL_DEV_2 + "/temp_bottom_2"] = roundToHundredths(toNumber(tempBottom2));
dev[VIRTUAL_DEV_2 + "/temp_top_avg"] = calculateAverage([tempTop1, tempTop2]);
dev[VIRTUAL_DEV_2 + "/hum_top_avg"] = calculateAverage([humTop1, humTop2]);
dev[VIRTUAL_DEV_2 + "/temp_bottom_avg"] = calculateAverage([tempBottom1, tempBottom2]);
}
}
// ------------------- УПРАВЛЕНИЕ РЕЛЕ С ЗАДЕРЖКОЙ (ДЛЯ ОБЕИХ ТЕПЛИЦ) -------------------
function setAllRelays(groupId, state) {
var relays = (groupId === 1) ? RELAYS_GROUP_1 : RELAYS_GROUP_2;
var boolState = toBool(state);
var virtualDev = (groupId === 1) ? VIRTUAL_DEV_1 : VIRTUAL_DEV_2;
// Если операция уже выполняется - игнорируем
if (activeOperation[groupId]) {
log.warn("Теплица " + groupId + ": операция уже выполняется, игнорирую");
// Возвращаем переключатель в исходное состояние
setTimeout(function() {
dev[virtualDev + "/all_on"] = !boolState;
}, 100);
return;
}
activeOperation[groupId] = true;
// Для обеих теплиц - поочерёдное переключение с задержкой
log.info("Теплица " + groupId + ": поочерёдное " + (boolState ? "включение" : "выключение") +
" " + relays.length + " реле (задержка " + DELAY_BETWEEN_RELAYS + " мс)");
for (var i = 0; i < relays.length; i++) {
(function(idx) {
setTimeout(function() {
dev[relays[idx]] = boolState;
var percent = Math.round((idx + 1) / relays.length * 100);
dev[virtualDev + "/progress"] = percent;
if (idx === relays.length - 1) {
activeOperation[groupId] = false;
log.info("Теплица " + groupId + ": операция завершена");
setTimeout(function() {
dev[virtualDev + "/progress"] = 0;
}, 1000);
}
}, idx * DELAY_BETWEEN_RELAYS);
})(i);
}
}
// ------------------- ПРАВИЛА ДЛЯ ДАТЧИКОВ -------------------
function createSensorRule(sensor, greenhouseId) {
if (sensor && typeof sensor === 'string') {
defineRule(sensor, {
whenChanged: sensor,
then: function() {
updateSensors(greenhouseId);
}
});
}
}
// Датчики теплицы 1
createSensorRule(TEMP_TOP_1_1, 1);
createSensorRule(TEMP_TOP_1_2, 1);
createSensorRule(HUM_TOP_1_1, 1);
createSensorRule(HUM_TOP_1_2, 1);
createSensorRule(TEMP_BOTTOM_1_1, 1);
createSensorRule(TEMP_BOTTOM_1_2, 1);
// Датчики теплицы 2
createSensorRule(TEMP_TOP_2_1, 2);
createSensorRule(TEMP_TOP_2_2, 2);
createSensorRule(HUM_TOP_2_1, 2);
createSensorRule(HUM_TOP_2_2, 2);
createSensorRule(TEMP_BOTTOM_2_1, 2);
createSensorRule(TEMP_BOTTOM_2_2, 2);
// ------------------- ПРАВИЛА УПРАВЛЕНИЯ -------------------
// Теплица 1
defineRule(VIRTUAL_DEV_1 + "/all_on", {
whenChanged: VIRTUAL_DEV_1 + "/all_on",
then: function(newValue) {
setAllRelays(1, newValue);
}
});
defineRule(VIRTUAL_DEV_1 + "/auto", {
whenChanged: VIRTUAL_DEV_1 + "/auto",
then: function(newValue) {
var val = toBool(newValue);
dev[auto_relay_on_1] = val;
dev[auto_relay_off_1] = !val;
dev[VIRTUAL_DEV_1 + "/auto_led"] = val;
dev[VIRTUAL_DEV_1 + "/manual_led"] = !val;
log.info("Теплица 1: " + (val ? "Включен" : "Выключен") + " авторежим");
}
});
defineRule(BUTTON_ALL_1, {
whenChanged: BUTTON_ALL_1,
then: function(newValue) {
if (!toBool(newValue)) return;
if (activeOperation[1]) return;
var current = toBool(dev[VIRTUAL_DEV_1 + "/all_on"]);
dev[VIRTUAL_DEV_1 + "/all_on"] = !current;
}
});
defineRule(BUTTON_AUTO_1, {
whenChanged: BUTTON_AUTO_1,
then: function(newValue) {
if (!toBool(newValue)) return;
var current = toBool(dev[VIRTUAL_DEV_1 + "/auto"]);
dev[VIRTUAL_DEV_1 + "/auto"] = !current;
}
});
// Теплица 2
defineRule(VIRTUAL_DEV_2 + "/all_on", {
whenChanged: VIRTUAL_DEV_2 + "/all_on",
then: function(newValue) {
setAllRelays(2, newValue);
}
});
defineRule(VIRTUAL_DEV_2 + "/auto", {
whenChanged: VIRTUAL_DEV_2 + "/auto",
then: function(newValue) {
var val = toBool(newValue);
dev[auto_relay_on_2] = val;
dev[auto_relay_off_2] = !val;
dev[VIRTUAL_DEV_2 + "/auto_led"] = val;
dev[VIRTUAL_DEV_2 + "/manual_led"] = !val;
log.info("Теплица 2: " + (val ? "Включен" : "Выключен") + " авторежим");
}
});
defineRule(BUTTON_ALL_2, {
whenChanged: BUTTON_ALL_2,
then: function(newValue) {
if (!toBool(newValue)) return;
if (activeOperation[2]) return;
var current = toBool(dev[VIRTUAL_DEV_2 + "/all_on"]);
dev[VIRTUAL_DEV_2 + "/all_on"] = !current;
}
});
defineRule(BUTTON_AUTO_2, {
whenChanged: BUTTON_AUTO_2,
then: function(newValue) {
if (!toBool(newValue)) return;
var current = toBool(dev[VIRTUAL_DEV_2 + "/auto"]);
dev[VIRTUAL_DEV_2 + "/auto"] = !current;
}
});
// ------------------- ИНИЦИАЛИЗАЦИЯ -------------------
function init() {
// Теплица 1
var allOn1 = true;
for (var i = 0; i < RELAYS_GROUP_1.length; i++) {
if (!toBool(dev[RELAYS_GROUP_1[i]])) {
allOn1 = false;
break;
}
}
dev[VIRTUAL_DEV_1 + "/all_on"] = allOn1;
dev[VIRTUAL_DEV_1 + "/progress"] = 0;
var auto1 = toBool(dev[VIRTUAL_DEV_1 + "/auto"]);
dev[auto_relay_on_1] = auto1;
dev[auto_relay_off_1] = !auto1;
dev[VIRTUAL_DEV_1 + "/auto_led"] = auto1;
dev[VIRTUAL_DEV_1 + "/manual_led"] = !auto1;
// Теплица 2
var allOn2 = true;
for (var i = 0; i < RELAYS_GROUP_2.length; i++) {
if (!toBool(dev[RELAYS_GROUP_2[i]])) {
allOn2 = false;
break;
}
}
dev[VIRTUAL_DEV_2 + "/all_on"] = allOn2;
dev[VIRTUAL_DEV_2 + "/progress"] = 0;
var auto2 = toBool(dev[VIRTUAL_DEV_2 + "/auto"]);
dev[auto_relay_on_2] = auto2;
dev[auto_relay_off_2] = !auto2;
dev[VIRTUAL_DEV_2 + "/auto_led"] = auto2;
dev[VIRTUAL_DEV_2 + "/manual_led"] = !auto2;
updateSensors(1);
updateSensors(2);
log.info("=========================================");
log.info("Скрипт управления вентиляцией теплиц загружен");
log.info("Теплица 1: " + RELAYS_GROUP_1.length + " реле, задержка " + DELAY_BETWEEN_RELAYS + " мс");
log.info("Теплица 2: " + RELAYS_GROUP_2.length + " реле, задержка " + DELAY_BETWEEN_RELAYS + " мс");
log.info("=========================================");
}
init();