Index
Pump schedule modules for automated watering.
This package defines the abstract base class for pump schedules and provides the dynamic loading mechanism. Schedules control when and how much water is delivered to a plant.
Writing a custom schedule module
- Create a new
.pyfile in this package (e.g.my_schedule.py). - Define a class called exactly
Schedulethat inherits fromPumpSchedule. - Implement the three abstract methods:
__init__,get_schedule, andrun_schedule. - Optionally implement
validate_schedule_confas a@staticmethodto validate config data before instantiation. -
Create a schedule JSON file in
~/.plant_controller/pump_schedules/named<plant_name>.json::{ "type": "my_schedule", "schedule": { ... schedule-specific data ... } }
The "type" value must match the module filename (without .py).
The "schedule" value is passed to Schedule.__init__.
Example minimal schedule::
import anyio
from plant_controller.pump_schedules import PumpSchedule
class Schedule(PumpSchedule):
def __init__(self, schedule):
self.dose = schedule["dose_ml"]
self.interval = schedule["interval_seconds"]
def get_schedule(self):
return f"Pump {self.dose}ml every {self.interval}s"
async def run_schedule(self, pump_function):
while True:
await anyio.sleep(self.interval)
await pump_function(self.dose)
@staticmethod
def validate_schedule_conf(schedule_conf):
if "dose_ml" not in schedule_conf:
raise ValueError("Must include 'dose_ml'")
if "interval_seconds" not in schedule_conf:
raise ValueError("Must include 'interval_seconds'")
PumpSchedule
¶
Bases: ABC
Abstract base class for all pump schedule implementations.
A pump schedule determines when watering events occur and how much water is delivered. The schedule has full control over timing, enabling both simple time-based schedules and dynamic sensor-driven strategies.
Subclasses must be named Schedule in their module so that the dynamic
loader can find them.
Source code in pt/controller_3/src/plant_controller/pump_schedules/__init__.py
__init__(schedule)
abstractmethod
¶
Initialize the schedule from configuration data.
The schedule parameter receives whatever was in the "schedule"
field of the JSON config file. Its structure is entirely up to the
implementer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
schedule
|
Any | None
|
Schedule-specific configuration data (type defined by the implementation). May be None if the schedule requires no configuration. |
required |
Source code in pt/controller_3/src/plant_controller/pump_schedules/__init__.py
get_schedule()
abstractmethod
¶
Return a human-readable representation of this schedule.
This is served via the HTTP API so that users can inspect the current watering plan without reading config files.
Returns:
| Type | Description |
|---|---|
str | dict
|
A string description or dict (serialized as JSON) explaining |
str | dict
|
when watering will occur and at what dosages. |
Source code in pt/controller_3/src/plant_controller/pump_schedules/__init__.py
run_schedule(pump_function)
abstractmethod
async
¶
Execute the schedule, calling pump_function at appropriate times.
This coroutine runs indefinitely. It should await anyio.sleep()
until the next watering event, then call
await pump_function(dosage_ml) to trigger the pump.
The method must not return under normal operation. If the schedule is cancelled externally (via CancelScope), it will be restarted with a freshly parsed config.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pump_function
|
Callable[[int], None]
|
Async callback that activates the pump. Call with an integer dosage in milliliters. |
required |
Source code in pt/controller_3/src/plant_controller/pump_schedules/__init__.py
validate_schedule_conf(schedule_conf)
staticmethod
¶
Validate schedule-specific configuration data.
Called during schedule loading to catch config errors early.
Should raise ValueError with a descriptive message if the
configuration is invalid.
If validation is not needed, this method can be left as a no-op.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
schedule_conf
|
Any
|
The "schedule" field from the JSON config file. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the configuration is invalid. |
Source code in pt/controller_3/src/plant_controller/pump_schedules/__init__.py
NonSchedule
¶
Bases: PumpSchedule
A no-op schedule that never triggers watering.
Used as a fallback when no valid schedule config exists or when schedule parsing fails.
Source code in pt/controller_3/src/plant_controller/pump_schedules/__init__.py
parse_schedule(schedule_location)
¶
Load and instantiate a PumpSchedule from a JSON config file.
If the file cannot be loaded or is invalid, returns a NonSchedule instance and logs the error.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
schedule_location
|
str
|
Filesystem path to the schedule JSON file. |
required |
Returns:
| Type | Description |
|---|---|
PumpSchedule
|
An initialized PumpSchedule instance (or NonSchedule on failure). |
Source code in pt/controller_3/src/plant_controller/pump_schedules/__init__.py
validate_schedule(schedule_config)
¶
Validate the top-level structure of a schedule config dict.
Checks that the required 'type' and 'schedule' keys exist, that the referenced module can be imported and contains a 'Schedule' class, and delegates to that class's validate_schedule_conf for content validation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
schedule_config
|
dict[str, Any]
|
Parsed JSON dict with 'type' and 'schedule' keys. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the config structure is invalid or the module/class cannot be loaded. |