diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,12 @@
+reactive-banana-automation (0.3.0) upstream; urgency=medium
+
+  * EventSource is now a data type with an extra value for expansion.
+    (API change)
+  * Added newEventSource, sensorUnavailable, sensedEventBehavior,
+    and automationStepper.
+
+ -- Joey Hess <id@joeyh.name>  Sat, 05 May 2018 19:27:56 -0400
+
 reactive-banana-automation (0.2.0) upstream; urgency=medium
 
   * Automation is now a newtype. (API change)
diff --git a/Reactive/Banana/Automation.hs b/Reactive/Banana/Automation.hs
--- a/Reactive/Banana/Automation.hs
+++ b/Reactive/Banana/Automation.hs
@@ -23,6 +23,8 @@
 	observeAutomation,
 	-- * Events
 	EventSource,
+	newEventSource,
+	fromEventSource,
 	gotEvent,
 	getEventFrom,
 	onEvent,
@@ -32,6 +34,9 @@
 	sensedBehavior,
 	sensed,
 	(=:),
+	sensorUnavailable,
+	sensedEventBehavior,
+	automationStepper,
 	-- * Time
 	Timestamped(..),
 	Timestamp(..),
@@ -72,7 +77,7 @@
 -- run as needed to keep the temperature in a safe range, while
 -- minimizing compressor starts.
 --
--- > data Sensors = Sensors { fridgeTemperature :: EventSource (Sensed Double) }
+-- > data Sensors = Sensors { fridgeTemperature :: EventSource (Sensed Double) () }
 -- > data Actuators = FridgePower PowerChange deriving (Show)
 -- > 
 -- > fridge :: Automation Sensors Actuators
@@ -138,7 +143,7 @@
 -- Continuing the above example of a fridge, here's how to run it:
 -- 
 -- > mkSensors :: IO Sensors
--- > mkSensors = Sensors <$> newAddHandler
+-- > mkSensors = Sensors <$> newEventSource ()
 -- > 
 -- > driveActuators :: Actuators -> IO ()
 -- > driveActuators = print
@@ -196,17 +201,29 @@
 	return runner
 
 -- | A source of events.
-type EventSource a = (AddHandler a, a -> IO ())
+--
+-- `v` is unused by this library, but is provided in case you
+-- need a way to track some extra data about an EventSource such as, for
+-- example, the timestamp of the most recent event.
+data EventSource a v = EventSource
+	{ getEventSource :: (AddHandler a, a -> IO ())
+	, fromEventSource :: v
+	-- ^ Get extra data from an EventSource.
+	}
 
-addHandler :: EventSource a -> AddHandler a
-addHandler = fst
+-- | Construct a new EventSource.
+newEventSource :: v -> IO (EventSource a v)
+newEventSource v = EventSource <$> newAddHandler <*> pure v
 
+addHandler :: EventSource a v -> AddHandler a
+addHandler = fst . getEventSource
+
 -- | Call this to trigger an event.
-gotEvent :: EventSource a -> a -> IO ()
-gotEvent = snd
+gotEvent :: EventSource a v -> a -> IO ()
+gotEvent = snd . getEventSource
 
 -- | Get an Event from an EventSource.
-getEventFrom :: EventSource a -> MomentAutomation (Event a)
+getEventFrom :: EventSource a v -> MomentAutomation (Event a)
 getEventFrom = MomentAutomation . fromAddHandler . addHandler
 
 -- | Runs an action when an event occurs.
@@ -224,7 +241,7 @@
 --
 -- The Event only contains values when the sensor provided a reading,
 -- not times when it was unavailable.
-sensedEvent :: EventSource (Sensed a) -> MomentAutomation (Event a)
+sensedEvent :: EventSource (Sensed a) v -> MomentAutomation (Event a)
 sensedEvent s = do
 	e <- getEventFrom s
 	return $ filterJust $ flip fmap e $ \case
@@ -232,22 +249,32 @@
 		Sensed a -> Just a
 
 -- | Create a Behavior from sensed values.
-sensedBehavior :: EventSource (Sensed a) -> MomentAutomation (Behavior (Sensed a))
-sensedBehavior s = 
-	MomentAutomation . stepper SensorUnavailable =<< getEventFrom s
+sensedBehavior :: EventSource (Sensed a) v -> MomentAutomation (Behavior (Sensed a))
+sensedBehavior s = sensedEventBehavior =<< getEventFrom s
 
+sensedEventBehavior :: Event (Sensed a) -> MomentAutomation (Behavior (Sensed a))
+sensedEventBehavior = automationStepper SensorUnavailable
+
+-- | `stepper` lifted into `MomentAutomation`
+automationStepper :: a -> Event a -> MomentAutomation (Behavior a)
+automationStepper a e = MomentAutomation $ stepper a e
+
 -- | Call when a sensor has sensed a value.
 --
 -- > getFridgeTemperature >>= sensed (fridgeTemperature sensors)
-sensed :: EventSource (Sensed a) -> a -> IO ()
+sensed :: EventSource (Sensed a) v -> a -> IO ()
 sensed s = gotEvent s . Sensed
 
 -- | Same as `sensed`
 -- 
 -- > fridgeTemperature sensors =: 0
-(=:) :: EventSource (Sensed a) -> a -> IO ()
+(=:) :: EventSource (Sensed a) v -> a -> IO ()
 (=:) = sensed
 
+-- | Call when a sensor is unavailable.
+sensorUnavailable :: EventSource (Sensed a) v -> IO ()
+sensorUnavailable s = gotEvent s SensorUnavailable
+
 -- | A timestamped value.
 --
 -- In reactive-banana, an `Event` is tagged with its time of occurrence,
@@ -289,13 +316,13 @@
 
 -- | Call when a sensor has sensed a value, which will be `Timestamped` with
 -- the current time.
-sensedNow :: Timestamp t => EventSource (Sensed (Timestamped t a)) -> a -> IO ()
+sensedNow :: Timestamp t => EventSource (Sensed (Timestamped t a)) v -> a -> IO ()
 sensedNow es a = do
 	now <- getCurrentTimestamp
 	gotEvent es (Sensed (Timestamped now a))
 
 -- | Call when a sensor sensed a value with a particular timestamp.
-sensedAt :: Timestamp t => t -> EventSource (Sensed (Timestamped t a)) -> a -> IO ()
+sensedAt :: Timestamp t => t -> EventSource (Sensed (Timestamped t a)) v -> a -> IO ()
 sensedAt ts es a = gotEvent es (Sensed (Timestamped ts a))
 
 -- | Given a `Timestamped` `Event` and a function, produces an `Event`
@@ -332,16 +359,16 @@
 
 -- | Call repeatedly to feed a clock signal to an `Automation`
 -- that needs to know what time it is.
-clockSignal :: Timestamp t => EventSource (ClockSignal t) -> IO ()
+clockSignal :: Timestamp t => EventSource (ClockSignal t) v -> IO ()
 clockSignal es = gotEvent es . ClockSignal =<< getCurrentTimestamp
 
 -- | Call to feed a particular time to an `Automation`.
-clockSignalAt :: Timestamp t => t -> EventSource (ClockSignal t) -> IO ()
+clockSignalAt :: Timestamp t => t -> EventSource (ClockSignal t) v -> IO ()
 clockSignalAt t es = gotEvent es (ClockSignal t)
 
 -- | Create a Behavior from a ClockSignal. It will initially be Nothing,
 -- and then updates with each incoming clock signal.
-clockSignalBehavior :: Timestamp t => EventSource (ClockSignal t) -> MomentAutomation (Behavior (Maybe (ClockSignal t)))
+clockSignalBehavior :: Timestamp t => EventSource (ClockSignal t) v -> MomentAutomation (Behavior (Maybe (ClockSignal t)))
 clockSignalBehavior s = MomentAutomation . stepper Nothing 
 	=<< fmap Just <$> getEventFrom s
 
diff --git a/Reactive/Banana/Automation/Examples.hs b/Reactive/Banana/Automation/Examples.hs
--- a/Reactive/Banana/Automation/Examples.hs
+++ b/Reactive/Banana/Automation/Examples.hs
@@ -6,7 +6,6 @@
 module Reactive.Banana.Automation.Examples where
 
 import Reactive.Banana
-import Reactive.Banana.Frameworks
 import Reactive.Banana.Automation
 import Data.Time.Clock.POSIX
 import Data.Time.LocalTime
@@ -15,10 +14,10 @@
 -- | We'll use a single Sensors type containing all the sensors
 -- used by the examples below.
 data Sensors = Sensors
-	{ fridgeTemperature :: EventSource (Sensed Double)
-	, motionSensor :: EventSource (Sensed (Timestamped POSIXTime Bool))
-	, clock :: EventSource (ClockSignal LocalTime)
-	, rainGaugeTipSensor :: EventSource (Sensed ())
+	{ fridgeTemperature :: EventSource (Sensed Double) ()
+	, motionSensor :: EventSource (Sensed (Timestamped POSIXTime Bool)) ()
+	, clock :: EventSource (ClockSignal LocalTime) ()
+	, rainGaugeTipSensor :: EventSource (Sensed ()) ()
 	}
 
 -- | And a single Actuators type containing all the actuators used by the
@@ -33,10 +32,10 @@
 -- | For running the examples, you'll need this, to construct a `Sensors`
 mkSensors :: IO Sensors
 mkSensors = Sensors
-	<$> newAddHandler
-	<*> newAddHandler
-	<*> newAddHandler
-	<*> newAddHandler
+	<$> newEventSource ()
+	<*> newEventSource ()
+	<*> newEventSource ()
+	<*> newEventSource ()
 
 -- | A fridge, containing the `fridgeTemperature` sensor and with
 -- its power controlled by the `FridgePower` actuator.
diff --git a/reactive-banana-automation.cabal b/reactive-banana-automation.cabal
--- a/reactive-banana-automation.cabal
+++ b/reactive-banana-automation.cabal
@@ -1,5 +1,5 @@
 Name: reactive-banana-automation
-Version: 0.2.0
+Version: 0.3.0
 Cabal-Version: >= 1.8
 License: AGPL-3
 Maintainer: Joey Hess <id@joeyh.name>
