Telemetry pipeline
This is where the pieces come together: the CSV reader from "Telemetry from CSV", the error handling from "Survive bad lines", the limits from the alert checks and the JSON from "JSON out". The ground station's export arrives every few seconds. Your program has to read it, refuse what it can't trust, raise the alarm on what is out of range and leave a summary the dashboard can read.
Three stages: validate, flag, save.
Finish stage 1 to unlock this stage.
Read telemetry.csv with csv.DictReader. Reject a row whose sensor is not in LIMITS, or whose value is not a number, with its line number in the file: the header is line 1, so the first reading is line 2. Keep every other row in readings, as a dict with time ("HH:MM:SS"), sensor and value (a float). The program prints:
Rejected line 5: value ERR is not a number Rejected line 8: unknown sensor ENG-9 Valid: 7, rejected: 2
enumerate(csv.DictReader(csv_file), start=2) numbers the rows the way the file does. Check the sensor first, then try the conversion.
Finish stage 1 to unlock this stage.
After the count, check every valid reading against its sensor's range in LIMITS. Collect each one outside it in alerts, as a dict with time, sensor, value, side ("above" or "below") and the limit it crossed, then print them and how many there were:
ALERT 09:30:15 ENG-1 455.2 above 450.0 ALERT 09:30:15 TANK-1 9.4 below 10.0 ALERT 09:30:20 CABIN 94.1 below 95.0 Alerts: 3
low, high = LIMITS[reading["sensor"]] unpacks the range.
Finish stage 2 to unlock this stage.
Save a summary for the dashboard to summary.json: a dict with valid (the number of readings), rejected and the alerts list, written with json.dump(), indent=2 and ensure_ascii=False. Then print one last line:
Saved summary.json
The hidden tests open summary.json and compare it with what they expect.
Hints
Import System Modules
# A module is a toolbox someone else already built and tested for you
# Plain import brings in the whole module
import sys
import platform
import math
# from ... import brings in just one tool
from math import sqrt
# as gives a module a shorter nickname
import random as rng
# With a plain import: module name, a dot, then the tool
print("Python version:", platform.python_version())
print("Running on:", platform.system())
print("Python lives at:", sys.executable)
# math carries constants you would not want to type from memory
radius_km = 6371
print("Earth circumference:", round(2 * math.pi * radius_km), "km")
# sqrt arrived on its own, so it needs no dot in front
print("Square root of 9:", sqrt(9))
# rng is simply a nickname for random
print("Random sol of the Martian year:", rng.randint(1, 687))
Separate arguments with commas. They're passed on every Run as sys.argv[1:].