def handler_value_changes(self, changes, path, senderId): try: service = self.servicesById[senderId] a = service.paths[path] except KeyError: # Either senderId or path isn't there, which means # it hasn't been scanned yet. return # If this properyChange does not involve a value, our work is done. if 'Value' not in changes: return service.set_seen(path) # First update our store to the new value changes['Value'] = unwrap_dbus_value(changes['Value']) if a.value == changes['Value']: return a.value = changes['Value'] try: a.text = changes['Text'] except KeyError: # Some services don't send Text with their PropertiesChanged events. a.text = str(a.value) # And do the rest of the processing in on the mainloop if self.valueChangedCallback is not None: idle_add(exit_on_error, self._execute_value_changes, service.name, path, changes, a.options)
def __init__(self, bus, serviceName, path, eventCallback=None, createsignal=True): # TODO: is it necessary to store _serviceName and _path? Isn't it # stored in the bus_getobjectsomewhere? self._serviceName = serviceName self._path = path self._match = None # TODO: _proxy is being used in settingsdevice.py, make a getter for that self._proxy = bus.get_object(serviceName, path, introspect=False) self.eventCallback = eventCallback assert eventCallback is None or createsignal == True if createsignal: self._match = self._proxy.connect_to_signal( "PropertiesChanged", weak_functor(self._properties_changed_handler)) # store the current value in _cachedvalue. When it doesn't exists set _cachedvalue to # None, same as when a value is invalid self._cachedvalue = None try: v = self._proxy.GetValue() except dbus.exceptions.DBusException: pass else: self._cachedvalue = unwrap_dbus_value(v)
def handler_value_changes(self, changes, path, senderId): try: service = self.servicesById[senderId] a = service['paths'][path] except KeyError: # Either senderId or path isn't there, which means # it hasn't been scanned yet. return # If this properyChange does not involve a value, our work is done. if 'Value' not in changes: return # First update our store to the new value changes['Value'] = unwrap_dbus_value(changes['Value']) if a[0] == changes['Value']: return a[0] = changes['Value'] try: a[1] = changes['Text'] except KeyError: # Some services don't send Text with their PropertiesChanged events. a[1] = str(a[0]) # And do the rest of the processing in on the mainloop if self.valueChangedCallback is not None: idle_add(exit_on_error, self._execute_value_changes, service['name'], path, changes, a[2])
def _on_dbus_value_changed(self, changes, path=None, service_id=None): service = self._service_ids.get(service_id) if service is None: return uid = service + path topic = self._topics.get(uid) if topic is None: for service_short_name, service_name in self._services.items(): if service_name == service: device_instance = service_short_name.split('/')[1] self._add_item(service, device_instance, path, publish=False, get_value=False) logging.info('New item found: {}{}'.format( service_short_name, path)) topic = self._topics[uid] break else: return value = changes.get("Value") if value is None: return value = unwrap_dbus_value(value) self._values[topic] = value self._publish(topic, value)
def handler_value_changes(self, changes, path, senderId): try: service = self.servicesById[senderId] a = service['paths'][path] except KeyError: # Either senderId or path isn't there, which means # it hasn't been scanned yet. return # If this properyChange does not involve a value, our work is done. if 'Value' not in changes: return # First update our store to the new value changes['Value'] = unwrap_dbus_value(changes['Value']) if a[0] == changes['Value']: return a[0] = changes['Value'] a[1] = changes['Text'] # And do the rest of the processing in on the mainloop if self.valueChangedCallback is not None: idle_add(exit_on_error, self._execute_value_changes, service['name'], path, changes, a[2])
def _properties_changed_handler(self, changes): if "Value" in changes: changes['Value'] = unwrap_dbus_value(changes['Value']) self._cachedvalue = changes['Value'] if self._eventCallback: # The reason behind this try/except is to prevent errors silently ending up the an error # handler in the dbus code. try: self._eventCallback(self._serviceName, self._path, changes) except: traceback.print_exc() os._exit(1) # sys.exit() is not used, since that also throws an exception
def _properties_changed_handler(self, changes): if "Value" in changes: changes['Value'] = unwrap_dbus_value(changes['Value']) self._cachedvalue = changes['Value'] if self._eventCallback: # The reason behind this try/except is to prevent errors silently ending up the an error # handler in the dbus code. try: self._eventCallback(self._serviceName, self._path, changes) except: traceback.print_exc() os._exit(1) # sys.exit() is not used, since that also throws an exception
def _scan_dbus_service(self, service, publish=True): try: logging.info('[Scanning] service: {}'.format(service)) try: device_instance = int( self._get_dbus_value(service, '/DeviceInstance')) except dbus.exceptions.DBusException as e: if e.get_dbus_name() == 'org.freedesktop.DBus.Error.UnknownObject' or \ e.get_dbus_name() == 'org.freedesktop.DBus.Error.UnknownMethod': device_instance = 0 else: raise except TypeError: device_instance = 0 short_service_name = get_short_service_name( service, device_instance) self._services[short_service_name] = service try: items = self._get_dbus_value(service, '/') except dbus.exceptions.DBusException as e: if e.get_dbus_name() == 'org.freedesktop.DBus.Error.UnknownObject' or \ e.get_dbus_name() == 'org.freedesktop.DBus.Error.UnknownMethod': self._introspect(service, device_instance, '/', publish) logging.warn( '[Scanning] {} does not provide an item listing'. format(service)) return else: raise if isinstance(items, dict): for path, value in items.items(): self._add_item(service, device_instance, path, value=unwrap_dbus_value(value), publish=publish, get_value=False) except dbus.exceptions.DBusException, e: if e.get_dbus_name() == 'org.freedesktop.DBus.Error.ServiceUnknown' or \ e.get_dbus_name() == 'org.freedesktop.DBus.Error.Disconnected': logging.info( "[Scanning] Service disappeared while being scanned: %s", service) elif e.get_dbus_name() == 'org.freedesktop.DBus.Error.NoReply': logging.info( "[Scanning] No response from service during scan: %s", service) else: raise
def SetValue(self, newvalue): if not self._writeable: return 1 # NOT OK newvalue = unwrap_dbus_value(newvalue) if newvalue == self._value: return 0 # OK # call the callback given to us, and check if new value is OK. if (self._onchangecallback is None or (self._onchangecallback is not None and self._onchangecallback(self.__dbus_object_path__, newvalue))): self.local_set_value(newvalue) return 0 # OK return 2 # NOT OK
def SetValue(self, newvalue): if not self._writeable: return 1 # NOT OK newvalue = unwrap_dbus_value(newvalue) if newvalue == self._value: return 0 # OK # call the callback given to us, and check if new value is OK. if (self._onchangecallback is None or (self._onchangecallback is not None and self._onchangecallback(self.__dbus_object_path__, newvalue))): self.local_set_value(newvalue) return 0 # OK return 2 # NOT OK
def __init__(self, bus, serviceName, path, eventCallback=None, createsignal=True): # TODO: is it necessary to store _serviceName and _path? Isn't it # stored in the bus_getobjectsomewhere? self._serviceName = serviceName self._path = path self._match = None # TODO: _proxy is being used in settingsdevice.py, make a getter for that self._proxy = bus.get_object(serviceName, path, introspect=False) self.eventCallback = eventCallback assert eventCallback is None or createsignal == True if createsignal: self._match = self._proxy.connect_to_signal( "PropertiesChanged", weak_functor(self._properties_changed_handler)) # store the current value in _cachedvalue. When it doesn't exists set _cachedvalue to # None, same as when a value is invalid self._cachedvalue = None try: v = self._proxy.GetValue() except dbus.exceptions.DBusException: pass else: self._cachedvalue = unwrap_dbus_value(v)
def scan_dbus_service_inner(self, serviceName): # make it a normal string instead of dbus string serviceName = str(serviceName) paths = self.dbusTree.get('.'.join(serviceName.split('.')[0:3]), None) if paths is None: logger.debug("Ignoring service %s, not in the tree" % serviceName) return False logger.info("Found: %s, scanning and storing items" % serviceName) serviceId = self.dbusConn.get_name_owner(serviceName) # we should never be notified to add a D-Bus service that we already have. If this assertion # raises, check process_name_owner_changed, and D-Bus workings. assert serviceName not in self.servicesByName assert serviceId not in self.servicesById # for vebus.ttyO1, this is workaround, since VRM Portal expects the main vebus # devices at instance 0. Not sure how to fix this yet. if serviceName == 'com.victronenergy.vebus.ttyO1' and self.vebusDeviceInstance0: di = 0 elif serviceName == 'com.victronenergy.settings': di = 0 elif serviceName.startswith('com.victronenergy.vecan.'): di = 0 else: try: di = self.dbusConn.call_blocking(serviceName, '/DeviceInstance', None, 'GetValue', '', []) except dbus.exceptions.DBusException: logger.info( " %s was skipped because it has no device instance" % serviceName) return False # Skip it else: di = int(di) logger.info(" %s has device instance %s" % (serviceName, di)) service = Service(serviceId, serviceName, di) # Let's try to fetch everything in one go values = {} texts = {} try: values.update( self.dbusConn.call_blocking(serviceName, '/', None, 'GetValue', '', [])) texts.update( self.dbusConn.call_blocking(serviceName, '/', None, 'GetText', '', [])) except: pass for path, options in paths.iteritems(): # path will be the D-Bus path: '/Ac/ActiveIn/L1/V' # options will be a dictionary: {'code': 'V', 'whenToLog': 'onIntervalAlways'} # check that the whenToLog setting is set to something we expect assert options['whenToLog'] is None or options[ 'whenToLog'] in Service.whentologoptions # Try to obtain the value we want from our bulk fetch. If we # cannot find it there, do an individual query. value = values.get(path[1:], notfound) if value != notfound: service.set_seen(path) text = texts.get(path[1:], notfound) if value is notfound or text is notfound: try: value = self.dbusConn.call_blocking( serviceName, path, None, 'GetValue', '', []) service.set_seen(path) text = self.dbusConn.call_blocking(serviceName, path, None, 'GetText', '', []) except dbus.exceptions.DBusException as e: if e.get_dbus_name() in ( 'org.freedesktop.DBus.Error.ServiceUnknown', 'org.freedesktop.DBus.Error.Disconnected'): raise # This exception will be handled below # TODO org.freedesktop.DBus.Error.UnknownMethod really # shouldn't happen but sometimes does. logger.debug("%s %s does not exist (yet)" % (serviceName, path)) value = None text = None service.paths[path] = MonitoredValue(unwrap_dbus_value(value), unwrap_dbus_value(text), options) if options['whenToLog']: service[options['whenToLog']].append(path) logger.debug("Finished scanning and storing items for %s" % serviceName) # Adjust self at the end of the scan, so we don't have an incomplete set of # data if an exception occurs during the scan. self.servicesByName[serviceName] = service self.servicesById[serviceId] = service self.servicesByClass[service.service_class].append(service) return True
def _refreshcachedvalue(self): self._cachedvalue = unwrap_dbus_value(self._proxy.GetValue())
def scan_dbus_service_inner(self, serviceName): # make it a normal string instead of dbus string serviceName = str(serviceName) paths = self.dbusTree.get('.'.join(serviceName.split('.')[0:3]), None) if paths is None: logger.debug("Ignoring service %s, not in the tree" % serviceName) return False logger.info("Found: %s, scanning and storing items" % serviceName) # we should never be notified to add a D-Bus service that we already have. If this assertion # raises, check process_name_owner_changed, and D-Bus workings. assert serviceName not in self.servicesByName service = {'name': serviceName, 'paths': {}} # create the empty list items. whentologoptions = ['configChange', 'onIntervalAlwaysAndOnEvent', 'onIntervalOnlyWhenChanged', 'onIntervalAlways'] # these lists will contain the VeDbusItemImport objects with that whenToLog setting. Used to for whentolog in whentologoptions: service[whentolog] = [] serviceId = self.dbusConn.get_name_owner(serviceName) service['id'] = serviceId assert serviceId not in self.servicesById # for vebus.ttyO1, this is workaround, since VRM Portal expects the main vebus # devices at instance 0. Not sure how to fix this yet. if serviceName == 'com.victronenergy.vebus.ttyO1' and self.vebusDeviceInstance0: di = 0 elif serviceName == 'com.victronenergy.settings': di = 0 elif serviceName.startswith('com.victronenergy.vecan.'): di = 0 else: try: di = self.dbusConn.call_blocking(serviceName, '/DeviceInstance', None, 'GetValue', '', []) except dbus.exceptions.DBusException: logger.info(" %s was skipped because it has no device instance" % serviceName) return False # Skip it else: di = int(di) service['deviceInstance'] = di logger.info(" %s has device instance %s" % (serviceName, di)) # Let's try to fetch everything in one go values = {} texts = {} try: values.update(self.dbusConn.call_blocking(serviceName, '/', None, 'GetValue', '', [])) texts.update(self.dbusConn.call_blocking(serviceName, '/', None, 'GetText', '', [])) except: pass for path, options in paths.iteritems(): # path will be the D-Bus path: '/Ac/ActiveIn/L1/V' # options will be a dictionary: {'code': 'V', 'whenToLog': 'onIntervalAlways'} # check that the whenToLog setting is set to something we expect assert options['whenToLog'] is None or options['whenToLog'] in whentologoptions # Try to obtain the value we want from our bulk fetch. If we # cannot find it there, do an individual query. value = values.get(path[1:], notfound) text = texts.get(path[1:], notfound) if value is notfound or text is notfound: try: value = self.dbusConn.call_blocking(serviceName, path, None, 'GetValue', '', []) text = self.dbusConn.call_blocking(serviceName, path, None, 'GetText', '', []) except dbus.exceptions.DBusException as e: if e.get_dbus_name() in ( 'org.freedesktop.DBus.Error.ServiceUnknown', 'org.freedesktop.DBus.Error.Disconnected'): raise # This exception will be handled below # TODO org.freedesktop.DBus.Error.UnknownMethod really # shouldn't happen but sometimes does. logger.debug("%s %s does not exist (yet)" % (serviceName, path)) value = None text = None service['paths'][path] = [unwrap_dbus_value(value), unwrap_dbus_value(text), options] if options['whenToLog']: service[options['whenToLog']].append(path) logger.debug("Finished scanning and storing items for %s" % serviceName) # Adjust self at the end of the scan, so we don't have an incomplete set of # data if an exception occurs during the scan. self.servicesByName[serviceName] = service self.servicesById[serviceId] = service return True
def scan_dbus_service_inner(self, serviceName): # make it a normal string instead of dbus string serviceName = str(serviceName) paths = self.dbusTree.get('.'.join(serviceName.split('.')[0:3]), None) if paths is None: logger.debug("Ignoring service %s, not in the tree" % serviceName) return False logger.info("Found: %s, scanning and storing items" % serviceName) # we should never be notified to add a D-Bus service that we already have. If this assertion # raises, check process_name_owner_changed, and D-Bus workings. assert serviceName not in self.servicesByName service = {'name': serviceName, 'paths': {}} # create the empty list items. whentologoptions = [ 'configChange', 'onIntervalAlwaysAndOnEvent', 'onIntervalOnlyWhenChanged', 'onIntervalAlways' ] # these lists will contain the VeDbusItemImport objects with that whenToLog setting. Used to for whentolog in whentologoptions: service[whentolog] = [] serviceId = self.dbusConn.get_name_owner(serviceName) service['id'] = serviceId assert serviceId not in self.servicesById # for vebus.ttyO1, this is workaround, since VRM Portal expects the main vebus # devices at instance 0. Not sure how to fix this yet. if serviceName == 'com.victronenergy.vebus.ttyO1' and self.vebusDeviceInstance0: di = 0 elif serviceName == 'com.victronenergy.settings': di = 0 else: di = self.dbusConn.call_blocking(serviceName, '/DeviceInstance', None, 'GetValue', '', []) di = int(di) service['deviceInstance'] = di logger.info(" %s has device instance %s" % (serviceName, di)) # Let's try to fetch everything in one go values = {} texts = {} try: values.update( self.dbusConn.call_blocking(serviceName, '/', None, 'GetValue', '', [])) texts.update( self.dbusConn.call_blocking(serviceName, '/', None, 'GetText', '', [])) except: pass for path, options in paths.iteritems(): # path will be the D-Bus path: '/Ac/ActiveIn/L1/V' # options will be a dictionary: {'code': 'V', 'whenToLog': 'onIntervalAlways'} # check that the whenToLog setting is set to something we expect assert options['whenToLog'] is None or options[ 'whenToLog'] in whentologoptions # Try to obtain the value we want from our bulk fetch. If we # cannot find it there, do an individual query. value = values.get(path[1:], notfound) text = texts.get(path[1:], notfound) if value is notfound or text is notfound: try: value = self.dbusConn.call_blocking( serviceName, path, None, 'GetValue', '', []) text = self.dbusConn.call_blocking(serviceName, path, None, 'GetText', '', []) except dbus.exceptions.DBusException as e: if e.get_dbus_name( ) == 'org.freedesktop.DBus.Error.UnknownObject': logger.debug("%s %s does not exist (yet)" % (serviceName, path)) value = None text = None else: raise service['paths'][path] = [ unwrap_dbus_value(value), unwrap_dbus_value(text), options ] if options['whenToLog']: service[options['whenToLog']].append(path) logger.debug("Finished scanning and storing items for %s" % serviceName) # Adjust self at the end of the scan, so we don't have an incomplete set of # data if an exception occurs during the scan. self.servicesByName[serviceName] = service self.servicesById[serviceId] = service return True
def _refreshcachedvalue(self): self._cachedvalue = unwrap_dbus_value(self._proxy.GetValue())
def _get_dbus_value(self, service, path): value = self._dbus_conn.call_blocking(service, path, None, 'GetValue', '', []) return unwrap_dbus_value(value)
def scan_dbus_service(self, serviceName): # make it a normal string instead of dbus string serviceName = str(serviceName) paths = self.dbusTree.get('.'.join(serviceName.split('.')[0:3]), None) if paths is None: logger.debug("Ignoring service %s, not in the tree" % serviceName) return False logger.info("Found: %s, scanning and storing items" % serviceName) # we should never be notified to add a D-Bus service that we already have. If this assertion # raises, check process_name_owner_changed, and D-Bus workings. assert serviceName not in self.servicesByName service = {'name': serviceName, 'paths': {}} # create the empty list items. whentologoptions = ['configChange', 'onIntervalAlwaysAndOnEvent', 'onIntervalOnlyWhenChanged', 'onIntervalAlways'] # these lists will contain the VeDbusItemImport objects with that whenToLog setting. Used to for whentolog in whentologoptions: service[whentolog] = [] serviceId = self.dbusConn.get_name_owner(serviceName) service['id'] = serviceId assert serviceId not in self.servicesById try: # for vebus.ttyO1, this is workaround, since VRM Portal expects the main vebus devices at # instance 0. Not sure how to fix this yet. if serviceName == 'com.victronenergy.vebus.ttyO1' and self.vebusDeviceInstance0: device_instance = 0 else: try: device_instance = self.dbusConn.call_blocking(serviceName, '/DeviceInstance', None, 'GetValue', '', []) device_instance = 0 if device_instance is None else int(device_instance) except dbus.exceptions.DBusException as e: device_instance = 0 service['deviceInstance'] = device_instance logger.info(" %s has device instance %s" % (serviceName, service['deviceInstance'])) for path, options in paths.iteritems(): # path will be the D-Bus path: '/Ac/ActiveIn/L1/V' # options will be a dictionary: {'code': 'V', 'whenToLog': 'onIntervalAlways'} # check that the whenToLog setting is set to something we expect assert options['whenToLog'] is None or options['whenToLog'] in whentologoptions try: value = self.dbusConn.call_blocking(serviceName, path, None, 'GetValue', '', []) except dbus.exceptions.DBusException as e: if e.get_dbus_name() == 'org.freedesktop.DBus.Error.ServiceUnknown' or \ e.get_dbus_name() == 'org.freedesktop.DBus.Error.Disconnected': raise # These exception will be handled below # TODO: Look into this, perhaps filter more specifically on this error: # org.freedesktop.DBus.Error.UnknownMethod logger.debug("%s %s does not exist (yet)" % (serviceName, path)) value = None service['paths'][path] = [unwrap_dbus_value(value), options] if options['whenToLog']: service[options['whenToLog']].append(path) logger.debug(" Added %s%s" % (serviceName, path)) logger.debug("Finished scanning and storing items for %s" % serviceName) # Adjust self at the end of the scan, so we don't have an incomplete set of # data if an exception occurs during the scan. self.servicesByName[serviceName] = service self.servicesById[serviceId] = service except dbus.exceptions.DBusException as e: if e.get_dbus_name() == 'org.freedesktop.DBus.Error.ServiceUnknown' or \ e.get_dbus_name() == 'org.freedesktop.DBus.Error.Disconnected': logger.info("Service disappeared while being scanned: %s" % serviceName) return False else: raise return True