DEV Community

Guatu
Guatu

Posted on • Originally published at guatulabs.dev

Equipment Health Scoring: How One Number Made My Operators Stop Checking the Dashboard

Operators in my last plant used to ignore dashboards — not because they didn’t care, but because the data was too noisy, too fragmented, and too abstract. I've seen this pattern again and again: a sea of metrics with no clear signal. But when I implemented a simple health scoring system that aggregated temperature, vibration, and pressure into a single number between 0 and 100, that changed everything. Now, operators check that number daily, and it’s the only metric they ask about during shift handovers.

The key was making the score intuitive, real-time, and tied directly to the equipment’s state. I built it using a simple weighted formula that reflects the relative importance of each sensor. Temperature and vibration are more sensitive to wear and tear, so I gave them higher weight. Pressure, while important, was less of a red flag unless it spiked suddenly. This isn’t perfect — it’s not an ML model, it’s a rule-based system — but it works for my use case and it’s easy to maintain.

Here’s how I implemented it in Python as part of a Node-RED flow that aggregates data from multiple sensors:

# equipment_health.py
import json
from flask import Flask, request, jsonify

app = Flask(__name__)

# Weights for each sensor type
WEIGHTS = {
    "vibration": 0.4,
    "temperature": 0.4,
    "pressure": 0.2
}

def calculate_health_score(data):
    # Normalize each metric to a 0-1 scale
    normalized = {}
    for sensor, value in data.items():
        if sensor in WEIGHTS:
            # Example: linear normalization between 0 and 100
            # This would be replaced with domain-specific logic
            normalized[sensor] = max(0, min(1, (value - 20) / 80))  # 20-100 range

    # Calculate weighted score
    score = 0
    for sensor, weight in WEIGHTS.items():
        if sensor in normalized:
            score += normalized[sensor] * weight

    # Map to 0-100 range
    return round(score * 100, 2)

@app.route("/health", methods=["POST"])
def health():
    data = request.json
    score = calculate_health_score(data)
    return jsonify({"health_score": score})

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)
Enter fullscreen mode Exit fullscreen mode

This is a basic example, but it shows the core idea: take raw data, normalize it, apply weights, and return a single score. The scoring function can be as simple or complex as needed. For example, I’ve used exponential decay for vibration data or applied thresholds based on historical failure data.

Operators now see this score on a Grafana dashboard with color-coded thresholds (red for <40, yellow for 40–60, green for 60+), and it's the only metric they ask about. The real win isn’t the algorithm, though — it’s that the score is actionable. When it drops below 40, they know to investigate. When it hits 20, they know it’s time to schedule maintenance. It's not perfect, but it’s what they check every day.

Top comments (0)