В общем один очень хороший человек написал полностью код по задаче:
теперь при звонке в домофон задействуется реле на контроллере для физического звонка в квартире, а после открытия двери (событии от геркона двери) - отбой звонка и выключение реле.
var HIK_HOST = “192.168.1.ххх”;
var HIK_USER = “admin”;
var HIK_PASSWORD = “ххххххххххх”;
var DOOR_SENSOR_DEVICE = “wb-gpio”;
var DOOR_SENSOR_CONTROL = “W1_IN”;
var BELL_RELAY_DEVICE = “wb-gpio”;
var BELL_RELAY_CONTROL = “MOD1_OUT1”;
var VIRTUAL_DEVICE_ID = “hikvision_intercom”;
var POLLING_INTERVAL_SEC = 2;
var DOOR_SENSOR_TOPIC = DOOR_SENSOR_DEVICE + “/” + DOOR_SENSOR_CONTROL;
var BELL_RELAY_TOPIC = BELL_RELAY_DEVICE + “/” + BELL_RELAY_CONTROL;
defineVirtualDevice(VIRTUAL_DEVICE_ID, {
title: “Домофон Hikvision”,
cells: {
callStatus: {
title: “Статус вызова”,
type: “text”,
value: “idle”,
readonly: true
},
openDoor: {
title: “Открыть дверь”,
type: “pushbutton”
},
rejectCall: {
title: “Сбросить вызов”,
type: “pushbutton”
}
}
});
function callHikvisionOpenDoor() {
log(“Hikvision: Отправка команды ‘Открыть дверь’ через VideoIntercom API”);
var xmlPayload = ‘unlock’;
var command = “curl --silent --digest -u " + HIK_USER + “:” + HIK_PASSWORD +
" -X PUT -d '” + xmlPayload + “'” +
" http://" + HIK_HOST + “/ISAPI/VideoIntercom/remoteOpenDoor”;
runShellCommand(command, {
exitCallback: function(exitCode, output) {
if (exitCode !== 0) {
log.error("Hikvision: Ошибка при открытии двери! Код: " + exitCode + " Ответ: " + output);
}
}
});
}
function callHikvisionReject() {
log(“Hikvision: Отправка команды ‘Сбросить вызов’”);
var command = “curl --silent --digest -u " + HIK_USER + “:” + HIK_PASSWORD +
" -X PUT -H ‘Content-Type: application/json’ -d ‘{"CallSignal":{"cmdType":"reject"}}’” +
" http://" + HIK_HOST + “/ISAPI/VideoIntercom/callSignal?format=json”;
runShellCommand(command);
}
defineRule(“poll_hikvision_status”, {
when: cron(“*/” + POLLING_INTERVAL_SEC + " * * * * *"),
then: function () {
var command = “curl --silent --digest -u " + HIK_USER + “:” + HIK_PASSWORD +
" http://” + HIK_HOST + “/ISAPI/VideoIntercom/callStatus?format=json”;
runShellCommand(command, {
captureOutput: true,
exitCallback: function (exitCode, output) {
if (exitCode === 0 && output) {
try {
var response = JSON.parse(output);
if (response && response.CallStatus && response.CallStatus.status) {
var currentStatus = response.CallStatus.status;
if (dev[VIRTUAL_DEVICE_ID + “/callStatus”] !== currentStatus) {
dev[VIRTUAL_DEVICE_ID + “/callStatus”] = currentStatus;
}
}
} catch (e) {
log.error("Hikvision: Не удалось разобрать ответ JSON: " + output);
}
} else {
log.error("Hikvision: Ошибка опроса статуса. Код выхода: " + exitCode + ", Ответ: " + output);
if (dev[VIRTUAL_DEVICE_ID + “/callStatus”] !== “error”) {
dev[VIRTUAL_DEVICE_ID + “/callStatus”] = “error”;
}
}
}
});
}
});
defineRule(“handle_doorbell_logic”, {
whenChanged: [VIRTUAL_DEVICE_ID + “/callStatus”, DOOR_SENSOR_TOPIC],
then: function (newValue, deviceName, cellName) {
var isRinging = (dev[VIRTUAL_DEVICE_ID + “/callStatus”] === “ring”);
// !!! ВОТ ОНО, ИСПРАВЛЕНИЕ !!!
var isDoorOpen = (dev[DOOR_SENSOR_TOPIC] == false);
var isBellRelayOn = (dev[BELL_RELAY_TOPIC] == true);
log("Логика звонка: Статус=" + dev[VIRTUAL_DEVICE_ID + "/callStatus"] + ", Дверь=" + (isDoorOpen ? "Открыта" : "Закрыта") + ", Реле=" + (isBellRelayOn ? "Вкл" : "Выкл"));
if (isRinging && !isDoorOpen && !isBellRelayOn) {
log("-> Сценарий 1: Входящий вызов. Включаю реле звонка.");
dev[BELL_RELAY_TOPIC] = true;
return;
}
if (isDoorOpen && isBellRelayOn) {
log("-> Сценарий 2: Дверь открыта во время звонка. Выключаю реле и сбрасываю вызов.");
dev[BELL_RELAY_TOPIC] = false;
callHikvisionReject();
return;
}
if (!isRinging && isBellRelayOn) {
log("-> Сценарий 3: Вызов завершен. Выключаю реле звонка.");
dev[BELL_RELAY_TOPIC] = false;
}
}
});
defineRule(“manual_intercom_control”, {
whenChanged: [
VIRTUAL_DEVICE_ID + “/openDoor”,
VIRTUAL_DEVICE_ID + “/rejectCall”
],
then: function (newValue, devName, cellName) {
switch(cellName) {
case “openDoor”:
callHikvisionOpenDoor();
break;
case “rejectCall”:
callHikvisionReject();
break;
}
}
});