Добрый день, подскажите как можно использовать текущую погоду с какого нибудь сайта в проекте, визуализировать ее и использовать показание погоды для самого проекта?
vyacheslav, Simple-Scada умеет читать текстовые файлы, это дает Вам возможность извернуться как хотите.
https://ru.wikipedia.org/wiki/Обходной_приём (https://ru.wikipedia.org/wiki/Обходной_приём)
Суть идеи:
Спарсить погоду с нужного сервиса в текстовый файл (любым путем как Вам удобно).
Прочитать файл и отобразить данные в Simple-Scada.
Рабочий пример:
Все действия сводятся просто к копированию файлов в нужные места и регистрации на сайте.
Погоду будем получать с сайта https://openweathermap.org.
Он предоставляет удобный API, данные выдает в JSON.
Просто регистрируемся, получаем свой API key согласно описания https://openweathermap.org/appid.
(appid заработает через 10 минут после регистрации).
Если все ок то по ссылке http://api.openweathermap.org/data/2.5/weather?q=Moscow,RU&appid=APPID&units=metric
Вы увидите что-то типа:
{"coord":{"lon":37.62,"lat":55.75},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01n"}],"base":"stations","main":{"temp":-4.5,"pressure":1010,"humidity":53,"temp_min":-5,"temp_max":-3},"visibility":10000,"wind":{"speed":3,"deg":210},"clouds":{"all":0},"dt":1521484200,"sys":{"type":1,"id":7325,"message":0.0029,"country":"RU","sunrise":1521430374,"sunset":1521474143},"id":524901,"name":"Moscow","cod":200}
Нам нужно просто получить этот json, дальше его обработать и перенаправить нужные нам данные в текстовый файл, который и прочитаем в Simple-Scada.
Для этого нам потребуются две утилиты:
1. jq
jq is a lightweight and flexible command-line JSON processor.
https://stedolan.github.io/jq/ <-качаем отсюда
2. curl
cURL — свободная (распространяемая по лицензии MIT), кроссплатформенная служебная программа командной строки, позволяющая взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
https://ru.wikipedia.org/wiki/CURL
https://curl.haxx.se/download.html <-качаем отсюда
Утилиты копируем куда Вам нравится, я для них в каталоге с проектом создал папку bin
Создаем там же weather.bat с таким содержимым:
echo off
cls
set dirPath=%~dp0
"%dirPath%curl.exe" "http://api.openweathermap.org/data/2.5/weather?q=Moscow,RU&appid=ВАШ_APIKEY&units=metric" | "%dirPath%jq.exe" ".main.temp" > "%dirPath%weather.txt"
BAT файл можно запускать или средствами СКАДЫ или сделать в планировщике задачу.
Я буду запускать средствами Simple-Scada.
1. Добавляю переменную типа DateTime и называю ее WeatherTimer.
2. Создаю скрипт типа Изменились переменные и добавляю в список переменных WeatherTimer.
Код скрипта:
var
aPath:String;
begin
if WeatherTimer.AsDateTime < StrToTime('00:00:01') then begin
if FileExists('weather.txt', GetProjectPath + 'bin\') then begin
TextFileOpen('weather.txt', GetProjectPath + 'bin\', fomReset, fcpUTF8);
txtWeather.Text:=TextFileReadLn+'°C';
TextFileClose;
end;
end;
if WeatherTimer.AsDateTime > StrToTime('00:00:10') then begin
aPath := '"' + GetProjectPath + 'bin\weather.bat"';
RunApplication(GetClientName, aPath,'');
TimerStart(WeatherTimer,0); //Сбрасываем таймер
end;
end.
Верно, дело в скобках.
с openweathermap.org - возвращает {} пары имя: значение. парсинг из текста выше работает.
с accuweather.com - возвращает [] массив данных
Как разобрать верно ответ с массивом средствами SCADA ?
мануал по JSON https://www.w3bai.com/ru/json/json_syntax.html
Работает, вопрос закрыт. Ниже код на выбор с двух серверов, vrWeather_Temperature для архивирования
begin
// если это результат выполнения запроса с тегом 666
if Response.Tag = 666 then
begin
// https://accuweather.com
txtLocalTime.Text := Response.Nodes[0]['LocalObservationDateTime'].AsStr;
vrWeather_Temperature.Value := Response.Nodes[0]['Temperature']['Metric']['Value'].AsFloat;
txtTemperature.Text := UTF8ToString(FloatToStr(vrWeather_Temperature.Value,1)) + ' °С';
{
// https://home.openweathermap.org
txtLocalTime.Text := TimeToStr(Now);
vrWeather_Temperature.Value := Response['main']['temp'].AsFloat;
txtTemperature.Text := UTF8ToString(FloatToStr(vrWeather_Temperature.Value,1)) + ' °С';
}
end;
end.
Обратите внимание, ответ от сервера пришёл внутри квадратных скобок [], которые указывают на то, что это массив данных, а внутри квадратных скобок элементы массива (в Вашем случае элементами массива являются объекты и массив состоит из одного элемента). При обращении к элементам массива нужно указывать индекс элемента. А при обращении к ключам объекта нужно указывать имя ключа. Поэтому код должен выглядеть следующим образом:
xtTemperature.Text:= Response.Nodes[0]['Temperature']['Metric']['Value'].AsStr + ' °С';
Описание разбора JSON с примерами есть в руководстве по этой ссылке (https://simple-scada.com/help/script/requesthttp.html?anchor=postget7). Там же описан пример прохода по элементам массива в цикле (на случай, если массив приходит от сервера с разным количеством элементов).
Здравствуйте.
В данном случае все работает в соответствии с кодом скрипта. Вы в коде скрипта сначала обращаетесь к полям ответа Response[], не проверяя был ли ответ. Если его не было (например, связь с HTTP-сервером была разорвана), то скрипт попытается обратиться к несуществующим полям ответа. Поэтому сначала проверьте код ответа "if Response.Code = 200 then", а затем уже извлекайте данные из ответа.
Также, если Вы считаете, что HTTP-сервер на один и тот же запрос может вернуть ответ с разным набором полей (что неправильно со стороны HTTP-сервера), то в скриптах можно проверить существование любых полей в ответе, прежде чем обращаться к ним. Например:
var
aValue: string;
aNode: TM_JSONNode;
begin
aNode := Response['current']; // получаем поле "current" из ответа HTTP-сервера
if aNode <> nil then // если такое поле действительно существует
aValue := aNode.AsStr; // то читаем из него значение
end.
пару раз приводило к полному отказу скрипта, приходилось перезагружать сервис SCADA.
Данная ошибка на 100% не может никак повлиять на работу сервера скады. Отказ скрипта явно был вызван чем-то другим.
да, скорее всего так и придется переделать. спасибо.
Уточнение - aNode при каждом вызове изменяет (обновляет) состояние в этом примере ?
То есть такой вариант возможен ?
begin
aNode := Response['X1'];
if aNode <> nil then aValue1 := aNode.AsStr;
aNode := Response['X2'];
if aNode <> nil then aValue2 := aNode.AsStr;
aNode := Response['X3'];
if aNode <> nil then aValue3 := aNode.AsStr;
end.