Bluetooth Bluez Pairing Agent funktioniert gut in Python, aber nicht mit Dotnet und tmds.dbusC#

Ein Treffpunkt für C#-Programmierer
Guest
 Bluetooth Bluez Pairing Agent funktioniert gut in Python, aber nicht mit Dotnet und tmds.dbus

Post by Guest »

Verwenden eines Raspberry Pi Zero 2W, mit Ubuntu Bookworm Lite, habe ich 2 Programme, eine in Python und eine in C#. Beide tun dasselbe (ich wechsle zwischen dem und dem anderen zum Testen): Implementieren Sie einen Agenten für Bluez und registrieren Sie sich über DBUs und verarbeiten Sie die Paarungsfunktionen. Die Python -Version empfängt den RequestConfirmations -Anruf ordnungsgemäß und zeigt den PassKey an. Wenn die C# -Version ausgeführt wird, gibt es einen DBUS -Fehler, der besagt, dass: Methode "RequestConfirmation" mit Signature "OU" auf der Schnittstelle "org.Bluez.agent1" nicht existiert. < /P>
Versionen < /h3>

[*] Debian GNU /Linux 12 (Buchwurm) - Kernel: Linux 6.6.51+RPT -RPI -V8 - ARM64 < /li>
< li> dotnet 9 mit tmds.dbus v0.21.2 (basiert auf Windows für Target Linux 64)
[*] Python 3.11.2
Bluez 5.66
Hinweis: Beide Apps werden mit Sudo gestartet, um Zugriff auf das System DBUS < /li>
< /ul>
Hier sind die 2 Implementierungen: < /p>
Die Python-Version < /h3>

Code: Select all

#!/usr/bin/env python3
import dbus
import dbus.exceptions
import dbus.mainloop.glib
import dbus.service
from gi.repository import GLib

AGENT_PATH = "/com/kevinisabelle/gamepad/agent"

class Agent(dbus.service.Object):
AGENT_INTERFACE = "org.bluez.Agent1"

def __init__(self, bus, path=AGENT_PATH):
dbus.service.Object.__init__(self, bus, path)

@dbus.service.method(AGENT_INTERFACE, in_signature="", out_signature="")
def Release(self):
print("Agent Released")

@dbus.service.method(AGENT_INTERFACE, in_signature="o", out_signature="u")
def RequestPasskey(self, device):
# Not used in JustWorks;  return a dummy passkey.
print("RequestPasskey for device:", device)
return dbus.UInt32(0)

@dbus.service.method(AGENT_INTERFACE, in_signature="ou", out_signature="")
def DisplayPasskey(self, device, passkey):
# No display needed for JustWorks.
print("DisplayPasskey for device:", device, passkey)

@dbus.service.method(AGENT_INTERFACE, in_signature="ou", out_signature="")
def RequestConfirmation(self, device, passkey):
print("Auto-confirming pairing for device:", device, "with passkey:", passkey)
# Simply return without raising an exception.
return

@dbus.service.method(AGENT_INTERFACE, in_signature="o", out_signature="s")
def RequestPinCode(self, device):
# Return a dummy PIN if requested.
print("RequestPinCode for device:", device)
return "0000"

@dbus.service.method(AGENT_INTERFACE, in_signature="o", out_signature="")
def RequestAuthorization(self, device):
# Auto-authorize pairing.
print("RequestAuthorization for device:", device)
return

# --- Add the missing method ---
@dbus.service.method(AGENT_INTERFACE, in_signature="os", out_signature="")
def AuthorizeService(self, device, uuid):
print("AuthorizeService called for device {} and service UUID {}".format(device, uuid))
# Auto-authorize the service request.
return

def register_agent(bus, capability="KeyboardDisplay"):
try:
manager = dbus.Interface(
bus.get_object("org.bluez", "/org/bluez"),
"org.bluez.AgentManager1")
manager.RegisterAgent(AGENT_PATH, capability)
manager.RequestDefaultAgent(AGENT_PATH)
print("Agent registered as default with {} capability".format(capability))
except Exception as e:
print("Failed to register agent:", e)

def main():
print("Starting pairing agent...")
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
bus = dbus.SystemBus()

# Register our DisplayYesNo pairing agent
agent = Agent(bus)
register_agent(bus, "KeyboardDisplay")

# Enable adapter pairing and discovery (if not already enabled)
try:
adapter = bus.get_object("org.bluez", "/org/bluez/hci0")
props_iface = dbus.Interface(adapter, "org.freedesktop.DBus.Properties")
props_iface.Set("org.bluez.Adapter1", "Powered", dbus.Boolean(True))
props_iface.Set("org.bluez.Adapter1", "Discoverable", dbus.Boolean(True))
props_iface.Set("org.bluez.Adapter1", "Pairable", dbus.Boolean(True))
try:
props_iface.Set("org.bluez.Adapter1", "MinConnectionInterval", dbus.UInt16(6))  # 7.5ms
props_iface.Set("org.bluez.Adapter1", "MaxConnectionInterval", dbus.UInt16(16)) # 20ms
props_iface.Set("org.bluez.Adapter1", "ConnectionLatency", dbus.UInt16(0))
props_iface.Set("org.bluez.Adapter1", "SupervisionTimeout", dbus.UInt16(500))  # 5s
except Exception as e:
print("Warning: Could not set connection parameters:", e)
print("Adapter set to Powered, Discoverable, and Pairable")
except Exception as e:
print("Error setting adapter properties:", e)

loop = GLib.MainLoop()
print("Running main loop")
loop.run()

if __name__ == "__main__":
main()

< /code>
 Die C# -Version < /h3>
using Tmds.DBus;

namespace AgentOnly;
// -------------------------------
// Define the D-Bus interfaces
// -------------------------------

[DBusInterface("org.bluez.Agent1")]
public interface IAgent1 : IDBusObject
{
// Called when the agent is unregistered.
Task ReleaseAsync();

// Called to request a numeric passkey for pairing.
// (Returns a uint between 0 and 999999.)
Task RequestPasskeyAsync(ObjectPath device);

// Called to display a passkey;  expects a uint passkey.
Task DisplayPasskeyAsync(ObjectPath device, uint passkey);

// Called to request confirmation of a passkey.
// (Here, we expect the passkey to be passed as a string, matching the Python "os" signature.)
Task RequestConfirmationAsync(ObjectPath device, uint passkey);

// Called to request a PIN code; returns a string PIN.
Task RequestPinCodeAsync(ObjectPath device);

// Called to request authorization for pairing.
Task RequestAuthorizationAsync(ObjectPath device);

// Called to authorize a service request; takes a device and a service UUID.
Task AuthorizeServiceAsync(ObjectPath device, string uuid);

Task CancelAsync();
}

// For agent registration
[DBusInterface("org.bluez.AgentManager1")]
public interface IAgentManager1 : IDBusObject
{
Task RegisterAgentAsync(ObjectPath agentPath, string capability);
Task RequestDefaultAgentAsync(ObjectPath agentPath);
}

[DBusInterface("org.bluez.Adapter1")]
public interface IAdapter1 : IDBusObject
{
Task SetAsync(string propertyName, object value);
}

// -------------------------------
// Implement the service classes
// -------------------------------

// Agent for pairing
[DBusInterface("org.bluez.Agent1")]
public class Agent1 : IAgent1
{
public ObjectPath ObjectPath { get; }
public Agent1(ObjectPath path) { ObjectPath = path; }

public Task ReleaseAsync()
{
Console.WriteLine("Agent Released");
return Task.CompletedTask;
}

public Task RequestPinCodeAsync(ObjectPath device)
{
Console.WriteLine("Requesting PIN code for device: " + device);
return Task.FromResult("0000");
}

public Task DisplayPinCodeAsync(ObjectPath device, string pincode)
{
Console.WriteLine("Displaying PIN code for device: " + device + " PIN: " + pincode);
return Task.CompletedTask;
}

public Task RequestPasskeyAsync(ObjectPath device)
{
Console.WriteLine("Requesting passkey for device: " + device);
return Task.FromResult((uint)123456);
}

public Task DisplayPasskeyAsync(ObjectPath device, uint passkey)
{
Console.WriteLine("Displaying passkey for device: " + device + " Passkey: " + passkey);
return Task.CompletedTask;
}

public Task RequestConfirmationAsync(ObjectPath device, uint passkey)
{
Console.WriteLine("Requesting confirmation for device: " + device + " Passkey: " + passkey);
return Task.CompletedTask;
}

public Task RequestAuthorizationAsync(ObjectPath device)
{
Console.WriteLine("Requesting authorization for device: " + device);
return Task.CompletedTask;
}

public Task AuthorizeServiceAsync(ObjectPath device, string uuid)
{
Console.WriteLine("Authorizing service for device: " + device + " UUID: " + uuid);
return Task.CompletedTask;
}

public Task CancelAsync()
{
Console.WriteLine("Agent request cancelled");
return Task.CompletedTask;
}
}

// -------------------------------
// Main program and registration helpers
// -------------------------------
public class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Starting BlueZ Agent...");
var connection = new Connection(Address.System);
await connection.ConnectAsync();

var agent = new Agent1(new ObjectPath("/com/kevinisabelle/agent"));
var capability = "KeyboardDisplay";

await connection.RegisterObjectAsync(agent);

if (args.Length > 0 && args[0] == "register")
{
var agentManager = connection.CreateProxy("org.bluez", new ObjectPath("/org/bluez"));

await agentManager.RegisterAgentAsync(agent.ObjectPath, capability);
Console.WriteLine("Agent registered with capability: "  + capability);

await Task.Delay(1000);

await agentManager.RequestDefaultAgentAsync(agent.ObjectPath);
Console.WriteLine($"Agent registered as default with {capability} capability");
}

try
{
var adapterProps = connection.CreateProxy("org.bluez", new ObjectPath("/org/bluez/hci0"));

await adapterProps.SetAsync("Powered", true);
await adapterProps.SetAsync("Discoverable", true);
await adapterProps.SetAsync("Pairable", true);

Console.WriteLine("Adapter set to Powered, Discoverable, and Pairable");
}
catch (Exception ex)
{
Console.WriteLine("Error setting adapter properties: " + ex.Message);
throw;
}

// Run forever
await Task.Delay(-1);
}
}
< /code>
Dinge, die ich bereits überprüft habe: < /p>

 Verschiedene Typen für den Uint -PassKey (mit int, String, ushort) , aber Uint ist das, was im DOC angegeben ist, und der Fehler sagt mir auch, dass die richtige Signatur "OU" (ObjectPath, uint32) < /li>
 versucht hat, einen einfachen DBus -Empfänger und Absender in C# zu erstellen Bestätigen Sie, dass ich tatsächlich Anrufe in meinem C# DBUS -Code erhalten kann. Dies funktioniert einwandfrei. Aber es scheint, dass diese Schnittstelle außerhalb von Bluez nicht verfügbar ist, da ich das gleiche "kein Ergebnis" erhalte, ob ich den Python -Agenten oder den C# Agent verwende. < /li>
< />  Immer dasselbe, der Python One ist in Ordnung, aber das C# 1 beschwert sich von dbus darüber, dass die Methode nicht vorhanden ist. >
CAL :1.259(90)->:1.273 /com/kevinisabelle/agent org.bluez.Agent1.RequestConfirmation ou
- /org/bluez/hci0/dev_B0_A4_60_E7_88_52
- 262106
ERR :1.273(8)->:1.259(90) org.freedesktop.DBus.Error.UnknownMethod s
- Method "RequestConfirmation" with signature "ou" on interface "org.bluez.Agent1" doesn't exist

< /code>
Und auch hier ist das Protokoll, wenn mein Agent startet und in Bluez registriert wird: < /p>
SIG org.freedesktop.DBus(4)->:1.277 /org/freedesktop/DBus org.freedesktop.DBus.NameLost s
- :1.277
CAL :1.278(1)->org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.Hello
RET org.freedesktop.DBus(1)->:1.278(1) s
- :1.278
SIG org.freedesktop.DBus(511)-> /org/freedesktop/DBus org.freedesktop.DBus.NameOwnerChanged sss
- :1.278
-
- :1.278
SIG org.freedesktop.DBus(2)->:1.278 /org/freedesktop/DBus org.freedesktop.DBus.NameAcquired s
- :1.278
CAL :1.278(2)->org.bluez /org/bluez org.bluez.AgentManager1.RegisterAgent os
- /com/kevinisabelle/agent
- KeyboardDisplay
CAL :1.259(93)->org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.AddMatch s
- type='signal',sender='org.freedesktop.DBus',path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0=':1.278'
RET org.freedesktop.DBus(28)->:1.259(93)
RET :1.259(94)->:1.278(2)
SIG :1.259(95)-> /org/bluez/hci0 org.freedesktop.DBus.Properties.PropertiesChanged sa{sv}as
- org.bluez.Adapter1
- Pairable: True
- []
CAL :1.278(3)->org.bluez /org/bluez org.bluez.AgentManager1.RequestDefaultAgent o
- /com/kevinisabelle/agent
RET :1.259(96)->:1.278(3)
CAL :1.278(4)->org.bluez /org/bluez/hci0 org.freedesktop.DBus.Properties.Set ssv
- org.bluez.Adapter1
- Powered
- True
RET :1.259(97)->:1.278(4)
CAL :1.278(5)->org.bluez /org/bluez/hci0 org.freedesktop.DBus.Properties.Set ssv
- org.bluez.Adapter1
- Discoverable
- True
RET :1.259(98)->:1.278(5)
CAL :1.278(6)->org.bluez /org/bluez/hci0 org.freedesktop.DBus.Properties.Set ssv
- org.bluez.Adapter1
- Pairable
- True
SIG :1.259(99)-> /org/bluez/hci0 org.freedesktop.DBus.Properties.PropertiesChanged sa{sv}as
- org.bluez.Adapter1
- Discoverable: True
- []
RET :1.259(100)->:1.278(6)
< /code>
 kleines Testprogramm < /h2>
Kleines Programm zum Validieren der Send- und Empfangen von C# -Funktionen. Ich starte den Server in einer Konsole, dann den Client in einer anderen.  DBUS und Protokolle Konfims Alle Kommunikation funktioniert gut: < /p>
CAL :1.38(2)->org.example.HelloService /com/kevinisabelle/Hello com.kevinisabelle.Hello.SayHello ou
- /org/bluez/hci0/dev_B0_A4_60_E7_88_52
- 123456
RET :1.37(3)->:1.38(2) s
- Hello, /org/bluez/hci0/dev_B0_A4_60_E7_88_52! with passkey 123456

< /code>
Quellcode: < /p>
using Tmds.DBus;

[DBusInterface("com.kevinisabelle.Hello")]
public interface IHello : IDBusObject
{
Task SayHelloAsync(ObjectPath name, uint passkey);
}

public class HelloService : IHello
{
// Set the object path where this service is available.
public ObjectPath ObjectPath { get; } = new ObjectPath("/com/kevinisabelle/Hello");

public Task SayHelloAsync(ObjectPath name, uint passkey)
{
Console.WriteLine("Hello called with name: " + name + " Passkey: " + passkey);
return Task.FromResult($"Hello, {name}! with passkey {passkey}");
}
}

public class Program
{
public static async Task Main(string[] args)
{
var isServer = args.Length > 0 && args[0] == "server";

if (isServer)
{
await MakeServer();
}
else
{
await MakeClient();
}
}

private static async Task MakeServer()
{
// Connect to the session bus.
var connection = new Connection(Address.System);
await connection.ConnectAsync();

// Create and register the service object.
var helloService = new HelloService();
await connection.RegisterObjectAsync(helloService);

// var agent = new TestAgent();
// await connection.RegisterObjectAsync(agent);

// Request a well-known bus name.
var serviceName = "org.example.HelloService";
await connection.RegisterServiceAsync(serviceName);

Console.WriteLine("Service is running. Press Ctrl+C to exit.");
await Task.Delay(-1); // Keep the service alive.

}

private static async Task MakeClient()
{
// Connect to the session bus.
var connection = new Connection(Address.System);
await connection.ConnectAsync();

// Create a proxy to the service object.
var hello = connection.CreateProxy("org.example.HelloService", new ObjectPath("/com/kevinisabelle/Hello"));

// Call the remote method.
var response = await hello.SayHelloAsync(new ObjectPath("/org/bluez/hci0/dev_B0_A4_60_E7_88_52"), 123456);
Console.WriteLine("Say Hello called: " + response);
}
}

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post