Delivering sensor data to an official platform by FTP
A strict file format, generated safely
canal_001 to canal_169 and writes an empty column for any channel without data, so a sensor outage never shifts the columns of the ones that did report. Filenames embed a full timestamp, making every delivery unique and traceable.Twelve lines of ftplib
FTP(host), login, cwd and storbinary inside a try/finally that guarantees quit(). Credentials are placeholders (FTP_USER, FTP_PASS) to be loaded from environment variables in production — never hardcode them in a script that lives in a repository.Failures leave evidence
A snippet from the implementation
Straight from the example as deployed on the Server (Node-RED) — copy it freely:
def read_readings(path):
"""Loads the JSON with the latest readings aggregated by Node-RED.
Expected format: {"channel_001": 12.34, "channel_002": -0.07, ...}
"""
try:
with open(path) as f:
return json.load(f)
except (OSError, ValueError) as e:
print(f"ERROR reading readings: {e}")
return {}The full example is a complete program — wiring header, setup and main loop — ready to adapt to your application.
Frequently asked questions
Why FTP instead of a REST API?
Because the receiving platform defines the interface, and in geotechnical monitoring FTP file drops remain the standard. The pattern is decades old, firewall-friendly and trivial to audit from the file listing.
Where does the channel data come from?
Node-RED polls each PLC station over HTTP, merges the readings into a JSON file on disk, and launches this script with an exec node each measurement interval. The script and the flows stay decoupled.
How should credentials be handled in production?
Keep FTP_USER and FTP_PASS out of the code. Load them from environment variables or a config file with restricted permissions outside the repository, and rotate them if the device is serviced by third parties.