def test_client_server(self): ADDRESS = 'localhost:44818' try: # same instance used as server and client enip = EnipProtocol( protocol=TestEnipProtocol.CLIENT_SERVER_PROTOCOL) # read a multikey what = ('SENSOR1', 1) enip._receive(what, ADDRESS) # read a single key what = ('ACTUATOR1',) enip._receive(what, ADDRESS) # write a multikey what = ('SENSOR1', 1) for value in range(5): enip._send(what, value, ADDRESS) # write a single key what = ('ACTUATOR1',) for value in range(5): enip._send(what, value, ADDRESS) EnipProtocol._stop_server(enip._server_subprocess) except Exception as error: EnipProtocol._stop_server(enip._server_subprocess) print 'ERROR test_client_server: ', error assert False
def test_send_multikey(self): enip = EnipProtocol( protocol=TestEnipProtocol.CLIENT_PROTOCOL) ADDRESS = 'localhost:44818' # TEST port TAGS = (('SENSOR1', 1, 'INT'), ('ACTUATOR1', 'INT')) try: server = EnipProtocol._start_server(ADDRESS, TAGS) # write a multikey what = ('SENSOR1', 1) for value in range(5): enip._send(what, value, ADDRESS) # write a single key what = ('ACTUATOR1',) for value in range(5): enip._send(what, value, ADDRESS) EnipProtocol._stop_server(server) except Exception as error: EnipProtocol._stop_server(server) print 'ERROR test_send_multikey: ', error assert False
def test_send_multikey(self): enip = EnipProtocol(protocol=CLIENT_PROTOCOL) TAGS = (('SENSOR1', 1, 'INT'), ('ACTUATOR1', 'INT')) cmd = EnipProtocol._start_server_cmd(tags=TAGS) try: server = subprocess.Popen(cmd, shell=False) # write a multikey what = ('SENSOR1', 1) address = 'localhost:44818' for value in range(5): enip._send(what, value, address) # write a single key what = ('ACTUATOR1', ) address = 'localhost:44818' for value in range(5): enip._send(what, value, address) EnipProtocol._stop_server(server) except Exception as error: EnipProtocol._stop_server(server) print 'ERROR test_client: ', error
def test_client_server(self): try: enip = EnipProtocol(protocol=CLIENT_SERVER_PROTOCOL) # read a multikey what = ('SENSOR1', 1) address = 'localhost:44818' enip._receive(what, address) # read a single key what = ('ACTUATOR1', ) address = 'localhost:44818' enip._receive(what, address) # write a multikey what = ('SENSOR1', 1) address = 'localhost:44818' for value in range(5): enip._send(what, value, address) # write a single key what = ('ACTUATOR1', ) address = 'localhost:44818' for value in range(5): enip._send(what, value, address) EnipProtocol._stop_server(enip._server_subprocess) except Exception as error: EnipProtocol._stop_server(enip._server_subprocess) print 'ERROR test_client_server: ', error
class Device(object): """Base class.""" # TODO: state dict convention (eg: multiple table support?) def __init__(self, name, protocol, state, disk={}, memory={}): """ :param str name: device name :param dict protocol: used to set up the network layer API :param dict state: used to set up the physical layer API :param dict disk: persistent memory :param dict memory: main memory Device construction example: >>> device = Device( >>> name='dev', >>> protocol={ >>> 'name': 'enip', >>> 'mode': 1, >>> 'server': { >>> 'address': '10.0.0.1', >>> 'tags': (('SENSOR1', 1), ('SENSOR2', 1)), >>> } >>> state={ >>> 'path': '/path/to/db.sqlite', >>> 'name': 'table_name', >>> } >>> ) """ self._validate_inputs(name, protocol, state, disk, memory) self.name = name self.state = state self.protocol = protocol self.memory = memory self.disk = disk self._init_state() self._init_protocol() self._start() self._stop() def _validate_inputs(self, name, protocol, state, disk, memory): # name string if type(name) is not str: raise TypeError('Name must be a string.') elif not name: raise ValueError('Name string cannot be empty.') # state dict if type(state) is not dict: raise TypeError('State must be a dict.') else: state_keys = state.keys() if (not state_keys) or (len(state_keys) != 2): raise KeyError('State must contain 2 keys.') else: for key in state_keys: if (key != 'path') and (key != 'name'): raise KeyError('%s is an invalid key.' % key) state_values = state.values() for val in state_values: if type(val) is not str: raise TypeError('state values must be strings.') # state['path'] subpath, extension = splitext(state['path']) # print 'DEBUG subpath: ', subpath # print 'DEBUG extension: ', extension if (extension != '.redis') and (extension != '.sqlite'): raise ValueError('%s extension not supported.' % extension) # state['name'] if type(state['name']) is not str: raise TypeError('State name must be a string.') # protocol if type(protocol) is not dict: if protocol is not None: raise TypeError('Protocol must be either None or a dict.') else: protocol_keys = protocol.keys() if (not protocol_keys) or (len(protocol_keys) != 3): raise KeyError('Protocol must contain 3 keys.') else: for key in protocol_keys: if ((key != 'name') and (key != 'mode') and (key != 'server')): raise KeyError('%s is an invalid key.' % key) # protocol['name'] if type(protocol['name']) is not str: raise TypeError('Protocol name must be a string.') else: name = protocol['name'] if (name != 'enip'): raise ValueError('%s protocol not supported.' % protocol) # protocol['mode'] if type(protocol['mode']) is not int: raise TypeError('Protocol mode must be a int.') else: mode = protocol['mode'] if (mode < 0): raise ValueError('Protocol mode must be positive.') # protocol['server'] TODO # protocol['client'] TODO after adding it to the API def _init_state(self): """Bind device to the physical layer API.""" subpath, extension = splitext(self.state['path']) if extension == '.sqlite': # TODO: add parametric value filed # print 'DEBUG state: ', self.state self._state = SQLiteState(self.state) elif extension == '.redis': # TODO: add parametric key serialization self._state = RedisState(self.state) else: print 'ERROR: %s backend not supported.' % self.state # TODO: add optional process name for the server and log location def _init_protocol(self): """Bind device to network API.""" if self.protocol is None: print 'DEBUG: %s has no networking capabilities.' % self.name pass else: name = self.protocol['name'] if name == 'enip': self._protocol = EnipProtocol(self.protocol) else: print 'ERROR: %s protocol not supported.' % self.protocol def _start(self): """Start a device.""" print "TODO _start: please override me" def _stop(self): """Start a device.""" print "TODO _stop: please override me" def set(self, what, value): """Set aka write a state value. :param tuple what: field[s] identifier[s] :param value: value to be setted :returns: setted value or ``TypeError`` if ``what`` is not a ``tuple`` """ if type(what) is not tuple: raise TypeError('Parameter must be a tuple.') else: return self._state._set(what, value) def get(self, what): """Get (read) a ``state`` value. :param tuple what: field[s] identifier[s] :returns: gotten value or ``TypeError`` if ``what`` is not a ``tuple`` """ if type(what) is not tuple: raise TypeError('Parameter must be a tuple.') else: return self._state._get(what) def send(self, what, value, address): """Send aka serve a value to another host. :param tuple what: field[s] identifier[s] :param value: value to be setted :param str address: ``ip[:port]`` :returns: ``None`` or ``TypeError`` if ``what`` is not a ``tuple`` """ if type(what) is not tuple: raise TypeError('Parameter must be a tuple.') else: return self._protocol._send(what, value, address) def recieve(self, what, address): """Receive a value from another host. :param tuple what: field[s] identifier[s] :param str address: ``ip[:port]`` :returns: recv value or ``TypeError`` if ``what`` is not a ``tuple`` """ if type(what) is not tuple: raise TypeError('Parameter must be a tuple.') else: return self._protocol._receive(what, address)