vantage-publisher.py reads live data from a Davis Vantage Pro2 console, optionally stores CSV rows locally, optionally publishes MQTT packets, and optionally sends Signal K deltas via websocket.
The technical and operational manual provides a detailed account of the implementation, its data semantics, and its operational limits:
- Architecture and timing
- Complete configuration reference
- Observation model, timestamps, units, and payloads
- MQTT, Signal K, AirLink, and HTTP integrations
- Installation and deployment
- Reliability, troubleshooting, backup, and recovery
- Historical archive collection
- Development and validation
- CI/CD and container releases
- Sources and terminology
- Continuous station stream with reconnect
- Parameter filtering via
parameters.json - Optional local CSV storage
- Optional MQTT publishing with offline queue
- Optional direct Signal K websocket publishing
- Dry run mode for configuration/debug checks
- Built-in HTTP server for browsing stored CSV files (optional basic auth)
- Python 3.8+
- Vantage Pro2 reachable as
tcp:127.0.0.1:<usbPort>(typically throughser2net)
Install dependencies:
python3 -m pip install -r requirements.txt{
"uuid": "it.uniparthenope.meteo.ws1",
"name": "Centro Direzionale",
"airlinkId": "",
"airlinkApiKey": "",
"airlinkApiSecret": "",
"lon": 14.2845,
"lat": 40.8569,
"storage": true,
"mqtt": false,
"signalk": false,
"usbPort": 22222,
"usbPollInterval": 1.0,
"delay": 10,
"timeout": 60,
"pathStorage": "/storage/vantage-pro/",
"mqttBroker": "mqtt-broker.local",
"mqttPort": 1883,
"mqttUser": "",
"mqttPass": "",
"mqttQos": 1,
"mqttFormat": "flat",
"signalkServerUrl": "ws://signalk.local:3000/signalk/v1/stream",
"signalkToken": "",
"signalkContext": "meteo.it.uniparthenope.meteo.ws1",
"signalkPathMap": {
"BarTrend": "environment.outside.pressureTrend",
"Barometer": "environment.outside.pressure",
"TempIn": "environment.inside.temperature",
"HumIn": "environment.inside.humidity",
"TempOut": "environment.outside.temperature",
"WindSpeed": "environment.wind.speedApparent",
"WindSpeed10Min": "environment.wind.speedAverage",
"WindDir": "environment.wind.angleApparent",
"HumOut": "environment.outside.humidity",
"RainRate": "environment.rain.rate",
"SolarRad": "environment.solar.radiation",
"RainStorm": "environment.rain.storm.total",
"StormStartDate": "environment.rain.storm.startDate",
"RainDay": "environment.rain.day",
"RainMonth": "environment.rain.month",
"RainYear": "environment.rain.year",
"ETDay": "environment.outside.evapoTranspiration.day",
"ETMonth": "environment.outside.evapoTranspiration.month",
"ETYear": "environment.outside.evapoTranspiration.year",
"BatteryStatus": "electrical.batteries.sensor.status",
"BatteryVolts": "electrical.batteries.sensor.voltage",
"ForecastIcon": "environment.weather.forecast.icon",
"ForecastRuleNo": "environment.weather.forecast.ruleNumber",
"SunRise": "environment.sun.rise",
"SunSet": "environment.sun.set"
},
"httpEnabled": false,
"httpHost": "0.0.0.0",
"httpPort": 8080,
"httpUser": "",
"httpPass": "",
"httpRoot": "/storage/vantage-pro/",
"offlineMaxMessages": 200000,
"offlineMaxAgeSec": 604800,
"airlinkIntervalSec": 300
}storage: enable/disable local CSV storage (default:true)mqtt: enable/disable MQTT publishing (default:false)signalk: enable/disable Signal K websocket publishing (default:false)
mqttFormat supports:
flat(default/fallback)geojson
AirLink credentials:
airlinkApiKey: WeatherLink API key for current conditions APIairlinkApiSecret: WeatherLink secret used inX-Api-Secret
Boolean map of station fields:
true: include fieldfalse: exclude field
If the file is missing, all fields are included.
--config <path>config file path (defaultconfig.json)--parameters <path>parameters file path (defaultparameters.json)--signalk true|falseoverride configsignalk--mqtt true|falseoverride configmqtt--storage true|falseoverride configstorage--drydry mode (no storage, no MQTT/Signal K/http connections; packets/rows logged only)
# Use config defaults
python3 vantage-publisher.py
# Enable MQTT and storage explicitly
python3 vantage-publisher.py --mqtt true --storage true
# Enable Signal K direct websocket together with MQTT and storage
python3 vantage-publisher.py --signalk true --mqtt true --storage true
# Dry mode validation (live console reads; no output publishing or CSV storage)
python3 vantage-publisher.py --dry
# Custom config + parameters
python3 vantage-publisher.py \
--config /etc/vantage/config.json \
--parameters /etc/vantage/parameters.jsonWhen --dry is active:
- MQTT connection/publish is disabled
- Signal K websocket connection/publish is disabled
- local CSV writes are disabled
- HTTP storage server is disabled
- station reads still connect to ser2net;
--dryis not an offline configuration validator - the configured
delayapplies between output cycles - generated outputs are logged (including datetime-valued station fields):
CSV_ROW;...MQTT_PACKET;...SIGNALK_UPDATE;...
If httpEnabled is true, the app starts an HTTP server exposing httpRoot.
Configuration keys:
httpEnabled(true|false)httpHost(default0.0.0.0)httpPort(default8080)httpRootdirectory to serve (defaultpathStorage)httpUseroptional basic auth usernamehttpPassoptional basic auth password
Authentication behavior:
- if
httpUseris empty, no authentication is required - if
httpUseris set, HTTP Basic Auth is required
{
"Datetime": "2026-02-24T10:15:40Z",
"TempOut": 12.7,
"WindSpeed": 3,
"position": { "latitude": 40.8569, "longitude": 14.2845 },
"name": "Centro Direzionale"
}{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [14.2845, 40.8569]
},
"properties": {
"Datetime": "2026-02-24T10:15:40Z",
"TempOut": 12.7,
"uuid": "it.uniparthenope.meteo.ws1",
"name": "Centro Direzionale"
}
}MQTT topic is always uuid.
All MQTT packets are written to the SQLite queue before publishing. A bounded batch is advanced each main-loop cycle, even when the station has no new readings. Records are removed only after Paho reports publish completion (broker acknowledgment for QoS 1/2; transmission for QoS 0). Queue age and size limits still apply, including before replay after a restart. A crash between delivery and queue deletion can cause duplicate delivery; consumers should tolerate duplicates. QoS 0 does not provide a broker acknowledgment. See Paho publish completion documentation.
When Signal K is enabled (signalk=true or --signalk true), the publisher sends deltas with:
context:signalkContext(defaultmeteo.<uuid>)navigation.position: station lat/lon- remaining fields:
- from
signalkPathMapif present - otherwise standard mappings for common weather keys
- otherwise, fallback to
environment.<field>.
- from
To publish directly to a Signal K server, set:
signalk: truesignalkServerUrl: websocket stream endpoint (ws://...orwss://...)signalkToken: API token (if your Signal K server requires authentication)signalkContext: target context (usuallymeteo.<uuid>)
Runtime behavior when Signal K is enabled:
- The publisher checks whether Signal K security is enabled.
- If security is enabled and
signalkTokenis missing or invalid, it automatically submits an access request. - While waiting for token approval, the main loop continues other enabled operations (CSV storage and/or MQTT).
- The publisher periodically re-checks access request status and token validity.
- As soon as a valid token is available, it is saved into
config.json(signalkToken) and direct websocket publishing starts automatically.
Note:
Datetime,DatetimeWS,position, andnameare handled internally by the publisher and are not required insignalkPathMap.
For the Signal K server https://signalk.meteo.uniparthenope.it, use the websocket stream URL:
wss://signalk.meteo.uniparthenope.it/signalk/v1/stream
{
"uuid": "it.uniparthenope.meteo.ws1",
"name": "Centro Direzionale",
"airlinkId": "",
"airlinkApiKey": "",
"airlinkApiSecret": "",
"lon": 14.2845,
"lat": 40.8569,
"storage": true,
"mqtt": false,
"signalk": true,
"usbPort": 22222,
"usbPollInterval": 1.0,
"delay": 10,
"timeout": 60,
"pathStorage": "/storage/vantage-pro/",
"mqttBroker": "",
"mqttPort": 1883,
"mqttUser": "",
"mqttPass": "",
"mqttQos": 1,
"mqttFormat": "flat",
"signalkServerUrl": "wss://signalk.meteo.uniparthenope.it/signalk/v1/stream",
"signalkToken": "REPLACE_WITH_SIGNAL_K_TOKEN",
"signalkContext": "meteo.it.uniparthenope.meteo.ws1",
"signalkPathMap": {
"BarTrend": "environment.outside.pressureTrend",
"Barometer": "environment.outside.pressure",
"TempIn": "environment.inside.temperature",
"HumIn": "environment.inside.humidity",
"TempOut": "environment.outside.temperature",
"WindSpeed": "environment.wind.speedApparent",
"WindSpeed10Min": "environment.wind.speedAverage",
"WindDir": "environment.wind.angleApparent",
"HumOut": "environment.outside.humidity",
"RainRate": "environment.rain.rate",
"SolarRad": "environment.solar.radiation",
"RainStorm": "environment.rain.storm.total",
"StormStartDate": "environment.rain.storm.startDate",
"RainDay": "environment.rain.day",
"RainMonth": "environment.rain.month",
"RainYear": "environment.rain.year",
"ETDay": "environment.outside.evapoTranspiration.day",
"ETMonth": "environment.outside.evapoTranspiration.month",
"ETYear": "environment.outside.evapoTranspiration.year",
"BatteryStatus": "electrical.batteries.sensor.status",
"BatteryVolts": "electrical.batteries.sensor.voltage",
"ForecastIcon": "environment.weather.forecast.icon",
"ForecastRuleNo": "environment.weather.forecast.ruleNumber",
"SunRise": "environment.sun.rise",
"SunSet": "environment.sun.set"
},
"httpEnabled": false,
"httpHost": "0.0.0.0",
"httpPort": 8080,
"httpUser": "",
"httpPass": "",
"httpRoot": "/storage/vantage-pro/",
"offlineMaxMessages": 200000,
"offlineMaxAgeSec": 604800,
"airlinkIntervalSec": 300
}- Create a local config from the sample:
cp config.json.sample config.json
- Edit
config.jsonand set:signalktotruesignalkServerUrltowss://signalk.meteo.uniparthenope.it/signalk/v1/streamsignalkTokento a valid token from your Signal K server
- Keep
mqttasfalseif you only want direct Signal K publishing. - Start the publisher:
python3 vantage-publisher.py --config config.json --signalk true
- If Signal K security is enabled, approve the pending access request on the Signal K server UI/API.
- Wait for the periodic token check; the publisher will save the approved token into
config.jsonand begin websocket publishing automatically. - Verify updates on Signal K:
- check that context
meteo.it.uniparthenope.meteo.ws1receivesnavigation.positionand weather paths.
- check that context
- Optional validation mode:
- run
python3 vantage-publisher.py --dryto inspect generatedSIGNALK_UPDATElogs without network publish.
- run
collect-history.py downloads archive records from the station using PyVantagePro normalized JSON rows (get_archives_as_json), so values are exported in SI-oriented units already provided by the library.
Behavior:
- Uses logging (no
print) - Supports start/stop date range from command line
- Applies
parameters.jsonfiltering (if provided) - Writes CSV only when
--outputis provided - If
--outputis omitted, rows are logged to console
--url <station-url>station connection URL (default:tcp:127.0.0.1:22222)--timeout <seconds>read timeout (default:10)--start <ISO-datetime>archive start datetime--stop <ISO-datetime>archive stop datetime (optional)--parameters <file>parameters map file (default:parameters.json)--output <file.csv>output file path (optional)--log-level <LEVEL>logger level (default:INFO)
# Collect from 2026-03-01 to 2026-03-08 and write CSV
python3 collect-history.py \
--start 2026-03-01T00:00:00 \
--stop 2026-03-08T00:00:00 \
--output /tmp/history.csv
# Collect from a date and log rows to console only
python3 collect-history.py --start 2026-03-07T00:00:00- CSV files (hourly rotation):
<pathStorage>/<uuid>/<YYYY>/<MM>/<DD>/<uuid>_<YYYYMMDD>Z<HH>00.csv- example:
/storage/vantage-pro/it.uniparthenope.meteo.ws1/2026/02/26/it.uniparthenope.meteo.ws1_20260226Z1400.csv
- example:
- MQTT offline queue DB:
<pathStorage>/mqtt_offline_queue.sqlite(ormqttSpoolFile)
CSV schema expansion uses an atomic file replacement so a failed rewrite preserves
the existing CSV. If expansion fails, the new row is skipped and the error is logged.
An empty pathStorage skips CSV storage, as reported at startup.
GitHub Actions checks Python 3.8, 3.12, and 3.13,
builds the runtime image, and smoke-tests its real dependencies. Successful pushes
to main and v* tags publish the tested linux/amd64 image to
ghcr.io/ccmmma/vantage-publisher. Pull requests and manual runs validate without
publishing. Station rollout remains operator-controlled.
See CI/CD documentation for permissions, image tags, installation, and validation limits.
python3 -m unittest discover -s tests -v
python3 -m py_compile vantage-publisher.py airlink.py collect-history.py tests/test_publisher.pyRegression tests use temporary storage and mocked station/network clients; they do not require a live station or installed network dependencies. Live station, MQTT, and Signal K integration should be checked in the deployment environment.
make run mounts configuration at the runtime's default paths under
/vantage-publisher. Use Docker Compose for the supplied persistent storage mount.
Apache-2.0