rewrite README.md
[~helmut/onoff.git] / README.md
1 About onoff
2 ===========
3
4 Onoff is a dbus service to manage physical or virtual devices that have two
5 distinct states. A managed device can be inactive or active or transitioning
6 from one of those two states to the other. A dbus client can request a device
7 to be activated for a specific amount of time or until a process dies. The
8 service is to ensure that the requested device resides in the active state as
9 long as at least one client requests the activation.
10
11 Currently onoff is mostly a library of common functionality for implementing
12 such a service or client. Code for configuring or starting the service is
13 notably absent.
14
15 Use cases
16 =========
17  * When printing a page, first switch on the printer and after printing, switch
18    off the printer. When printing two jobs, do not turn it of between the jobs.
19    This can be achieved with [sispmctl][] or [slugpower][] for example.
20  * Similarly when scanning, turn on the scanner.
21  * Using [redshift][] is a nice thing in the evening. Occasionally you may need
22    clear colours though. Videos tend to look bad with redshift activated. So
23    consider automatically inhibiting redshift during video playback.
24  * Monitor the local [mpd][]. Whenever it plays music switch on the sound
25    device and turn it of when music stops. Also turn on sound when watching a
26    video of course.
27  * The inhibitor concept can also be applied to [mpd][] itself. When your phone
28    rings, stop mpd.
29  * When you suspend the whole machine, clients should disconnect from remote
30    services. This is another inhibiting strategy. It is already being solved by
31    [systemd-inhibit][] though.
32
33 API
34 ===
35
36 On the python API side there is the base class OnoffDevice. A device must
37 implement `activate` and `deactivate` methods to initiate state transitions. It
38 also must provide a `state` attribute to query the current device state. When
39 the devices changes its state, it must invoke the `changestate` method to
40 signal interested parties.
41
42 There currently are four implementations. An `OnoffCommand` can be used if the
43 state of a device can be changed by invoking a command for either direction.
44 The transition is considered complete when the respective command terminates.
45 This device is used to implement a power socket with [sispmctl][] in
46 `onoff.tools.sispmctl_device`.
47
48 An `OnoffProcess` can be used if the device is considered active as long as the
49 process runs. Deactivation is achieved by killing the process. For example the
50 [redshift][] can be started in this way.
51
52     dev = onoff.processs.OnoffProcess(["redshift"], 3)
53
54 An `InvertedDevice` can be used to swap the activation states. It can be used
55 to activate a device all the time and inhibit activation whenever the inverted
56 device is activated. So an `InvertedDevice` wraps an existing `OnoffDevice`.
57
58 A `ThrottledDevice` can be used to add artificial delays to the transition
59 periods of the activation and deactivation. If a device takes noticeable time
60 to settle even after it has been signaled as active, the activation signal can
61 be delayed. Similarly if a device should not be switched too often,
62 deactivation can be delayed. If the device is reactivated shortly after it has
63 been released, it simply keeps being active.
64
65 Once you have an `OnoffDevice` you can pass a dbus bus connection, a name and
66 the device to the `OnoffControl` constructor. The created object exports the
67 device via under the given name on the given bus.
68
69 On the dbus side the API is versioned. The current API is version as
70 `de.subdivi.onoff0` with a number 0 to declare an unstable API. Each device is
71 represented as an object. For each object there is a `changestate` signal. A
72 client can connect to this signal to learn when a device becomes usable. Each
73 object also provides two methods for requesting activation. The `activatetime`
74 method takes a number of seconds and activates the device for the specified
75 number of seconds. It returns the state after activation, which most likely is
76 the transition state to active. If the interval is too short a device may never
77 reach the active state. The other method is `activatefd`. It takes no
78 parameters and returns a file descriptor in addition to the current state. The
79 device is considered activated until the client closes the returned file
80 descriptor. The intended use here is to duplicate the file descriptor to a high
81 number and inherit it to an external process such as a video player. When that
82 process terminates, the file descriptor is automatically closed and the device
83 released.
84
85 Configuration
86 =============
87
88 To use onoff you need two components. First of all a dbus service is needed.
89 Since there is no configuration language for onoff yet, you are supposed to
90 write a python script and plug the pieces together yourself. An example service
91 can be found in `dbus_service.py`. In such a script you configure all available
92 devices. It is up to you to decide whether to use the system bus or the session
93 bus. For a power socket the system bus is suggested and for tools like redshift
94 the session bus is suggested. If you intend to use the system bus, you will
95 need to configure dbus to allow interaction. An example dbus policy can be
96 found in `dbus_policy.conf`. It is also up to you to start the service script.
97 In theory it should be possible to use dbus activation to activate it on demand
98 (unless you use an `InvertedDevice`). If you have multiple devices, that
99 require different permission, you can spread them to multiple services. In this
100 case you can no longer use the common busname `de.subdivi.onoff0` for all
101 services. You need to override it.
102
103 Once you have a service running, you can use the `dbus_client.py` to invoke the
104 dbus methods. Of course you can also use the dbus API directly. For instance to
105 inhibit the example `redshift` device exported from the `dbus_service.py`
106 example as long as you watch a video, you can use the following invocation.
107
108     ./dbus_client.py --device redshift mplayer -fs cool_video.webm
109
110 Another example client can be found in `mpd_watcher.py`. It monitors the local
111 [mpd][] for the playing state and activates the device given on command line
112 whenever mpd plays music. As such it also is a background process and it is
113 your task to start it.
114
115 [sispmctl]: http://sispmctl.sf.net
116 [slugpower]: http://chezphil.org/slugpower/
117 [redshift]: http://jonls.dk/redshift/
118 [mpd]: http://www.musicpd.org
119 [systemd-inhibit]: http://www.freedesktop.org/software/systemd/man/systemd-inhibit.html