use the enum module to represent states master
authorHelmut Grohne <helmut@subdivi.de>
Fri, 20 Apr 2018 18:35:00 +0000 (20:35 +0200)
committerHelmut Grohne <helmut@subdivi.de>
Fri, 20 Apr 2018 18:35:00 +0000 (20:35 +0200)
dbus_client.py
onoff/command.py
onoff/common.py
onoff/dbusutils.py
onoff/gpio.py
onoff/process.py

index 1650033..5013f0d 100755 (executable)
@@ -12,7 +12,7 @@ import os
 from dbus.mainloop.glib import DBusGMainLoop
 from gi.repository import GObject
 
-from onoff.common import ST_ACTIVE
+from onoff.common import OnoffState
 import onoff.dbusutils
 
 def wait_for_signal(proxy, signal, desired_state):
@@ -42,20 +42,21 @@ def main():
     elif args.command:
         proxy = onoff.dbusutils.get_dbus_proxy(args)
         st, fd = proxy.activatefd()
+        st = OnoffState(st)
         fd = fd.take()
         os.dup2(fd, 254)
         os.close(fd)
-        if st != ST_ACTIVE:
-            print("state is %d waiting for signal" % st)
-            wait_for_signal(proxy, "changestate", ST_ACTIVE)
+        if st != OnoffState.active:
+            print("state is %s waiting for signal" % st.name)
+            wait_for_signal(proxy, "changestate", OnoffState.active.value)
             print("new state is actived")
         os.execvp(args.command[0], args.command)
     else:
         proxy = onoff.dbusutils.get_dbus_proxy(args)
-        st = proxy.activatetime(args.duration)
-        if st != ST_ACTIVE:
-            print("state is %d waiting for signal" % st)
-            wait_for_signal(proxy, "changestate", ST_ACTIVE)
+        st = OnoffState(proxy.activatetime(args.duration))
+        if st != OnoffState.active:
+            print("state is %s waiting for signal" % st.name)
+            wait_for_signal(proxy, "changestate", OnoffState.active.value)
             print("new state is active")
 
 if __name__ == "__main__":
index d9b12c0..7a40bbd 100644 (file)
@@ -1,6 +1,6 @@
 import logging
 
-from .common import OnoffDevice, ST_ACTIVE, ST_TRANSITION
+from .common import OnoffDevice, OnoffState
 from .gobject import spawn_child
 
 logger = logging.getLogger("onoff.command")
@@ -29,14 +29,14 @@ class OnoffCommand(OnoffDevice):
         OnoffDevice.__init__(self)
         self.oncommand = oncommand
         self.offcommand = offcommand
-        self.desired_state = 0 # bit mask of just ST_ACTIVE
+        self.desired_state = OnoffState.inactive
         self.pid = None
-        self.target_state = 0 # state the last command targeted
+        self.target_state = OnoffState.inactive  # last command target state
 
     @property
     def state(self):
         if self.pid is not None:
-            return self.desired_state | ST_TRANSITION
+            return self.desired_state | OnoffState.transition
         return self.desired_state
 
     def transition(self, state):
@@ -51,22 +51,24 @@ class OnoffCommand(OnoffDevice):
     def process_died(self, pid, condition):
         assert self.pid == pid
         self.pid = None
-        logger.info("command %d targeting %d completed", pid, self.target_state)
+        logger.info("command %d targeting %s completed", pid,
+                    self.target_state.name)
         if self.desired_state == self.target_state:
             self.changestate(self.state)
         else:
-            logger.info("desired state changed to %d during invocation " +
-                        "targeting %d", self.desired_state, self.target_state)
+            logger.info("desired state changed to %s during invocation " +
+                        "targeting %s", self.desired_state.name,
+                        self.target_state.name)
             self.transition(self.desired_state)
 
     def activate(self):
-        if self.desired_state != ST_ACTIVE:
-            self.desired_state = ST_ACTIVE
+        if self.desired_state != OnoffState.active:
+            self.desired_state = OnoffState.active
             if self.pid is None:
                 self.transition(self.desired_state)
 
     def deactivate(self):
-        if self.desired_state != 0:
-            self.desired_state = 0
+        if self.desired_state != OnoffState.inactive:
+            self.desired_state = OnoffState.inactive
             if self.pid is None:
                 self.transition(self.desired_state)
index 2aa79b6..5d9565c 100644 (file)
@@ -1,19 +1,18 @@
-"""
-Defined states:
- - 0: The device is inactive.
- - ST_ACTIVE|ST_TRANSITION: The device is transitioning from inactive to active.
- - ST_ACTIVE: The device is active.
- - ST_TRANSITION: The device is transitioning from active to inactive.
-"""
-
+import enum
 import logging
 
 from .gobject import ScheduledFunction
 
 logger = logging.getLogger("onoff.common")
 
-ST_ACTIVE = 1
-ST_TRANSITION = 2
+
+class OnoffState(enum.Flag):
+    inactive = 0
+    active = 1
+    deactivating = 2
+    activating = 3
+    transition = 2
+
 
 class OnoffDevice(object):
     """A device is a thing with two states, that can be asked to transition
@@ -56,11 +55,11 @@ class InvertedDevice(OnoffDevice):
         self.device.notify.add(self.changestate)
 
     def changestate(self, state):
-        OnoffDevice.changestate(self, state ^ ST_ACTIVE)
+        OnoffDevice.changestate(self, state ^ OnoffState.active)
 
     @property
     def state(self):
-        return self.device.state ^ ST_ACTIVE
+        return self.device.state ^ OnoffState.active
 
     def activate(self):
         self.device.deactivate()
@@ -80,7 +79,8 @@ class ThrottledDevice(OnoffDevice):
         """
         @type device: OnoffDevice
         @type ondelay: int or float
-        @param ondelay: delay the report of ST_ACTIVE by this many seconds
+        @param ondelay: delay the report of OnoffState.active by this many
+                        seconds
         @type offdelay: int or float
         @param offdelay: delay the actual deactivation by this many seconds
         """
@@ -88,7 +88,7 @@ class ThrottledDevice(OnoffDevice):
         self.device = device
         self.ondelay = ondelay
         self.offdelay = offdelay
-        self.desired_state = 0
+        self.desired_state = OnoffState.inactive
         self.transition = None
         self.device.notify.add(self.changestate)
 
@@ -96,7 +96,7 @@ class ThrottledDevice(OnoffDevice):
     def state(self):
         if self.transition is None:
             return self.device.state
-        return self.desired_state | ST_TRANSITION
+        return self.desired_state | OnoffState.transition
 
     def _schedule_transition(self, delay, func):
         assert self.transition is None
@@ -108,10 +108,10 @@ class ThrottledDevice(OnoffDevice):
         self.transition = None
 
     def changestate(self, state):
-        if state != ST_ACTIVE:
+        if state != OnoffState.active:
             OnoffDevice.changestate(self, state)
         else:
-            if self.desired_state == 0:
+            if self.desired_state == OnoffState.inactive:
                 logger.warning("device became active but we want inactive," +
                                "suppresing signal")
             elif self.transition is None:
@@ -122,39 +122,41 @@ class ThrottledDevice(OnoffDevice):
                 logger.debug("suppressing duplicate activation signal")
 
     def _report_active(self):
-        assert self.desired_state == ST_ACTIVE
+        assert self.desired_state == OnoffState.active
         assert self.transition is not None
         self.transition = None
         logger.debug("delivering activation signal")
-        OnoffDevice.changestate(self, ST_ACTIVE)
+        OnoffDevice.changestate(self, OnoffState.active)
 
     def activate(self):
-        if self.desired_state == 0 and self.transition is not None:
+        if self.desired_state == OnoffState.inactive and \
+                self.transition is not None:
             logger.debug("cancelling pending deactivation")
             self._cancel_transition()
             curstate = self.device.state
-            if curstate == ST_ACTIVE:
-                self.desired_state = ST_ACTIVE
-                OnoffDevice.changestate(self, ST_ACTIVE)
+            if curstate == OnoffState.active:
+                self.desired_state = OnoffState.active
+                OnoffDevice.changestate(self, OnoffState.active)
                 return
             logger.warning("device should be active during delayed " +
-                           "deactivation, but is in state %d", curstate)
-        self.desired_state = ST_ACTIVE
+                           "deactivation, but is in state %s", curstate.name)
+        self.desired_state = OnoffState.active
         self.device.activate()
         self.changestate(self.device.state)
 
     def _do_stop(self):
-        assert self.desired_state == 0
+        assert self.desired_state == OnoffState.inactive
         assert self.transition is not None
         self.transition = None
         logger.debug("actually deactivating")
         self.device.deactivate()
 
     def deactivate(self):
-        if self.desired_state == ST_ACTIVE and self.transition is not None:
+        if self.desired_state == OnoffState.active and \
+                self.transition is not None:
             logger.debug("cancelling pending activation report")
             self._cancel_transition()
-        self.desired_state = 0
+        self.desired_state = OnoffState.inactive
         if self.transition is None:
             logger.debug("scheduling actual deactivate in %.1fs",
                          self.offdelay)
@@ -167,7 +169,7 @@ class ThrottledDevice(OnoffDevice):
         if self.transition is not None:
             logger.info("cancelling pending transition")
             self._cancel_transition()
-            if self.desired_state == 0:
+            if self.desired_state == OnoffState.inactive:
                 logger.info("invoking pending deactivate early during close")
                 self.device.deactivate()
         self.device.notify.remove(self.changestate)
index 0477ed1..31b51cf 100644 (file)
@@ -103,15 +103,19 @@ class OnoffControl(dbus.service.Object):
         dbus.service.Object.__init__(self, busname, "%s/%s" % (self.path, name))
         self.device = device
         self.usecount = 0
-        device.notify.add(self.changestate)
+        device.notify.add(self._changestate_notifier)
+
+    def _changestate_notifier(self, state):
+        logger.debug("emitting state %s", state.name)
+        self.changestate(state.value)
 
     @dbus.service.signal(domain, signature="q")
     def changestate(self, state):
-        logger.debug("emitting state %d", state)
+        pass
 
     @dbus.service.method(domain, out_signature="q")
     def state(self):
-        return self.device.state
+        return self.device.state.value
 
     @dbus.service.method(domain, in_signature="q", out_signature="q")
     def activatetime(self, duration):
@@ -137,7 +141,7 @@ class OnoffControl(dbus.service.Object):
         self.usecount += 1
         if self.usecount <= 1:
             self.device.activate()
-        return self.device.state
+        return self.device.state.value
 
     def unuse(self):
         self.usecount -= 1
index bea9708..954c6ff 100644 (file)
@@ -1,6 +1,6 @@
 import os.path
 
-from .common import OnoffDevice, ST_ACTIVE
+from .common import OnoffDevice, OnoffState
 
 def _write_file_value(path, content):
     with open(path, "w") as f:
@@ -17,7 +17,7 @@ class OnoffGPIO(OnoffDevice):
         @param active_low: whether the GPIO should be inverted
         """
         OnoffDevice.__init__(self)
-        self.current_state = 0
+        self.current_state = OnoffState.inactive
         basedir = "/sys/class/gpio"
         self.gpiodir = "%s/gpio%d" % (basedir, gpionumber)
         if not os.path.isdir(self.gpiodir):
@@ -28,7 +28,7 @@ class OnoffGPIO(OnoffDevice):
     def _set_state(self, state):
         self.current_state = state
         _write_file_value("%s/value" % self.gpiodir,
-                         "1" if self.current_state == ST_ACTIVE else "0")
+                          "1" if state == OnoffState.active else "0")
         self.changestate(self.current_state)
 
     @property
@@ -36,7 +36,7 @@ class OnoffGPIO(OnoffDevice):
         return self.current_state
 
     def activate(self):
-        self._set_state(ST_ACTIVE)
+        self._set_state(OnoffState.active)
 
     def deactivate(self):
-        self._set_state(0)
+        self._set_state(OnoffState.inactive)
index 572cbd9..6d738c7 100644 (file)
@@ -2,7 +2,7 @@ import logging
 import os
 import signal
 
-from .common import ST_ACTIVE, ST_TRANSITION, OnoffDevice
+from .common import OnoffDevice, OnoffState
 from .gobject import spawn_child
 
 logger = logging.getLogger("onoff.process")
@@ -32,14 +32,14 @@ class OnoffProcess(OnoffDevice):
         OnoffDevice.__init__(self)
         self.command = command
         self.termsig = termsig
-        self.desired_state = 0 # bit mask of just ST_ACTIVE
+        self.desired_state = OnoffState.inactive
         self.pid = None
         self.killed = False
 
     @property
     def state(self):
         if self.killed:
-            return self.desired_state | ST_TRANSITION
+            return self.desired_state | OnoffState.transition
         return self.desired_state
 
     def start_process(self):
@@ -47,7 +47,7 @@ class OnoffProcess(OnoffDevice):
         logger.info("starting command %s", " ".join(self.command))
         self.pid = spawn_child(self.command, self.process_died)
         logger.debug("started as pid %d", self.pid)
-        assert self.desired_state == ST_ACTIVE
+        assert self.desired_state == OnoffState.active
         logger.debug("process started")
         self.changestate(self.state)
 
@@ -56,22 +56,22 @@ class OnoffProcess(OnoffDevice):
         self.pid = None
         self.killed = False
         logger.info("process %d died", pid)
-        if self.desired_state == ST_ACTIVE:
+        if self.desired_state == OnoffState.active:
             self.start_process()
         else:
             self.changestate(self.state)
 
     def activate(self):
-        if self.desired_state != ST_ACTIVE:
-            self.desired_state = ST_ACTIVE
+        if self.desired_state != OnoffState.active:
+            self.desired_state = OnoffState.active
             if self.pid is None:
                 self.start_process()
             else:
                 logger.debug("already activated. nothing to do")
 
     def deactivate(self):
-        if self.desired_state != 0:
-            self.desired_state = 0
+        if self.desired_state != OnoffState.inactive:
+            self.desired_state = OnoffState.inactive
             if self.pid is not None and not self.killed:
                 logger.info("killing process %d", self.pid)
                 os.kill(self.pid, self.termsig)