Search code examples
pythondbusconnman

Accessing iwd dbus interface from python


I am trying to use python3 dbus package to control wireless on an embedded Linux target (mips MT7628, if it matters).

System is most likely set up correctly because I have iwd + dhclient up-and-running on this embedded target.

I can connect through both eth0 and wlan0.

I can also control iwd through iwctl. So far so good.

I now need to control iwd from python3; specifically I need to be able to send scan results through serial line (real target, as opposed to my development board, will be headless).

I am at a loss with dbus interface. I need some examples to start with.

I tried something along the lines:

# python
Python 3.8.1 (default, Feb 21 2020, 11:13:38) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import dbus
>>> bus = dbus.SystemBus()
>>> wlan0 = bus.get_object('net.connman.iwd', '/net/connman/iwd/phy1/1')
>>> p = wlan0.Properties(dbus_interface='net.connman.iwd.Station')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.8/site-packages/dbus/proxies.py", line 72, in __call__
  File "/usr/lib/python3.8/site-packages/dbus/proxies.py", line 141, in __call__
  File "/usr/lib/python3.8/site-packages/dbus/connection.py", line 652, in call_blocking
dbus.exceptions.DBusException: org.freedesktop.DBus.Error.NotFound: No matching method found
>>> p = wlan0.Scan(dbus_interface='net.connman.iwd.Station')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.8/site-packages/dbus/proxies.py", line 141, in __call__
  File "/usr/lib/python3.8/site-packages/dbus/connection.py", line 652, in call_blocking
dbus.exceptions.DBusException: org.freedesktop.DBus.Error.NotFound: No matching method found
>>> 

This while WiFi is working:

# iwctl 
[iwd]# adapter list
                                    Adapters                                  *
--------------------------------------------------------------------------------
  Name               Powered   Vendor              Model               
--------------------------------------------------------------------------------
  phy1               on        --

[iwd]# device list
                                    Devices                                   *
--------------------------------------------------------------------------------
  Name                Address             Powered   Adapter   Mode      
--------------------------------------------------------------------------------
  wlan1               42:c1:f8:85:67:ba   on        phy1      station   

[iwd]# station list
                            Devices in Station Mode                           *
--------------------------------------------------------------------------------
  Name                State          Scanning
--------------------------------------------------------------------------------
  wlan1               connected              

[iwd]# 

... but I'm obviously missing something very basic.

Can someone point me in the right direction, please?


Solution

  • Answering my own question to help whoever will stumble here:

    It turns out both iwd and connman repositories come with complete python3 examples in subdirectory "test".

    Adapting those to my specific needs proved trivial.

    Relevant directories can be found here (iwd) and here (connman).

    The solution to my specific question is in the following scripts: scan-for-networks and list-known-networks.

    scan-for-networks:

    #!/usr/bin/python3
    
    import sys
    import dbus
    
    
    if (len(sys.argv) != 2):
        print("Usage: %s <device>" % (sys.argv[0]))
        sys.exit(1)
    
    bus = dbus.SystemBus()
    device = dbus.Interface(bus.get_object("net.connman.iwd", sys.argv[1]),
                                        "net.connman.iwd.Station")
    device.Scan()
    

    list_known_networks:

    #!/usr/bin/python3
    
    import sys
    import dbus
    
    bus = dbus.SystemBus()
    
    manager = dbus.Interface(bus.get_object('net.connman.iwd', '/'),
                             'org.freedesktop.DBus.ObjectManager')
    
    forget = None
    if len(sys.argv) >= 4 and sys.argv[1] == 'forget':
        forget = (sys.argv[2], sys.argv[3])
    
    print('Known Networks:')
    
    for path, interfaces in manager.GetManagedObjects().items():
        if 'net.connman.iwd.KnownNetwork' not in interfaces:
            continue
    
        network = interfaces['net.connman.iwd.KnownNetwork']
    
        if (network['Name'], network['Type']) == forget:
            obj = dbus.Interface(bus.get_object('net.connman.iwd', path),
                                 'net.connman.iwd.KnownNetwork')
            obj.Forget()
            continue
    
        print("[ %s ]" % network['Name'])
    
        for key in network:
            val = network[key]
            if type(val) == dbus.Boolean:
                val = 'True' if val else 'False'
            print("    %s = %s" % (key, val))