Apply Venus OS best practices across all services
- Standardize multilog to s25000 n4 (~100KB cap) to prevent filling /data - Use VeDbusService register=False + deferred register() in dbus-generator-ramp and dbus-vrm-history - Add @exit_on_error decorator to template GLib callback - Document best practices in README and template README Made-with: Cursor
This commit is contained in:
16
README.md
16
README.md
@@ -74,6 +74,22 @@ Some projects require API keys or credentials. These are excluded from version c
|
||||
- `dbus-windy-station/station_config.example.json` --> `station_config.json`
|
||||
- `watermaker/ui/.env.example` --> `.env`
|
||||
|
||||
## Venus OS Best Practices
|
||||
|
||||
These projects follow guidelines from the [Venus OS wiki](https://github.com/victronenergy/venus/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](https://github.com/victronenergy/venus/wiki/dbus-api)).
|
||||
|
||||
**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](https://github.com/victronenergy/venus/wiki/howto-add-a-driver-to-Venus#4-stability---exceptions-handling)).
|
||||
|
||||
**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.
|
||||
|
||||
@@ -34,6 +34,15 @@ Update these for your service:
|
||||
| `/Connected` | int | Connection status (0/1) |
|
||||
| `/Settings/Template/Enabled` | int | Enable/disable via settings |
|
||||
|
||||
## Venus OS Best Practices
|
||||
|
||||
The template follows these [Venus OS wiki](https://github.com/victronenergy/venus/wiki) guidelines:
|
||||
|
||||
- **`register=False`** -- `VeDbusService` is created with `register=False`, paths are added, then `register()` is called to prevent race conditions with consumers.
|
||||
- **`@exit_on_error`** -- Applied to the `GLib.timeout_add` callback so unhandled exceptions crash the process instead of silently dropping the callback.
|
||||
- **`daemon=True`** -- Set on background threads so they don't prevent process exit.
|
||||
- **multilog** -- Log size capped at `s25000 n4` (~100KB) to avoid filling the `/data` partition.
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] Unique service name in `config.py` (`com.victronenergy.yourservice`)
|
||||
@@ -41,4 +50,6 @@ Update these for your service:
|
||||
- [ ] All file references updated in `service/run`, `install.sh`, `build-package.sh`
|
||||
- [ ] Custom D-Bus paths added
|
||||
- [ ] Settings paths updated
|
||||
- [ ] `@exit_on_error` on all `GLib.timeout_add` callbacks
|
||||
- [ ] Background threads use `daemon=True`
|
||||
- [ ] README replaced with your own documentation
|
||||
|
||||
@@ -20,6 +20,7 @@ import time
|
||||
sys.path.insert(1, os.path.join(os.path.dirname(__file__), 'ext', 'velib_python'))
|
||||
|
||||
from vedbus import VeDbusService # noqa: E402
|
||||
from ve_utils import exit_on_error # noqa: E402
|
||||
from settingsdevice import SettingsDevice # noqa: E402
|
||||
import dbus # noqa: E402
|
||||
from gi.repository import GLib # noqa: E402
|
||||
@@ -84,6 +85,7 @@ class TemplateService:
|
||||
self._running = True
|
||||
GLib.timeout_add(MAIN_LOOP_INTERVAL_MS, self._update)
|
||||
|
||||
@exit_on_error
|
||||
def _update(self):
|
||||
"""Called every MAIN_LOOP_INTERVAL_MS. Return True to keep running."""
|
||||
if not self._running:
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#!/bin/sh
|
||||
exec multilog t s99999 n8 /var/log/dbus-template
|
||||
exec multilog t s25000 n4 /var/log/dbus-template
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#!/bin/sh
|
||||
exec multilog t s99999 n8 /var/log/dbus-raymarine-publisher
|
||||
exec multilog t s25000 n4 /var/log/dbus-raymarine-publisher
|
||||
|
||||
@@ -157,7 +157,7 @@ class GeneratorRampController:
|
||||
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
self.dbus_service = VeDbusService(SERVICE_NAME, self.bus)
|
||||
self.dbus_service = VeDbusService(SERVICE_NAME, self.bus, register=False)
|
||||
break # Success
|
||||
except dbus.exceptions.NameExistsException:
|
||||
if attempt < max_retries - 1:
|
||||
@@ -317,6 +317,7 @@ class GeneratorRampController:
|
||||
onchangecallback=self._on_setting_changed,
|
||||
gettextcallback=lambda p, v: f"{v} min")
|
||||
|
||||
self.dbus_service.register()
|
||||
self.logger.info("D-Bus service created")
|
||||
|
||||
def _generator_state_text(self, path, value):
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#!/bin/sh
|
||||
exec multilog t s99999 n8 /var/log/dbus-generator-ramp-webui
|
||||
exec multilog t s25000 n4 /var/log/dbus-generator-ramp-webui
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
# Logs service output using multilog
|
||||
#
|
||||
|
||||
exec multilog t s99999 n8 /var/log/dbus-generator-ramp
|
||||
exec multilog t s25000 n4 /var/log/dbus-generator-ramp
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#!/bin/sh
|
||||
exec multilog t s99999 n8 /var/log/dbus-lightning
|
||||
exec multilog t s25000 n4 /var/log/dbus-lightning
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#!/bin/sh
|
||||
exec multilog t s99999 n8 /var/log/dbus-meteoblue-forecast
|
||||
exec multilog t s25000 n4 /var/log/dbus-meteoblue-forecast
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
# Logs service output using multilog
|
||||
#
|
||||
|
||||
exec multilog t s99999 n8 /var/log/dbus-no-foreign-land
|
||||
exec multilog t s25000 n4 /var/log/dbus-no-foreign-land
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#!/bin/sh
|
||||
exec multilog t s99999 n8 /var/log/dbus-tides
|
||||
exec multilog t s25000 n4 /var/log/dbus-tides
|
||||
|
||||
@@ -93,7 +93,7 @@ class VrmHistoryService:
|
||||
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
self.dbus_service = VeDbusService(SERVICE_NAME, self.bus)
|
||||
self.dbus_service = VeDbusService(SERVICE_NAME, self.bus, register=False)
|
||||
break
|
||||
except dbus.exceptions.NameExistsException:
|
||||
if attempt < max_retries - 1:
|
||||
@@ -135,6 +135,9 @@ class VrmHistoryService:
|
||||
svc.add_path('/History/GeneratorRuntime', '')
|
||||
svc.add_path('/History/BatteryCycles', '')
|
||||
|
||||
# Register service after all paths added (Venus OS best practice)
|
||||
svc.register()
|
||||
|
||||
def _setup_settings(self):
|
||||
try:
|
||||
base = DBUS_CONFIG['settings_path']
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#!/bin/sh
|
||||
exec multilog t s99999 n8 /var/log/dbus-vrm-history
|
||||
exec multilog t s25000 n4 /var/log/dbus-vrm-history
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#!/bin/sh
|
||||
exec multilog t s99999 n8 /var/log/dbus-windy-station
|
||||
exec multilog t s25000 n4 /var/log/dbus-windy-station
|
||||
|
||||
Reference in New Issue
Block a user