Ejemplo n.º 1
0
class BlueZGattService(DBusObject):
    """
    org.bluez.GattService1 interface implementation
    """

    interface_name: str = defs.GATT_SERVICE_INTERFACE

    iface: DBusInterface = DBusInterface(
            interface_name,
            Property("UUID", "s"),
            Property("Primary", "b"),
            )

    dbusInterfaces: List[DBusInterface] = [iface]

    uuid: DBusProperty = DBusProperty("UUID")
    primary: DBusProperty = DBusProperty("Primary")

    def __init__(
            self,
            uuid: str,
            primary: bool,
            index: int,
            app: 'BlueZGattApplication',  # noqa: F821
            ):
        """
        Initialize the DBusObject

        Parameters
        ----------
        uuid : str
            A string representation of the unique identifier
        primary : bool
            Whether the service is the primary service for the application it
            belongs to
        index : int
            The index of the service amongst the other service of the
            application
        app : BlueZApp
            A BlueZApp object that owns this service
        """
        self.path: str = app.base_path + "/service" + str(index)
        self.bus: client = app.bus
        self.destination: str = app.destination
        self.uuid: str = uuid
        self.primary: bool = primary
        self.loop: asyncio.AbstractEventLoop = app.loop
        self.app: 'BlueZGattApplication' = app  # noqa: F821

        self.characteristics: List[BlueZGattCharacteristic] = []
        super(BlueZGattService, self).__init__(self.path)
Ejemplo n.º 2
0
    def iface(self):
        if hasattr(self, "_iface"):
            iface = self._iface
        else:
            iface_methods = []
            for method_name, (args_xform, returns_xform,
                              fn) in self.methods.items():
                iface_methods.append(
                    Method(
                        method_name,
                        arguments=args_xform.signature(),
                        returns=returns_xform.signature(),
                    ))

            iface_properties = []
            for prop_name, (xform, _, kwargs) in self.properties.items():
                iface_properties.append(
                    Property(prop_name, xform.signature(), **kwargs))

            iface_signals = []
            for signal_name, xform in self.signals.items():
                iface_signals.append(Signal(signal_name, xform.signature()))

            iface = DBusInterface(
                f"{self.service.namespace}.{self.iface_name}",
                *(iface_methods + iface_properties + iface_signals),
            )
            self._iface = iface
        return iface
Ejemplo n.º 3
0
class BlueZLEAdvertisement(DBusObject):
    """
    org.bluez.LEAdvertisement1 interface implementation
    """

    interface_name: str = "org.bluez.LEAdvertisement1"

    iface: DBusInterface = DBusInterface(
        interface_name, Method("Release"), Property("Type", "s"),
        Property("ServiceUUIDs", "as"), Property("ManufacturerData", "a{qay}"),
        Property("SolicitUUIDs", "as"), Property("ServiceData", "a{sv}"),
        Property("IncludeTxPower", "b"))

    dbusInterfaces: List[DBusInterface] = [iface]

    ad_type: DBusProperty = DBusProperty("Type")
    service_uuids: DBusProperty = DBusProperty("ServiceUUIDs")
    # manufacturer_data = DBusProperty("ManufacturerData")
    # solicit_uuids = DBusProperty("SolicitUUIDs")
    # service_data = DBusProperty("ServiceData")
    include_tx_power: DBusProperty = DBusProperty("IncludeTxPower")

    def __init__(
            self,
            advertising_type: Type,
            index: int,
            app: "BlueZGattApplication"  # noqa: F821
    ):
        """
        New Low Energy Advertisement

        Parameters
        ----------
        advertising_type : Type
            The type of advertisement
        index : int,
            The index of the advertisement
        app : BlueZGattApplication
            The Application that is responsible for this advertisement
        """
        self.ad_type: str = advertising_type.value
        self.path = app.base_path + "/advertisement" + str(index)

        self.service_uuids: List[str] = []
        self.manufacturer_data: Dict = {}
        self.solicit_uuids = ['']
        self.service_data = {'': 0}

        self.include_tx_power: bool = False

        self.data = None
        super(BlueZLEAdvertisement, self).__init__(self.path)

    @dbusMethod(interface_name, "Release")
    def Release(self):  # noqa: N802
        print("%s: Released!" % self.path)
Ejemplo n.º 4
0
class BlueZGattService(DBusObject):
    """
    org.bluez.GattService1 interface implementation
    """

    interface_name: str = defs.GATT_SERVICE_INTERFACE

    iface: DBusInterface = DBusInterface(
        interface_name,
        Property("UUID", "s"),
        Property("Primary", "b"),
    )

    dbusInterfaces: List[DBusInterface] = [iface]

    uuid: DBusProperty = DBusProperty("UUID")
    primary: DBusProperty = DBusProperty("Primary")

    def __init__(
        self,
        uuid: str,
        primary: bool,
        index: int,
        app: "BlueZGattApplication",  # noqa: F821
    ):
        """
        Initialize the DBusObject

        Parameters
        ----------
        uuid : str
            A string representation of the unique identifier
        primary : bool
            Whether the service is the primary service for the application it
            belongs to
        index : int
            The index of the service amongst the other service of the
            application
        app : BlueZApp
            A BlueZApp object that owns this service
        """
        hex_index: str = hex(index)[2:].rjust(4, "0")
        self.path: str = app.base_path + "/service" + hex_index
        self.bus: client = app.bus
        self.destination: str = app.destination
        self.uuid: str = uuid
        self.primary: bool = primary
        self.loop: asyncio.AbstractEventLoop = app.loop
        self.app: "BlueZGattApplication" = app  # noqa: F821

        self.characteristics: List[BlueZGattCharacteristic] = []
        super(BlueZGattService, self).__init__(self.path)

    async def add_characteristic(
        self, uuid: str, flags: List[Flags], value: Any
    ) -> BlueZGattCharacteristic:
        """
        Adds a BlueZGattCharacteristic to the service.

        Parameters
        ----------
        uuid : str
            The string representation of the UUID for the characteristic
        flags : List[Flags],
            A list of flags to apply to the characteristic
        value : Any
            The characteristic's value
        """
        index: int = len(self.characteristics) + 1
        characteristic: BlueZGattCharacteristic = BlueZGattCharacteristic(
            uuid, flags, index, self
        )
        characteristic.value = value
        self.characteristics.append(characteristic)
        await self.app._register_object(characteristic)
        return characteristic

    async def get_obj(self) -> Dict:
        """
        Obtain the underlying dictionary within the BlueZ API that describes
        the service

        Returns
        -------
        Dict
            The dictionary that describes the service
        """
        dbus_obj: RemoteDBusObject = await self.app.bus.getRemoteObject(
            self.app.destination, self.path
        ).asFuture(self.app.loop)
        dict_obj: Dict = await dbus_obj.callRemote(
            "GetAll",
            defs.GATT_SERVICE_INTERFACE,
            interface=defs.PROPERTIES_INTERFACE,
        ).asFuture(self.app.loop)
        return dict_obj
Ejemplo n.º 5
0
class Rfm69DBusService(objects.DBusObject):
	
	class NotImplementedError(Exception):
		dbusErrorName = "org.agile-rfm69.NotImplemented"
	
	class IOError(Exception):
		dbusErrorName = "org.agile-rfm69.IOError"
	
	class ValueError(Exception):
		dbusErrorName = "org.agile-rfm69.ValueError"
	
	class TypeError(Exception):
		dbusErrorName = "org.agile-rfm69.TypeError"
	
	iface = DBusInterface("iot.agile.Protocol",
					Method("Connect"),
					Method("Connected", returns="b"),
					Method("Disconnect"),
					Method("Setup", arguments="a{sv}"),
					Method("Send", arguments="a{sv}"),
					Method("Receive", returns="a{sv}"),
					Method("Subscribe", arguments="a{sv}"),
					Method("StartDiscovery"),
					Method("StopDiscovery"),
					Property("Devices", "av", writeable=False),
					Property("Name", "s", writeable=False),
					Property("Driver", "s", writeable=False),
					Property("Data", "a{sv}", writeable=False),
					Property("Status", "n", writeable=False)
					)
	
	_devices = DBusProperty("Devices")
	_name = DBusProperty("Name")
	_driver = DBusProperty("Driver")
	_lastRecord = DBusProperty("Data")
	_status = DBusProperty("Status")
	
	dbusInterfaces = [iface]
	
	def __init__(self, objectPath):
		super(Rfm69DBusService, self).__init__(objectPath)
		
		self._lastRecord = {"STATUS": "TIMEOUT"}
		self._status = 0
		self._driver = "No driver"
		self._name = PROTOCOL_NAME
		self._devices = ["None"]
		
		self._logger = logging.getLogger()
		self._full_path = PROTOCOL_PATH
		self._connected = False
		self._setup = {
			"MODEM_CONFIG_TABLE": MODEM_CONFIG_TABLE,
			"MODEM_CONFIG": MODEM_CONFIG,
			"key": MODEM_KEY,
			"channel": CHANNEL
		}

	def _setModemConfig(self):
		# Set RFM69 registers as per config
		settings = MODEM_CONFIG_TABLE[self._setup["MODEM_CONFIG"]]
		addresses = [0x02, 0x03, 0x04, 0x05, 0x06, 0x19, 0x1a, 0x37]
		for value, address in zip(settings, addresses):
			self._rfm69.spi_write(address, value)
			
	def _setModemKey(self):
		self._logger.debug("enabling ecryption")
		self._rfm69.set_encryption(self._setup["key"])
		
	def _getConnected(self):
		return self._connected
	
	def _setConnected(self, status):
		if status:
			self._connected = True
		else:
			self._connected = False 
	
	def dbus_Connect(self):
		self._logger.debug(
			"%s@Connect: Connect INIT", self._full_path)
		if self._getConnected():
			self._logger.debug(
				"%s@Connect: Module is already connected", self._full_path)
			raise self.IOError("Module is already connected.")
		
		self._logger.debug(
			"%s@Connect: MODE=%s", self._full_path, self._setup["MODEM_CONFIG"])
		self._rfm69 = rfm69.RFM69(25, 24, 0, rfm69.RFM69Configuration(), True)
		self._rfm69.set_channel(self._setup["channel"])
		self._rfm69.set_address(1)
		
		self._logger.debug("Class initialized")
		self._logger.debug("Calibrating RSSI")
		# self._rfm69.calibrate_rssi_threshold()
		self._logger.debug("Checking temperature")
		self._logger.debug(self._rfm69.read_temperature())
		
		# Make sure settings are correct to talk to other radios
		self._setModemConfig()
		self._setModemKey()
		
		self._logger.debug("reading all registers")
		for result in self._rfm69.read_registers():
			self._logger.debug(result)
		
		# Won't get here if something went wrong reading temps etc.
		self._setConnected(True)
		self._logger.debug("%s@Connect: Connect OK", self._full_path)
		
	def dbus_Connected(self):
		return self._connected

	def dbus_Disconnect(self):
		self._logger.debug(
			"%s@Disconnect: Disconnect INIT", self._full_path)
		self._setConnected(False)
		self._rfm69.disconnect()
		self._logger.debug("%s@Disconnect: Disconnect OK", self._full_path) 

	def dbus_Setup(self, args):
		self._logger.debug("%s@Setup: Setup INIT", self._full_path)
		self._setup.clear()
		self._setup = {}
		
		modemConfigTable = args.pop("MODEM_CONFIG_TABLE", MODEM_CONFIG_TABLE)
		self._setup["MODEM_CONFIG_TABLE"] = modemConfigTable
		
		modemConfig = args.pop("MODEM_CONFIG", MODEM_CONFIG)
		self._setup["MODEM_CONFIG"] = modemConfig
			
		modemKey = args.pop("key", MODEM_KEY)
		self._setup["key"] = modemKey
		
		channel = args.pop("channel", CHANNEL)
		self._setup["channel"] = channel
		
		self._logger.debug(
			"%s@Setup: Parameters=%s", self._full_path, self._setup)
		self._logger.debug(
			"%s@Setup: Setup OK", self._full_path)

	def dbus_Send(self, args):
		self._logger.debug(
			"%s@Send: Send INIT", self._full_path)
		
		if not self._getConnected():
			self._logger.debug(
				"%s@Send: Module is not connected", self._full_path)
			raise self.IOError("Module is not connected.")
		
		sendData = args.pop("DATA", "")
		
		if not sendData:
			self._logger.debug(
				"%s@Send/Rfm69: No data provided", self._full_path)
			raise self.ValueError("You must provide the data.")
		
		if not type(sendData) is list:
			self._logger.debug(
				"%s@Send/Rfm69: Data in wrong format", self._full_path)
			raise self.TypeError("You must provide the data as a list of values.")
		
		# Turn it back into bytes again, since D-Bus turns it into a list
		sendData = struct.pack("B"*len(sendData), *sendData)
		self._rfm69.send_packet(sendData)
	
	def dbus_Receive(self):
		self._logger.debug("%s@Receive: Receive INIT", self._full_path)
		if not self._getConnected():
			self._logger.debug(
				"%s@Receive: Module is not connected", self._full_path)
			raise self.IOError("Module is not connected.")
		
		response = self._rfm69.wait_for_packet(timeout=60)
		if response:
			(data, rssi) = response
			self._logger.debug("%s@Receive: receiveDone()", self._full_path)
			self._lastRecord = {"DATA": data, "RSSI": rssi, "STATUS": "OK"}
		else:
			self._lastRecord = {"STATUS": "TIMEOUT"}
		
		return self._lastRecord
		
	def dbus_Subscribe(self, args):
		raise self.NotImplementedError("Function not supported.")
	
	def dbus_StartDiscovery(self):
		pass
	
	def dbus_StopDiscovery(self):
		pass
Ejemplo n.º 6
0
class BlueZGattCharacteristic(DBusObject):
    """
    org.bluez.GattCharacteristic1 interface implementation
    """

    interface_name: str = defs.GATT_CHARACTERISTIC_INTERFACE

    iface: DBusInterface = DBusInterface(
        interface_name,
        Method("ReadValue", arguments="a{sv}", returns="ay"),
        Method("WriteValue", arguments="aya{sv}"),
        Method("StartNotify"),
        Method("StopNotify"),
        Property("UUID", "s"),
        Property("Service", "o"),
        Property("Value", "ay"),
        Property("Notifying", "b"),
        Property("Flags", "as"),
    )

    dbusInterfaces: List[DBusInterface] = [iface]

    uuid: DBusProperty = DBusProperty("UUID")
    service: DBusProperty = DBusProperty("Service")
    flags: DBusProperty = DBusProperty("Flags")
    value: DBusProperty = DBusProperty("Value")
    notifying: DBusProperty = DBusProperty("Notifying")

    def __init__(
            self,
            uuid: str,
            flags: List[Flags],
            index: int,
            service: "BlueZGattService",  # noqa: F821
    ):
        """
        Create a BlueZ Gatt Characteristic

        Parameters
        ----------
        uuid : str
            The unique identifier for the characteristic
        flags : List[Flags]
            A list of strings that represent the properties of the
            characteristic
        index : int
            The index number for this characteristic in the service
        service : BlueZService
            The Gatt Service that owns this characteristic
        """
        self.path: str = service.path + "/char" + f"{index:04d}"
        self.uuid: str = uuid
        self.flags: List[str] = [x.value for x in flags]
        self.service: str = service.path  # noqa: F821
        self._service: "BlueZGattService" = service  # noqa: F821

        self.value: bytes = b""
        self.notifying: bool = False
        self.descriptors: List["BlueZGattDescriptor"] = []  # noqa: F821

        super(BlueZGattCharacteristic, self).__init__(self.path)

    @dbusMethod(interface_name, "ReadValue")
    def ReadValue(self, options: Dict) -> bytearray:  # noqa: N802
        """
        Read the value of the characteristic.
        This is to be fully implemented at the application level

        Parameters
        ----------
        options : Dict
            A list of options

        Returns
        -------
        bytearray
            The bytearray that is the value of the characteristic
        """
        f = self._service.app.Read
        if f is None:
            raise NotImplementedError()
        return f(self)

    @dbusMethod(interface_name, "WriteValue")
    def WriteValue(self, value: bytearray, options: Dict):  # noqa: N802
        """
        Write a value to the characteristic
        This is to be fully implemented at the application level

        Parameters
        ----------
        value : bytearray
            The value to set
        options : Dict
            Some options for you to select from
        """
        f = self._service.app.Write
        if f is None:
            raise NotImplementedError()
        f(self, value)

    @dbusMethod(interface_name, "StartNotify")
    def StartNotify(self):  # noqa: N802
        """
        Begin a subscription to the characteristic
        """
        f = self._service.app.StartNotify
        if f is None:
            raise NotImplementedError()
        f(None)
        self._service.app.subscribed_characteristics.append(self.uuid)

    @dbusMethod(interface_name, "StopNotify")
    def StopNotify(self):  # noqa: N802
        """
        Stop a subscription to the characteristic
        """
        f = self._service.app.StopNotify
        if f is None:
            raise NotImplementedError()
        f(None)
        self._service.app.subscribed_characteristics.remove(self.uuid)

    async def get_obj(self) -> Dict:
        """
        Obtain the underlying dictionary within the BlueZ API that describes
        the characteristic

        Returns
        -------
        Dict
            The dictionary that describes the characteristic
        """
        dbus_obj: RemoteDBusObject = await self._service.app.bus.getRemoteObject(
            self._service.app.destination,
            self.path).asFuture(self._service.app.loop)
        dict_obj: Dict = await dbus_obj.callRemote(
            "GetAll",
            defs.GATT_CHARACTERISTIC_INTERFACE,
            interface=defs.PROPERTIES_INTERFACE,
        ).asFuture(self._service.app.loop)
        return dict_obj