NEWS
Скрипт для Лоран
-
Добрый день!
Прошу совета по скрипту.
Я написал скрипт для Лорана (http://www.kernelchip.ru/Laurent-2.php)
! ````
var IP = "192.168.0.104";
var Period = 5000;
! //Создаем переменные
createState('laurent.temperature','',{type:'number',role:'value.temperature',read:true,unit:'°C'});
createState('laurent.systemtime','',{type:'number',role:'value',read:true});
createState('laurent.inline1','',{type:'boolean',role:'state',read:true});
createState('laurent.inline2','',{type:'boolean',role:'state',read:true});
createState('laurent.inline3','',{type:'boolean',role:'state',read:true});
createState('laurent.inline4','',{type:'boolean',role:'state',read:true});
createState('laurent.inline5','',{type:'boolean',role:'state',read:true});
createState('laurent.inline6','',{type:'boolean',role:'state',read:true});
createState('laurent.relay1','',{type:'boolean',role:'switch',read:true,write:true});
createState('laurent.relay2','',{type:'boolean',role:'switch',read:true,write:true});
createState('laurent.relay3','',{type:'boolean',role:'switch',read:true,write:true});
createState('laurent.relay4','',{type:'boolean',role:'switch',read:true,write:true});
! var request = require('request');
! //Функция для извлечения значений из XML
function XMLElement(tag, xmlcontent)
{
var reg = "<"+tag+">(.*)";
return xmlcontent.match(reg)[1];
}
! //Функция для переключения реле - отослать команду
function relaySwitch (obj)
{
if (obj.state.ack === false && obj.state.val === true)
{
request ('http://'+IP+'/cmd.cgi?cmd=REL,'+obj.id.match(/[1-9]/)+',1');
}else if (obj.state.ack === false && obj.state.val === false) { request ('http://'+IP+'/cmd.cgi?cmd=REL,'+obj.id.match(/[1-9]/)+',0'); }
}
! //Функция обработки ответа
function statusProcessing(error, response, body)
{
//Температура = Конвертируем строку в число (запрошенную по тегу temp в ответе Лорана).округляем (до 1 знака после запятой)
var temperature = parseFloat(XMLElement ("temp", body)).toFixed(1);
setState('laurent.temperature', parseFloat(temperature), true);! //Время Лорана
setState('laurent.systemtime', parseInt(XMLElement ("systime", body)), true);
! //Строка состояния реле
var relayString = XMLElement ("rele", body);
var relayTable = relayString.split("");
//Запишем состояния в каждое реле
setState('laurent.relay1', Boolean(parseFloat(relayTable[0])), true);
setState('laurent.relay2', Boolean(parseFloat(relayTable[1])), true);
setState('laurent.relay3', Boolean(parseFloat(relayTable[2])), true);
setState('laurent.relay4', Boolean(parseFloat(relayTable[3])), true);//Строка состояния входов var inlineString = XMLElement ("in", body); var inlineTable = inlineString.split(""); //Запишем состояния в каждый вход setState('laurent.inline1', Boolean(parseFloat(inlineTable[0]))); setState('laurent.inline2', Boolean(parseFloat(inlineTable[1]))); setState('laurent.inline3', Boolean(parseFloat(inlineTable[2]))); setState('laurent.inline4', Boolean(parseFloat(inlineTable[3]))); setState('laurent.inline5', Boolean(parseFloat(inlineTable[4]))); setState('laurent.inline6', Boolean(parseFloat(inlineTable[5])));
}
! //Главная периодическая функция
function mainPoll ()
{
request ('http://'+IP+'/state.xml', statusProcessing);
}
! //Подписываемся на состояние реле/выключателя
on('javascript.0.laurent.relay1', relaySwitch);
on('javascript.0.laurent.relay2', relaySwitch);
on('javascript.0.laurent.relay3', relaySwitch);
on('javascript.0.laurent.relay4', relaySwitch);
! //Задаем выполенение функции через определенный интервал
var timerID = setInterval(mainPoll, Period);В целом он работает нормально, за одним исключением. Я думаю там понятно, но на всякий случай объясню поподробнее. Актуальна работа реле. В Лоране их 4. В интерфейсе создаются выключатели (объекты), там их 4. Например первый выключатель, для реле 1 вот этот: createState('laurent.relay1','',{type:'boolean',role:'switch',read:true,write:true}); Там есть функция, которая периодически вызывается, эта функция опрашивает Лоран, получает xml c состояниями, в том числе и реле: function mainPoll () { request ('http://'+IP+'/state.xml', statusProcessing); } Потом есть функция, которая парсит этот файл, узнает состояние реле, и записывает его в наш объект. setState('laurent.relay1', Boolean(parseFloat(relayTable[0])), true); Далее, мы хотим управлять реле. Подписываемся на его состояние (объекта): on('javascript.0.laurent.relay1', relaySwitch); Функция проверяет, что состояние объекта было изменено, и если оно было изменено в интерфейсе (проверяет ack), то посылает http-команду Лорану. function relaySwitch (obj) { if (obj.state.ack === false && obj.state.val === true) { request ('http://'+IP+'/cmd.cgi?cmd=REL,'+obj.id.match(/[1-9]/)+',1'); } else if (obj.state.ack === false && obj.state.val === false) { request ('http://'+IP+'/cmd.cgi?cmd=REL,'+obj.id.match(/[1-9]/)+',0'); } } И это работает. Но иногда возникает конфликт. Например, реле выключено. Включаешь в интерфейсе этот выключатель, соответствующий реле. Он нормально становится включенным, команда посылается, реле щелкает. Но видимо как раз в этот момент происходит опрос, в результате которого реле еще выключено. И состояние его в интерфейсе становится выключенным. Ну, и после следующего периода опроса становится нормальным (включенным). Надеюсь, понятно объяснил. Что можно сделать в этом случае?
-
Подправил скрипт, так работает лучше.
Может кому пригодится.
Скрипт разделен на две части, одна кладется в Global. В основном это для того, чтобы можно было опрашивать несколько Лоранов, копируя скрипт (у меня 3 штуки, например).
! ````
var IP = "192.168.0.104";
var Period = 5000;
var laurentID = "000";
! //Функция в "global" для создания
createMain ();
! var request = require('request');
! //Определяем переменные снаружи функции (чтобы были видны снаружи функции)
var relayString = "0000";
var inlineString = "000000";
var outlineString = "000000000000";
! //Функция обработки ответа
function statusProcessing(error, response, body)
{
if (!error && response.statusCode == 200)
{
setState('laurent'+laurentID+'.connectIndicator', true, true);//Температура = Конвертируем строку в число (запрошенную по тегу temp в ответе Лорана).округляем (до 1 знака после запятой) var temperature = parseFloat(XMLElement ("temp", body)).toFixed(1); setState('laurent'+laurentID+'.temperature', parseFloat(temperature), true); //Время Лорана setState('laurent'+laurentID+'.systemtime', parseInt(XMLElement ("systime", body)), true);
! //Строка состояния реле
relayString = XMLElement ("rele", body);
setState('laurent'+laurentID+'.relayString', relayString);//Строка состояния входов inlineString = XMLElement ("in", body); setState('laurent'+laurentID+'.inlineString', inlineString); //Строка состояния выходов outlineString = XMLElement ("out", body); setState('laurent'+laurentID+'.outlineString', outlineString); } else { setState('laurent'+laurentID+'.connectIndicator', false, true); }
}
! //Главная периодическая функция
function mainPoll ()
{
request ('http://'+IP+'/state.xml', statusProcessing);
}
! //Подписываемся на состояние вспомогательно объекта (строки состояния) реле
on('javascript.0.laurent'+laurentID+'.relayString', updateRelaysStates);
! //Подписываемся на состояние вспомогательно объекта (строки состояния) входных линий
on('javascript.0.laurent'+laurentID+'.inlineString', updateInlinesStates);
! //Подписываемся на состояние вспомогательно объекта (строки состояния) выходных линий
on('javascript.0.laurent'+laurentID+'.outlineString', updateOutlinesStates);
! //Подписываемся на состояние реле/выключателя (для управления из визуализации)
on('javascript.0.laurent'+laurentID+'.relay1', relaySwitch);
on('javascript.0.laurent'+laurentID+'.relay2', relaySwitch);
on('javascript.0.laurent'+laurentID+'.relay3', relaySwitch);
on('javascript.0.laurent'+laurentID+'.relay4', relaySwitch);
! //Подписываемся на состояние выходной линии/выключателя (для управления из визуализации)
on('javascript.0.laurent'+laurentID+'.outline1', outlineSwitch);
on('javascript.0.laurent'+laurentID+'.outline2', outlineSwitch);
on('javascript.0.laurent'+laurentID+'.outline3', outlineSwitch);
on('javascript.0.laurent'+laurentID+'.outline4', outlineSwitch);
on('javascript.0.laurent'+laurentID+'.outline5', outlineSwitch);
on('javascript.0.laurent'+laurentID+'.outline6', outlineSwitch);
on('javascript.0.laurent'+laurentID+'.outline7', outlineSwitch);
on('javascript.0.laurent'+laurentID+'.outline8', outlineSwitch);
on('javascript.0.laurent'+laurentID+'.outline9', outlineSwitch);
on('javascript.0.laurent'+laurentID+'.outline10', outlineSwitch);
on('javascript.0.laurent'+laurentID+'.outline11', outlineSwitch);
on('javascript.0.laurent'+laurentID+'.outline12', outlineSwitch);
! //Callback-функции находятся в "global"
! //Задаем выполнение функции через определенный интервал
var timerID = setInterval(mainPoll, Period);И вот это в Global: >! ```` function updateInlinesStates () { var inlineTable = inlineString.split(""); setState('laurent'+laurentID+'.inline1', Boolean(parseFloat(inlineTable[0])), true); setState('laurent'+laurentID+'.inline2', Boolean(parseFloat(inlineTable[1])), true); setState('laurent'+laurentID+'.inline3', Boolean(parseFloat(inlineTable[2])), true); setState('laurent'+laurentID+'.inline4', Boolean(parseFloat(inlineTable[3])), true); setState('laurent'+laurentID+'.inline5', Boolean(parseFloat(inlineTable[4])), true); setState('laurent'+laurentID+'.inline6', Boolean(parseFloat(inlineTable[5])), true); } >! function updateOutlinesStates () { var outlineTable = outlineString.split(""); setState('laurent'+laurentID+'.outline1', Boolean(parseFloat(outlineTable[0])), true); setState('laurent'+laurentID+'.outline2', Boolean(parseFloat(outlineTable[1])), true); setState('laurent'+laurentID+'.outline3', Boolean(parseFloat(outlineTable[2])), true); setState('laurent'+laurentID+'.outline4', Boolean(parseFloat(outlineTable[3])), true); setState('laurent'+laurentID+'.outline5', Boolean(parseFloat(outlineTable[4])), true); setState('laurent'+laurentID+'.outline6', Boolean(parseFloat(outlineTable[5])), true); setState('laurent'+laurentID+'.outline7', Boolean(parseFloat(outlineTable[6])), true); setState('laurent'+laurentID+'.outline8', Boolean(parseFloat(outlineTable[7])), true); setState('laurent'+laurentID+'.outline9', Boolean(parseFloat(outlineTable[8])), true); setState('laurent'+laurentID+'.outline10', Boolean(parseFloat(outlineTable[9])), true); setState('laurent'+laurentID+'.outline11', Boolean(parseFloat(outlineTable[10])), true); setState('laurent'+laurentID+'.outline12', Boolean(parseFloat(outlineTable[11])), true); >! } >! //Функция для переключения реле - отослать команду function relaySwitch (obj) { var reg = "relay([1-9])"; if (obj.state.ack === false && obj.state.val === true) { request ('http://'+IP+'/cmd.cgi?cmd=REL,'+obj.id.match(reg)[1]+',1'); } else if (obj.state.ack === false && obj.state.val === false) { request ('http://'+IP+'/cmd.cgi?cmd=REL,'+obj.id.match(reg)[1]+',0'); } } >! //Функция для переключения выходной линии - отослать команду function outlineSwitch (obj) { var reg = "outline([1-9]*)"; if (obj.state.ack === false && obj.state.val === true) { request ('http://'+IP+'/cmd.cgi?cmd=OUT,'+obj.id.match(reg)[1]+',1'); } else if (obj.state.ack === false && obj.state.val === false) { request ('http://'+IP+'/cmd.cgi?cmd=OUT,'+obj.id.match(reg)[1]+',0'); } }