ship some documentation
[~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.process
18
19 logger = logging.getLogger("dbus_service")
20
21 def dbus_socket_pair():
22     """Create a socket pair where the latter end is suitable for dbus.
23     @rtype: (socket, dbus.types.UnixFd)
24     """
25     s1, s2 = socket.socketpair()
26     s3 = dbus.types.UnixFd(s2)
27     s2.close()
28     return s1, s3
29
30 class OnoffControl(dbus.service.Object):
31     domain = "de.subdivi.onoff0"
32     path = "/de/subdivi/onoff0"
33
34     def __init__(self, bus, name, device):
35         busname = dbus.service.BusName(self.domain, bus=bus)
36         dbus.service.Object.__init__(self, busname, "%s/%s" % (self.path, name))
37         self.device = device
38         device.notify.add(self.changestate)
39         self.usecount = 0
40
41     @dbus.service.signal(domain, signature="q")
42     def changestate(self, st):
43         logger.debug("emitting state %d", st)
44
45     @dbus.service.method(domain, out_signature="q")
46     def state(self):
47         return self.device.state
48
49     @dbus.service.method(domain, in_signature="q", out_signature="q")
50     def activatetime(self, duration):
51         logger.info("activatetime %d", duration)
52         GObject.timeout_add(duration * 1000, self.unuse)
53         return self.use()
54
55     @dbus.service.method(domain, in_signature="q", out_signature="qh")
56     def activatefd(self, duration):
57         logger.info("activatefd duration %d", duration)
58         notifyfd, retfd = dbus_socket_pair()
59         def callback(fd, _):
60             logger.info("fd %d completed", fd.fileno())
61             fd.close()
62             GObject.timeout_add(duration * 1000, self.unuse)
63             return False
64         GObject.io_add_watch(notifyfd, GObject.IO_HUP|GObject.IO_ERR, callback)
65         return (self.use(), retfd)
66
67     def use(self):
68         self.usecount += 1
69         if self.usecount <= 1:
70             self.device.activate()
71         return self.device.state
72
73     def unuse(self):
74         self.usecount -= 1
75         if not self.usecount:
76             self.device.deactivate()
77         else:
78             logger.debug("%d users left", self.usecount)
79         return False
80
81
82 def main():
83     logging.basicConfig()
84     logging.getLogger().setLevel(logging.DEBUG)
85     DBusGMainLoop(set_as_default=True)
86     bus = dbus.SessionBus()
87     dev = onoff.process.OnoffProcess(["redshift"], 3)
88     dev = onoff.common.InvertedDevice(dev)
89     OnoffControl(bus, "redshift", dev)
90     GObject.MainLoop().run()
91
92 if __name__ == "__main__":
93     main()