Скрипт для Лоран

Вопросы и информация о скриптах для ioBroker
Antworten
Vital
starter
Beiträge: 10
Registriert: 16.09.2017, 16:22

Скрипт для Лоран

Beitrag von Vital » 11.10.2017, 14:26

Добрый день!

Прошу совета по скрипту.

Я написал скрипт для Лорана (http://www.kernelchip.ru/Laurent-2.php)
Spoiler: Show hidden text

Code: Alles auswählen

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+">(.*)</"+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');
}
}

И это работает.
Но иногда возникает конфликт.
Например, реле выключено.
Включаешь в интерфейсе этот выключатель, соответствующий реле. Он нормально становится включенным, команда посылается, реле щелкает. Но видимо как раз в этот момент происходит опрос, в результате которого реле еще выключено. И состояние его в интерфейсе становится выключенным. Ну, и после следующего периода опроса становится нормальным (включенным).

Надеюсь, понятно объяснил.

Что можно сделать в этом случае?

Vital
starter
Beiträge: 10
Registriert: 16.09.2017, 16:22

Re: Скрипт для Лоран

Beitrag von Vital » 23.10.2017, 18:03

Подправил скрипт, так работает лучше.
Может кому пригодится.

Скрипт разделен на две части, одна кладется в Global. В основном это для того, чтобы можно было опрашивать несколько Лоранов, копируя скрипт (у меня 3 штуки, например).
Spoiler: Show hidden text

Code: Alles auswählen

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:
Spoiler: Show hidden text

Code: Alles auswählen

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');
    }
}

Antworten