1
Ваши вопросы / Re: Вопросы по скриптам в Simple-Scada 2
« : 04 Октября 2021, 08:16:31 »
Понял, спасибо!
Официальный форум Simple-Scada.
В этом разделе можно просмотреть все сообщения, сделанные этим пользователем.
Поскольку процесс получения состояния службы периодический и не связан с действиями оператора (как в примере), то анализ файла можно смело перенести до 55 такта (секунды).Так и сделаю пожалуй.
Вывод названия параметра на разных языках ("Состояние" <-> "STATE") это, предположительно, отголосок локализации ОС. Я бы проверял строку на наличие подстрок ": 4 RUNNING" и ": 1 STOPPED".Проект работает на конкретном компьютере, универсальность не требуется, поэтому усложнять лишний раз не хочется.
И ещё одна особенность автомата при запуске проекта, с вероятностью 1/30 в течение первой минуты будет выдано сообщение "Ошибка получения статуса службы опроса модемов".Совсем не критично, перезапуски - редкое явление. Но раз есть возможность улучшить - почему бы и нет.
Для устранения этого можно использовать условие (начальное значение переменной - 0)
Файл результата открывается как перезаписываемый - т.е. новый замещает старый. Узнать что файл обновился можно по изменению даты записи файла, она должна быть больше чем дата начала выполнения скрипта.
var
aPath: String;
i: integer;
tempString: String;
const
servName:string = 'iRZ_Collector_Server';
begin
if SecondOf(Now) = 0 then begin //проверяем статус службы и создаем файл с информацией 1 раз в минуту
aPath := GetProjectPath + 'User Files\';
StartTime.Value := NOW; // начало ожидания
// чтение состояния службы через VB скрипт для подавления вывода окна командной строки
TextFileOpen('Service.vbs', aPath, fomRewrite, fcpUTF8);
TextFileWriteLn('Set WshShell = CreateObject("WScript.Shell")');
TextFileWriteLn('WshShell.Run "cmd /A /C sc query ' + servName + '> ""' // выполнить команду чтения состояния службы
+ 'D:\Service.txt""", 0'); // и записать результат в файл
TextFileWriteLn('Set WshShell = Nothing');
TextFileClose;
RunApplication(SS_SERVER_NAME, aPath + 'Service.vbs', ''); // выполнить VBS-файл
end;
/////////////////////////////////////////////////
if SecondOf(Now) = 2 then begin //считываем файл для анализа через 2 секунды после создания
if (FileExists('Service.txt', 'D:\')) and (SecondsBetween(FileAge('D:\Service.txt'), StartTime.AsDateTime) < 10) then begin // условия корректности файла
TextFileOpen('Service.txt', 'D:\', fomReset, fcpCyrillic_windows866); //открываем файл
tempString := UTF8Encode(TextFileReadLn); //переходим к требуемой строчке в файле
tempString := UTF8Encode(TextFileReadLn);
tempString := UTF8Encode(TextFileReadLn);
tempString := UTF8Encode(TextFileReadLn);
if tempString = ' Состояние : 4 RUNNING ' then
begin txtService.Text := 'Служба опроса модемов работает';
txtService.BorderColor := clLime;
end
else if tempString = ' STATE : 1 STOPPED ' then
begin txtService.Text := 'Служба опроса модемов остановлена';
txtService.BorderColor := clRed;
end
else
begin txtService.Text := 'Ошибка получения статуса службы опроса модемов'; //в нужной строчке не те данные, которых мы ожидали
txtService.BorderColor := clYellow;
end;
TextFileClose; // закрыть файл
end
else begin txtService.Text := 'Ошибка получения статуса службы опроса модемов'; //файл не существует либо слишком старый
txtService.BorderColor := clYellow;
end;
end; // if SecondOf(Now) = 2
end.
Пример из вложения после ввода имени службы получает её состояние.Спасибо! Была проблема, из-за русского имени пользователя в винде не создавался текстовый файл. Но с переездом в "D:\" все заработало.
uses
WinSvc;
function ServiceGetStatus(sMachine, sService: PChar): DWORD;
{******************************************}
{*** Parameters: ***}
{*** sService: specifies the name of the service to open
{*** sMachine: specifies the name of the target computer
{*** ***}
{*** Return Values: ***}
{*** -1 = Error opening service ***}
{*** 1 = SERVICE_STOPPED ***}
{*** 2 = SERVICE_START_PENDING ***}
{*** 3 = SERVICE_STOP_PENDING ***}
{*** 4 = SERVICE_RUNNING ***}
{*** 5 = SERVICE_CONTINUE_PENDING ***}
{*** 6 = SERVICE_PAUSE_PENDING ***}
{*** 7 = SERVICE_PAUSED ***}
{******************************************}
var
SCManHandle, SvcHandle: SC_Handle;
SS: TServiceStatus;
dwStat: DWORD;
begin
dwStat := 0;
// Open service manager handle.
SCManHandle := OpenSCManager(sMachine, nil, SC_MANAGER_CONNECT);
if (SCManHandle > 0) then
begin
SvcHandle := OpenService(SCManHandle, sService, SERVICE_QUERY_STATUS);
// if Service installed
if (SvcHandle > 0) then
begin
// SS structure holds the service status (TServiceStatus);
if (QueryServiceStatus(SvcHandle, SS)) then
dwStat := ss.dwCurrentState;
CloseServiceHandle(SvcHandle);
end;
CloseServiceHandle(SCManHandle);
end;
Result := dwStat;
end;
function ServiceRunning(sMachine, sService: PChar): Boolean;
begin
Result := SERVICE_RUNNING = ServiceGetStatus(sMachine, sService);
end;
if ServiceRunning(nil, 'Имя службы') then
begin
{Действия если служба запущена}
end else
begin
{Действия если служба не запущена}
end;
Здравствуйте.Но при перезапуске проекта они тут же все будут выданы. Тут ключевое "IsFirstChange() = false", не понимаю, почему этого нет в стандартном функционале сообщений, как и задержек на срабатывание.
Сообщения можно добавлять/редактировать без использования скриптов, через меню сообщений. Для создания множества однотипных сообщений можно использовать шаблонные сообщения.
При сравнении значения переменной лучше использовать явное приведение значения переменной к нужному типу. Например, при сравнении с True/False нужно брать значение переменной переведенное в тип Boolean(свойство AsBool)Учту, спасибо.
Для получения доступа к переменной, изменение которой привело к выполнению скрипта "изменились переменные" можно использовать параметр Variable.Спасибо!Код: (delphi)if (Variable.AsBool = false) and (IsFirstChange = false) then
AddMessageToGroup(Now, mkAlarm, 4, 'Котельная 24 - нет сети 220В!', true, true);
if (B24_220.Value = false) and (IsFirstChange() = false) then
AddMessageToGroup(Now, mkAlarm, 4, 'Котельная 24 - нет сети 220В!', true, true);
if (var0.Value = false) and (IsFirstChange() = false) then
AddMessageToGroup(Now, mkAlarm, 4, 'Котельная 24 - нет сети 220В!', true, true);
Здравствуйте.Нет, вопрос конкретно о сообщениях, которые строятся на основе дискретных переменных.
Возможно Вы создаете сообщения по нарушению границ переменной? Если это так, то у переменой можно задать границы, в опции "Сообщения о нарушении границ" выбрать к примеру "Для любых границ", тогда при нарушении границ переменной будут выдаваться автоматически генерируемые сообщения о нарушении граничных значений. Там же имеется возможность задать параметр "Зона нечувствительности" используемый для выдачи сообщений о нарушении границ переменной. Параметр предназначен для того, чтобы после выхода значения переменной из состояния аварии/предупреждения она не могла вернуться в него вследствие случайных колебаний значения переменной. В настройках проекта имеется возможность задать свой текст для автоматически генерируемых сообщений о нарушении границ. Также, при необходимости можно управлять границами переменных из клиента скады.