Organizes 11 projects for Cerbo GX/Venus OS into a single repository: - axiom-nmea: Raymarine LightHouse protocol decoder - dbus-generator-ramp: Generator current ramp controller - dbus-lightning: Blitzortung lightning monitor - dbus-meteoblue-forecast: Meteoblue weather forecast - dbus-no-foreign-land: noforeignland.com tracking - dbus-tides: Tide prediction from depth + harmonics - dbus-vrm-history: VRM cloud history proxy - dbus-windy-station: Windy.com weather upload - mfd-custom-app: MFD app deployment package - venus-html5-app: Custom Victron HTML5 app fork - watermaker: Watermaker PLC control UI Adds root README, .gitignore, project template, and per-project .gitignore files. Sensitive config files excluded via .gitignore with .example templates provided. Made-with: Cursor
136 lines
4.4 KiB
Python
136 lines
4.4 KiB
Python
"""
|
|
Sensor configuration and metadata.
|
|
|
|
This module provides configuration for tanks, batteries, and network settings
|
|
specific to the vessel. These can be customized for different installations.
|
|
"""
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Dict, Tuple, Optional
|
|
|
|
|
|
@dataclass
|
|
class TankInfo:
|
|
"""Configuration for a tank sensor."""
|
|
name: str
|
|
capacity_gallons: Optional[float] = None
|
|
tank_type: str = "fuel" # fuel, water, waste, other
|
|
|
|
@property
|
|
def capacity_liters(self) -> Optional[float]:
|
|
"""Return capacity in liters."""
|
|
if self.capacity_gallons is None:
|
|
return None
|
|
return self.capacity_gallons * 3.78541
|
|
|
|
|
|
@dataclass
|
|
class BatteryInfo:
|
|
"""Configuration for a battery sensor."""
|
|
name: str
|
|
nominal_voltage: float = 12.0 # 12V, 24V, 48V
|
|
battery_type: str = "house" # house, engine, starter
|
|
|
|
|
|
# Default tank configuration
|
|
# Key is the tank ID from Raymarine
|
|
TANK_CONFIG: Dict[int, TankInfo] = {
|
|
1: TankInfo("Fuel Starboard", 265, "fuel"),
|
|
2: TankInfo("Fuel Port", 265, "fuel"),
|
|
10: TankInfo("Water Bow", 90, "water"),
|
|
11: TankInfo("Water Stern", 90, "water"),
|
|
100: TankInfo("Black Water", 53, "blackwater"),
|
|
}
|
|
|
|
# Default battery configuration
|
|
# Key is the battery ID from Raymarine
|
|
# IDs 1000+ are engine batteries (1000 + engine_id)
|
|
BATTERY_CONFIG: Dict[int, BatteryInfo] = {
|
|
11: BatteryInfo("House Battery Bow", 24.0, "house"),
|
|
13: BatteryInfo("House Battery Stern", 24.0, "house"),
|
|
1000: BatteryInfo("Engine Port", 24.0, "engine"),
|
|
1001: BatteryInfo("Engine Starboard", 24.0, "engine"),
|
|
}
|
|
|
|
# Raymarine multicast groups
|
|
# Each tuple is (group_address, port)
|
|
#
|
|
# OPTIMIZATION: Based on testing, ALL sensor data (GPS, wind, depth, heading,
|
|
# temperature, tanks, batteries) comes from the primary group. The other groups
|
|
# contain only heartbeats, display sync, or zero/empty data.
|
|
#
|
|
# Test results showed:
|
|
# 226.192.206.102:2565 - 520 pkts, 297 decoded (GPS, heading, wind, depth, temp, tanks, batteries)
|
|
# 226.192.219.0:3221 - 2707 pkts, 0 decoded (display sync - high traffic, no data!)
|
|
# 226.192.206.99:2562 - 402 pkts, 0 decoded (heartbeat only)
|
|
# 226.192.206.98:2561 - 356 pkts, 0 decoded (mostly zeros)
|
|
# Others - <30 pkts each, 0 decoded
|
|
#
|
|
# Using only the primary group reduces:
|
|
# - Thread count: 7 → 1 (less context switching)
|
|
# - Packet processing: ~4000 → ~500 packets (87% reduction)
|
|
# - CPU usage: significant reduction on embedded devices
|
|
|
|
# Primary multicast group - contains ALL sensor data
|
|
MULTICAST_GROUPS: list[Tuple[str, int]] = [
|
|
("226.192.206.102", 2565), # PRIMARY sensor data (GPS, wind, depth, tanks, batteries, etc.)
|
|
]
|
|
|
|
# Legacy: All groups (for debugging/testing only)
|
|
MULTICAST_GROUPS_ALL: list[Tuple[str, int]] = [
|
|
("226.192.206.98", 2561), # Navigation sensors (mostly zeros)
|
|
("226.192.206.99", 2562), # Heartbeat/status
|
|
("226.192.206.100", 2563), # Alternative data (low traffic)
|
|
("226.192.206.101", 2564), # Alternative data (low traffic)
|
|
("226.192.206.102", 2565), # PRIMARY sensor data
|
|
("226.192.219.0", 3221), # Display synchronization (HIGH traffic, no sensor data!)
|
|
("239.2.1.1", 2154), # Tank/engine data (not used on this vessel)
|
|
]
|
|
|
|
# Primary multicast group for most sensor data
|
|
PRIMARY_MULTICAST_GROUP = ("226.192.206.102", 2565)
|
|
|
|
|
|
def get_tank_name(tank_id: int) -> str:
|
|
"""Get the display name for a tank ID."""
|
|
if tank_id in TANK_CONFIG:
|
|
return TANK_CONFIG[tank_id].name
|
|
return f"Tank #{tank_id}"
|
|
|
|
|
|
def get_tank_capacity(tank_id: int) -> Optional[float]:
|
|
"""Get the capacity in gallons for a tank ID."""
|
|
if tank_id in TANK_CONFIG:
|
|
return TANK_CONFIG[tank_id].capacity_gallons
|
|
return None
|
|
|
|
|
|
def get_battery_name(battery_id: int) -> str:
|
|
"""Get the display name for a battery ID."""
|
|
if battery_id in BATTERY_CONFIG:
|
|
return BATTERY_CONFIG[battery_id].name
|
|
return f"Battery #{battery_id}"
|
|
|
|
|
|
def get_battery_nominal_voltage(battery_id: int) -> float:
|
|
"""Get the nominal voltage for a battery ID."""
|
|
if battery_id in BATTERY_CONFIG:
|
|
return BATTERY_CONFIG[battery_id].nominal_voltage
|
|
# Default to 12V for unknown batteries
|
|
return 12.0
|
|
|
|
|
|
__all__ = [
|
|
"TankInfo",
|
|
"BatteryInfo",
|
|
"TANK_CONFIG",
|
|
"BATTERY_CONFIG",
|
|
"MULTICAST_GROUPS",
|
|
"MULTICAST_GROUPS_ALL",
|
|
"PRIMARY_MULTICAST_GROUP",
|
|
"get_tank_name",
|
|
"get_tank_capacity",
|
|
"get_battery_name",
|
|
"get_battery_nominal_voltage",
|
|
]
|