Python libmm problems
colin.helliwell at ln-systems.com
Wed Sep 13 17:41:29 UTC 2017
> On 13 September 2017 at 17:57 Dan Williams <dcbw at redhat.com> wrote:
> On Wed, 2017-09-13 at 17:23 +0100, colin.helliwell at ln-systems.com
> > I'm trying to write some python to get the operator id off the
> > modem.
> > Due to limited knowledge of such things, I'm *not* using any
> > notifcation
> > callbacks etc, but simply trying to poll things.
> > I've wrapped the functionality into a class (thinking to thus be able
> > to
> > easily contain the modem's objects etc in the instance).
> > I poll an initial 'get modem' method:
> > if self.connection is None:
> > self.connection = Gio.bus_get_sync (Gio.BusType.SYSTEM,
> > None)
> > self.manager = ModemManager.Manager.new_sync
> > (self.connection,
> > Gio.DBusObjectManagerClientFlags.DO_NOT_AUTO_START, None)
> > if self.manager is None:
> > # MM not found
> > self.connection = None
> > self.modem = None
> > self.obj = None
> > return None
> > # Search for the modem
> > for obj in self.manager.get_objects():
> > m = obj.get_modem()
> > # Look for my modem
> > if (m.get_primary_port() == "ttyS1"):
> > self.obj = obj
> > self.modem = m
> > return self.modem
> > Then, once the modem has been found by this, I go on to try to get
> > the
> > operator code by polling a further method:
> > MccMnc = None
> > if self.modem is not None:
> > # Return MCC/MNC if registered
> > if (self.modem.get_state() >=
> > ModemManager.ModemState.REGISTERED):
> > MccMnc =
> > self.obj.get_modem_3gpp().get_operator_code()
> > else:
> > print 'GetMccMnc', self.modem.get_state()
> > return MccMnc
> > What I'm seeing is that, even though mmcli shows the modem getting to
> > 'connected', this function continues to just get a state of
> > 'MM_MODEM_STATE_ENABLING'.
> > If I (re)run the script after the modem has got connected, then it's
> > working
> > as expected.
> > I'm not sure if this in an error in my python oop, or incorrect use
> > of
> > libmm. Why aren't the repeated calls to get_state() seeing the change
> > of
> > state?
> Internally all this stuff is still an event-based system listening on a
> socket for data from ModemManager. Which means you have to let that
> code do some work to handle those events at some point, and the way
> that happens is by letting the GLib mainloop run periodically.
> What I'd suggest is to do your polling and work from a GLib timeout.
> That lets the mainloop run, and it lets your code essentially poll in a
> simple way without doing callbacks and signals:
> #!/usr/bin/env python
> import gi
> gi.require_version('ModemManager', '1.0')
> from gi.repository import GLib, GObject, Gio, ModemManager
> import sys, signal
> main_loop = None
> watcher = None
> def signal_handler(data):
> def get_modem_state(obj):
> modem = obj.get_modem()
> print "State: %s" % ModemManager.ModemState.get_string(modem.get_state())
> # Do whatever other work you need to do, as long as it doesn't take many seconds
> # True = continue running this timeout
> return True
> main_loop = GLib.MainLoop()
> GLib.unix_signal_add(GLib.PRIORITY_HIGH, signal.SIGHUP, signal_handler, None)
> GLib.unix_signal_add(GLib.PRIORITY_HIGH, signal.SIGTERM, signal_handler, None)
> connection = Gio.bus_get_sync(Gio.BusType.SYSTEM, None)
> manager = ModemManager.Manager.new_sync(connection,
> modems = manager.get_objects()
> if len(modems) == 0:
> print "no modems found"
> GLib.timeout_add_seconds(5, get_modem_state, modems)
> except KeyboardInterrupt:
Thanks for the input, Dan.
If I'm reading you right, you're suggesting having a Glib mainloop that runs on - and catches - the MM signals/events, and then use get_modem_state() to be able to peek into the status of things?
I did try to read up on the loop stuff, but found it hard going to understand [aka find usable documentation on] - which is why I was trying to simplify it by being all dumbly-polled ;)
e.g. As a general question: what is *actually* executed by a GLib.MainLoop() call - I kinda thought there must surely be a function name that you'd pass it to tell it *what* to 'loop around'. Is it just some intrinsic function that's invoked?
In the bigger scheme of things, I'm parsing the Operator Code and then using it to modify the appropriate NetworkManager connection properties - which in itself involves waiting till NM is present 'n ready! Hence probably gonna be an issue in view of your "Do whatever other work you need to do, **as long as it doesn't take many seconds**" comment?
Which leaves me puzzling further how to tie the elements together... :S
Perhaps I can have multiple things ['threads' in a sense, even if not strictly so] hung off invocations of GLib.timeout_add_seconds(), and have them each monitor, maybe through globals [again, taking a dirty approach rather than signals..!] what each other is coming up with?
My very first idea for all this was to just script using mmcli & nmcli, but I thought it'd be more future-proof - mainly to mitigate against possible changes to their text strings - to try n be smarter... Hmmmm... ! ;)
More information about the ModemManager-devel