Skip to content
 
 

Repository files navigation

PyVantagePro

CI

Python tools to communicate with Davis Vantage Pro2 weather stations.

CI targets Python 3.10–3.14 on Linux. Current source requires Python 3; historical Python 2 compatibility claims no longer apply.

Documentation

The documentation index covers:

Built HTML is available as the documentation artifact on successful CI runs.

This project provides:

  • A Python API (VantagePro2) for live data, archives, and station metadata
  • A CLI (pyvantagepro) for common operational workflows
  • Parsers for LOOP and archive records

Highlights

  • Read current station time (gettime) and set it (settime)
  • Read live LOOP data (get_current_data)
  • Download archive records (get_archives)
  • Get normalized live payloads (get_current_data_as_json, get_current_data_as_list)
  • Get normalized archive payloads (get_archives_as_json, get_archives_as_list)
  • Read station diagnostics, firmware info, and barometer calibration data
  • Export data to CSV from API and CLI
  • Connection recovery on BrokenPipeError (automatic reconnect/retry)

Examples

  • Full runnable catalog: examples/README.md
  • Includes examples/14_stream.py for production-style streaming with:
    • hourly UTC CSV rotation,
    • MQTT store-and-forward buffering,
    • optional per-key filtering via examples/parameters.json,
    • dry/no-csv/no-mqtt runtime switches,
    • flat config.json deployment schema.

Installation

From source (recommended)

git clone https://github.com/CCMMMA/PyVantagePro.git
cd PyVantagePro
python3 -m pip install -U .

In editable mode for development

python3 -m pip install -U -e .

Upgrade an existing environment

python -m pip uninstall -y pyvantagepro PyVantagePro
python -m pip install --no-cache-dir -U git+https://github.com/CCMMMA/PyVantagePro.git@main

Quick Start (Python API)

from pyvantagepro import VantagePro2

device = VantagePro2.from_url('tcp:127.0.0.1:22222', timeout=10)

station_time = device.gettime()
print(station_time)

current = device.get_current_data()
print(current['TempIn'])
print(current['RainRate'])

# Keep only selected fields and serialize as CSV
print(current.filter(('Datetime', 'TempIn', 'TempOut', 'RainRate')).to_csv())

archives = device.get_archives()
print(len(archives))

# Always close when done
device.close()

More API Examples

1. List available live-data variables and units

from pyvantagepro import VantagePro2

device = VantagePro2.from_url('tcp:127.0.0.1:22222')
meta = device.meta()  # {"TempIn": {"internal_unit": "degF", "si_unit": "degC"}, ...}
print(meta["TempIn"]["internal_unit"])  # degF
print(meta["TempIn"]["si_unit"])        # degC
print(meta["RainRate"]["internal_unit"])  # in/h
print(meta["RainRate"]["si_unit"])        # mm/h
device.close()

2. Read only selected live fields

from pyvantagepro import VantagePro2

device = VantagePro2.from_url('tcp:127.0.0.1:22222')
data = device.get_current_data()

subset = data.filter(('Datetime', 'TempIn', 'TempOut', 'HumOut', 'RainRate', 'WindSpeed'))
print(subset)
print(subset.to_csv())
device.close()

3. Get live data as a normalized JSON object

import json
from pyvantagepro import VantagePro2

device = VantagePro2.from_url('tcp:127.0.0.1:22222')
payload = device.get_current_data_as_json()

print(type(payload))          # dict
print(payload['TempIn'])      # degC
print(payload['HumOut'])      # percent (0..100)
print(payload['Datetime'])    # ISO8601 datetime string

# Optional: serialize to JSON string
print(json.dumps(payload))
device.close()

3b. Get live data as an ordered list

get_current_data_as_list() returns values in the same order as meta(). If a value fails sanity checks (or matches known sentinel values), the element is None.

from pyvantagepro import VantagePro2

device = VantagePro2.from_url('tcp:127.0.0.1:22222')

meta = device.meta()
values = device.get_current_data_as_list()

for info, value in zip(meta, values):
    print(info, value, meta[info]["internal_unit"], "=>", meta[info]["si_unit"])

device.close()

3c. get_current_data_as_csv() compatibility

New code should use get_current_data_as_list(). If you need compatibility with older snippets that call get_current_data_as_csv(), use:

from pyvantagepro import VantagePro2

device = VantagePro2.from_url('tcp:127.0.0.1:22222')
get_values = getattr(device, "get_current_data_as_csv", device.get_current_data_as_list)
values = get_values()
print(values)
device.close()

3d. Normalization rules used by JSON/list payloads

  • Date/time fields are exported as ISO8601 strings.
  • LOOP storm dates use their own packed date format, distinct from archive timestamps; missing or invalid calendar dates become None.
  • LOOP alarm flags follow the console's least-significant-bit-first numbering, including separate soil/leaf alarm bits.
  • Values are converted to SI where applicable (for example: degF -> degC, in -> mm, mph -> m/s, inHg -> hPa).
  • HumIn and HumOut are normalized as percent values in the 0..100 range.
  • Selected fields are rounded to fixed precision for stable downstream processing.
  • Alarm/sentinel fields are filtered in JSON output and set to None in list output.
  • Sanity checks are applied; JSON drops invalid values and records their names in failed, while list output keeps position and sets invalid entries to None.

3e. Example of failing sensor values in normalized outputs

Some console values are sentinel readings that indicate missing/invalid sensor data (for example UV=255, SolarRad=32767).

get_current_data_as_json() behavior:

payload = device.get_current_data_as_json()

# When UV/SolarRad are sentinel values:
# - keys are removed from payload
# - failed list includes dropped keys
print(payload.get("UV"))        # None
print(payload.get("SolarRad"))  # None
print(payload.get("failed"))    # ['UV', 'SolarRad'] (if both failed)

get_current_data_as_list() behavior:

meta = device.meta()
row = device.get_current_data_as_list()

uv_idx = list(meta).index("UV")
solar_idx = list(meta).index("SolarRad")

# Same failing sensors become None in-place to preserve column order.
print(row[uv_idx])     # None
print(row[solar_idx])  # None

4. Download archives for a specific time window

from datetime import datetime
from pyvantagepro import VantagePro2

device = VantagePro2.from_url('tcp:127.0.0.1:22222')

start = datetime(2026, 2, 19, 0, 0)
stop = datetime(2026, 2, 19, 23, 59)
archives = device.get_archives(start_date=start, stop_date=stop)

print(f"records: {len(archives)}")
print(archives[0])
print(archives[-1])
device.close()

4b. Download normalized archives as JSON rows

from datetime import datetime
from pyvantagepro import VantagePro2

device = VantagePro2.from_url('tcp:127.0.0.1:22222')
start = datetime(2026, 2, 19, 0, 0)
stop = datetime(2026, 2, 19, 23, 59)

rows = device.get_archives_as_json(start_date=start, stop_date=stop)
print(type(rows))      # list
print(type(rows[0]))   # dict
print(rows[0])         # ISO8601 + SI-normalized values
device.close()

4c. Download normalized archives as ordered lists

from datetime import datetime
from pyvantagepro import VantagePro2

device = VantagePro2.from_url('tcp:127.0.0.1:22222')
start = datetime(2026, 2, 19, 0, 0)
stop = datetime(2026, 2, 19, 23, 59)

meta = device.meta()
rows = device.get_archives_as_list(start_date=start, stop_date=stop)
print(len(rows))
if rows:
    print(rows[0])  # archive field order; different from live meta() order
device.close()

Archive normalization reuses live conversion rules and has known limitations for archive-only fields and offset temperature sensors. See data formats before using normalized archives for analysis.

5. Keep a local CSV archive up to date

from pathlib import Path
from pyvantagepro import VantagePro2

device = VantagePro2.from_url('tcp:127.0.0.1:22222')
db_path = Path("weather_archive.csv")

new_rows = device.get_archives()
if new_rows:
    csv_text = new_rows.to_csv(header=not db_path.exists())
    mode = "a" if db_path.exists() else "w"
    with db_path.open(mode) as f:
        f.write(csv_text)

device.close()

6. Read station metadata and diagnostics

from pyvantagepro import VantagePro2

device = VantagePro2.from_url('tcp:127.0.0.1:22222')

print("Firmware date:", device.firmware_date)
print("Firmware version:", device.firmware_version)
print("Archive period (min):", device.getperiod())
print("Timezone:", device.timezone)
print("Diagnostics:", device.getdiagnostics())
print("Barometer calibration:", device.getbar())

device.close()

7. Set station time and archive period

from datetime import datetime
from pyvantagepro import VantagePro2

device = VantagePro2.from_url('tcp:127.0.0.1:22222')

before = device.gettime()
device.settime(datetime.now())
after = device.gettime()
print("time:", before, "->", after)

old_period = device.getperiod()
device.setperiod(10)  # allowed values: 1, 5, 10, 15, 30, 60, 120
print("archive period:", old_period, "->", device.getperiod())

device.close()

8. Handle recoverable link errors

from pyvantagepro import VantagePro2
from pyvantagepro.device import NoDeviceException, BadAckException

device = VantagePro2.from_url('tcp:127.0.0.1:22222', timeout=10)

try:
    data = device.get_current_data()
except (NoDeviceException, BadAckException) as exc:
    # The library retries internally; this handles final failure.
    print("station read failed:", exc)
finally:
    device.close()

Python API Summary

Commonly used methods/properties on VantagePro2:

  • Constructors: from_url, from_serial
  • Clock/period: gettime, settime, getperiod, setperiod
  • Live data:
    • get_current_data
    • meta
    • get_current_data_as_json
    • get_current_data_as_list
  • Archives:
    • get_archives
    • get_archives_as_json
    • get_archives_as_list
  • Diagnostics/info:
    • getdiagnostics, getbar
    • firmware_date, firmware_version, timezone

Connection URLs

PyVantagePro uses pylink URLs, for example:

  • tcp:host:port
  • serial:/dev/ttyUSB0:19200:8N1

Use the transport format that matches your hardware setup.

CLI Usage

pyvantagepro --help

Available commands include:

  • gettime
  • settime
  • getinfo
  • getbar
  • getdata
  • getarchives
  • update
  • getperiod
  • setperiod

CLI examples

# Read station time
pyvantagepro gettime tcp:127.0.0.1:22222

# Read one live packet and print CSV to stdout
pyvantagepro getdata tcp:127.0.0.1:22222

# Download archives between two timestamps
pyvantagepro getarchives \
  --start "2026-02-19 00:00" \
  --stop "2026-02-19 23:59" \
  tcp:127.0.0.1:22222

# Update a local CSV database file with new archive rows
pyvantagepro update tcp:127.0.0.1:22222 weather_archive.csv

Troubleshooting

BrokenPipeError: [Errno 32] Broken pipe

If your station/proxy drops idle connections, writes can fail with BrokenPipeError. Recent versions of this repository include automatic reconnect and retry logic.

If you still see this error:

  1. Make sure your environment is running the latest code (pip install -U ...).
  2. Recreate the VantagePro2 instance after long idle periods.
  3. Verify host/port serial bridge health (e.g. TCP proxy, USB serial adapter).
  4. Increase timeout if your link is slow.

Imported package does not match repository code

If stack traces point to .../site-packages/pyvantagepro/..., your virtualenv may use an older installed package. Reinstall from this repository in that exact virtualenv.

Development

Install development dependencies and run the checks:

python3 -m pip install -e . -r requirements-dev.txt
python3 -m pytest -q
python3 -m build
python3 -m twine check --strict dist/*
python3 -m sphinx -W --keep-going -b html docs docs/_build/html

Open docs/_build/html/index.html for the local guide. Repository guidance for agents/contributors is documented in AGENTS.md.

CI/CD

  • CI: pull requests, pushes to main, and manual runs test Python 3.10–3.14, verify the CLI, build/check packages, test the source distribution, smoke-test the installed wheel, and build documentation with warnings as errors.
  • Release delivery: publishing a GitHub Release reruns CI on its tag, then attaches validated wheel/source packages and a documentation ZIP using GITHUB_TOKEN. No additional secret is needed.

See the release guide for versioning, reruns, and repository requirements. PyPI publishing and GitHub Pages are not configured.

Notes

  • Historical release information remains in CHANGES.rst.
  • setup.py currently reads README.rst for package metadata.

License

GNU GPL v3 (see COPYING).

About

Communication tools for the Davis VantagePro2 devices. http://pyvantagepro.readthedocs.org

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages