Erxin
Erxin

Reputation: 1856

Two issue about python OpenOPC library

Issues description and environments

The OpenOPC library is friendly and easy to use, the api is simple too, but I have found two issues during the development of a tool to record real time OPC items data.

  1. The development environment is: Window 8.1, Python 2.7.6, wxpython 2.8 unicode
  2. The testing environment is: Window XP SP3, Python 2.7.6, wxpython 2.8 unicode, Rockwell's soft logix as OPC Server Test environment snapshot0 Test environment snapshot1
  3. The deploy environment is: Window XP SP3, connected with Rockwell's real PLC, installed RSLogix 5000 and RSLinx Classic Gateway

Questions

  1. the opc.list function doesn't list all the item of specify node both in testing and workstaion environment. The question is how to list the 't' from the opc server?
    • An int array 'dint100' and a dint 't' is added with RS logix 5000 at the scope of soft_1 Add dint tag 't' with RS logix 5000
    • With the default OPC client test tool from Rockwell it could list the new added 't' Rockwell's default opc test tool could display 't'
    • With OpenOPC library, I couldn't find out how to list the item 't', but I could read it's value by opc.read('[soft_1]t') with it's tag. Try to list tag 't' with OpenOPC with pythonwin but failed
    • If the 't' could be listed, it could be added into the IO tree of my tool. Personal opc monitor tool snapshot
  2. The opc.servers function will encounter an OPCError on the deploy environment, but the client could connect the 'RSLinx OPC Server' directly with the server name. Does opc.servers function dependent on some special dll or service? opc.servers function failed on deploy environments

    Any suggestions will be appreciated! Thanks in advance!

Upvotes: 4

Views: 4381

Answers (2)

R0NUT
R0NUT

Reputation: 3

I realize that I'm really late to this game. I found what was causing this issue. OpenOPC.py assumes that there cannot be both a "Leaf" and a "Branch" on the same level. Replace the function ilist with this:

def ilist(self, paths='*', recursive=False, flat=False, include_type=False):
  """Iterable version of list()"""

  try:
     self._update_tx_time()
     pythoncom.CoInitialize()
     
     try:
        browser = self._opc.CreateBrowser()
     # For OPC servers that don't support browsing
     except:
        return

     paths, single, valid = type_check(paths)
     if not valid:
        raise TypeError("list(): 'paths' parameter must be a string or a list of strings")

     if len(paths) == 0: paths = ['*']
     nodes = {}

     for path in paths:
        
        if flat:
           browser.MoveToRoot()
           browser.Filter = ''
           browser.ShowLeafs(True)

           pattern = re.compile('^%s$' % wild2regex(path) , re.IGNORECASE)
           matches = filter(pattern.search, browser)
           if include_type:  matches = [(x, node_type) for x in matches]

           for node in matches: yield node
           continue
           
        queue = []
        queue.append(path)

        while len(queue) > 0:
           tag = queue.pop(0)
        
           browser.MoveToRoot()
           browser.Filter = ''
           pattern = None

           path_str = '/'
           path_list = tag.replace('.','/').split('/')
           path_list = [p for p in path_list if len(p) > 0]
           found_filter = False
           path_postfix = '/'

           for i, p in enumerate(path_list):
              if found_filter:
                 path_postfix += p + '/'
              elif p.find('*') >= 0:
                 pattern = re.compile('^%s$' % wild2regex(p) , re.IGNORECASE)
                 found_filter = True
              elif len(p) != 0:
                 pattern = re.compile('^.*$')
                 browser.ShowBranches()

                 # Branch node, so move down
                 if len(browser) > 0:
                    try:
                       browser.MoveDown(p)
                       path_str += p + '/'
                    except:
                       if i < len(path_list)-1: return
                       pattern = re.compile('^%s$' % wild2regex(p) , re.IGNORECASE)

                 # Leaf node, so append all remaining path parts together
                 # to form a single search expression
                 else:
                    ###################################### JG Edit - Flip the next two rows comment/uncommented
                    p = '.'.join(path_list[i:])
                    # p = string.join(path_list[i:], '.')
                    pattern = re.compile('^%s$' % wild2regex(p) , re.IGNORECASE)
                    break
     
           
           ###################################### JG Edit - Comment this to return to original

           browser.ShowBranches()
           
           node_types = ['Branch','Leaf']

           if len(browser) == 0:
              lowest_level = True
              node_types.pop(0)
           else:
              lowest_level = False

           for node_type in node_types:
              if node_type=='Leaf':
                 browser.ShowLeafs(False)

              matches = filter(pattern.search, browser)
              
              if not lowest_level and recursive:
                 queue += [path_str + x + path_postfix for x in matches]
              else:
                 ###################################### JG Edit - Flip the next two rows comment/uncommented
                 if lowest_level or node_type=='Leaf':  matches = [exceptional(browser.GetItemID,x)(x) for x in matches]
                 # if lowest_level:  matches = [exceptional(browser.GetItemID,x)(x) for x in matches]
                 if include_type:  matches = [(x, node_type) for x in matches]
                 for node in matches:
                    if not node in nodes: yield node
                    nodes[node] = True

           ###################################### Uncomment this to return to original

           # browser.ShowBranches()

           # if len(browser) == 0:
           #    browser.ShowLeafs(False)
           #    lowest_level = True
           #    node_type = 'Leaf'
           # else:
           #    lowest_level = False
           #    node_type = 'Branch'

           # matches = filter(pattern.search, browser)
           
           # if not lowest_level and recursive:
           #    queue += [path_str + x + path_postfix for x in matches]
           # else:
           #    if lowest_level:  matches = [exceptional(browser.GetItemID,x)(x) for x in matches]
           #    if include_type:  matches = [(x, node_type) for x in matches]
           #    for node in matches:
           #       if not node in nodes: yield node
           #       nodes[node] = True

  except pythoncom.com_error as err:
     error_msg = 'list: %s' % self._get_error_str(err)
     raise OPCError(error_msg)

Upvotes: 0

ZbynekZ
ZbynekZ

Reputation: 1608

Consider that the browsing problems ("opc.list") may not be on your side. RSLinx is notorious for its broken OPC browsing. Try some test/simulation server from a different vendor, to test this hypothesis.

Upvotes: 1

Related Questions