make clients configurable via argparse
[~helmut/onoff.git] / dbus_service.py
1 #!/usr/bin/env python
2 """
3 A dbus service example currently providing a device called redshift, that runs
4 redshift whenever it is not activated. This could be useful to temporarily
5 disable redshift e.g. while watching a movie.
6 """
7
8 import logging
9 import socket
10
11 import dbus
12 import dbus.service
13 from dbus.mainloop.glib import DBusGMainLoop
14 from gi.repository import GObject
15
16 import onoff.common
17 import onoff.dbusutils
18 import onoff.process
19
20 logger = logging.getLogger("dbus_service")
21
22 def dbus_socket_pair():
23     """Create a socket pair where the latter end is suitable for dbus.
24     @rtype: (socket, dbus.types.UnixFd)
25     """
26     s1, s2 = socket.socketpair()
27     s3 = dbus.types.UnixFd(s2)
28     s2.close()
29     return s1, s3
30
31 class OnoffControl(dbus.service.Object):
32     domain = "de.subdivi.onoff0"
33     path = onoff.dbusutils.object_prefix
34
35     def __init__(self, bus, name, device):
36         busname = dbus.service.BusName(self.domain, bus=bus)
37         dbus.service.Object.__init__(self, busname, "%s/%s" % (self.path, name))
38         self.device = device
39         device.notify.add(self.changestate)
40         self.usecount = 0
41
42     @dbus.service.signal(domain, signature="q")
43     def changestate(self, st):
44         logger.debug("emitting state %d", st)
45
46     @dbus.service.method(domain, out_signature="q")
47     def state(self):
48         return self.device.state
49
50     @dbus.service.method(domain, in_signature="q", out_signature="q")
51     def activatetime(self, duration):
52         logger.info("activatetime %d", duration)
53         GObject.timeout_add(duration * 1000, self.unuse)
54         return self.use()
55
56     @dbus.service.method(domain, in_signature="q", out_signature="qh")
57     def activatefd(self, duration):
58         logger.info("activatefd duration %d", duration)
59         notifyfd, retfd = dbus_socket_pair()
60         def callback(fd, _):
61             logger.info("fd %d completed", fd.fileno())
62             fd.close()
63             GObject.timeout_add(duration * 1000, self.unuse)
64             return False
65         GObject.io_add_watch(notifyfd, GObject.IO_HUP|GObject.IO_ERR, callback)
66         return (self.use(), retfd)
67
68     def use(self):
69         self.usecount += 1
70         if self.usecount <= 1:
71             self.device.activate()
72         return self.device.state
73
74     def unuse(self):
75         self.usecount -= 1
76         if not self.usecount:
77             self.device.deactivate()
78         else:
79             logger.debug("%d users left", self.usecount)
80         return False
81
82
83 def main():
84     logging.basicConfig()
85     logging.getLogger().setLevel(logging.DEBUG)
86     DBusGMainLoop(set_as_default=True)
87     bus = dbus.SessionBus()
88     dev = onoff.process.OnoffProcess(["redshift"], 3)
89     dev = onoff.common.InvertedDevice(dev)
90     OnoffControl(bus, "redshift", dev)
91     GObject.MainLoop().run()
92
93 if __name__ == "__main__":
94     main()