Простая Scada на Python — АСУ ТП: сообщество инженеров

Простая Scada на Python

Коротко о статье

Описан опыт создания самодельной SCADA-программы ScadaPy на Python для контроля дизель-генератора. Показано, как через Modbus TCP получать данные с контроллера и отображать их на мнемосхеме в Tkinter.

Главное
  • Для контроля дизель-генератора требовалось фиксировать по часам уровень топлива, давление масла, температуру, заряд батарей, токи, напряжения и наработку.
  • Контроллер генератора поддерживает Modbus RTU, что позволило подключиться по RS-485 через витую пару.
  • В Python применяется библиотека modbus_tk: создаётся TcpMaster с указанием IP и порта, задаётся таймаут 1.0.
  • Чтение данных выполняется методом execute с константами READ_DISCRETE_INPUTS, READ_COILS, READ_INPUT_REGISTERS, READ_HOLDING_REGISTERS.
  • Окно программы строится на Tkinter: создаётся Canvas, размещается фон, элементы меняют цвет в зависимости от состояния регистров.
  • Опрос устройства организован процедурой jobModbusTCP с вызовом root.after(1000, jobModbusTCP), то есть раз в секунду.
Термины и технологии
  • SCADA
  • ScadaPy
  • Modbus RTU
  • Modbus TCP
  • RS-485
  • modbus_tk
  • Tkinter
  • TcpMaster

Кому полезно: Инженерам АСУ ТП, знакомым с Python и желающим сделать простую SCADA

По теме на сайте

Выжимка составлена редакцией сайта с помощью ИИ по тексту статьи.

Ниже приведу пример собственной реализации простой SCADA программы выполненной, как обычно говорят, «на коленке».

Поставлена задача по осуществлению контроля за дизель генератором. Необходимо вести журнал с указанием почасовых параметров, таких как: уровень топлива, давление масла, температура, заряд батарей, токи, напряжения, наработка часов.

Генератор находился на расстоянии пол километра от офиса и со временем эти хождения начали напрягать, особенно в плохую погоду.

Как выяснилось на генераторе установлен контроллер, который поддерживает протокол обмена Modbus RTU, это значит, что можно проложить кабель витую пару и подключиться по RS-485.
После изучения адресной таблицы, решили сами сделать простенькую программу.
В результате получилась ScadaPy.

Modbus TCP

Интерфейс обмена. Сперва подключаем modbus библиотеку.

import modbus_tk
import modbus_tk.defines as cst
import modbus_tk.modbus_tcp as modbus_tcp

Создаем ссылку на объект куда подключаемся и указываем:

host=«IP адрес устройства, с которым устанавливаем связь»
port=«порт устройства, к которому подключаемся»

master = modbus_tcp.TcpMaster(host=slaveIP, port=int(slavePort))
master.set_timeout(1.0)

Теперь пробуем получить данные от устройства, в данном случае начиная с адреса регистра 0, получаем 10 регистров дискретных сигналов (ТС).

getDI=master.execute(1, cst.READ_DISCRETE_INPUTS, 0, 10)

Для других видов регистров необходимо указать другие наименования.

master.execute(1,сst.READ_COILS, 0, 10) 
master.execute(1,cst.READ_INPUT_REGISTERS, 100, 3) 
master.execute(1,cst.READ_HOLDING_REGISTERS, 100, 12)

Теперь если сделать:

print getDi

Мы получим массив данных от устройства с адреса 0 по адрес 9.

(0,1,0,1,0,0,0,0,0)

Если что-то подобное появится, то значит устройство на связи. Получение данных от других видов регистров происходит аналогично.

Формирование окна программы

Подключаем библиотеку.

from Tkinter import *

Создаем ссылку на объект (окно).

root = Tk()

Устанавливаем картинку фона окна.

im = PhotoImage(file=backGroundPath) 

Создаем объект canvas.

canv = Canvas(root,width=1900,height=950,bg="black",bd=0, highlightthickness=0, relief='ridge')

Помещаем в окне.

canv.place(x=0, y=25)

Выводим фон.

canv.create_image(1, 1,anchor=NW, image=im)

Запускаем цикл.

root.mainloop()

Функция опроса

Для того, чтобы осуществлять постоянный опрос устройств по протоколу modbusTCP в tkinter существуют методы after и mainloop, но сначала необходимо создать процедуру jobModbusTCP.

def jobModbusTCP():
    getDI=master.execute(1, cst.READ_DISCRETE_INPUTS, 0, 10)
    if(int(getDI[0]) == 1): 
        canv.itemconfig(diFig1,fill='red') 
    if(int(getDI[0]) == 0): 
        canv.itemconfig(diFig1,fill='green') 
    if(int(getDI[1]) == 1): 
        canv.itemconfig(diFig2,fill='red') 
    if(int(getDI[1]) == 0): 
        canv.itemconfig(diFig2,fill='green') 
    root.after(1000, jobModbusTCP) 

Код программы
Ниже приведен код программы, который отображает состояние регистров [0] и [1], если логическое состояние регистра равно 0 квадрат на canvas будет зеленого цвета, если логическое состояние равно 1 — красного.

from Tkinter import * 
import modbus_tk
import modbus_tk.defines as cst
import modbus_tk.modbus_tcp as modbus_tcp
import math 
def jobModbusTCP():
    getDI=master.execute(1, cst.READ_DISCRETE_INPUTS, 0, 10)

    if(int(getDI[0]) == 1): 
        canv.itemconfig(diFig1,fill='red') 
    if(int(getDI[0]) == 0): 
        canv.itemconfig(diFig1,fill='green') 
    if(int(getDI[1]) == 1): 
        canv.itemconfig(diFig2,fill='red') 
    if(int(getDI[1]) == 0): 
        canv.itemconfig(diFig2,fill='green') 
    root.after(1000, jobModbusTCP)

master = modbus_tcp.TcpMaster(host='192.168.0.1', port=502)
master.set_timeout(1.0)

root = Tk() 
im = PhotoImage(file='bg.gif') 
canv = Canvas(root,width=1900,height=950,bg="black",bd=0, highlightthickness=0, relief='ridge')
canv.place(x=0, y=25) 
canv.create_image(1, 1,anchor=NW, image=im) 
diFig1=canv.create_rectangle(10,10,30,30,fill='gray', outline='black')
diFig2=canv.create_oval(50,50,80,80,fill='gray', outline='black')
root.after(1, jobModbusTCP)
root.mainloop()

Теперь один раз в секунду программа будет отсылать запрос в устройство и отображать ответ на мнемосхеме.

Источник: https://habr.com/ru/post/339008/

🔗 Простая Scada на Python

Оставьте комментарий

Войти

Зарегистрироваться

Сбросить пароль

Пожалуйста, введите ваше имя пользователя или эл. адрес, вы получите письмо со ссылкой для сброса пароля.

Прокрутить вверх