rewrite README.md
authorHelmut Grohne <helmut@subdivi.de>
Sun, 14 Jul 2013 19:04:05 +0000 (21:04 +0200)
committerHelmut Grohne <helmut@subdivi.de>
Sun, 14 Jul 2013 19:04:05 +0000 (21:04 +0200)
Thanks to Joachim Breitner for asking good questions. Most of his
questions are answered by this revised version.

README.md

index 86d9356..d0488f3 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,15 +1,19 @@
-onoff
-=====
-
-Activate devices on demand and turn them off after usage automatically. This is
-what onoff is for. From the perspective of onoff a device has four states. It
-may be active, inactive of transitioning to one of those two states. Devices
-are exported via a dbus interface (currently versioned 0 to declare API
-instability). A client can activate a device for a particular duration or
-activate it until a filedescriptor is closed. The latter allows inheriting
-filedescriptors to other processes and getting a signal once they terminate.
-Consider the following use cases:
+About onoff
+===========
 
+Onoff is a dbus service to manage physical or virtual devices that have two
+distinct states. A managed device can be inactive or active or transitioning
+from one of those two states to the other. A dbus client can request a device
+to be activated for a specific amount of time or until a process dies. The
+service is to ensure that the requested device resides in the active state as
+long as at least one client requests the activation.
+
+Currently onoff is mostly a library of common functionality for implementing
+such a service or client. Code for configuring or starting the service is
+notably absent.
+
+Use cases
+=========
  * When printing a page, first switch on the printer and after printing, switch
    off the printer. When printing two jobs, do not turn it of between the jobs.
    This can be achieved with [sispmctl][] or [slugpower][] for example.
@@ -26,19 +30,87 @@ Consider the following use cases:
    services. This is another inhibiting strategy. It is already being solved by
    [systemd-inhibit][] though.
 
+API
+===
+
+On the python API side there is the base class OnoffDevice. A device must
+implement `activate` and `deactivate` methods to initiate state transitions. It
+also must provide a `state` attribute to query the current device state. When
+the devices changes its state, it must invoke the `changestate` method to
+signal interested parties.
+
+There currently are four implementations. An `OnoffCommand` can be used if the
+state of a device can be changed by invoking a command for either direction.
+The transition is considered complete when the respective command terminates.
+This device is used to implement a power socket with [sispmctl][] in
+`onoff.tools.sispmctl_device`.
+
+An `OnoffProcess` can be used if the device is considered active as long as the
+process runs. Deactivation is achieved by killing the process. For example the
+[redshift][] can be started in this way.
+
+    dev = onoff.processs.OnoffProcess(["redshift"], 3)
+
+An `InvertedDevice` can be used to swap the activation states. It can be used
+to activate a device all the time and inhibit activation whenever the inverted
+device is activated. So an `InvertedDevice` wraps an existing `OnoffDevice`.
+
+A `ThrottledDevice` can be used to add artificial delays to the transition
+periods of the activation and deactivation. If a device takes noticeable time
+to settle even after it has been signaled as active, the activation signal can
+be delayed. Similarly if a device should not be switched too often,
+deactivation can be delayed. If the device is reactivated shortly after it has
+been released, it simply keeps being active.
+
+Once you have an `OnoffDevice` you can pass a dbus bus connection, a name and
+the device to the `OnoffControl` constructor. The created object exports the
+device via under the given name on the given bus.
+
+On the dbus side the API is versioned. The current API is version as
+`de.subdivi.onoff0` with a number 0 to declare an unstable API. Each device is
+represented as an object. For each object there is a `changestate` signal. A
+client can connect to this signal to learn when a device becomes usable. Each
+object also provides two methods for requesting activation. The `activatetime`
+method takes a number of seconds and activates the device for the specified
+number of seconds. It returns the state after activation, which most likely is
+the transition state to active. If the interval is too short a device may never
+reach the active state. The other method is `activatefd`. It takes no
+parameters and returns a file descriptor in addition to the current state. The
+device is considered activated until the client closes the returned file
+descriptor. The intended use here is to duplicate the file descriptor to a high
+number and inherit it to an external process such as a video player. When that
+process terminates, the file descriptor is automatically closed and the device
+released.
+
 Configuration
 =============
-Activation with sispmctl using the first socket of the first usb device
-delaying of deactivation by 3 seconds:
 
-    dev = onoff.command.OnoffCommand(["sispmctl", "-o", "1"],
-                                     ["sispmctl", "-f", "1"])
-    dev = onoff.common.ThrottledDevice(dev, 3)
+To use onoff you need two components. First of all a dbus service is needed.
+Since there is no configuration language for onoff yet, you are supposed to
+write a python script and plug the pieces together yourself. An example service
+can be found in `dbus_service.py`. In such a script you configure all available
+devices. It is up to you to decide whether to use the system bus or the session
+bus. For a power socket the system bus is suggested and for tools like redshift
+the session bus is suggested. If you intend to use the system bus, you will
+need to configure dbus to allow interaction. An example dbus policy can be
+found in `dbus_policy.conf`. It is also up to you to start the service script.
+In theory it should be possible to use dbus activation to activate it on demand
+(unless you use an `InvertedDevice`). If you have multiple devices, that
+require different permission, you can spread them to multiple services. In this
+case you can no longer use the common busname `de.subdivi.onoff0` for all
+services. You need to override it.
 
-When inhibiting redshift, run redshift from the dbus service:
+Once you have a service running, you can use the `dbus_client.py` to invoke the
+dbus methods. Of course you can also use the dbus API directly. For instance to
+inhibit the example `redshift` device exported from the `dbus_service.py`
+example as long as you watch a video, you can use the following invocation.
 
-    dev = onoff.processs.OnoffProcess(["redshift"], 3)
-    dev = onoff.common.InvertedDevice(dev)
+    ./dbus_client.py --device redshift mplayer -fs cool_video.webm
+
+Another example client can be found in `mpd_watcher.py`. It monitors the local
+[mpd][] for the playing state and activates the device given on command line
+whenever mpd plays music. As such it also is a background process and it is
+your task to start it.
 
 [sispmctl]: http://sispmctl.sf.net
 [slugpower]: http://chezphil.org/slugpower/