HackatonSmall / modules /watering.py
Crocolil's picture
Upload folder using huggingface_hub
4e9208d verified
Raw
History Blame Contribute Delete
4.84 kB
import datetime
import re
from modules.plant import Plant
from modules.weather_utils import did_or_will_rain, weather_values
# ── 1. Watering frequency parser ───────────────────────────────────────────────
_RECOMMENDATION_MAP: dict[str, int] = {
# ── Fixed cadence ──────────────────────────────────────────────────────
"water weekly": 7,
# ── Always moist ──────────────────────────────────────────────────────
"keep soil moist": 2,
"keep soil consistently moist": 2,
"keep soil evenly moist": 2,
"keep soil slightly moist": 3,
"regular, moist soil": 3,
# ── Regular ───────────────────────────────────────────────────────────
"regular watering": 4,
"regular, well-drained soil": 4,
# ── Water when dry ────────────────────────────────────────────────────
"water when soil is dry": 5,
"water when topsoil is dry": 5,
"water when soil feels dry": 5,
"let soil dry between watering": 7,
}
_FALLBACK_RULES: list[tuple[str, int | None]] = [
(r"daily", 1),
(r"twice.{0,10}week", 3),
(r"every\s+(\d+)\s+day", None), # extracted dynamically
(r"once.{0,10}week|weekly", 7),
(r"once.{0,10}fortnight|every.{0,6}two.{0,6}week", 14),
(r"monthly", 30),
(r"moist", 2),
(r"dry", 6),
(r"regular", 4),
]
DEFAULT_INTERVAL = 4
def _parse_watering_frequency(recommendation: str) -> int:
"""Map a free-text watering recommendation to a watering interval in days.
Args:
recommendation: e.g. "Water weekly", "Keep soil moist"
Returns:
Watering interval in days (>= 1).
"""
if not recommendation or not recommendation.strip():
return DEFAULT_INTERVAL
cleaned = recommendation.strip().lower()
if cleaned in _RECOMMENDATION_MAP:
return _RECOMMENDATION_MAP[cleaned]
for key, days in _RECOMMENDATION_MAP.items():
if cleaned.startswith(key) or key.startswith(cleaned):
return days
for pattern, days in _FALLBACK_RULES:
m = re.search(pattern, cleaned)
if m:
if days is None:
try:
return max(1, int(m.group(1)))
except (IndexError, ValueError):
return DEFAULT_INTERVAL
return days
return DEFAULT_INTERVAL
def get_watering_frequency(plant: Plant) -> int:
"""Determine the watering frequency for a plant, in days.
Args:
plant: The plant to determine the watering frequency for.
Returns:
Watering frequency in days (>= 1).
"""
if plant.watering_frequency:
return _parse_watering_frequency(plant.watering_frequency)
return DEFAULT_INTERVAL
def should_water(plant: Plant,last_watered: datetime.date | None, date: datetime.date, LAT: float, LON: float) -> bool:
"""Determine if a plant should be watered on a given date.
# returns true if its not raining and the plant wasnt watered since the last watering frequency interval
Args:
plant: The plant to check.
last_watered: The date the plant was last watered.
date: The date to check for.
LAT: The latitude of the plant's location.
LON: The longitude of the plant's location.
"""
if last_watered is None:
return True
frequency = get_watering_frequency(plant)
# convert last_watered to datetime.date if it's a string
if isinstance(last_watered, str):
last_watered = datetime.datetime.strptime(last_watered, "%Y-%m-%d").date()
next_watering_date = last_watered + datetime.timedelta(days=frequency)
if date >= next_watering_date and not did_or_will_rain(date, LAT, LON, forecast_threshold=50):
return True
return False