Build a Machine Fault Detector
Simulate industrial sensors and diagnose machine faults with Python.
Introduction
30 Second Summary
Every machine in a factory has sensors monitoring its health. Temperature spikes, unusual vibrations, or pressure drops are warning signs that something is about to fail.
In this project, you will build a machine fault detector in Python that simulates industrial sensor readings and diagnoses whether a machine is healthy, needs attention, or is about to fail.
What You'll Build
You run the detector and instantly see a status report with randomized sensor data and a clear diagnosis, just like the output a real maintenance engineer would see on a monitoring dashboard.
By the end of this project, you'll have:
- A working fault detector that simulates three industrial sensors and gives you a different diagnosis every time you run it.
- Compound conditional logic that catches dangerous failures a simple if/elif/else would miss, like two sensors warning at the same time.
- A formatted status report with sensor readings, diagnoses, and action recommendations that looks like real industrial monitoring output.
- Secret Mission: Add a repair recommendation engine that tells the engineer exactly what to fix based on the fault pattern.
Are there any prerequisites?
None. This project uses the Codedex browser editor, which runs Python directly in your browser with no downloads or setup needed.
Before We Start
Before We Start...
Before we dive in, let's lock in what you're about to build and why it matters.
Set Up Your Sensor Readings
Before you can diagnose a machine, you need data to work with. Real industrial monitoring systems read temperature, vibration, and pressure sensors hundreds of times per second.
In this step, you'll simulate those sensor readings with random numbers and print them to the console. This gives you raw data that the rest of your program will interpret.
In this step, get ready to:
- Create your sensor simulation file in the Codedex editor.
- Generate random readings for temperature, vibration, and pressure.
- Print all three readings with labels and run the program.
Open the Codedex editor
The Codedex editor gives you a single Python file and a Run button. You'll write all your code in this file.
- Switch back to the Codedex editor in your browser.
- Clear any existing code in the editor so you start with a blank file.
What about the filename?
The Codedex editor uses a single file for your code. Throughout this project, we'll refer to it as fault_detector.py so you know what you're building. Everything goes in this one file.
Generate random sensor readings
A real motor has sensors that output floating-point numbers. You'll simulate this with Python's random module, which can generate random decimal numbers within a range.
- Add the following code to your editor to import the random module, generate three sensor readings, and print them with labels:
import random
# Generate sensor readings
temperature = random.uniform(20.0, 120.0)
vibration = random.uniform(0.0, 15.0)
pressure = random.uniform(80.0, 200.0)
print(f"Temperature: {temperature:.1f} C")
print(f"Vibration: {vibration:.1f} mm/s")
print(f"Pressure: {pressure:.1f} bar")
What does this code do?
import random loads Python's built-in module for generating random numbers.
random.uniform(20.0, 120.0) returns a random decimal number between 20.0 and 120.0. Each sensor gets its own realistic range: temperature in Celsius, vibration in mm/s, and pressure in bar.
The :.1f inside each f-string formats the number to one decimal place, just like a real sensor display would show.
Run and verify your readings
Before you click Run, what do you think you'll see in the output panel?
- Click the Run button in the Codedex editor.
You should see three lines of output with labels and random numbers, something like this:
Temperature: 73.4 C
Vibration: 5.2 mm/s
Pressure: 142.8 bar
- Click Run two more times and confirm the numbers change each time.
Every run produces different readings because random.uniform() generates a new value each time the program executes.
Not seeing any output?
- Check that import random is the very first line of your file with no typos.
- Make sure the print lines use the letter f before the opening quote. Without the f, the curly braces print as literal text.
- Verify there are no extra spaces or missing colons. Python is strict about syntax.
Why aren't my sensor readings printing in the Codedex editor?
✔️ Awesome, I've got everything!
Great. Make sure your code is saved in the editor before moving on.
ⓧ I'd like to double check the full code
Here's the complete code you should have in your editor right now:
import random
# Generate sensor readings
temperature = random.uniform(20.0, 120.0)
vibration = random.uniform(0.0, 15.0)
pressure = random.uniform(80.0, 200.0)
print(f"Temperature: {temperature:.1f} C")
print(f"Vibration: {vibration:.1f} mm/s")
print(f"Pressure: {pressure:.1f} bar")
Your sensor simulation is live. Next up, you'll turn those raw numbers into meaningful diagnoses by writing conditional logic that classifies each reading as NORMAL, WARNING, or CRITICAL.
Diagnose Each Sensor
Your program generates sensor readings, but right now they're just numbers. A temperature of 87.3 means nothing unless you know whether that's safe or dangerous.
In this step, you'll turn each raw number into a diagnosis: NORMAL, WARNING, or CRITICAL. This is the core pattern of control flow. Your code will check each reading against threshold ranges and decide which status to assign.
In this step, get ready to:
- Write if/elif/else blocks that classify each sensor reading into a status.
- Handle a tricky case where pressure can be too high OR too low.
- Print each reading with its status label so you can see the diagnosis.
Diagnose the temperature sensor
Real monitoring systems check sensor readings against threshold ranges. For temperature, anything above 85 C indicates a critical overheating problem. Between 60 and 85 is a warning zone. Below 60 is normal.
Python's if/elif/else structure lets you check these ranges in order. The program tests from the most severe condition first and works its way down.
- In your fault_detector.py file, find the blank line between the pressure generation line and the first print statement.
- Add the following temperature diagnosis block in that gap:
# Temperature diagnosis
if temperature > 85:
temp_status = "CRITICAL"
elif temperature >= 60:
temp_status = "WARNING"
else:
temp_status = "NORMAL"
What does this code do?
This is an if/elif/else chain. Python checks each condition from top to bottom and stops at the first one that's true.
- if temperature > 85: checks the most dangerous case first. If true, it assigns "CRITICAL" and skips the rest.
- elif temperature >= 60: only runs if the first check was false. This catches the warning zone (60 to 85).
- else: catches everything remaining (below 60). No condition needed because it's the only case left.
Now update the temperature print line so you can actually see the diagnosis. Find this line:
print(f"Temperature: {temperature:.1f} C")
- Replace it with this line that adds the status in brackets:
print(f"Temperature: {temperature:.1f} C [{temp_status}]")
- Click the Run button to test your diagnosis.
You should see the temperature reading followed by its status in brackets, like Temperature: 87.3 C [CRITICAL]. Run it a few times to confirm different statuses appear as the random number changes.
Seeing a NameError for temp_status?
- Make sure your diagnosis block is above the print statement. Python reads top to bottom, so temp_status must be created before it's used.
- Check that your if/elif/else lines are indented correctly. The temp_status = lines need 4 spaces of indentation under each condition.
Help me fix my temperature diagnosis code
Diagnose the vibration sensor
Vibration follows the same pattern as temperature. Readings above 7.0 mm/s indicate damage. Between 4.0 and 7.0 is a warning zone.
- Add this vibration diagnosis block directly below your temperature diagnosis (above the print statements):
# Vibration diagnosis
if vibration > 7.0:
vib_status = "CRITICAL"
elif vibration >= 4.0:
vib_status = "WARNING"
else:
vib_status = "NORMAL"
Why 7.0 and 4.0?
These thresholds are simplified from real industrial vibration monitoring standards. In practice, vibration above 7 mm/s on rotating machinery signals incipient damage that needs immediate attention.
Now update the vibration print line. Find this line:
print(f"Vibration: {vibration:.1f} mm/s")
- Replace it with this version that includes the status:
print(f"Vibration: {vibration:.1f} mm/s [{vib_status}]")
- Click Run to confirm both temperature and vibration now show their statuses.
You should see two lines with statuses in brackets and the pressure line still showing just the number.
Only temperature shows a status?
- Check that your vibration diagnosis block is placed between the temperature diagnosis and the print statements. It should not be below the prints.
- Make sure you replaced the original vibration print line and didn't leave both the old and new versions in the file.
Help me debug my vibration diagnosis
Diagnose the pressure sensor
Pressure is different from temperature and vibration. It can be dangerous in two directions. Too high means a blockage. Too low means a leak. The normal range is 100 to 160 bar.
This requires Python's or operator to check both directions in a single condition.
- Add this pressure diagnosis block below your vibration diagnosis (still above the print statements):
# Pressure diagnosis (too high OR too low is bad)
if pressure < 90 or pressure > 170:
pres_status = "CRITICAL"
elif pressure < 100 or pressure > 160:
pres_status = "WARNING"
else:
pres_status = "NORMAL"
What does the or operator do here?
The or keyword means "if either condition is true." So pressure < 90 or pressure > 170 triggers when pressure is below 90 (leak) OR above 170 (blockage).
The warning zone catches readings that are outside the normal 100-160 range but haven't reached the critical extremes yet. This two-direction check is common in industrial monitoring where both over-pressure and under-pressure cause failures.
Finally, update the pressure print line. Find this line:
print(f"Pressure: {pressure:.1f} bar")
- Replace it with this version:
print(f"Pressure: {pressure:.1f} bar [{pres_status}]")
Before you click Run, look at your three diagnosis blocks. What status do you think each sensor will get this time?
- Click Run to see all three sensors diagnosed.
You should see three lines, each with a reading and a status in brackets. Run the program 3-4 more times. Because the readings are random, you'll see different combinations of NORMAL, WARNING, and CRITICAL appear across runs.
Seeing a SyntaxError or wrong status?
- If you see a SyntaxError, check that each elif and else is aligned with its matching if (no extra indentation).
- If pressure always shows NORMAL, check that your conditions use or (not and). Pressure needs to be outside the range on either side.
- Make sure the critical check (< 90 or > 170) comes before the warning check (< 100 or > 160). Python checks top to bottom.
Help me fix my pressure diagnosis logic
✔️ Awesome, I've got everything!
Great. Make sure you've saved your file before moving on.
ⓧ I'd like to double check the full code
Scroll through your file and confirm these sections are present, in this order:
- The import random line and the three sensor generation lines (temperature, vibration, pressure).
- The temperature diagnosis if/elif/else block (checking >85, >=60, else).
- The vibration diagnosis if/elif/else block (checking >7.0, >=4.0, else).
- The pressure diagnosis if/elif/else block (checking <90 or >170, <100 or >160, else).
- Three print statements at the bottom, each showing the reading and its status in brackets.
Each sensor now gets its own diagnosis. But here's the problem: what happens when two sensors are both at WARNING? Right now the code treats that the same as a single warning. In the next step, you'll discover why that's dangerous and fix it with compound conditions.
Catch Compound Failures
Your fault detector can now diagnose each sensor individually. But real monitoring systems don't check sensors in isolation.
Two sensors at WARNING simultaneously signals a systemic problem, not isolated wear. A single-sensor approach misses this dangerous case entirely. In this step, you'll add compound failure detection that cross-correlates all three sensors to determine an overall system status.
In this step, get ready to:
- Count how many sensors are at WARNING or CRITICAL status.
- Write compound conditional logic that determines the overall system status.
- Print the overall status below the individual sensor lines.
Run the current code and spot the gap
Right now your program diagnoses each sensor on its own. Before adding anything new, run the code a few times and think about what it misses.
Before you click Run, think about this: if temperature shows WARNING and vibration shows WARNING at the same time, what does your program tell you about the overall machine health?
- Click Run a few times and watch the output.
You'll see individual readings with their statuses. Sometimes two or even three sensors land in WARNING or CRITICAL at the same time. But the program says nothing about what that combination means for the overall machine.
That's the gap. In real industrial monitoring, two sensors failing together points to a systemic breakdown, not just coincidence. Your code treats each sensor as if the others don't exist. Time to fix that.
Count how many sensors are non-NORMAL
To detect compound failures, you first need to know how many sensors are in trouble. A counter variable will track this.
- In fault_detector.py, find the line that says print(f"Temperature: (the first print statement).
- Add the following code ABOVE that print line, with a blank line separating it from the pressure diagnosis above and the prints below:
# Compound failure detection
warning_count = 0
if temp_status != "NORMAL":
warning_count += 1
if vib_status != "NORMAL":
warning_count += 1
if pres_status != "NORMAL":
warning_count += 1
What does this code do?
This block counts how many sensors are NOT in a normal state.
- warning_count = 0 starts the counter at zero.
- Each if checks one sensor. If its status is anything other than "NORMAL", the counter goes up by 1.
- After all three checks, warning_count holds a number between 0 and 3. This tells you how many sensors are in trouble.
Now use that count to determine the overall system status. Add this code directly below the counter block you just wrote, still above the print statements:
if warning_count >= 2 or temp_status == "CRITICAL" or vib_status == "CRITICAL" or pres_status == "CRITICAL":
overall_status = "CRITICAL"
elif warning_count == 1:
overall_status = "WARNING"
else:
overall_status = "NORMAL"
What does this compound conditional do?
This is the logic that catches what single-sensor diagnosis misses.
- The first condition uses or to check multiple danger signs at once. If 2+ sensors are non-NORMAL, OR any single sensor hit CRITICAL, the overall status is CRITICAL.
- The elif catches the case where exactly one sensor is at WARNING. That's worth noting but not an emergency.
- The else means everything is NORMAL. All sensors passed.
This is the same cross-correlation pattern real industrial systems use. A single WARNING might be noise. Two WARNINGs together point to a systemic problem.
Print the overall system status
The overall_status variable now holds a verdict, but the program doesn't display it yet. You need one more print line so the learner (or engineer) can actually see it.
- Find the last print line in your file (the one that prints pressure).
- Add this line directly below it:
print(f"OVERALL STATUS: {overall_status}")
Before you click Run, predict: do you think you'll ever see OVERALL STATUS: CRITICAL when all three individual sensors show WARNING (none at CRITICAL)?
- Click Run several times.
You'll see the three individual sensor readings followed by OVERALL STATUS: and either NORMAL, WARNING, or CRITICAL. When two or more sensors land in WARNING or CRITICAL at the same time, the overall status reads CRITICAL. That's the compound failure detection working.
Not seeing an OVERALL STATUS line?
- Make sure the new print(f"OVERALL STATUS: {overall_status}") line is AFTER the three existing print lines, not inside the if/elif/else block above.
- Check that the compound detection code (the warning_count block and the if/elif/else for overall_status) is placed ABOVE the print statements, not below them. Python reads top to bottom, so overall_status must be defined before you try to print it.
- If you see a NameError, the code that creates overall_status is likely missing or indented incorrectly.
Why isn't my OVERALL STATUS printing in the Codedex editor?
✔️ Awesome, I've got everything!
Great. Double check you've saved your file before moving on.
ⓧ I'd like to double check the full code
Here's the full fault_detector.py at this point. Compare yours against it:
Your file has grown past 30 lines, so scroll through these sections in order to confirm each one is present:
- The import random line and the three random.uniform() sensor reading lines.
- Three if/elif/else blocks diagnosing temperature, vibration, and pressure into status strings.
- The # Compound failure detection section with warning_count and the if/elif/else for overall_status.
- Four print statements at the bottom: temperature, vibration, pressure, then overall status.
Your detector now catches failures that a simple single-sensor check would miss. Next up, you'll turn this raw output into a formatted status report that looks like what a real maintenance engineer would see on a monitoring dashboard.
Build the Status Report
Your detector now catches compound failures that single-sensor diagnosis misses. The output still looks like plain text thrown at the console, though.
A real monitoring dashboard has clear sections, separator lines, and an action recommendation. In this step, you'll turn your raw output into a formatted status report that looks like something a maintenance engineer would actually read.
In this step, get ready to:
- Add a dictionary that maps each status to an action recommendation.
- Replace the plain print statements with a formatted report that has headers, separators, and a recommended action.
Add the action lookup dictionary
Right now your program says the machine is CRITICAL or WARNING, but it doesn't say what to do about it. A dictionary lets you map each status directly to a recommended action without writing another if/elif/else chain.
- In fault_detector.py, find the four print statements at the bottom of your file. Add the following code directly above them:
# Action lookup
actions = {
"NORMAL": "No action required. Next scheduled check in 30 days.",
"WARNING": "Schedule inspection within 7 days.",
"CRITICAL": "IMMEDIATE SHUTDOWN - Inspect before restarting."
}
action = actions[overall_status]
What does this code do?
The actions dictionary stores three key-value pairs. Each key is a status string, and each value is the recommended action for that status.
The line action = actions[overall_status] looks up the action by using overall_status as the key. If overall_status is "WARNING", action becomes "Schedule inspection within 7 days." automatically.
- Run your file to confirm it still works without errors.
You'll see the same plain output as before. The dictionary is working behind the scenes, but you haven't used it in your output yet. That's what you'll fix next.
Seeing a KeyError?
A KeyError means the dictionary can't find the key you're looking up. Check that your overall_status variable uses exactly "NORMAL", "WARNING", or "CRITICAL" (all caps) to match the dictionary keys.
Help me debug my KeyError in the actions dictionary.
Replace the plain prints with a formatted report
Your current output dumps raw numbers with no visual structure. A formatted report uses separator lines and indentation so an engineer can scan it in seconds.
- In fault_detector.py, find these four print statements at the bottom of your file:
print(f"Temperature: {temperature:.1f} C [{temp_status}]")
print(f"Vibration: {vibration:.1f} mm/s [{vib_status}]")
print(f"Pressure: {pressure:.1f} bar [{pres_status}]")
print(f"OVERALL STATUS: {overall_status}")
- Delete all four of those print lines.
- In their place, add this formatted report block:
# Status report
print("=" * 45)
print(" MACHINE HEALTH STATUS REPORT")
print("=" * 45)
print(f" Temperature: {temperature:.1f} C [{temp_status}]")
print(f" Vibration: {vibration:.1f} mm/s [{vib_status}]")
print(f" Pressure: {pressure:.1f} bar [{pres_status}]")
print("-" * 45)
print(f" OVERALL STATUS: {overall_status}")
if warning_count >= 2:
print(" (Compound failure: multiple sensors triggered)")
print("-" * 45)
print(f" ACTION: {action}")
print("=" * 45)
What does this code do?
The report is built with three visual sections separated by lines of = and - characters. "=" * 45 repeats the = character 45 times to create a solid line.
The if warning_count >= 2: line is a conditional print. It only shows the compound failure note when multiple sensors triggered at once. This is the same logic you wrote in Step 3 put to a new use.
The action variable (from your dictionary lookup) appears in the final ACTION line. This is where the dictionary pays off. One lookup replaces what would have been another if/elif/else block.
Before you run this, picture what you expect the output to look like now. Do you think it will look different from before?
- Run your file.
You should see a clearly formatted report with a header, separator lines, each sensor reading with its status, the overall verdict, and an ACTION recommendation at the bottom. Run it a few times to see different readings and diagnoses.
Report looks jumbled or has a syntax error?
Make sure you deleted all four of the original print statements. If any remain, they'll print above or below the report and break the formatting.
Check that the if warning_count >= 2: line is indented correctly. The print inside it should be indented one level further than the if.
Help me fix my status report formatting.
✔️ Awesome, I've got everything!
Great. Double check you've saved your file.
ⓧ I'd like to double check the full code
Scroll through your file and confirm these sections appear in order:
- The import random line and the three sensor generation lines at the top.
- Three diagnosis blocks (temperature, vibration, pressure) using if/elif/else.
- The compound failure detection block with warning_count and overall_status.
- The actions dictionary and action = actions[overall_status] lookup.
- The status report block starting with print("=" * 45) and ending with the same line.
- No leftover plain print statements from earlier steps.
Secret mission
Add a Repair Recommendation Engine
Your detector knows something is wrong, but it doesn't tell the engineer what to fix. Can you build a system that maps specific fault patterns to specific repair instructions using dictionaries?
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely in your browser using the Codedex editor, so there are no ongoing costs or background processes to worry about.
Resources you used:
- fault_detector.py in the Codedex editor (saved to your account).
Keep everything running
No action needed. Choose this if you want to keep your code available in the Codedex editor to revisit or extend later.
- Your fault_detector.py file stays saved in your Codedex account automatically.
- You can return to it anytime by logging back in.
Pause - I'll come back to this later
Since the Codedex editor is browser-based with no running processes, there is nothing to pause. Your code is already saved to your account.
- Close the browser tab whenever you're done.
- Your file will be waiting for you next time you log in.
Delete - I don't want to use this again
Remove your project file from the Codedex editor if you no longer need it.
- Open the Codedex editor and locate fault_detector.py in your files.
- Delete the file from your workspace.
- Once deleted, the code is gone unless you saved a copy elsewhere.
Nice Work!
Nice Work!
You just built a machine fault detector that uses the same conditional logic patterns real industrial monitoring systems rely on. Every time you run it, randomized sensor data flows through your diagnosis engine and produces an actionable status report.
You've learned how to:
- Simulate industrial sensor readings with random.uniform() and diagnose each one against threshold ranges using if/elif/else chains.
- Detect compound failures that single-sensor diagnosis misses by writing compound conditionals with and/or operators.
- Build a formatted status report with action recommendations using dictionaries for data lookup and f-strings for clean output.
- Secret Mission: Added a repair recommendation engine that maps specific fault patterns to maintenance instructions using computed dictionary keys.
Ready to quiz yourself?