Здравствуйте. У меня по дому установили 7 роллет (или рольставен, не знаю, как правильно), которые управляются каждая двумя возвратными кнопками: нажимаешь одну, мотор крутит в одну сторону, нажимаешь другую - в другую. Две кнопки сразу не пробовал нажимать, в крайних положениях полотна есть концевые выключатели, так что можно давить сколько хочешь в разумных пределах. Они полностью открываются/закрываются N секунд, никакого датчика положения нет, но захотелось мне это автоматизировать.
К сожалению, у меня не совсем получилось: я по лени своей и неумению программировать создаю по одному виртуальному устройству и три правила для каждой из своих роллет, пробегая в цикле по объекту с настройками и статусами для каждой из них. Устройства создаются, но правила нормально работают только для последней роллеты, а предыдущие не работают. Такое впечатление, что программа статусы выставляет последней роллете, а не каждой соотвествующей. Что-то со скоупами переменных, объявленных внутри функций. Я, понятное дело, видимо читаю не ту документацию или не понимаю ее.
Я заменил var на const, и оно перестало компилироваться вообще с такой ошибкой:
SyntaxError: parse error (line 40) duk_js_compiler.c:3391
Не подскажете ли, как правильно делать? Я уверен у меня какая-то тупая ошибка или невнимательность, и мне будет стыдно, когда вы укажете на нее… Либо мне надо вначале каждой функции и колбека копировать “текущий девайс”, чтобы он не ссылался все время на последний, или вообще лучше по технологии “копи-пасте” задавать правила и девайсы…
Вот мой код (только вместо const у меня var):
var openMillis = 3 * 1000;
//var shutterPosition = new PersistentStorage("shutterPosition");
var shutters = {
fl1_kitchen_shutter_left: {
name: 'Left Kitchen Shutter',
up: 'wb-mrm2-mini_92/K1',
down: 'wb-mrm2-mini_92/K2',
max: openMillis,
startedMovingUp: -1,
startedMovingDown: -1
},
fl1_kitchen_shutter_right: {
name: 'Right Kitchen Shutter',
up: 'wb-mrm2-mini_93/K1',
down: 'wb-mrm2-mini_93/K2',
max: openMillis,
startedMovingUp: -1,
startedMovingDown: -1
},
fl1_dining_shutter: {
name: 'Dining Room Shutter',
up: 'wb-mrm2-mini_220/K1',
down: 'wb-mrm2-mini_220/K2',
max: openMillis,
startedMovingUp: -1,
startedMovingDown: -1
},
fl1_living_shutter: {
name: 'Living Room Shutter',
up: 'wb-mrm2-mini_222/K1',
down: 'wb-mrm2-mini_222/K2',
max: openMillis,
startedMovingUp: -1,
startedMovingDown: -1
}
};
for (const curDevice1 in shutters) {
const curDevice = curDevice1;
const curDeviceTarget = curDevice + '/targetPosition';
const curDeviceActual = curDevice + '/position';
const curRelayUp = shutters[curDevice].up;
const curRelayDown = shutters[curDevice].down;
defineVirtualDevice(curDevice, {
title: shutters[curDevice].name,
cells: {
position: {
title: "Position",
type: "range",
value: 0,
max: shutters[curDevice].max,
min: 0
},
targetPosition: {
title: "Desired Position",
type: "range",
value: 0,
max: shutters[curDevice].max,
min: 0
}
}
});
defineRule(curDevice + '_target', {
whenChanged: curDeviceTarget,
then: function (newValue, devName, cellName) { // how to get the oldValue?
if (!dev[curRelayUp] && !dev[curRelayDown] && dev[curDeviceTarget] !== dev[curDeviceActual]) {
if (dev[curDeviceTarget] > dev[curDeviceActual]) {
dev[curRelayUp] = true;
} else {
dev[curRelayDown] = true;
}
}
}
});
defineRule(curDevice + '_up', {
whenChanged: curRelayUp,
then: function (newValue, devName, cellName) {
if (newValue) { // started moving up
if (dev[curRelayDown]) { // simultaneous press
dev[curRelayUp] = false; // switch off immediately
shutters[curDevice].startedMovingUp = -1; //we're not moving up
return;
}
if (shutters[curDevice].startedMovingUp > 0) { // already moving up!
return; //ignore
}
shutters[curDevice].startedMovingUp = Date.now();
var targetDiff = dev[curDeviceTarget] - dev[curDeviceActual];
if (targetDiff <= 0) {
// the command to move up didn't come from the target slider
// which means it comes from the physical buttons
targetDiff = shutters[curDevice].max - dev[curDeviceActual] + 1000;
// move to the end
// work for extra sec just in case
}
// never move longer then the max
setTimeout(function () {
dev[curRelayUp] = false;
}, targetDiff);
} else { // stopped moving up
if (shutters[curDevice].startedMovingUp < 0) {
// we werent moving up, ignore
return;
}
// record the position in the device
var curPos = dev[curDeviceActual] +
(Date.now() - shutters[curDevice].startedMovingUp);
shutters[curDevice].startedMovingUp = -1;
// what if it's too high
if (curPos > shutters[curDevice].max) {
curPos = shutters[curDevice].max;
}
dev[curDeviceActual] = curPos;
dev[curDeviceTarget] = curPos;
}
}
});
defineRule(curDevice + '_down', {
whenChanged: curRelayDown,
then: function (newValue, devName, cellName) {
if (newValue) { // started moving down
if (dev[curRelayUp]) { // simultaneous press
dev[curRelayDown] = false; // switch off immediately
shutters[curDevice].startedMovingDown = -1; //we're not moving down
return;
}
if (shutters[curDevice].startedMovingDown > 0) { // already moving down!
return; //ignore
}
shutters[curDevice].startedMovingDown = Date.now();
var targetDiff = dev[curDeviceActual] - dev[curDeviceTarget];
if (targetDiff <= 0) {
// the command to move down didn't come from the target slider
// which means it comes from the physical buttons
targetDiff = dev[curDeviceActual] + 1000;
// move to the end
// work for extra sec just in case
}
// never move longer then the max
setTimeout(function () {
dev[curRelayDown] = false;
}, targetDiff);
} else { // stopped moving up
if (shutters[curDevice].startedMovingDown < 0) {
// we werent moving down, ignore
return;
}
// record the position in the device
var curPos = dev[curDeviceActual] - // note the minus here as we were moving down
(Date.now() - shutters[curDevice].startedMovingDown);
shutters[curDevice].startedMovingDown = -1;
// what if it's too low
if (curPos < 0) {
curPos = 0;
}
dev[curDeviceActual] = curPos;
dev[curDeviceTarget] = curPos;
}
}
});
}