def add_attributes(self, node_or_edge, xml_obj, data, default): # Add attrvalues to node or edge attvalues = Element('attvalues') if len(data) == 0: return data if 'start' in data or 'end' in data: mode = 'dynamic' else: mode = 'static' for k, v in list(data.items()): attr_id = self.get_attr_id(make_str(k), self.xml_type[type(v)], node_or_edge, default, mode) if type(v) == list: # dynamic data for val, start, end in v: e = Element("attvalue") e.attrib['for'] = attr_id e.attrib['value'] = make_str(val) e.attrib['start'] = make_str(start) e.attrib['end'] = make_str(end) attvalues.append(e) else: # static data e = Element("attvalue") e.attrib['for'] = attr_id e.attrib['value'] = make_str(v) attvalues.append(e) xml_obj.append(attvalues) return data
def add_nodes(self, G, graph_element): nodes_element = Element('nodes') for node, data in G.nodes_iter(data=True): node_data = data.copy() # node_id = node_data.pop('id', make_str(node)) kw = {'id': node_id} label = node_data.pop('label', make_str(node)) kw['label'] = label pid = node_data.pop('pid', False) if pid: kw['pid'] = pid # add node element with attributes node_element = Element("node", **kw) # add node element and attr subelements default = G.graph.get('node_default', {}) node_data = self.add_parents(node_element, node_data) node_data = self.add_slices(node_element, node_data) node_data = self.add_viz(node_element, node_data) node_data = self.add_attributes("node", node_element, node_data, default) nodes_element.append(node_element) graph_element.append(nodes_element)
def add_nodes(self, G, graph_element): nodes_element = Element('nodes') for node,data in G.nodes_iter(data=True): node_data=data.copy() # node_id=node_data.pop('id',make_str(node)) kw={'id':node_id} label=node_data.pop('label',make_str(node)) kw['label']=label pid=node_data.pop('pid',False) if pid: kw['pid']=pid # add node element with attributes node_element = Element("node", **kw) # add node element and attr subelements default=G.graph.get('node_default',{}) node_data=self.add_parents(node_element, node_data) node_data=self.add_slices(node_element, node_data) node_data=self.add_viz(node_element,node_data) node_data=self.add_attributes("node", node_element, node_data, default) nodes_element.append(node_element) graph_element.append(nodes_element)
def add_attributes(self, node_or_edge, xml_obj, data, default): # Add attrvalues to node or edge attvalues=Element('attvalues') if len(data)==0: return data if 'start' in data or 'end' in data: mode='dynamic' else: mode='static' for k,v in list(data.items()): attr_id = self.get_attr_id(make_str(k), self.xml_type[type(v)], node_or_edge, default, mode) if type(v)==list: # dynamic data for val,start,end in v: e=Element("attvalue") e.attrib['for']=attr_id e.attrib['value']=make_str(val) e.attrib['start']=make_str(start) e.attrib['end']=make_str(end) attvalues.append(e) else: # static data e=Element("attvalue") e.attrib['for']=attr_id e.attrib['value']=make_str(v) attvalues.append(e) xml_obj.append(attvalues) return data
def get_attr_id(self, title, attr_type, edge_or_node, default, mode): # find the id of the attribute or generate a new id try: return self.attr[edge_or_node][mode][title] except KeyError: # generate new id self.attr_id.next() new_id=str( self.attr_id ) self.attr[edge_or_node][mode][title] = new_id attr_kwargs = {"id":new_id, "title":title, "type":attr_type} attribute=Element("attribute",**attr_kwargs) # add subelement for data default value if present default_title=default.get(title) if default_title is not None: default_element=Element("default") default_element.text=make_str(default_title) attribute.append(default_element) # new insert it into the XML attributes_element=None for a in self.graph_element.findall("attributes"): # find existing attributes element by class and mode a_class=a.get('class') a_mode=a.get('mode','static') # default mode is static if a_class==edge_or_node and a_mode==mode: attributes_element=a if attributes_element is None: # create new attributes element attr_kwargs = {"mode":mode,"class":edge_or_node} attributes_element=Element('attributes', **attr_kwargs) self.graph_element.insert(0,attributes_element) attributes_element.append(attribute) return new_id
def get_attr_id(self, title, attr_type, edge_or_node, default, mode): # find the id of the attribute or generate a new id try: return self.attr[edge_or_node][mode][title] except KeyError: # generate new id self.attr_id.next() new_id = str(self.attr_id) self.attr[edge_or_node][mode][title] = new_id attr_kwargs = {"id": new_id, "title": title, "type": attr_type} attribute = Element("attribute", **attr_kwargs) # add subelement for data default value if present default_title = default.get(title) if default_title is not None: default_element = Element("default") default_element.text = make_str(default_title) attribute.append(default_element) # new insert it into the XML attributes_element = None for a in self.graph_element.findall("attributes"): # find existing attributes element by class and mode a_class = a.get('class') a_mode = a.get('mode', 'static') # default mode is static if a_class == edge_or_node and a_mode == mode: attributes_element = a if attributes_element is None: # create new attributes element attr_kwargs = {"mode": mode, "class": edge_or_node} attributes_element = Element('attributes', **attr_kwargs) self.graph_element.insert(0, attributes_element) attributes_element.append(attribute) return new_id
def _list_ctrls(device): global _ctrls_cache device = utils.make_str(device) if device in _ctrls_cache: return _ctrls_cache[device] output = '' started = time.time() p = subprocess.Popen('v4l2-ctl -d "%(device)s" --list-ctrls' % { 'device': device}, shell=True, stdout=subprocess.PIPE, bufsize=1) fd = p.stdout.fileno() fl = fcntl.fcntl(fd, fcntl.F_GETFL) fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) while True: try: data = p.stdout.read(1024) if not data: break except IOError: data = '' time.sleep(0.01) output += data if len(output) > 10240: logging.warn('v4l2-ctl command returned more than 10k of output') break if time.time() - started > 3: logging.warn('v4l2-ctl command ran for more than 3 seconds') break try: # try to kill the v4l2-ctl subprocess p.kill() except: pass # nevermind controls = {} for line in output.split('\n'): if not line: continue match = re.match('^\s*(\w+)\s+\(\w+\)\s*\:\s*(.+)\s*', line) if not match: continue (control, properties) = match.groups() properties = dict([v.split('=', 1) for v in properties.split(' ') if v.count('=')]) controls[control] = properties _ctrls_cache[device] = controls return controls
def init(self, xml_or_file): text = xml_or_file.read( ) if hasattr(xml_or_file, 'read') else xml_or_file self.xml = mod_utils.make_str(text) self.valid = False self.error = None self.gpx = mod_gpx.GPX()
def device_present(device): device = utils.make_str(device) try: st = os.stat(device) return stat.S_ISCHR(st.st_mode) except: return False
def init(self, xml_or_file): text = xml_or_file.read() if hasattr(xml_or_file, 'read') else xml_or_file self.xml = mod_utils.make_str(text) self.valid = False self.error = None self.gpx = mod_gpx.GPX()
def add_edges(self, G, graph_element): def edge_key_data(G): # helper function to unify multigraph and graph edge iterator if G.is_multigraph(): for u, v, key, data in G.edges_iter(data=True, keys=True): edge_data = data.copy() edge_data.update(key=key) edge_id = edge_data.pop('id', None) if edge_id is None: edge_id = self.edge_id.next() yield u, v, edge_id, edge_data else: for u, v, data in G.edges_iter(data=True): edge_data = data.copy() edge_id = edge_data.pop('id', None) if edge_id is None: edge_id = next(self.edge_id) yield u, v, edge_id, edge_data edges_element = Element('edges') for u, v, key, edge_data in edge_key_data(G): kw = {'id': make_str(key)} edge_weight = edge_data.pop('weight', False) if edge_weight: kw['weight'] = make_str(edge_weight) edge_type = edge_data.pop('type', False) if edge_type: kw['type'] = make_str(edge_type) edge_element = Element("edge", source=make_str(u), target=make_str(v), **kw) default = G.graph.get('edge_default', {}) edge_data = self.add_viz(edge_element, edge_data) edge_data = self.add_attributes("edge", edge_element, edge_data, default) edges_element.append(edge_element) graph_element.append(edges_element)
def add_edges(self, G, graph_element): def edge_key_data(G): # helper function to unify multigraph and graph edge iterator if G.is_multigraph(): for u,v,key,data in G.edges_iter(data=True,keys=True): edge_data=data.copy() edge_data.update(key=key) edge_id=edge_data.pop('id',None) if edge_id is None: edge_id=self.edge_id.next() yield u,v,edge_id,edge_data else: for u,v,data in G.edges_iter(data=True): edge_data=data.copy() edge_id=edge_data.pop('id',None) if edge_id is None: edge_id=next(self.edge_id) yield u,v,edge_id,edge_data edges_element = Element('edges') for u,v,key,edge_data in edge_key_data(G): kw={'id':make_str(key)} edge_weight=edge_data.pop('weight',False) if edge_weight: kw['weight']=make_str(edge_weight) edge_type=edge_data.pop('type',False) if edge_type: kw['type']=make_str(edge_type) edge_element = Element("edge", source=make_str(u),target=make_str(v), **kw) default=G.graph.get('edge_default',{}) edge_data=self.add_viz(edge_element,edge_data) edge_data=self.add_attributes("edge", edge_element, edge_data, default) edges_element.append(edge_element) graph_element.append(edges_element)
def find_persistent_device(device): device = utils.make_str(device) try: devs_by_id = os.listdir(_DEV_V4L_BY_ID) except OSError: return device for p in devs_by_id: p = os.path.join(_DEV_V4L_BY_ID, p) if os.path.realpath(p) == device: return p return device
def _get_ctrl(device, control): global _ctrl_values_cache device = utils.make_str(device) if not device_present(device): return None if device in _ctrl_values_cache and control in _ctrl_values_cache[device]: return _ctrl_values_cache[device][control] controls = _list_ctrls(device) properties = controls.get(control) if properties is None: logging.debug('control %(control)s not found for device %(device)s' % { 'control': control, 'device': device }) return None value = int(properties['value']) # adjust the value range if 'min' in properties and 'max' in properties: min_value = int(properties['min']) max_value = int(properties['max']) value = int( round((value - min_value) * 100.0 / (max_value - min_value))) else: logging.warn( 'min and max values not found for control %(control)s of device %(device)s' % { 'control': control, 'device': device }) logging.debug('control %(control)s of device %(device)s is %(value)s%%' % { 'control': control, 'device': device, 'value': value }) return value
def _get_ctrl(device, control): global _ctrl_values_cache device = utils.make_str(device) if not device_present(device): return None if device in _ctrl_values_cache and control in _ctrl_values_cache[device]: return _ctrl_values_cache[device][control] controls = _list_ctrls(device) properties = controls.get(control) if properties is None: logging.warn("control %(control)s not found for device %(device)s" % {"control": control, "device": device}) return None value = int(properties["value"]) # adjust the value range if "min" in properties and "max" in properties: min_value = int(properties["min"]) max_value = int(properties["max"]) value = int(round((value - min_value) * 100.0 / (max_value - min_value))) else: logging.warn( "min and max values not found for control %(control)s of device %(device)s" % {"control": control, "device": device} ) logging.debug( "control %(control)s of device %(device)s is %(value)s%%" % {"control": control, "device": device, "value": value} ) return value
def _get_ctrl(device, control): global _ctrl_values_cache device = utils.make_str(device) if not device_present(device): return None if device in _ctrl_values_cache and control in _ctrl_values_cache[device]: return _ctrl_values_cache[device][control] controls = _list_ctrls(device) properties = controls.get(control) if properties is None: logging.debug('control %(control)s not found for device %(device)s' % { 'control': control, 'device': device}) return None value = int(properties['value']) # adjust the value range if 'min' in properties and 'max' in properties: min_value = int(properties['min']) max_value = int(properties['max']) value = int(round((value - min_value) * 100.0 / (max_value - min_value))) else: logging.warn('min and max values not found for control %(control)s of device %(device)s' % { 'control': control, 'device': device}) logging.debug('control %(control)s of device %(device)s is %(value)s%%' % { 'control': control, 'device': device, 'value': value}) return value
def _list_ctrls(device): global _ctrls_cache device = utils.make_str(device) if device in _ctrls_cache: return _ctrls_cache[device] output = '' started = time.time() p = subprocess.Popen('v4l2-ctl -d %(device)s --list-ctrls' % {'device': pipes.quote(device)}, shell=True, stdout=subprocess.PIPE, bufsize=1) fd = p.stdout.fileno() fl = fcntl.fcntl(fd, fcntl.F_GETFL) fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) while True: try: data = p.stdout.read(1024) if not data: break except IOError: data = '' time.sleep(0.01) output += data if len(output) > 10240: logging.warn('v4l2-ctl command returned more than 10k of output') break if time.time() - started > 3: logging.warn('v4l2-ctl command ran for more than 3 seconds') break try: # try to kill the v4l2-ctl subprocess p.kill() except: pass # nevermind controls = {} for line in output.split('\n'): if not line: continue match = re.match('^\s*(\w+)\s+\(\w+\)\s*:\s*(.+)\s*', line) if not match: continue (control, properties) = match.groups() properties = dict( [v.split('=', 1) for v in properties.split(' ') if v.count('=')]) controls[control] = properties _ctrls_cache[device] = controls return controls
def _set_ctrl(device, control, value): global _ctrl_values_cache device = utils.make_str(device) if not device_present(device): return controls = _list_ctrls(device) properties = controls.get(control) if properties is None: logging.debug('control %(control)s not found for device %(device)s' % { 'control': control, 'device': device }) return _ctrl_values_cache.setdefault(device, {})[control] = value # adjust the value range if 'min' in properties and 'max' in properties: min_value = int(properties['min']) max_value = int(properties['max']) value = int(round(min_value + value * (max_value - min_value) / 100.0)) else: logging.warn( 'min and max values not found for control %(control)s of device %(device)s' % { 'control': control, 'device': device }) logging.debug( 'setting control %(control)s of device %(device)s to %(value)s' % { 'control': control, 'device': device, 'value': value }) output = '' started = time.time() cmd = 'v4l2-ctl -d %(device)s --set-ctrl %(control)s=%(value)s' % { 'device': pipes.quote(device), 'control': pipes.quote(control), 'value': pipes.quote(str(value)) } p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, bufsize=1) fd = p.stdout.fileno() fl = fcntl.fcntl(fd, fcntl.F_GETFL) fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) while True: try: data = p.stdout.read(1024) if not data: break except IOError: data = '' time.sleep(0.01) output += data if len(output) > 10240: logging.warn('v4l2-ctl command returned more than 10k of output') break if time.time() - started > 3: logging.warn('v4l2-ctl command ran for more than 3 seconds') break try: # try to kill the v4l2-ctl subprocess p.kill() except: pass # nevermind
def list_resolutions(device): global _resolutions_cache device = utils.make_str(device) if device in _resolutions_cache: return _resolutions_cache[device] logging.debug('listing resolutions of device %(device)s...' % {'device': device}) resolutions = set() output = '' started = time.time() p = subprocess.Popen('v4l2-ctl -d "%(device)s" --list-formats-ext | grep -vi stepwise | grep -oE "[0-9]+x[0-9]+" || true' % { 'device': device}, shell=True, stdout=subprocess.PIPE, bufsize=1) fd = p.stdout.fileno() fl = fcntl.fcntl(fd, fcntl.F_GETFL) fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) while True: try: data = p.stdout.read(1024) if not data: break except IOError: data = '' time.sleep(0.01) output += data if len(output) > 10240: logging.warn('v4l2-ctl command returned more than 10k of output') break if time.time() - started > 3: logging.warn('v4l2-ctl command ran for more than 3 seconds') break try: # try to kill the v4l2-ctl subprocess p.kill() except: pass # nevermind for pair in output.split('\n'): pair = pair.strip() if not pair: continue width, height = pair.split('x') width = int(width) height = int(height) if (width, height) in resolutions: continue # duplicate resolution if width < 96 or height < 96: # some reasonable minimal values continue if width % 16 or height % 16: # ignore non-modulo 16 resolutions continue resolutions.add((width, height)) logging.debug('found resolution %(width)sx%(height)s for device %(device)s' % { 'device': device, 'width': width, 'height': height}) if not resolutions: logging.debug('no resolutions found for device %(device)s, using common values' % {'device': device}) # no resolution returned by v4l2-ctl call, add common default resolutions resolutions = utils.COMMON_RESOLUTIONS resolutions = list(sorted(resolutions, key=lambda r: (r[0], r[1]))) _resolutions_cache[device] = resolutions return resolutions
def _set_ctrl(device, control, value): global _ctrl_values_cache device = utils.make_str(device) if not device_present(device): return controls = _list_ctrls(device) properties = controls.get(control) if properties is None: logging.debug('control %(control)s not found for device %(device)s' % { 'control': control, 'device': device}) return _ctrl_values_cache.setdefault(device, {})[control] = value # adjust the value range if 'min' in properties and 'max' in properties: min_value = int(properties['min']) max_value = int(properties['max']) value = int(round(min_value + value * (max_value - min_value) / 100.0)) else: logging.warn('min and max values not found for control %(control)s of device %(device)s' % { 'control': control, 'device': device}) logging.debug('setting control %(control)s of device %(device)s to %(value)s' % { 'control': control, 'device': device, 'value': value}) output = '' started = time.time() p = subprocess.Popen('v4l2-ctl -d "%(device)s" --set-ctrl %(control)s=%(value)s' % { 'device': device, 'control': control, 'value': value}, shell=True, stdout=subprocess.PIPE, bufsize=1) fd = p.stdout.fileno() fl = fcntl.fcntl(fd, fcntl.F_GETFL) fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) while True: try: data = p.stdout.read(1024) if not data: break except IOError: data = '' time.sleep(0.01) output += data if len(output) > 10240: logging.warn('v4l2-ctl command returned more than 10k of output') break if time.time() - started > 3: logging.warn('v4l2-ctl command ran for more than 3 seconds') break try: # try to kill the v4l2-ctl subprocess p.kill() except: pass # nevermind
def list_resolutions(device): import motionctl global _resolutions_cache device = utils.make_str(device) if device in _resolutions_cache: return _resolutions_cache[device] logging.debug('listing resolutions of device %(device)s...' % {'device': device}) resolutions = set() output = '' started = time.time() cmd = 'v4l2-ctl -d %(device)s --list-formats-ext | grep -vi stepwise | grep -oE "[0-9]+x[0-9]+" || true' % { 'device': pipes.quote(device) } p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, bufsize=1) fd = p.stdout.fileno() fl = fcntl.fcntl(fd, fcntl.F_GETFL) fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) while True: try: data = p.stdout.read(1024) if not data: break except IOError: data = '' time.sleep(0.01) output += data if len(output) > 10240: logging.warn('v4l2-ctl command returned more than 10k of output') break if time.time() - started > _V4L2_TIMEOUT: logging.warn('v4l2-ctl command ran for more than %s seconds' % _V4L2_TIMEOUT) break try: # try to kill the v4l2-ctl subprocess p.kill() except: pass # nevermind for pair in output.split('\n'): pair = pair.strip() if not pair: continue width, height = pair.split('x') width = int(width) height = int(height) if (width, height) in resolutions: continue # duplicate resolution if width < 96 or height < 96: # some reasonable minimal values continue if not motionctl.resolution_is_valid(width, height): continue resolutions.add((width, height)) logging.debug( 'found resolution %(width)sx%(height)s for device %(device)s' % { 'device': device, 'width': width, 'height': height }) if not resolutions: logging.debug( 'no resolutions found for device %(device)s, using common values' % {'device': device}) # no resolution returned by v4l2-ctl call, add common default resolutions resolutions = utils.COMMON_RESOLUTIONS resolutions = [ r for r in resolutions if motionctl.resolution_is_valid(*r) ] resolutions = list(sorted(resolutions, key=lambda r: (r[0], r[1]))) _resolutions_cache[device] = resolutions return resolutions