shift_handover
shift_handover ¤
Automated shift handover report generation.
Standardize shift-to-shift communication: - Production summary - Quality summary - Downtime summary - Issues to watch
Two modes of operation:
1. From raw signals: generate_report(counter_uuid, ok_counter_uuid, ...)
2. From pre-computed DataFrames: from_shift_data(production_df, quality_df, downtime_df)
ShiftHandoverEvents ¤
ShiftHandoverEvents(
dataframe: DataFrame,
*,
time_column: str = "systime",
shift_definitions: (
dict[str, tuple[str, str]] | None
) = None
)
Bases: Base
Generate automated shift handover reports.
Combines production, quality, and downtime data into a single summary suitable for shift handover meetings.
Merge keys: [date, shift] — the report output is keyed on these columns.
Two usage patterns:
Pattern A — from raw signals (one-step):
report = ShiftHandoverEvents(df)
result = report.generate_report(
counter_uuid='prod', ok_counter_uuid='ok',
nok_counter_uuid='nok', run_state_uuid='state',
targets={'shift_1': 450, 'shift_2': 450},
)
Pattern B — pipeline (compose from upstream modules):
# Step 1: compute upstream DataFrames
prod = ShiftReportEvents(df).shift_production('counter')
qual = QualityEvents(df).nok_by_shift('ok', 'nok')
downtime = DowntimeEvents(df).downtime_by_shift('state')
# Step 2: assemble into handover report
result = ShiftHandoverEvents.from_shift_data(
production_df=prod,
quality_df=qual,
downtime_df=downtime,
targets={'shift_1': 450, 'shift_2': 450},
)
Both patterns return the same output schema.
Run state may be a string state signal (running_value="Running" in
value_string) or a boolean run signal (value_bool, True =
running); see :meth:generate_report. downtime_seconds is the
downtime in seconds; downtime_minutes is kept as a convenience.
from_shift_data
staticmethod
¤
from_shift_data(
production_df: DataFrame,
quality_df: DataFrame | None = None,
downtime_df: DataFrame | None = None,
*,
targets: dict[str, float] | None = None,
report_date: str | None = None
) -> pd.DataFrame
Build a handover report from pre-computed shift-level DataFrames.
This is the pipeline-friendly entry-point. Instead of reading raw signals, it accepts DataFrames that were already computed by upstream modules (ShiftReportEvents, QualityEvents, DowntimeEvents, etc.).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
production_df
|
DataFrame
|
DataFrame with [date, shift, quantity] — e.g. from
|
required |
quality_df
|
DataFrame | None
|
DataFrame with [date, shift, ok_parts, nok_parts, quality_pct]
— e.g. from |
None
|
downtime_df
|
DataFrame | None
|
DataFrame with [date, shift, availability_pct,
downtime_seconds] — e.g. from
|
None
|
targets
|
dict[str, float] | None
|
Per-shift production targets (dict). |
None
|
report_date
|
str | None
|
Specific date (YYYY-MM-DD). If None, uses latest. |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
DataFrame with columns: |
DataFrame
|
date, shift, production, production_target, production_achievement_pct, |
DataFrame
|
ok_parts, nok_parts, quality_pct, availability_pct, downtime_minutes, |
DataFrame
|
downtime_seconds. When |
DataFrame
|
|
DataFrame
|
from it. |
generate_report ¤
generate_report(
counter_uuid: str,
ok_counter_uuid: str,
nok_counter_uuid: str,
run_state_uuid: str,
*,
targets: dict[str, float] | None = None,
quality_target_pct: float = 98.0,
availability_target_pct: float = 90.0,
running_value: str | bool = "Running",
value_column_counter: str = "value_integer",
value_column_state: str = "value_string",
report_date: str | None = None,
handle_resets: bool = True,
production_day: bool = True
) -> pd.DataFrame
Generate a shift handover report from raw timeseries signals.
For pipeline usage with pre-computed DataFrames, use
:meth:from_shift_data instead.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
counter_uuid
|
str
|
UUID of production counter. |
required |
ok_counter_uuid
|
str
|
UUID of good parts counter. |
required |
nok_counter_uuid
|
str
|
UUID of the NOK part counter. |
required |
run_state_uuid
|
str
|
UUID of machine state signal. |
required |
targets
|
dict[str, float] | None
|
Per-shift production targets. |
None
|
quality_target_pct
|
float
|
Quality target percentage. |
98.0
|
availability_target_pct
|
float
|
Availability target percentage. |
90.0
|
running_value
|
str | bool
|
Value indicating machine is running. A bool
matches a boolean run signal ( |
'Running'
|
value_column_counter
|
str
|
Column for counter values. |
'value_integer'
|
value_column_state
|
str
|
Column for state values. |
'value_string'
|
report_date
|
str | None
|
Specific date (YYYY-MM-DD). If None, uses latest date. |
None
|
handle_resets
|
bool
|
When True (default), treat a decreasing counter as a reset and
count the production after the reset for production, ok_parts and
nok_parts. A shift boundary is exactly where counters commonly
reset, so |
True
|
production_day
|
bool
|
When True, an overnight shift's post-midnight
readings are attributed to the shift's start date, so a night
shift is one contiguous |
True
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
DataFrame with columns: |
DataFrame
|
start, end, duration_seconds (the shift window from |
DataFrame
|
|
DataFrame
|
shift ends on the next day), date, shift, production, |
DataFrame
|
production_target, production_achievement_pct, ok_parts, |
DataFrame
|
nok_parts, quality_pct, availability_pct, downtime_minutes |
DataFrame
|
(convenience), downtime_seconds, and |
DataFrame
|
|
highlight_issues ¤
highlight_issues(
counter_uuid: str | None = ...,
ok_counter_uuid: str | None = ...,
nok_counter_uuid: str | None = ...,
run_state_uuid: str | None = ...,
*,
report_df: DataFrame | None = ...,
thresholds: dict[str, float] | None = ...,
targets: dict[str, float] | None = ...,
running_value: str | bool = ...,
value_column_counter: str = ...,
value_column_state: str = ...,
report_date: str | None = ...,
as_frame: Literal[True] = ...
) -> pd.DataFrame
highlight_issues(
counter_uuid: str | None = ...,
ok_counter_uuid: str | None = ...,
nok_counter_uuid: str | None = ...,
run_state_uuid: str | None = ...,
*,
report_df: DataFrame | None = ...,
thresholds: dict[str, float] | None = ...,
targets: dict[str, float] | None = ...,
running_value: str | bool = ...,
value_column_counter: str = ...,
value_column_state: str = ...,
report_date: str | None = ...,
as_frame: Literal[False]
) -> list[dict[str, Any]]
highlight_issues(
counter_uuid: str | None = None,
ok_counter_uuid: str | None = None,
nok_counter_uuid: str | None = None,
run_state_uuid: str | None = None,
*,
report_df: DataFrame | None = None,
thresholds: dict[str, float] | None = None,
targets: dict[str, float] | None = None,
running_value: str | bool = "Running",
value_column_counter: str = "value_integer",
value_column_state: str = "value_string",
report_date: str | None = None,
as_frame: bool = True
) -> pd.DataFrame | list[dict[str, Any]]
Identify issues that need attention.
Can be called in two ways:
-
From raw signals (provide UUIDs):
highlight_issues('prod', 'ok', 'nok', 'state', thresholds={...}) -
From a pre-built report DataFrame:
highlight_issues(report_df=my_report, thresholds={...})
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
counter_uuid
|
str | None
|
UUID of production counter (raw-signal mode). |
None
|
ok_counter_uuid
|
str | None
|
UUID of good parts counter (raw-signal mode). |
None
|
nok_counter_uuid
|
str | None
|
UUID of the NOK part counter (raw-signal mode). |
None
|
run_state_uuid
|
str | None
|
UUID of machine state signal (raw-signal mode). |
None
|
report_df
|
DataFrame | None
|
Pre-computed report DataFrame (pipeline mode). If provided, UUID arguments are ignored. |
None
|
thresholds
|
dict[str, float] | None
|
Minimum acceptable values for each metric. Defaults to production_achievement_pct=95, quality_pct=98, availability_pct=90. |
None
|
targets
|
dict[str, float] | None
|
Per-shift production targets. |
None
|
running_value
|
str | bool
|
Value indicating machine is running. |
'Running'
|
value_column_counter
|
str
|
Column for counter values. |
'value_integer'
|
value_column_state
|
str
|
Column for state values. |
'value_string'
|
report_date
|
str | None
|
Specific date (YYYY-MM-DD). |
None
|
as_frame
|
bool
|
When True (default), return a DataFrame (see below).
|
True
|
Returns:
| Type | Description |
|---|---|
DataFrame | list[dict[str, Any]]
|
With |
:attr:`ISSUE_COLUMNS`
|
start, end, duration_seconds (the shift |
DataFrame | list[dict[str, Any]]
|
window of the report row; NaT / NaN when the report has none, |
DataFrame | list[dict[str, Any]]
|
e.g. one built by :meth: |
DataFrame | list[dict[str, Any]]
|
value, threshold, severity, severity_level (warn / critical). |
DataFrame | list[dict[str, Any]]
|
With |
DataFrame | list[dict[str, Any]]
|
shift, metric, value, threshold, severity. |
DataFrame | list[dict[str, Any]]
|
severity is 'warning' (within 5% of threshold) or 'critical'. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |