diff --git a/python_payload/st3m/input.py b/python_payload/st3m/input.py
index 049ce0c424afbc41b5ccd9d63cab46f6024f05e2..af3723a8ea24cb4cd8b66ea07ba03cb2d02cdcae 100644
--- a/python_payload/st3m/input.py
+++ b/python_payload/st3m/input.py
@@ -72,46 +72,50 @@ class InputState:
     If you want to detect edges, use the stateful InputController.
     """
 
-    def __init__(
-        self,
-        captouch: captouch.CaptouchState,
-        buttons: InputButtonState,
-        imu: IMUState,
-        temperature: float,
-        battery_voltage: float,
-    ) -> None:
-        # self.petal_pads = petal_pads
-        self.captouch = captouch
-        self.buttons = buttons
-        self.imu = imu
-        self.temperature = temperature
-        self.battery_voltage = battery_voltage
-
-    @classmethod
-    def gather(cls) -> "InputState":
-        """
-        Build InputState from current hardware state. Should only be used by the
-        Reactor.
-        """
-        cts = captouch.read()
-        app = sys_buttons.get_app()
-        os = sys_buttons.get_os()
-        app_is_left = sys_buttons.app_is_left()
-        buttons = InputButtonState(app, os, app_is_left)
-
-        acc = imu.acc_read()
-        gyro = imu.gyro_read()
-        pressure, temperature = imu.pressure_read()
-        imu_state = IMUState(acc, gyro, pressure)
-
-        battery_voltage = power.battery_voltage
-        return InputState(
-            cts,
-            buttons,
-            imu_state,
-            temperature,
-            battery_voltage,
-        )
+    def __init__(self) -> None:
+        self._captouch = None
+        self._buttons = None
+        self._imu = None
+        self._temperature = None
+        self._battery_voltage = None
+        self._pressure = None
+
+    @property
+    def captouch(self):
+        if self._captouch is None:
+            self._captouch = captouch.read()
+        return self._captouch
+
+    @property
+    def buttons(self):
+        if self._buttons is None:
+            app = sys_buttons.get_app()
+            os = sys_buttons.get_os()
+            app_is_left = sys_buttons.app_is_left()
+            self._buttons = InputButtonState(app, os, app_is_left)
+        return self._buttons
+
+    @property
+    def imu(self):
+        if self._imu is None:
+            acc = imu.acc_read()
+            gyro = imu.gyro_read()
+            if self._pressure is None:
+                self._pressure, self._temperature = imu.pressure_read()
+            self._imu = IMUState(acc, gyro, self._pressure)
+        return self._imu
+
+    @property
+    def battery_voltage(self):
+        if self._battery_voltage is None:
+            self._battery_voltage = power.battery_voltage
+        return self._battery_voltage
+
+    @property
+    def temperature(self):
+        if self._temperature is None:
+            self._pressure, self._temperature = imu.pressure_read()
+        return self._temperature
 
 
 class RepeatSettings:
@@ -463,14 +467,38 @@ class Touchable:
 class PetalState:
     def __init__(self, ix: int) -> None:
         self.ix = ix
-        self.whole = Pressable(False)
-        self.pressure = 0
-        self.gesture = Touchable()
+        self._whole = Pressable(False)
+        self._gesture = Touchable()
+        self._whole_updated = False
+        self._gesture_updated = False
+        self._ts = None
+        self._petal = None
 
     def _update(self, ts: int, petal: captouch.CaptouchPetalState) -> None:
-        self.whole._update(ts, petal.pressed)
-        self.pressure = petal.pressure
-        self.gesture._update(ts, petal)
+        self._ts = ts
+        self._petal = petal
+        self._whole_updated = False
+        self._gesture_updated = False
+
+    @property
+    def whole(self):
+        if self._petal and not self._whole_updated:
+            self._whole._update(self._ts, self._petal.pressed)
+            self._whole_updated = True
+        return self._whole
+
+    @property
+    def pressure(self):
+        if not self._petal:
+            return 0
+        return self._petal.pressure
+
+    @property
+    def gesture(self):
+        if self._petal and not self._gesture_updated:
+            self._gesture._update(self._ts, self._petal)
+            self._gesture_updated = True
+        return self._gesture
 
 
 class CaptouchState:
@@ -481,17 +509,27 @@ class CaptouchState:
     socket, then the numbering continues clockwise.
     """
 
-    __slots__ = "petals"
-
     def __init__(self) -> None:
-        self.petals = [PetalState(i) for i in range(10)]
+        self._petals = [PetalState(i) for i in range(10)]
+        self._ins = None
+        self._ts = None
+        self._updated = False
 
     def _update(self, ts: int, ins: InputState) -> None:
-        for i, petal in enumerate(self.petals):
-            petal._update(ts, ins.captouch.petals[i])
+        self._ins = ins
+        self._ts = ts
+        self._updated = False
+
+    @property
+    def petals(self):
+        if self._ins and not self._updated:
+            for i, petal in enumerate(self._petals):
+                petal._update(self._ts, self._ins.captouch.petals[i])
+            self._updated = True
+        return self._petals
 
     def _ignore_pressed(self) -> None:
-        for petal in self.petals:
+        for petal in self._petals:
             petal.whole._ignore_pressed()
 
 
diff --git a/python_payload/st3m/reactor.py b/python_payload/st3m/reactor.py
index 46bb5a744faf817d4901e1294629d643fce16944..a96a8a14bd2a42e4c409dfb0101a4bf7f4f3f24a 100644
--- a/python_payload/st3m/reactor.py
+++ b/python_payload/st3m/reactor.py
@@ -141,7 +141,7 @@ class Reactor:
         # upcoming input api refactor
         captouch.refresh_events()
 
-        hr = InputState.gather()
+        hr = InputState()
 
         # Think!
         self._top.think(hr, delta)