At Sharif University of Technology I worked as an embedded software engineer on an air-conditioning monitoring device in a research setting. The job was easy to state and long to do: acquire the environmental sensor data, process it, log it and show it clearly to users. Since then, in Germany and in Italy, I have found the same chain wherever a physical quantity had to become a decision.
You start from the signal, not from the code. Which quantities do you need, how often, how precisely? What happens when a sensor disconnects, saturates or returns an absurd value? Answering first avoids the most common problem: discovering months later that the recorded data cannot answer the question it was meant for.
The firmware, in C or C++ on the microcontroller, does a few things but must always do them: it reads the sensors, timestamps every measurement, drops or flags values outside the plausible range, and packs them. Every packet has delimiters and a checksum, whether the link is a serial line, an I²C bus, a CAN bus or a radio: the receiver must recognise a corrupted packet instead of displaying it as real data.
Logging is the part that is always underestimated. I save the raw data, with the session metadata, before any processing, and I never overwrite it. One file per session, with the date and time in its name, is enough to start. Those files are what you debug with, what you run acceptance tests on and, later, what you train models on.
Processing, usually in Python, applies filters, unit conversions and calibrations, and computes derived quantities. Calibration must be versioned like code: if a sensor coefficient changes, old and new data have to stay comparable. At the end comes visualisation, designed for whoever uses the device: few quantities, readable, with anomalies highlighted.
Then you test the whole chain, not the pieces. Injecting known values at the sensor end and checking they arrive unchanged on the screen is the fastest way to find a scaling error, a wrong unit or a lost packet. It is the same principle I used at Voltfang in Aachen, building the package that reads the batteries' CAN data and the automatic generation of test reports.
Today this experience is why I rarely trust an AI model without looking at how its data was born. Predictive maintenance, anomaly detection, forecasting: they work when acquisition was designed well. If you are planning a project like this, the embedded systems and IoT page explains how I work.