- Added lib/signal_reader.py with SignalGpsReader, SignalMeteoReader, and SignalDepthReader that use PropertiesChanged signal subscriptions instead of polling via GetValue(), reducing D-Bus overhead at steady state. - Each reader discovers its service dynamically, seeds its cache with a one-shot GetValue, then relies on signals for all subsequent updates. - Refactored dbus-tides, dbus-windy-station, dbus-no-foreign-land, dbus-lightning, and dbus-meteoblue-forecast to import from the shared library, removing ~600 lines of duplicated _unwrap() helpers and per-service GPS/meteo/depth reader classes. - Updated install.sh for all five services to deploy signal_reader.py to /data/lib/ on the target device. - Updated build-package.sh for all five services to bundle signal_reader.py into the .tar.gz package. - Updated README.md with the new lib/ entry in the project table and documented the shared D-Bus readers pattern. - Bumped version numbers in affected services (e.g. nfl_tracking 2.0.1). Made-with: Cursor
Venus OS Boat Addons
Custom addons for a Cerbo GX running Venus OS on a sailboat. These services extend the system with weather monitoring, tide prediction, navigation tracking, generator management, and custom MFD displays.
All D-Bus services follow the same deployment pattern: build a .tar.gz package, copy it to /data/ on the Cerbo GX, and run install.sh. Services are managed by daemontools and survivase firmware updates via rc.local.
Projects
| Project | Type | Language | Description |
|---|---|---|---|
| axiom-nmea | Library + Service | Python | Decodes Raymarine LightHouse protobuf multicast into NMEA 0183 sentences and Venus OS D-Bus services. Includes protocol documentation, debug tools, and a deployable D-Bus publisher. |
| dbus-generator-ramp | D-Bus Service | Python | Gradually ramps inverter/charger input current when running on generator to avoid overload. Features warm-up hold, overload detection with fast recovery, and a persistent power correlation learning model. |
| lib | Shared Library | Python | Signal-based D-Bus readers for GPS, meteo, and depth data. Uses PropertiesChanged subscriptions instead of polling, shared across all D-Bus services that consume sensor data. |
| dbus-lightning | D-Bus Service | Python | Monitors real-time lightning strikes from the Blitzortung network via WebSocket. Filters by distance, analyzes storm approach speed, and estimates ETA. |
| dbus-meteoblue-forecast | D-Bus Service | Python | Fetches 7-day weather forecasts from the Meteoblue API (wind, waves, precipitation, temperature). Adjusts refresh rate based on boat movement. |
| dbus-no-foreign-land | D-Bus Service | Python | Sends GPS position and track data to noforeignland.com. Includes a QML settings page for the Venus OS GUI. |
| dbus-tides | D-Bus Service | Python | Predicts tides by combining depth sensor readings with harmonic tidal models (NOAA stations and coastal grid). Records depth history in SQLite, detects high/low tides, and calibrates to chart depth. |
| dbus-vrm-history | D-Bus Service | Python | Proxies historical data from the VRM cloud API and exposes it on D-Bus/MQTT for the frontend dashboard. |
| dbus-windy-station | D-Bus Service | Python | Uploads weather observations from Raymarine sensors to Windy.com Stations API. Supports both legacy and v2 Venus OS GUI plugins. |
| mfd-custom-app | Deployment Package | Shell | Builds and deploys the custom HTML5 app to the Cerbo GX. Overrides the stock Victron app with custom pages served via nginx. Supports SSH and USB installation. |
| venus-html5-app | Frontend App | TypeScript/React | Fork of the Victron Venus HTML5 app with custom Marine2 views for weather, tides, tracking, generator status, and mooring. Displayed on Raymarine Axiom and other MFDs. |
| watermaker | UI + API Docs | React/JS | Control interface for a watermaker PLC system. React SPA with REST/WebSocket/MQTT integration. Backend runs on a separate PLC controller. |
Common D-Bus Service Structure
All Python D-Bus services share this layout:
dbus-<name>/
├── <name>.py # Main service entry point
├── config.py # Configuration constants
├── service/
│ ├── run # daemontools entry point
│ └── log/run # multilog configuration
├── install.sh # Venus OS installation
├── uninstall.sh # Cleanup
├── build-package.sh # Creates deployable .tar.gz
└── README.md
At install time, install.sh symlinks velib_python from /opt/victronenergy/, installs the shared lib/signal_reader.py to /data/lib/, registers the service with daemontools, and adds an rc.local entry for persistence across firmware updates.
Shared D-Bus Readers -- Services that read GPS, meteo, or depth data from D-Bus should use the signal-based readers in lib/signal_reader.py (SignalGpsReader, SignalMeteoReader, SignalDepthReader) instead of polling with GetValue(). These readers bootstrap with a one-shot read, then subscribe to PropertiesChanged signals for zero-cost steady-state updates.
Deployment
# Build a package
cd dbus-<name>
./build-package.sh
# Copy to Cerbo GX
scp dbus-<name>-*.tar.gz root@<cerbo-ip>:/data/
# Install on device
ssh root@<cerbo-ip>
cd /data && tar -xzf dbus-<name>-*.tar.gz
bash /data/dbus-<name>/install.sh
# Check service status
svstat /service/dbus-<name>
tail -f /var/log/dbus-<name>/current | tai64nlocal
Development Prerequisites
- Python 3.8+ -- for all D-Bus services
- Node.js 20+ and npm -- for venus-html5-app and watermaker UI
- SSH/root access to the Cerbo GX
- Venus OS v3.10+ on the target device
Sensitive Configuration
Some projects require API keys or credentials. These are excluded from version control. Copy the example templates and fill in your values:
dbus-meteoblue-forecast/forecast_config.example.json-->forecast_config.jsondbus-windy-station/station_config.example.json-->station_config.jsonwatermaker/ui/.env.example-->.env
Venus OS Best Practices
These projects follow guidelines from the Venus OS wiki:
D-Bus Service Registration -- Create VeDbusService with register=False, add all paths and populate initial values, then call register(). This prevents consumers from querying the service before it is fully initialized (details).
Mandatory D-Bus Paths -- Every service must publish: /Mgmt/ProcessName, /Mgmt/ProcessVersion, /Mgmt/Connection, /DeviceInstance, /ProductId, /ProductName, /FirmwareVersion, /Connected.
Stability and Exception Handling -- Don't code too defensively. If something goes wrong, let the process exit cleanly and let daemontools restart it. For GLib.timeout_add callbacks in Python, an unhandled exception silently drops the callback without exiting; use exit_on_error() from ve_utils.py to ensure crashes propagate. Background threads should always set daemon=True (details).
Logging -- Use multilog t s25000 n4 in service/log/run to cap log storage at ~100KB per service (4 files x 25KB). This matches the Victron v2.23 standard and prevents filling the /data partition on space-constrained devices.
Service Directory -- Symlink services to /opt/victronenergy/service (not /service, which is a tmpfs overlay). The install.sh scripts handle this with fallback logic.
Persistence -- Install code under /data/ so it survives firmware updates. Add an entry in /data/rc.local to restore the service symlink after updates.
New Project Template
See [_template/](_template/) for a skeleton D-Bus service with all the boilerplate: main script, config, daemontools service, install/uninstall scripts, and build packaging.