add a sispmctl_device
[~helmut/onoff.git] / dbus_client.py
index a1f1041..91d9f37 100755 (executable)
@@ -1,46 +1,79 @@
 #!/usr/bin/env python
+"""
+A simpe client for an onoff device. If no command is given, the device is
+temporarily activated. When a command is given, the device is activated, then
+the command is run. Some time after the command finishes, the device is
+released.
+"""
 
+import argparse
 import os
-import socket
-import sys
+import xml.parsers.expat
 
-import dbus
 from dbus.mainloop.glib import DBusGMainLoop
-import gobject
+from gi.repository import GObject
 
 from onoff.common import ST_ACTIVE
+import onoff.dbusutils
 
-def wait_for_signal(proxy, signal):
-    loop = gobject.MainLoop()
-    state = []
+def wait_for_signal(proxy, signal, desired_state):
+    loop = GObject.MainLoop()
     def callback(st):
-        state.append(st)
-        loop.quit()
+        if st == desired_state:
+            loop.quit()
     proxy.connect_to_signal(signal, callback)
     loop.run()
-    return state[0]
+
+def parse_introspection(xmlstring):
+    parser = xml.parsers.expat.ParserCreate()
+    nodes = []
+    def start_element(name, attrs):
+        if name != "node":
+            return
+        try:
+            value = attrs["name"]
+        except KeyError:
+            return
+        nodes.append(value)
+    parser.StartElementHandler = start_element
+    parser.Parse(xmlstring)
+    return nodes
 
 def main():
-    s1, s2 = socket.socketpair()
+    parser = argparse.ArgumentParser(parents=[onoff.dbusutils.dbus_options])
+    parser.add_argument("--duration", type=int, default=10,
+                        help="how long to activate the device in seconds " +
+                        "(default: %(default)d")
+    parser.add_argument("command", nargs=argparse.REMAINDER,
+                        help="a command to be executed with the device being" +
+                             "activated for the duration of the execution")
+    parser.add_argument("--list", action="store_true",
+                        help="list available devices and exit")
+    args = parser.parse_args()
     DBusGMainLoop(set_as_default=True)
-    bus = dbus.SessionBus()
-    proxy = bus.get_object("de.subdivi.onoff", "/de/subdivi/onoff/5")
-    if len(sys.argv) > 1:
-        st = proxy.activatefd(dbus.types.UnixFd(s1), 10)
-        s1.close()
-        os.dup2(s2.fileno(), 254)
-        s2.close()
+    if args.list:
+        bus = onoff.dbusutils.get_dbus(args)
+        proxy = bus.get_object(args.busname, onoff.dbusutils.object_prefix)
+        for elem in parse_introspection(proxy.Introspect()):
+            print(elem)
+    elif args.command:
+        proxy = onoff.dbusutils.get_dbus_proxy(args)
+        st, fd = proxy.activatefd()
+        fd = fd.take()
+        os.dup2(fd, 254)
+        os.close(fd)
         if st != ST_ACTIVE:
             print("state is %d waiting for signal" % st)
-            st = wait_for_signal(proxy, "state")
-            print("new state is %d" % st)
-        os.execvp(sys.argv[1], sys.argv[1:])
+            wait_for_signal(proxy, "changestate", ST_ACTIVE)
+            print("new state is actived")
+        os.execvp(args.command[0], args.command)
     else:
-        st = proxy.activatetime(10)
+        proxy = onoff.dbusutils.get_dbus_proxy(args)
+        st = proxy.activatetime(args.duration)
         if st != ST_ACTIVE:
             print("state is %d waiting for signal" % st)
-            st = wait_for_signal(proxy, "state")
-            print("new state is %d" % st)
+            wait_for_signal(proxy, "changestate", ST_ACTIVE)
+            print("new state is active")
 
 if __name__ == "__main__":
     main()