# ============================================================================= # 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. Priority 1 is SPILL, PUMP_TRIP and LEVEL_SIGNAL_FAULT - losing the level signal on a well that can spill is a priority 1 condition, and the fixtures already treat it as one. This comment previously named only SPILL and PUMP_TRIP and disagreed with the data, which matters because this is the line an engineer reads when checking a priority_1_count. - 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