Files
venus/axiom-nmea/raymarine_nmea/sensors/__init__.py
dev 9756538f16 Initial commit: Venus OS boat addons monorepo
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
2026-03-16 17:04:16 +00:00

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",
]