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)
Beispiel #2
0
    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])
Beispiel #4
0
 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)
Beispiel #5
0
    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])
Beispiel #6
0
	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
Beispiel #7
0
	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
Beispiel #8
0
 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
Beispiel #9
0
	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
Beispiel #10
0
	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
Beispiel #11
0
	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
Beispiel #13
0
	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
Beispiel #15
0
    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
Beispiel #16
0
	def _refreshcachedvalue(self):
		self._cachedvalue = unwrap_dbus_value(self._proxy.GetValue())
Beispiel #17
0
 def _get_dbus_value(self, service, path):
     value = self._dbus_conn.call_blocking(service, path, None, 'GetValue',
                                           '', [])
     return unwrap_dbus_value(value)
Beispiel #18
0
	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