yau-plant-assistant/cube/model/alarms.yml
Claude 34d2ccc576 Scaffold the WRPS plant operations assistant repository
Build spec and host brief carried in from C:\Claude and WRPS/02-env; the
plant model (equipment, tags, alarm bitmask, enums, unit conversions) is
derived from WRPS/04-plc/register-map.csv, WRPS/05-scada/modbus/scada-points.csv
and WRPS-CTL-003.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 13:56:32 +10:00

171 lines
5.7 KiB
YAML

# =============================================================================
# alarms.yml — alarm and event history.
#
# SOURCE: fixture.alarm_history while USE_FIXTURES=true. When imh is live this
# becomes the agreed imh alarm table and the column names below change with it.
# Nothing else in this file should need to change; that is the point of it.
#
# THREE DEFINITIONS THAT DECIDE WHETHER THE ANSWERS ARE RIGHT. They are here in
# comments because the person checking the number needs to read them, and they
# are not obvious from the measure names.
#
# 1. AN ALARM IS A TRANSITION INTO THE ACTIVE STATE.
# state = 'ACTIVE' only. RTN is the return-to-normal of the activation that
# preceded it, and ACK is an operator acknowledging one. Counting every row
# roughly doubles every answer. "6 times last week" must mean six
# activations.
#
# 2. "LAST WEEK" IS A ROLLING 7 x 24 h WINDOW IN SITE_TIMEZONE.
# Not the previous calendar week, not 7 calendar days. Storage is UTC and
# the conversion happens here, once. If someone means the calendar week they
# have to say so, and the answer must state the window it used.
#
# 3. CHATTERING IS 3 OR MORE ACTIVATIONS OF THE SAME TAG WITHIN 60 MINUTES.
# An arbitrary threshold, chosen to match the site's alarm rationalisation
# convention. It is stated in the answer whenever chattering is reported,
# because a different threshold gives a different story.
# =============================================================================
cubes:
- name: alarms
sql_table: fixture.alarm_history # -> imh alarm table at Phase 4
description: >
Alarm and event history for the Waterloo Road Pump Station. One row per
state transition. Activations only are counted as alarms.
joins:
- name: equipment
sql: "{CUBE}.equipment_id = {equipment}.equipment_id"
relationship: many_to_one
dimensions:
- name: alarm_id
sql: alarm_id
type: number
primary_key: true
- name: event_time
sql: event_time
type: time
description: Transition time. Stored UTC, presented in SITE_TIMEZONE.
- name: tag_id
sql: tag_id
type: string
- name: equipment_id
sql: equipment_id
type: string
- name: alarm_type
sql: alarm_type
type: string
description: >
HIGH_LEVEL, HIGH_HIGH_LEVEL, LOW_LOW_LEVEL, SPILL, PUMP_TRIP,
SEAL_LEAK, HIGH_VIBRATION, LEVEL_SIGNAL_FAULT, MAINS_FAILURE,
SETPOINT_REJECTED. These correspond to the bits of the PLC alarm
bitmask %QW17 - see db/seed/tags.csv, PS_STN_ALARM_BITMASK.
- name: state
sql: state
type: string
description: ACTIVE, RTN or ACK. Only ACTIVE counts as an alarm.
- name: priority
sql: priority
type: number
description: 1 highest, 3 lowest. SPILL and PUMP_TRIP are priority 1.
- name: value
sql: value
type: number
description: Process value at the transition, in engineering_unit.
- name: is_fixture
sql: is_fixture
type: boolean
description: >
TRUE means this row came from db/002_fixtures.sql and is generated
test data, not plant history. The API surfaces this to the operator.
measures:
- name: alarm_count
type: count
filters:
- sql: "{CUBE}.state = 'ACTIVE'"
description: >
Number of alarm ACTIVATIONS. Definition 1 above. This is the measure
behind "how many times did X alarm come up".
- name: transition_count
type: count
description: >
Every row including RTN and ACK. Diagnostics only - do not answer an
operator question with this.
- name: distinct_tags
sql: tag_id
type: count_distinct
filters:
- sql: "{CUBE}.state = 'ACTIVE'"
description: How many different tags alarmed in the window.
- name: first_alarm
sql: event_time
type: min
filters:
- sql: "{CUBE}.state = 'ACTIVE'"
- name: last_alarm
sql: event_time
type: max
filters:
- sql: "{CUBE}.state = 'ACTIVE'"
- name: priority_1_count
type: count
filters:
- sql: "{CUBE}.state = 'ACTIVE' AND {CUBE}.priority = 1"
description: Priority 1 activations - trips and spills.
pre_aggregations:
# Keeps "count alarms last week" fast without repeatedly scanning imh.
# Materialised into pg-ai schema cube_preagg. Watch its growth on
# /datadisk; the retention policy is the refresh_key plus manual pruning.
- name: alarms_by_hour
measures: [alarm_count, distinct_tags, priority_1_count]
dimensions: [alarm_type, equipment_id, tag_id]
time_dimension: event_time
granularity: hour
partition_granularity: month
refresh_key:
every: 10 minutes
build_range_start:
sql: "SELECT now() - interval '180 days'"
build_range_end:
sql: "SELECT now()"
views:
- name: alarm_activity
description: >
Alarm activations joined to equipment, so a question about "Pump 02" can
be answered without the caller knowing which tags belong to it.
cubes:
- join_path: alarms
includes:
- event_time
- alarm_type
- tag_id
- state
- priority
- value
- is_fixture
- alarm_count
- distinct_tags
- priority_1_count
- join_path: alarms.equipment
prefix: true
includes:
- equipment_id
- display_name
- equipment_type