def _read_health(self, tags): """Return values of special system health monitoring tags""" self._update_tx_time() tags, single, valid = type_check(tags) time_str = time.strftime("%x %H:%M:%S") results = [] for t in tags: if t == "@MemFree": value = SystemHealth.mem_free() elif t == "@MemUsed": value = SystemHealth.mem_used() elif t == "@MemTotal": value = SystemHealth.mem_total() elif t == "@MemPercent": value = SystemHealth.mem_percent() elif t == "@DiskFree": value = SystemHealth.disk_free() elif t == "@SineWave": value = SystemHealth.sine_wave() elif t == "@SawWave": value = SystemHealth.saw_wave() elif t == "@CpuUsage": if self.cpu == None: self.cpu = SystemHealth.CPU() time.sleep(0.1) value = self.cpu.get_usage() else: value = None m = re.match("@TaskMem\((.*?)\)", t) if m: image_name = m.group(1) value = SystemHealth.task_mem(image_name) m = re.match("@TaskCpu\((.*?)\)", t) if m: image_name = m.group(1) value = SystemHealth.task_cpu(image_name) m = re.match("@TaskExists\((.*?)\)", t) if m: image_name = m.group(1) value = SystemHealth.task_exists(image_name) if value == None: quality = "Error" else: quality = "Good" if single: results.append((value, quality, time_str)) else: results.append((t, value, quality, time_str)) return results
def read(self, tags=None, group=None, size=None, pause=0, source='hybrid', update=-1, timeout=5000, sync=False, include_error=False, rebuild=False): """Return list of (value, quality, time) tuples for the specified tag(s)""" tags_list, single, valid = type_check(tags) if not valid: raise TypeError("read(): 'tags' parameter must be a string or a list of strings") num_health_tags = len([t for t in tags_list if t[:1] == '@']) num_opc_tags = len([t for t in tags_list if t[:1] != '@']) if num_health_tags > 0: if num_opc_tags > 0: raise TypeError("read(): system health and OPC tags cannot be included in the same group") results = self._read_health(tags) else: results = self.iread(tags, group, size, pause, source, update, timeout, sync, include_error, rebuild) if single: return list(results)[0] else: return list(results)
def iread(self, tags=None, group=None, size=None, pause=0, source='hybrid', update=-1, timeout=5000, sync=False, include_error=False, rebuild=False): """ Iterable version of read() """ def add_items(tags): names = list(tags) names.insert(0,0) errors = [] if self.trace: self.trace('Validate(%s)' % tags2trace(names)) try: errors = opc_items.Validate(len(names)-1, names) except: pass valid_tags = [] valid_values = [] client_handles = [] if not sub_group in self._group_handles_tag: self._group_handles_tag[sub_group] = {} n = 0 elif len(self._group_handles_tag[sub_group]) > 0: n = max(self._group_handles_tag[sub_group]) + 1 else: n = 0 for i, tag in enumerate(tags): if errors[i] == 0: valid_tags.append(tag) client_handles.append(n) self._group_handles_tag[sub_group][n] = tag n += 1 elif include_error: error_msgs[tag] = self._opc.GetErrorString(errors[i]) if self.trace and errors[i] != 0: self.trace('%s failed validation' % tag) client_handles.insert(0,0) valid_tags.insert(0,0) server_handles = [] errors = [] if self.trace: self.trace('AddItems(%s)' % tags2trace(valid_tags)) try: server_handles, errors = opc_items.AddItems(len(client_handles)-1, valid_tags, client_handles) except: pass valid_tags_tmp = [] server_handles_tmp = [] valid_tags.pop(0) if not sub_group in self._group_server_handles: self._group_server_handles[sub_group] = {} for i, tag in enumerate(valid_tags): if errors[i] == 0: valid_tags_tmp.append(tag) server_handles_tmp.append(server_handles[i]) self._group_server_handles[sub_group][tag] = server_handles[i] elif include_error: error_msgs[tag] = self._opc.GetErrorString(errors[i]) valid_tags = valid_tags_tmp server_handles = server_handles_tmp return valid_tags, server_handles def remove_items(tags): if self.trace: self.trace('RemoveItems(%s)' % tags2trace(['']+tags)) server_handles = [self._group_server_handles[sub_group][tag] for tag in tags] server_handles.insert(0,0) errors = [] try: errors = opc_items.Remove(len(server_handles)-1, server_handles) except pythoncom.com_error as err: error_msg = 'RemoveItems: %s' % self._get_error_str(err) raise OPCError(error_msg) try: self._update_tx_time() pythoncom.CoInitialize() sync = True update = -1 tags, single, valid = type_check(tags) #doesnt need to be called everytime, we check on first pass if not valid: raise TypeError("iread(): 'tags' parameter must be a string or a list of strings") #start here # Group exists if group in self._groups and not rebuild: num_groups = self._groups[group] data_source = SOURCE_CACHE #? need to specify this every time? # Group non-existant else: if size: # Break-up tags into groups of 'size' tags tag_groups = [tags[i:i+size] for i in range(0, len(tags), size)] else: tag_groups = [tags] num_groups = len(tag_groups) data_source = SOURCE_DEVICE results = [] for gid in range(num_groups): if gid > 0 and pause > 0: time.sleep(pause/1000.0) error_msgs = {} opc_groups = self._opc.OPCGroups opc_groups.DefaultGroupUpdateRate = update #?? need to specify this everytime? # Anonymous group if group == None: try: if self.trace: self.trace('AddGroup()') opc_group = opc_groups.Add() except pythoncom.com_error as err: error_msg = 'AddGroup: %s' % self._get_error_str(err) raise OPCError(error_msg) sub_group = group new_group = True else: sub_group = '%s.%d' % (group, gid) # Existing named group try: if self.trace: self.trace('GetOPCGroup(%s)' % sub_group) opc_group = opc_groups.GetOPCGroup(sub_group) new_group = False # New named group except: try: if self.trace: self.trace('AddGroup(%s)' % sub_group) opc_group = opc_groups.Add(sub_group) except pythoncom.com_error as err: error_msg = 'AddGroup: %s' % self._get_error_str(err) raise OPCError(error_msg) self._groups[str(group)] = len(tag_groups) new_group = True opc_items = opc_group.OPCItems if new_group: #opc_group.IsSubscribed = 1 opc_group.IsActive = 1 # do we need to specify this every time? tags = tag_groups[gid] valid_tags, server_handles = add_items(tags) self._group_tags[sub_group] = tags self._group_valid_tags[sub_group] = valid_tags # Rebuild existing group elif rebuild: tags = tag_groups[gid] valid_tags = self._group_valid_tags[sub_group] add_tags = [t for t in tags if t not in valid_tags] del_tags = [t for t in valid_tags if t not in tags] if len(add_tags) > 0: valid_tags, server_handles = add_items(add_tags) valid_tags = self._group_valid_tags[sub_group] + valid_tags if len(del_tags) > 0: remove_items(del_tags) valid_tags = [t for t in valid_tags if t not in del_tags] self._group_tags[sub_group] = tags self._group_valid_tags[sub_group] = valid_tags if source == 'hybrid': data_source = SOURCE_DEVICE # Existing group else: tags = self._group_tags[sub_group] valid_tags = self._group_valid_tags[sub_group] if sync: server_handles = [item.ServerHandle for item in opc_items] # grabs server handles from an existing group. do these actually change? #server_handles = self._group_server_handles[sub_group] if self.trace: self.trace('Server Handles(%s)' % self._group_server_handles[sub_group] ) #End Here #-------- tag_value = {} tag_quality = {} tag_time = {} tag_error = {} # Sync Read if sync: values = [] errors = [] qualities = [] timestamps= [] if len(valid_tags) > 0: server_handles.insert(0,0) if source != 'hybrid': data_source = SOURCE_CACHE if source == 'cache' else SOURCE_DEVICE if self.trace: self.trace('SyncRead(%s)' % data_source) try: values, errors, qualities, timestamps = opc_group.SyncRead(data_source, len(server_handles)-1, server_handles) except pythoncom.com_error as err: error_msg = 'SyncRead: %s' % self._get_error_str(err) raise OPCError(error_msg) for i,tag in enumerate(valid_tags): tag_value[tag] = values[i] tag_quality[tag] = qualities[i] tag_time[tag] = timestamps[i] tag_error[tag] = errors[i] for tag in tags: if tag in tag_value: if (sync and tag_error[tag] == 0): value = tag_value[tag] if type(value) == pywintypes.TimeType: value = str(value) quality = quality_str(tag_quality[tag]) #look to apply time conversion here!?? timestamp = str(tag_time[tag]) else: value = None quality = 'Error' timestamp = None if include_error: error_msgs[tag] = self._opc.GetErrorString(tag_error[tag]).strip('\r\n') else: value = None quality = 'Error' timestamp = None if include_error and not tag in error_msgs: error_msgs[tag] = '' if single: if include_error: yield (value, quality, timestamp, error_msgs[tag]) else: yield (value, quality, timestamp) else: if include_error: yield (tag, value, quality, timestamp, error_msgs[tag]) else: yield (tag, value, quality, timestamp) if group == None: try: if self.trace: self.trace('RemoveGroup(%s)' % opc_group.Name) opc_groups.Remove(opc_group.Name) except pythoncom.com_error as err: error_msg = 'RemoveGroup: %s' % self._get_error_str(err) raise OPCError(error_msg) except pythoncom.com_error as err: error_msg = 'read: %s' % self._get_error_str(err) raise OPCError(error_msg)
def iread(self, tags=None, group=None, size=None, pause=0, source='hybrid', update=-1, timeout=5000, sync=False, include_error=False, rebuild=False): """ Iterable version of read() """ def add_items(tags): names = list(tags) names.insert(0,0) errors = [] if self.trace: self.trace('Validate(%s)' % tags2trace(names)) try: errors = opc_items.Validate(len(names)-1, names) except: pass valid_tags = [] valid_values = [] client_handles = [] if not sub_group in self._group_handles_tag: self._group_handles_tag[sub_group] = {} n = 0 elif len(self._group_handles_tag[sub_group]) > 0: n = max(self._group_handles_tag[sub_group]) + 1 else: n = 0 for i, tag in enumerate(tags): if errors[i] == 0: valid_tags.append(tag) client_handles.append(n) self._group_handles_tag[sub_group][n] = tag n += 1 elif include_error: error_msgs[tag] = self._opc.GetErrorString(errors[i]) if self.trace and errors[i] != 0: self.trace('%s failed validation' % tag) client_handles.insert(0,0) valid_tags.insert(0,0) server_handles = [] errors = [] if self.trace: self.trace('AddItems(%s)' % tags2trace(valid_tags)) try: server_handles, errors = opc_items.AddItems(len(client_handles)-1, valid_tags, client_handles) except: pass valid_tags_tmp = [] server_handles_tmp = [] valid_tags.pop(0) if not sub_group in self._group_server_handles: self._group_server_handles[sub_group] = {} for i, tag in enumerate(valid_tags): if errors[i] == 0: valid_tags_tmp.append(tag) server_handles_tmp.append(server_handles[i]) self._group_server_handles[sub_group][tag] = server_handles[i] elif include_error: error_msgs[tag] = self._opc.GetErrorString(errors[i]) valid_tags = valid_tags_tmp server_handles = server_handles_tmp return valid_tags, server_handles def remove_items(tags): if self.trace: self.trace('RemoveItems(%s)' % tags2trace(['']+tags)) server_handles = [self._group_server_handles[sub_group][tag] for tag in tags] server_handles.insert(0,0) errors = [] try: errors = opc_items.Remove(len(server_handles)-1, server_handles) except pythoncom.com_error as err: error_msg = 'RemoveItems: %s' % self._get_error_str(err) raise OPCError(error_msg) try: self._update_tx_time() pythoncom.CoInitialize() if include_error: sync = True if sync: update = -1 tags, single, valid = type_check(tags) if not valid: raise TypeError("iread(): 'tags' parameter must be a string or a list of strings") # Group exists if group in self._groups and not rebuild: num_groups = self._groups[group] data_source = SOURCE_CACHE # Group non-existant else: if size: # Break-up tags into groups of 'size' tags tag_groups = [tags[i:i+size] for i in range(0, len(tags), size)] else: tag_groups = [tags] num_groups = len(tag_groups) data_source = SOURCE_DEVICE results = [] for gid in range(num_groups): if gid > 0 and pause > 0: time.sleep(pause/1000.0) error_msgs = {} opc_groups = self._opc.OPCGroups opc_groups.DefaultGroupUpdateRate = update # Anonymous group if group == None: try: if self.trace: self.trace('AddGroup()') opc_group = opc_groups.Add() except pythoncom.com_error as err: error_msg = 'AddGroup: %s' % self._get_error_str(err) raise OPCError(error_msg) sub_group = group new_group = True else: sub_group = '%s.%d' % (group, gid) # Existing named group try: if self.trace: self.trace('GetOPCGroup(%s)' % sub_group) opc_group = opc_groups.GetOPCGroup(sub_group) new_group = False # New named group except: try: if self.trace: self.trace('AddGroup(%s)' % sub_group) opc_group = opc_groups.Add(sub_group) except pythoncom.com_error as err: error_msg = 'AddGroup: %s' % self._get_error_str(err) raise OPCError(error_msg) self._groups[str(group)] = len(tag_groups) new_group = True opc_items = opc_group.OPCItems if new_group: opc_group.IsSubscribed = 1 opc_group.IsActive = 1 if not sync: if self.trace: self.trace('WithEvents(%s)' % opc_group.Name) #global current_client #current_client = self GroupEvents.client = self self._group_hooks[opc_group.Name] = win32com.client.WithEvents(opc_group, GroupEvents) #self._group_hooks[opc_group.Name] = win32com.client.WithEvents(opc_group, GroupEvent) tags = tag_groups[gid] valid_tags, server_handles = add_items(tags) self._group_tags[sub_group] = tags self._group_valid_tags[sub_group] = valid_tags # Rebuild existing group elif rebuild: tags = tag_groups[gid] valid_tags = self._group_valid_tags[sub_group] add_tags = [t for t in tags if t not in valid_tags] del_tags = [t for t in valid_tags if t not in tags] if len(add_tags) > 0: valid_tags, server_handles = add_items(add_tags) valid_tags = self._group_valid_tags[sub_group] + valid_tags if len(del_tags) > 0: remove_items(del_tags) valid_tags = [t for t in valid_tags if t not in del_tags] self._group_tags[sub_group] = tags self._group_valid_tags[sub_group] = valid_tags if source == 'hybrid': data_source = SOURCE_DEVICE # Existing group else: tags = self._group_tags[sub_group] valid_tags = self._group_valid_tags[sub_group] if sync: server_handles = [item.ServerHandle for item in opc_items] tag_value = {} tag_quality = {} tag_time = {} tag_error = {} # Sync Read if sync: values = [] errors = [] qualities = [] timestamps= [] if len(valid_tags) > 0: server_handles.insert(0,0) if source != 'hybrid': data_source = SOURCE_CACHE if source == 'cache' else SOURCE_DEVICE if self.trace: self.trace('SyncRead(%s)' % data_source) try: values, errors, qualities, timestamps = opc_group.SyncRead(data_source, len(server_handles)-1, server_handles) except pythoncom.com_error as err: error_msg = 'SyncRead: %s' % self._get_error_str(err) raise OPCError(error_msg) for i,tag in enumerate(valid_tags): tag_value[tag] = values[i] tag_quality[tag] = qualities[i] tag_time[tag] = timestamps[i] tag_error[tag] = errors[i] # Async Read else: if len(valid_tags) > 0: if self._tx_id >= 0xFFFF: self._tx_id = 0 self._tx_id += 1 if source != 'hybrid': data_source = SOURCE_CACHE if source == 'cache' else SOURCE_DEVICE if self.trace: self.trace('AsyncRefresh(%s)' % data_source) try: opc_group.AsyncRefresh(data_source, self._tx_id) #svr_tx_id = opc_group.AsyncRefresh(data_source, self._tx_id) #opc_group.AsyncRead(data_source, self._tx_id) #opc_group.AsyncRead(len(server_handles)-1, server_handles, self._tx_id) except pythoncom.com_error as err: error_msg = 'AsyncRefresh: %s' % self._get_error_str(err) raise OPCError(error_msg) tx_id = 0 start = time.time() * 1000 while tx_id != self._tx_id: now = time.time() * 1000 if now - start > timeout: raise TimeoutError('Callback: Timeout waiting for data') if self.callback_queue.empty(): pythoncom.PumpWaitingMessages() else: tx_id, handles, values, qualities, timestamps = self.callback_queue.get() for i,h in enumerate(handles): tag = self._group_handles_tag[sub_group][h] tag_value[tag] = values[i] tag_quality[tag] = qualities[i] tag_time[tag] = timestamps[i] for tag in tags: if tag in tag_value: if (not sync and len(valid_tags) > 0) or (sync and tag_error[tag] == 0): value = tag_value[tag] if type(value) == pywintypes.TimeType: value = str(value) quality = quality_str(tag_quality[tag]) timestamp = str(tag_time[tag]) else: value = None quality = 'Error' timestamp = None if include_error: error_msgs[tag] = self._opc.GetErrorString(tag_error[tag]).strip('\r\n') else: value = None quality = 'Error' timestamp = None if include_error and not tag in error_msgs: error_msgs[tag] = '' if single: if include_error: yield (value, quality, timestamp, error_msgs[tag]) else: yield (value, quality, timestamp) else: if include_error: yield (tag, value, quality, timestamp, error_msgs[tag]) else: yield (tag, value, quality, timestamp) if group == None: try: if not sync and opc_group.Name in self._group_hooks: if self.trace: self.trace('CloseEvents(%s)' % opc_group.Name) self._group_hooks[opc_group.Name].close() if self.trace: self.trace('RemoveGroup(%s)' % opc_group.Name) opc_groups.Remove(opc_group.Name) except pythoncom.com_error as err: error_msg = 'RemoveGroup: %s' % self._get_error_str(err) raise OPCError(error_msg) except pythoncom.com_error as err: error_msg = 'read: %s' % self._get_error_str(err) raise OPCError(error_msg)
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: p = string.join(path_list[i:], ".") pattern = re.compile("^%s$" % wild2regex(p), re.IGNORECASE) break 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)
def iproperties(self, tags, id=None): """Iterable version of properties()""" try: self._update_tx_time() pythoncom.CoInitialize() tags, single_tag, valid = type_check(tags) if not valid: raise TypeError( "properties(): 'tags' parameter must be a string or a list of strings" ) try: id.remove(0) include_name = True except: include_name = False if id != None: descriptions = [] if isinstance(id, list) or isinstance(id, tuple): property_id = list(id) single_property = False else: property_id = [id] single_property = True for i in property_id: descriptions.append("Property id %d" % i) else: single_property = False properties = [] for tag in tags: if id == None: descriptions = [] property_id = [] ( count, property_id, descriptions, datatypes, ) = self._opc.QueryAvailableProperties(tag) # Remove bogus negative property id (not sure why this sometimes happens) tag_properties = list( map(lambda x, y: (x, y), property_id, descriptions)) property_id = [p for p, d in tag_properties if p > 0] descriptions = [d for p, d in tag_properties if p > 0] property_id.insert(0, 0) values = [] errors = [] values, errors = self._opc.GetItemProperties( tag, len(property_id) - 1, property_id) property_id.pop(0) values = [ str(v) if type(v) == pywintypes.TimeType else v for v in values ] # Replace variant id with type strings try: i = property_id.index(1) values[i] = vt[values[i]] except: pass # Replace quality bits with quality strings try: i = property_id.index(3) values[i] = quality_str(values[i]) except: pass # Replace access rights bits with strings try: i = property_id.index(5) values[i] = ACCESS_RIGHTS[values[i]] except: pass if id != None: if single_property: if single_tag: tag_properties = values else: tag_properties = [values] else: tag_properties = list( map(lambda x, y: (x, y), property_id, values)) else: tag_properties = list( map(lambda x, y, z: (x, y, z), property_id, descriptions, values)) tag_properties.insert( 0, (0, "Item ID (virtual property)", tag)) if include_name: tag_properties.insert(0, (0, tag)) if not single_tag: tag_properties = [ tuple([tag] + list(p)) for p in tag_properties ] for p in tag_properties: yield p except pythoncom.com_error as err: error_msg = "properties: %s" % self._get_error_str(err) raise OPCError(error_msg)