Sotavento
Capstone project · Data Science 2025 · Asociación Tecnolóxica A Industriosa

Sotavento

Telemetry, monitoring and data analysis for an experimental wind farm.

From each turbine's RS-232 serial line to a real-time dashboard and wind-forecasting models: a complete capture, ingest and data-science system built end to end — custom hardware, firmware, protocol, backend and analytics.

21 turbines Izar-Bonus 1.3 MW · Gamesa G-47 RS-232 → WiFi Raspberry Pi Pico W FastAPI + MariaDB Wind ML
UART0 · TXD channel · 2400 baud · captured frame
RXD ◂ 01 30 42 04 2F 30 35 2F 31 34 33 32 2F 30 30 2F 31 32 2E 34 2F 39 36 30 2F 04  ▸ ingest
Site
43.35°N -7.88°W
Node↔Backend protocol
v1.1.0
Database
39 tables · MariaDB 11
Weather ML providers
4 + ensemble
01 · Context

Every turbine speaks its own dialect over a serial cable.

The Sotavento Experimental Wind Farm (Xermade, Galicia) hosts turbines from several manufacturers installed as a test bench: Izar-Bonus 1.3 MW, Gamesa G-47, MADE, Vestas / Neg Micon and Ecotecnia. Each model exposes its controller over an RS-232 line speaking a different proprietary SCADA protocol — from SOH/EOT-delimited ASCII at 2400 baud (Bonus) to IEC 60870-5 FT 1.2 at 9600 baud (Gamesa).

The challenge: capture, centralize and analyze that scattered data without replacing the turbines' original electronics. The answer is a small device — the "Node" — that listens on each turbine's serial bus and uploads it to a shared platform where all the analysis lives.

And it's no ordinary site: Sotavento is Galicia's reference experimental wind farm — Spain's 3rd region by installed wind power, with some 3,874 MW (2025). The province of A Coruña alone contributes nearly 1,240 MW, across more than 35 wind farms and some 1,590 turbines: working here means working on a real test bench for that industry.

The starting point

Today the farm is operated from a Windows 98/XP PC running the software the manufacturer shipped 20 years ago. The brief was clear: move turbine control —start, stop, errors— onto a modern, reliable system reachable from any device, and along the way optimize operation based on the energy sale price.

02 · Architecture

From the serial bus to the predictive model

A single signal chain runs through the whole system: the turbine's electrical frame becomes bytes, gets batched, travels over WiFi, is validated against a versioned contract, and ends up feeding the dashboard and the machine-learning models.

Source

Wind turbine

SCADA controller with a proprietary RS-232 output per machine.

RS-232 · 2400–9600 bd
Hardware

Node

Custom PCB: MAX3232 + Raspberry Pi Pico W. Reads TXD and RXD.

UART0 / UART1
Firmware

Capture + batch

MicroPython: frame detection, queue and batched upload.

HTTP/JSON + token
Backend

Ingest

FastAPI validates against the contract and persists to MariaDB.

39 tables · partitions
Analytics

Dashboard + ML

Real time, production, OMIE prices and wind forecasting.

SSE · Chart.js
Design decision

Node and backend are developed separately and only talk through a formal, versioned contract (interface/PROTOCOL.md): 8 endpoints, JSON Schemas and SemVer versioning. Neither side can break the other without bumping the protocol version.

Sotavento panel · Dashboard
Live operational dashboard: farm KPIs and turbine cards with telemetry
The end of the chain — the live operational dashboard (SSE): farm KPIs (active, wind power, PV, to-grid, wind, radiation), forecast, and one card per turbine with power, direction, RPM, voltage, current, temperature and a sparkline of the last 24 readings.
03 · Hardware

The Node: custom electronics, from trace to 3D case

The bridge between the turbine's RS-232 bus and the IP world is a board designed, fabricated and assembled from scratch in KiCad. It is bidirectional: it captures both the PLC's replies (TXD channel) and the PC's queries (RXD channel) without interfering with the original link.

01 PCB design

A family of KiCad boards, iterated to the bidirectional version:

  • Base Board V3 — bidirectional
  • MCU V3 — houses the Pico W
  • Interposer V6 — bidirectional
  • MAX3222E test board — transceiver validation
  • placaDualCNC SMD — double-sided variant

02 Serial interface

Level shifting and dual capture of the bus:

  • MAX3232 / MAX3222E: RS-232 ↔ 3.3 V TTL
  • UART0 (GP0/GP1) → TXD channel (PLC → PC)
  • UART1 (GP4/GP5) → RXD channel (PC → PLC)
  • Common ground and data-line protection
  • SSD1306 OLED + status LED

03 Fabrication

Full lab prototyping:

  • Double-sided CNC milling of the board
  • Laser-cut stencil for the solder paste
  • SMD assembly and reflow soldering
  • 3D-printed enclosure (modeled in Cinema 4D)
  • Gerbers + BOM ready for a production run
Hardware note

The transceiver must be a MAX3232 (3.3 V compatible), not a classic 5 V MAX232: the latter would damage the Pico. A common ground between the Pico and the RS-232 bus is mandatory.

04 · Firmware

MicroPython on the Pico W

Every Node runs the same firmware; its identity comes from its MAC + a token persisted to flash after the first registration. The firmware captures frames, ships them in batches and keeps itself running — including its own over-the-air update with automatic rollback.

Frame capture

  • Silence detection: a gap > GAP_MS marks the end of a frame
  • Batched upload at 20 frames or every 5 s
  • Queue with backpressure (drops oldest when saturated)
  • Stamps each frame with monotonic ts_ms + ts_unix (if NTP)

Autonomous operation

  • Auto-registration: shows up as "pending" on its first frame
  • Heartbeat every 60 s with RSSI, IP and version
  • Remote config applied hot (no reboot)
  • OTA: atomic rename, trial period and rollback if 3 boots fail
  • Remote drop_to_repl command for diagnosis without visiting the site
MCU
Raspberry Pi Pico W / RP2350 · MicroPython
BAUD_RATE
2400 (Bonus ASCII) · 9600 (Gamesa)
GAP_MS
100 ms · end-of-frame threshold
Batch
BATCH_SIZE=20 frames · BATCH_INTERVAL=5000 ms
Queue
MAX_QUEUE=200 · MAX_FRAME=512 bytes
OTA
Poll every 300 s · WDT keepalive · trial + rollback to .bak
PulseView · UART/RS-232 analyzer · real capture
Real decoded Bonus frame: SOH ( 0 2 / S / 0 2 2 9 8 EOT
A real frame, byte by byte — a logic-analyzer capture of a Bonus frame on the RS-232 line: the SOH…EOT delimiters wrap the ASCII payload (( 0 2 / S / 0 2 2 9 8). This is exactly what the Node detects, batches and uploads to /api/ingest.
05 · Protocol

A versioned contract between two teams

The firmware (Pico team) and the backend (web team) are developed independently. Everything that crosses between them is written down in a contract: endpoints, headers, authentication and error policies, with SemVer versioning and JSON Schema validation.

EndpointUseAuth
POST /api/gateways/registroInitial registration → returns token—
POST /api/gateways/pingHeartbeat + pending remote commandsBearer
POST /api/ingestBatched upload of captured framesBearer
POST /api/gateways/logsNode log flush (debug→error)Bearer
GET /api/firmware/latestManifest of the active OTA versionBearer
GET /api/gateways/configRuntime parameters (applied hot)Bearer

Versioning

X-Sotavento-Protocol on every request. If the MAJOR mismatches → 426 Upgrade Required and the Node forces an OTA.

Guarantees

Idempotent ingest by ts_unix, order preserved within a batch, and at-most-once command delivery.

Security

Revocable 64-hex gateway token; on 401/403 the Node deletes its token and re-registers itself.

Sotavento panel · Nodes
Node management: registration, status and OTA firmware
Node management — add/retire gateways, status, turbine reassignment and OTA firmware publishing from the panel. Each Node auto-registers on its first frame and shows up here as "pending".
06 · Backend & Web

The platform that centralizes the farm

A FastAPI backend on a Raspberry Pi at the site itself receives the frames, parses them and serves an operational web app. All with reproducible deployment, two environments (staging / production) and secure remote access.

Real time

  • SSE dashboard: power, wind, RPM, voltage per machine
  • Power sparklines and the day's OMIE prices
  • Start / stop / query commands with full traceability

Data & parsing

  • MariaDB 11, 39 tables, monthly partitions of frames
  • Bonus parser (ASCII) over the raw frames
  • Monthly archival to ZIP with Time-Machine-style retention

Operations

  • rsync + systemd deploy; Tailscale / Cloudflare Tunnel
  • Installable PWA and ES / GL / EN i18n
  • Encrypted backups synced to NAS
Sotavento panel · Public view
Public park view: 21 turbine cards with real-time power and wind
Public park view — all 21 turbines from 5 manufacturers (Bonus, Vestas/Neg Micon, Gamesa, Ecotecnia, MADE) with real-time power and wind. The full panel — operational dashboard, frames, production, maintenance and weather — sits behind login.
Sotavento panel · Production
Production analytics: KPIs, charts and OMIE price
Production analytics — total production, estimated revenue, capacity factor and average price; curves for wind energy + net balance, PV vs. solar radiation and control-centre consumption, plus per-turbine production read from OPC.
07 · Data Science

What the course taught, applied to the farm

This is where the course becomes tangible. Each week of the syllabus maps directly onto a real feature of the system — the same problem you solve with a toy dataset, solved instead with Sotavento's real frames and production data.

Course weekTechniqueWhere it lives in Sotavento
Fitting Curve fitting / regression Power curve (Cp) fitted from real production vs. wind; per-turbine degradation detection over time.
Machine Learning Supervised models, ensemble, stacking Wind forecasting with 4 providers + 5 models retrained nightly (TensorFlow / LSTM), bias correction, stacking and a weighted ensemble ∝ 1/MAE.
Probability Uncertainty, quantiles Quantile forecasting, gust estimation and a 0–3 h nowcast against the farm's real measurement.
Density Estimation Error distribution Error histogram (forecast − real) per provider: 20 bins of 2 km/h, with mean, σ and RMSE. Reveals each model's bias and spread.
Transforms Domain changes, feature engineering Vectorial wind u/v → magnitude/direction (Windy), adaptive time buckets (averages, not subsampling) and hourly/daily aggregation.
Presentation Communicating results This document, the operational dashboard and the PDF/Excel production & maintenance reports.
Sotavento panel · Weather
Weather analytics: 4-provider forecast vs real wind, ML panel and wind roses
Wind analytics — forecast vs. reality — the 4 forecast sources against the farm's real wind, with a gust ensemble and the active stacking · GBR · LSTM · Quantile panel. Below, two wind roses: industrial anemometer and turbines. Machine Learning, Probability and Transforms all live here.

Evaluation Which model is most accurate?

The system doesn't just predict: it evaluates itself continuously against the real wind measured by the turbines.

  • MAE and bias per provider, always shown in the anemometer header
  • Rolling 7-day MAE to detect drift (is someone getting worse by season?)
  • Adaptive scoreboard: % of wins by intensity (calm <5 · moderate 5–10 · strong >10 m/s)
  • Ensemble with weights ∝ 1/MAE that usually beats any single provider

Pipeline From frame to dataset

All the analysis rests on a reproducible data flow that turns heterogeneous sources into clean, queryable tables.

MDB / RS-232→ CSV export→ Ingest→ h/d aggregation→ Partitions→ Archival
Sotavento panel · Maintenance
Maintenance: fitted Cp power curve and per-turbine health/degradation
Power curve & farm health — the Cp curve (theoretical reference vs. the last 30 days' real data) is a direct application of the Fitting week. Below, mean efficiency per model and per-turbine degradation with its 3-month delta.

🔧 Predictive maintenance + work orders

With the full work-order history since 2001 —over 13,000 operations and their SCADA code catalogs— the system anticipates failures, prioritizes them and proposes fixes drawing on past cases.

  • Work-order manager that replaces the paper form (entry, signature, PDF/Excel reports)
  • Per-turbine health and degradation, flagged when efficiency drops
  • Per-model / manufacturer comparison to spot systemic problems

💶 Operating by price

Production is crossed with the electricity market (OMIE) to put every kWh in euros and make operational calls on economic grounds.

  • Opportunity cost: how much revenue is lost by stopping a machine
  • Best window for maintenance — the slots where stopping costs least
  • Estimated revenue and average price, at fixed price or at market

The data sources

SourceContent
Gamesa_registroTurbine records: active/reactive power, voltage, wind speed, state and alarms (sot_am); hourly production (sot_ah); stops and losses (sot_epp); billed energy and availability (sot_sh).
OMIEHourly electricity-market price — crossed with production to estimate revenue and opportunity cost.
EfiventoMaintenance history: 13,495 operations (2000→2026) with SCADA code catalogs.
WeatherForecasts from Open-Meteo, AEMET, MeteoGalicia and Windy — the raw material for the models.
08 · Closing

A datum is only worth it if it arrives, gets cleaned and is understood.

Sotavento began as an electronics problem — reading a serial cable — and ended up being, above all, a data problem: capturing it without loss, storing it at scale, aggregating it with judgment and extracting a useful forecast from it.

The Data Science course supplied exactly the last piece: going from "I have the frames saved" to fitting curves, training models, measuring their error and picking the one that's right. The firmware and boards bring the data in; the analysis makes sense of it.