알쓸전컴(알아두면 쓸모있는 전자 컴퓨터)
HOST secs gem 샘플 코드 본문
HOST secs gem 샘플 코드
소스 코드 실행은 329번째 줄 commLogFileHandler = CommunicationLogFileHandler("C:/", "h")
에서 보시는게 가독성에 더 좋을듯 합니다.
import secsgem import code import logging #로그 남기는 코드 #http://idlecomputer.tistory.com/17 (참고) from communication_log_file_handler import CommunicationLogFileHandler import secsgem.secs.functions #커스텀 하게 사용할 변수 클래스 등록 #class 변수이름(부모) # __type__ = secsgem.SecsVarDynamic # __allowedtypes__ = [허용하는 자료 구조] # [허용 되는 자료 구조] = http://secsgem.readthedocs.io/en/latest/reference/secs/variables.html 와 http://idlecomputer.tistory.com/19 에서 참조 class RPM_1(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarString] class RPM_1_SVID(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarU4] class RPM_2(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarString] class RPM_2_SVID(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarU4] class RPM_3(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarString] class RPM_3_SVID(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarU4] class VACUUM_1(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarString] class VACUUM_1_SVID(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarU4] class VACUUM_2(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarString] class VACUUM_2_SVID(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarU4] class VACUUM_3(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarString] class VACUUM_3_SVID(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarU4] class EXHAUST_1(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarString] class EXHAUST_1_SVID(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarU4] class EXHAUST_2(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarString] class EXHAUST_2_SVID(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarU4] class EXHAUST_3(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarString] class EXHAUST_3_SVID(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarU4] class TRID(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarU4,secsgem.SecsVarI2] class SMPLN(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarU4,secsgem.SecsVarI2] class DSPER(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarString] class TOTSMP(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarU4] class REPGSZ(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarU4] class s2_23list1(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarList] class STIME(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarString] class s06f01_list(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarList] class SecsS01F02_(secsgem.SecsStreamFunction): """on line data :param value: parameters for this function (see example) :type value: list """ _stream = 1 _function = 2 _dataFormat = [ secsgem.MDLN, secsgem.SOFTREV ] _toHost = True _toEquipment = True _hasReply = False _isReplyRequired = False _isMultiBlock = False class SecsS02F23_(secsgem.SecsStreamFunction): _stream = 2 _function = 23 _dataFormat = [TRID, DSPER, TOTSMP, REPGSZ, s2_23list1 ] _toHost = False _toEquipment = True _hasReply = False _isReplyRequired = False _isMultiBlock = False class SecsS06F01_(secsgem.SecsStreamFunction): """abort transaction stream 6 :param value: function has no parameters :type value: None """ _stream = 6 _function = 1 _dataFormat = [ TRID, SMPLN, STIME, [RPM_1,RPM_2] ] _toHost = True _toEquipment = True _hasReply = True _isReplyRequired = True _isMultiBlock = False class SecsS06F02_(secsgem.SecsStreamFunction): """event report - acknowledge :param value: parameters for this function (see example) :type value: byte """ _stream = 6 _function = 2 _dataFormat = secsgem.ACKC6 _toHost = False _toEquipment = True _hasReply = False _isReplyRequired = False _isMultiBlock = False class SampleHost(secsgem.GemHostHandler): def __init__(self, address, port, active, session_id, name, custom_connection_handler=None): secsgem.GemHostHandler.__init__(self, address, port, active, session_id, name, custom_connection_handler) self.MDLN = "gemhost" self.SOFTREV = "1.0.0" #핸들러에 한 항목들을 등록해 줍니다. #코드를 보시면 직관적으로 알겠지만 # secsStreamsFunctions[시나리오 번호].update({ # 펑션번호:클래스 self.secsStreamsFunctions[1].update({ #secsgem.secs.functions.SecsS01F01은 일반 적인 표준코드 1:secsgem.secs.functions.SecsS01F01, #SecsS01F02_는 위에서 클래스로 따라 만든 커스텀 펑션 2:SecsS01F02_, }) self.secsStreamsFunctions[2].update({ # SecsS02F23_는 위에서 클래스로 따라 만든 커스텀 펑션 23:SecsS02F23_ }) self.secsStreamsFunctions[6].update({ 1:SecsS06F01_, 2:SecsS06F02_, 11: secsgem.secs.functions.SecsS06F11, }) # 패킷을 받을때 def _on_hsms_packet_received(self, packet): """Packet received from hsms layer :param packet: received data packet :type packet: :class:`secsgem.HsmsPacket` """ print(packet.header) super(SampleHost, self)._on_hsms_packet_received(packet=packet) #_on_s시나리오f펑션 #으로 함수를 등록해 주면 콜백 함수로 패킷을 받았을때 해당 함수가 실행됩니다. def _on_s06f01(self, handler, packet): """Callback handler for Stream 6, Function 11, Establish Communication Request :param handler: handler the message was received on :type handler: :class:`secsgem.hsms.handler.HsmsHandler` :param packet: complete message received :type packet: :class:`secsgem.hsms.packets.HsmsPacket` """ #del handler # unused parameters print(packet) print(packet.header) print(packet.data) message = self.secs_decode(packet) #type: secsgem.secs.functions.SecsS06F01 #리턴시에는 self.secsStreamsFunctions[6].update 에서 등록한 클래스가 호출되며 (인자) #인자로는 _dataFormat 에 등록한 순서 대로 인자를 입력 하면 됩니다. #시나리오펑션 클래스로 만든 클래스를 반환 시키면서 통신으로 해당 시나리오펑션 으로통신 이 됩니다. return SecsS06F02_(0) def _on_s06f11(self, handler, packet): """Callback handler for Stream 6, Function 11, Establish Communication Request :param handler: handler the message was received on :type handler: :class:`secsgem.hsms.handler.HsmsHandler` :param packet: complete message received :type packet: :class:`secsgem.hsms.packets.HsmsPacket` """ del handler # unused parameters print(packet.header) print(packet.data) message = self.secs_decode(packet) print(message.data["CEID"].value.value[0]) return self.stream_function(6, 12)(0) def _on_s06f05(self, handler, packet): """Callback handler for Stream 6, Function 11, Establish Communication Request :param handler: handler the message was received on :type handler: :class:`secsgem.hsms.handler.HsmsHandler` :param packet: complete message received :type packet: :class:`secsgem.hsms.packets.HsmsPacket` """ del handler # unused parameters print(packet.header) print(packet.data) message = self.secs_decode(packet) #type: secsgem.secs.functions.SecsS06F05 return self.stream_function(6, 6)(0) def _on_s01f01(self,handler, packet): """Callback handler for Stream 1, Function 01, Establish Communication Request :param handler: handler the message was received on :type handler: :class:`secsgem.hsms.handler.HsmsHandler` :param packet: complete message received :type packet: :class:`secsgem.hsms.packets.HsmsPacket` """ del handler # unused parameters print(packet.header) print(packet.data) message = self.secs_decode(packet) #type: secsgem.secs.functions.SecsS06F01 return self.stream_function(1, 2)({"MDLN":"","SOFTREV":""}) def _on_s01f02(self,handler, packet): """Callback handler for Stream 1, Function 01, Establish Communication Request :param handler: handler the message was received on :type handler: :class:`secsgem.hsms.handler.HsmsHandler` :param packet: complete message received :type packet: :class:`secsgem.hsms.packets.HsmsPacket` """ del handler # unused parameters print(packet.header) print(packet.data) message = self.secs_decode(packet) #type: secsgem.secs.functions.SecsS01F02 return; #접속이 체결될 경우 콜백 함수입니다. def on_connection_established(self, _): """Connection was established""" self.connected = True # update connection state self.connectionState.connect() self.events.fire("hsms_connected", {'connection': self}) v = secsgem.SecsVarList([RPM_1_SVID, RPM_2_SVID, RPM_3_SVID, VACUUM_1_SVID, VACUUM_2_SVID, VACUUM_3_SVID, EXHAUST_1_SVID,EXHAUST_2_SVID, EXHAUST_3_SVID]) v.RPM_1_SVID = 1111001 v.RPM_2_SVID = 1111002 v.RPM_3_SVID = 1111003 v.VACUUM_1_SVID = 1111004 v.VACUUM_2_SVID = 1111005 v.VACUUM_3_SVID = 1111006 v.EXHAUST_1_SVID = 1111007 v.EXHAUST_2_SVID = 1111008 v.EXHAUST_3_SVID = 1111009 #Trace Initialize Send h.send_stream_function(SecsS02F23_([10000,"4",10000,1,v])) commLogFileHandler = CommunicationLogFileHandler("C:/", "h") commLogFileHandler.setFormatter(logging.Formatter("%(asctime)s: %(message)s")) logging.getLogger("hsms_communication").addHandler(commLogFileHandler) logging.getLogger("hsms_communication").propagate = False logging.basicConfig(format='%(asctime)s %(name)s.%(funcName)s: %(message)s', level=logging.DEBUG) h = SampleHost("10.23.10.98", 5000, True, 1, "samplehost") h.enable() code.interact("host object is available as variable 'h'", local=locals()) h.disable()
class RPM_1(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarString] class RPM_1_SVID(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarU4]
class SecsS06F01_(secsgem.SecsStreamFunction): """abort transaction stream 6 :param value: function has no parameters :type value: None """ _stream = 6 _function = 1 _dataFormat = [ TRID, SMPLN, STIME, [RPM_1,RPM_2] ] _toHost = True _toEquipment = True _hasReply = True _isReplyRequired = True _isMultiBlock = False
h = SampleHost("10.23.10.98", 5000, True, 1, "samplehost")
코드로 IP,포트,ACTIVE 모드,DEICEID,로그파일 이름 을 지정하고
시나리오 평선으로 메세지를 보낼때 예를 들면 SecsS02F23_(위 소스에 정의됨) 의 클래스로 S02F23 통신을 할때는
class SecsS02F23_(secsgem.SecsStreamFunction): _stream = 2 _function = 23 _dataFormat = [TRID, DSPER, TOTSMP, REPGSZ, s2_23list1 ] _toHost = False _toEquipment = True _hasReply = False _isReplyRequired = False _isMultiBlock = False
의 _dataFormat 의 형식에 맞추어 보내어 주면 됩니다.
TRID 는
class TRID(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarU4,secsgem.SecsVarI2]
이므로 숫자를 인자로 주고
DSPER 은
class DSPER(secsgem.DataItemBase): __type__ = secsgem.SecsVarDynamic __allowedtypes__ = [secsgem.SecsVarString]
String으로 문자열을 인자로 주면 됩니다.
v = secsgem.SecsVarList([RPM_1_SVID, RPM_2_SVID, RPM_3_SVID, VACUUM_1_SVID, VACUUM_2_SVID, VACUUM_3_SVID, EXHAUST_1_SVID,EXHAUST_2_SVID, EXHAUST_3_SVID]) v.RPM_1_SVID = 1111001 v.RPM_2_SVID = 1111002 v.RPM_3_SVID = 1111003 v.VACUUM_1_SVID = 1111004 v.VACUUM_2_SVID = 1111005 v.VACUUM_3_SVID = 1111006 v.EXHAUST_1_SVID = 1111007 v.EXHAUST_2_SVID = 1111008 v.EXHAUST_3_SVID = 1111009 #Trace Initialize Send h.send_stream_function(SecsS02F23_([10000,"4",10000,1,v]))
여기서 h는 접속한 핸들러 입니다
또한 통신을 받을때에는 아래와 같이 커스텀화 할수 있습니다.
#_on_s시나리오f펑션 #으로 함수를 등록해 주면 콜백 함수로 패킷을 받았을때 해당 함수가 실행됩니다. def _on_s06f01(self, handler, packet): """Callback handler for Stream 6, Function 11, Establish Communication Request :param handler: handler the message was received on :type handler: :class:`secsgem.hsms.handler.HsmsHandler` :param packet: complete message received :type packet: :class:`secsgem.hsms.packets.HsmsPacket` """ #del handler # unused parameters print(packet) print(packet.header) print(packet.data) message = self.secs_decode(packet) #type: secsgem.secs.functions.SecsS06F01 #리턴시에는 self.secsStreamsFunctions[6].update 에서 등록한 클래스가 호출되며 (인자) #인자로는 _dataFormat 에 등록한 순서 대로 인자를 입력 하면 됩니다. #시나리오펑션 클래스로 만든 클래스를 반환 시키면서 통신으로 해당 시나리오펑션 으로통신 이 됩니다. return SecsS06F02_(0)
테스트
연결 되고 나서 S02F23 이라는 커스텀으로 만들 시나리오펑션 코드를 실행 했습니다.
#접속이 체결될 경우 콜백 함수입니다. def on_connection_established(self, _): """Connection was established""" self.connected = True # update connection state self.connectionState.connect() self.events.fire("hsms_connected", {'connection': self}) v = secsgem.SecsVarList([RPM_1_SVID, RPM_2_SVID, RPM_3_SVID, VACUUM_1_SVID, VACUUM_2_SVID, VACUUM_3_SVID, EXHAUST_1_SVID,EXHAUST_2_SVID, EXHAUST_3_SVID]) v.RPM_1_SVID = 1111001 v.RPM_2_SVID = 1111002 v.RPM_3_SVID = 1111003 v.VACUUM_1_SVID = 1111004 v.VACUUM_2_SVID = 1111005 v.VACUUM_3_SVID = 1111006 v.EXHAUST_1_SVID = 1111007 v.EXHAUST_2_SVID = 1111008 v.EXHAUST_3_SVID = 1111009 #Trace Initialize Send h.send_stream_function(SecsS02F23_([10000,"4",10000,1,v]))
로그는 위의 테스트 사진과 같이 통신이 정상적으로 이루어 졌습니다
또한 저희 모듈에서 남긴 로그를 보게습니다 .
S2F23
<L [5]
<U4 10000 >
<A "4">
<U4 10000 >
<U4 1 >
<L [9]
<U4 1111001 >
<U4 1111002 >
<U4 1111003 >
<U4 1111004 >
<U4 1111005 >
<U4 1111006 >
<U4 1111007 >
<U4 1111008 >
<U4 1111009 >
>
> .
2017-08-10 19:54:00,467: < 'header': {sessionID:0x0001, stream:02, function:24, pType:0x00, sType:0x00, system:0x02c3e1a9, requireResponse:False}
None
위와 같은 로그가 남습니다.
각 클래스에대한 정의 방법은 API 문서를 봐도 되겠지만 기존에 라이브러리에서 사용중인 클래스를 참고하는 것이 제일 좋은것 같습니다,
예를 들면
제가 직접 정의한 SecsStreamFunction
class SecsS06F01_(secsgem.SecsStreamFunction): """abort transaction stream 6 :param value: function has no parameters :type value: None """ _stream = 6 _function = 1 _dataFormat = [ TRID, SMPLN, STIME, [RPM_1,RPM_2] ] _toHost = True _toEquipment = True _hasReply = True _isReplyRequired = True _isMultiBlock = False
라이브러리에서 적당히 비슷한 코드로
lib\site-packges\secsgem\secs\functions.py 에 원본 코드가 있습니다.
class SecsS06F05(SecsStreamFunction): _stream = 6 _function = 5 _dataFormat = [ DATAID, DATALENGTH ] _toHost = True _toEquipment = False _hasReply = True _isReplyRequired = True _isMultiBlock = False
이런 소스 코드를 참조하여 사용합니다.
또한 기본적으로 핸들러가 사용하는 코드는 우리가 등록을 안해도 표준 secs gem 시나리오펑션은 등록되어 있습니다.
lib\site-packges\secsgem\secs\functions.py에 코드가 있습니다.
secsStreamsFunctions = { 0: { 0: SecsS00F00, }, 1: { 0: SecsS01F00, 1: SecsS01F01, 2: SecsS01F02, 3: SecsS01F03, 4: SecsS01F04, 11: SecsS01F11, 12: SecsS01F12, 13: SecsS01F13, 14: SecsS01F14, 15: SecsS01F15, 16: SecsS01F16, 17: SecsS01F17, 18: SecsS01F18, }, 2: { 0: SecsS02F00, 13: SecsS02F13, 14: SecsS02F14, 15: SecsS02F15, 16: SecsS02F16, 17: SecsS02F17, 18: SecsS02F18, 29: SecsS02F29, 30: SecsS02F30, 33: SecsS02F33, 34: SecsS02F34, 35: SecsS02F35, 36: SecsS02F36, 37: SecsS02F37, 38: SecsS02F38, 41: SecsS02F41, 42: SecsS02F42, }, 5: { 0: SecsS05F00, 1: SecsS05F01, 2: SecsS05F02, 3: SecsS05F03, 4: SecsS05F04, 5: SecsS05F05, 6: SecsS05F06, 7: SecsS05F07, 8: SecsS05F08, 9: SecsS05F09, 10: SecsS05F10, 11: SecsS05F11, 12: SecsS05F12, 13: SecsS05F13, 14: SecsS05F14, 15: SecsS05F15, 16: SecsS05F16, 17: SecsS05F17, 18: SecsS05F18, }, 6: { 0: SecsS06F00, 5: SecsS06F05, 6: SecsS06F06, 7: SecsS06F07, 8: SecsS06F08, 11: SecsS06F11, 12: SecsS06F12, 15: SecsS06F15, 16: SecsS06F16, 19: SecsS06F19, 20: SecsS06F20, 21: SecsS06F21, 22: SecsS06F22, }, 7: { 1: SecsS07F01, 2: SecsS07F02, 3: SecsS07F03, 4: SecsS07F04, 5: SecsS07F05, 6: SecsS07F06, 17: SecsS07F17, 18: SecsS07F18, 19: SecsS07F19, 20: SecsS07F20, }, 9: { 0: SecsS09F00, 1: SecsS09F01, 3: SecsS09F03, 5: SecsS09F05, 7: SecsS09F07, 9: SecsS09F09, 11: SecsS09F11, 13: SecsS09F13, }, 10: { 0: SecsS10F00, 1: SecsS10F01, 2: SecsS10F02, 3: SecsS10F03, 4: SecsS10F04, }, 12: { 0: SecsS12F00, 1: SecsS12F01, 2: SecsS12F02, 3: SecsS12F03, 4: SecsS12F04, 5: SecsS12F05, 6: SecsS12F06, 7: SecsS12F07, 8: SecsS12F08, 9: SecsS12F09, 10: SecsS12F10, 11: SecsS12F11, 12: SecsS12F12, 13: SecsS12F13, 14: SecsS12F14, 15: SecsS12F15, 16: SecsS12F16, 17: SecsS12F17, 18: SecsS12F18, 19: SecsS12F19, }, 14: { 0: SecsS14F00, 1: SecsS14F01, 2: SecsS14F02, 3: SecsS14F03, 4: SecsS14F04, }, }
secsgem.GemHostHandler
HOST 핸들러에 대한 설명은
http://secsgem.readthedocs.io/en/latest/reference/gem/hosthandler.html
HostHandler
- class
secsgem.gem.hosthandler.
GemHostHandler
(address, port, active, session_id, name, custom_connection_handler=None)[source] Bases:
secsgem.gem.handler.GemHandler
Baseclass for creating host models. Inherit from this class and override required functions.
Parameters: - address (string) – IP address of remote host
- port (integer) – TCP port of remote host
- active (boolean) – Is the connection active (True) or passive (False)
- session_id (integer) – session / device ID to use for connection
- name (string) – Name of the underlying configuration
- custom_connection_handler (
secsgem.hsms.connections.HsmsMultiPassiveServer
) – object for connection handling (ie multi server)
자세히 나와 있습니다.
또한 기타 필요한 콜백 함수 또한 http://secsgem.readthedocs.io/en/latest/reference/gem/hosthandler.html 에 설명되어 있습니다.
'산업용 프로토콜 > secs gem open api' 카테고리의 다른 글
설비쪽 기본 샘플 secs gem 코드 작성 (0) | 2017.08.10 |
---|---|
secs/gem 통신 로그 남기는 기본 코드 (0) | 2017.08.09 |
[python]secs gem open source 라이브러리 (0) | 2017.08.09 |