Add Bento 1 fresh bentonite consumption

This commit is contained in:
2026-09-06 13:29:06 +02:00
parent ed0e20a04b
commit be8d76507a
11 changed files with 430 additions and 14 deletions
@@ -1,5 +1,6 @@
"""Single-cycle live material polling orchestration."""
from collections.abc import Callable
from dataclasses import dataclass
from datetime import datetime
from typing import Protocol
@@ -53,7 +54,13 @@ class MaterialPollingService:
gate_variable_id: str,
gate_threshold: float,
max_sample_gap_seconds: float,
application_variable_ids: tuple[str, ...] = (),
nominal_width_provider: Callable[[str], float] | None = None,
) -> None:
self._application_variable_ids = application_variable_ids
self._nominal_width_provider = nominal_width_provider
if application_variable_ids and nominal_width_provider is None:
raise ValueError("area application requires a nominal width provider")
self._gateway = gateway
self._state_store = state_store
self._machine_id = machine_id
@@ -71,6 +78,8 @@ class MaterialPollingService:
if run is None or now < run.start:
return None
width = (self._nominal_width_provider(run.production_order)
if self._application_variable_ids else None)
saved_polling_state = self._state_store.load(
self._machine_id,
run.production_order,
@@ -91,7 +100,7 @@ class MaterialPollingService:
if previous.end is None or previous.end > run.start:
raise ValueError("Historical production run overlaps the current open run")
integrated = self._integrate(
initial_state, start=previous.start, end=previous.end,
initial_state, start=previous.start, end=previous.end, width=width,
)
initial_state = MaterialIntegrationState(
cumulative_consumption_kg=integrated.cumulative_consumption_kg,
@@ -116,7 +125,7 @@ class MaterialPollingService:
if now < start:
return None
state = self._integrate(initial_state, start=start, end=now)
state = self._integrate(initial_state, start=start, end=now, width=width)
self._state_store.save(
self._machine_id,
@@ -134,13 +143,20 @@ class MaterialPollingService:
def _integrate(
self, initial_state: MaterialIntegrationState, *, start: datetime, end: datetime,
width: float | None = None,
) -> MaterialIntegrationState:
integrator = MaterialConsumptionIntegrator(self._config, initial_state=initial_state)
source_options = {}
if self._application_variable_ids:
source_options = dict(
application_variable_ids=self._application_variable_ids, nominal_width_m=width,
)
samples = self._gateway.get_material_samples(
machine_id=self._machine_id,
rate_variable_id=self._rate_variable_id,
gate_variable_id=self._gate_variable_id,
start=start,
end=end,
**source_options,
)
return integrator.process_many(samples)