Как стать автором
Обновить

Как просто подключить любой датчик OPC сервера к проекту narodmon.ru

Время на прочтение 4 мин
Количество просмотров 27K
Здравствуйте.

Совсем недавно я узнал что существует один простой, но полезный проект «Народный мониторинг» Смысл его в том, если вкратце, чтобы объединить множество разрозненных датчиков мониторинга окружающей среды в одном месте. Ведь одно дело например посмотреть прогноз погоды в интернете и совсем другое дело увидеть реально где какие температура, влажность, давление и их изменение с течением времени.

Или например если банально лень встать и посмотреть на градусник за окном)



Проект этот позволяет «складировать», отображать и смотреть историю изменения данных. В общем все что для счастья надо — там есть. Можно датчики делать публичными или приватными.

Для желающих приобщится существуют готовые устройства и как их заполучить можно узнать на сайте. Вот ссылка на пост с которого все начиналось и пример устройства там же.

Кроме этого существует множество датчиков в составе SCADA систем и многие из них могут отражать параметры окружающей среды в самых различных географических точках. Вот об этом я и хочу рассказать — как любой датчик OPC сервера любой SCADA системы прикрутить к вышеописанному сервису.

Итак нам понадобится:

1. Python 2.7
2. Open OPC for Python
3. Python for Windows extensions

Все это устанавливается на машину туда же где крутится OPC сервер, или удаленно. Я устанавливал локально.

Далее просто запускаем мой скрипт поражающий своей сложностью:

import OpenOPC
import time
import socket

while True:
	try:
		opc = OpenOPC.client()
		opc.connect("OWEN.RS485")
		s = socket.socket( socket.AF_INET, socket.SOCK_DGRAM ) # UDP
		addr = ('narodmon.ru',1234) #реальный ip:port смотрите в разделе "для разработчиков" 
		val = opc['Com1/TRM138(8bit adr=24)/ChannelData3/rEAd']
		buf = "#123456789ABCDE\n#123456789ABCDE10#" +"%.1f#"%val + "\n##"
		s.sendto(buf,addr)
		opc.close()
		s.close()
    
	except :
		pass

	time.sleep(180)


Как видно я подключаюсь к ОРС серверу «OWEN.RS485» и считываю значение «итема» 'Com1/TRM138(8bit adr=24)/ChannelData3/rEAd'. Таким образом можно читать значение любого «итема» ОРС сервера.

Кстати если изучить документацию к OpenOPC то вы там найдете много полезных функций которых вполне достаточно для создания например небольшой визуализации.

Пакет для отправки формируется из уникального ID устройства 123456789ABCDE (можно придумать и свой, но лучше использовать серийный номер датчика или модуля ввода) и уникального ID датчика. Последний я получил добавив к ID устройства 0x10, что означает что это температурный датчик. Подробнее можно почитать на сайте проекта в разделе для разработчиков.

Само подключение к сервису происходит очень просто. Нужно зарегистрироваться на сайте и начинать отсылать пакеты. Когда система получит несколько пакетов можно будет создать новое устройство и добавить в него датчик. Для отладки есть мониторинг пакетов с вашего IP в разделе для разработчиков. Со всеми вопросами, благодарностями и предложениями по поводу сервиса можете обращаться к создателю сервиса SSar

Для тех кто не ищет легких путей добавлю листинг службы windows которая делает тоже самое:

# -*- coding: utf-8 -*-

import win32serviceutil
import win32service
import win32event
import servicemanager
import OpenOPC
import socket
 
class AppServerSvc (win32serviceutil.ServiceFramework):
    _svc_name_ = "ServiceForNarodmon"
    _svc_display_name_ = "ServiceForNarodmon"
    _svc_description_ = "Service For Narodmon.ru"
 
    def __init__(self,args):
        win32serviceutil.ServiceFramework.__init__(self,args)
        self.hWaitStop = win32event.CreateEvent(None,0,0,None)
        self.hWaitResume = win32event.CreateEvent(None, 0, 0, None)
        self.timeout = 60000 #Пауза между выполнением основного цикла службы в миллисекундах
        self.resumeTimeout = 1000
        self._paused = False
 
    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)
        #servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                              #servicemanager.PYS_SERVICE_STOPPED,
                              #(self._svc_name_, ''))
       
    def SvcPause(self):
        self.ReportServiceStatus(win32service.SERVICE_PAUSE_PENDING)
        self._paused = True
        self.ReportServiceStatus(win32service.SERVICE_PAUSED)
        #servicemanager.LogInfoMsg("The %s service has paused." % (self._svc_name_, ))
   
    def SvcContinue(self):
        self.ReportServiceStatus(win32service.SERVICE_CONTINUE_PENDING)
        win32event.SetEvent(self.hWaitResume)
        self.ReportServiceStatus(win32service.SERVICE_RUNNING)
        #servicemanager.LogInfoMsg("The %s service has resumed." % (self._svc_name_, ))
               
 
    def SvcDoRun(self):
        #servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
        #                      servicemanager.PYS_SERVICE_STARTED,
        #                      (self._svc_name_,""))
        self.main()  
   
    #В этом методе реализовываем нашу службу    
    def main(self):
        #Здесь выполняем необходимые действия при старте службы
        #servicemanager.LogInfoMsg("Hello! Im a Narodmon.ru Service.")
        
        while 1:
		
            #Здесь должен находиться основной код сервиса
            #servicemanager.LogInfoMsg("I'm still here.")
                
            try:
				opc = OpenOPC.client()
				opc.connect("OWEN.RS485")
				s = socket.socket( socket.AF_INET, socket.SOCK_DGRAM ) # UDP
				addr = ('narodmon.ru',1234) #реальный ip:port смотрите в разделе "для разработчиков" 
				val = opc['Com1/TRM138(8bit adr=24)/ChannelData3/rEAd']
				buf = "#123456789ABCDE\n#123456789ABCDE10#" +"%.1f#"%val + "\n##"
				s.sendto(buf,addr)
				opc.close()
				s.close()
    
            except :
				pass
            
            
            #Проверяем не поступила ли команда завершения работы службы
            rc = win32event.WaitForSingleObject(self.hWaitStop, self.timeout)
            if rc == win32event.WAIT_OBJECT_0:
                #Здесь выполняем необходимые действия при остановке службы
                #servicemanager.LogInfoMsg("Bye!")
                break
 
            #Здесь выполняем необходимые действия при приостановке службы
            if self._paused:
				pass
                #servicemanager.LogInfoMsg("I'm paused... Keep waiting...")
            #Приостановка работы службы                
            while self._paused:
                #Проверям не поступила ли команда возобновления работы службы
                rc = win32event.WaitForSingleObject(self.hWaitResume, self.resumeTimeout)
                if rc == win32event.WAIT_OBJECT_0:
                    self._paused = False
                    #Здесь выполняем необходимые действия при возобновлении работы службы
                    #servicemanager.LogInfoMsg("Yeah! Let's continue!")
                    break                  
 
if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(AppServerSvc)
 


Все попытки писать сообщения в системный журнал закомментированны потому что в WinXP они не работают. Разбираться дальше не стал потому что на Win7 все нормально. Можете «запилить» себе свою службу с «блэкджеком и женщинами легкого провидения».

Удачи!
Теги:
Хабы:
+8
Комментарии 5
Комментарии Комментарии 5

Публикации

Истории

Работа

Data Scientist
66 вакансий
Python разработчик
136 вакансий

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн
PG Bootcamp 2024
Дата 16 апреля
Время 09:30 – 21:00
Место
Минск Онлайн
EvaConf 2024
Дата 16 апреля
Время 11:00 – 16:00
Место
Москва Онлайн