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
148 lines
4.0 KiB
Python
148 lines
4.0 KiB
Python
"""
|
|
Wind-related NMEA sentences.
|
|
|
|
MWV - Wind Speed and Angle
|
|
MWD - Wind Direction and Speed
|
|
"""
|
|
|
|
from typing import Optional
|
|
|
|
from ..sentence import NMEASentence
|
|
|
|
|
|
class MWVSentence(NMEASentence):
|
|
"""MWV - Wind Speed and Angle.
|
|
|
|
Format:
|
|
$IIMWV,A.A,R,S.S,U,A*CC
|
|
|
|
Fields:
|
|
1. Wind angle in degrees (0-360)
|
|
2. Reference (R=Relative/Apparent, T=True)
|
|
3. Wind speed
|
|
4. Wind speed units (K=km/h, M=m/s, N=knots, S=statute mph)
|
|
5. Status (A=valid, V=invalid)
|
|
|
|
Example:
|
|
$IIMWV,045.0,R,12.5,N,A*28
|
|
|
|
Note:
|
|
MWV can represent either apparent or true wind:
|
|
- Relative (R): Wind angle relative to bow, clockwise
|
|
- True (T): True wind direction relative to bow
|
|
"""
|
|
|
|
talker_id = "II"
|
|
sentence_type = "MWV"
|
|
|
|
def __init__(
|
|
self,
|
|
angle: Optional[float] = None,
|
|
reference: str = "R",
|
|
speed: Optional[float] = None,
|
|
speed_units: str = "N",
|
|
status: str = "A",
|
|
):
|
|
"""Initialize MWV sentence.
|
|
|
|
Args:
|
|
angle: Wind angle in degrees (0-360)
|
|
reference: R=Relative/Apparent, T=True
|
|
speed: Wind speed
|
|
speed_units: K=km/h, M=m/s, N=knots, S=mph
|
|
status: A=valid, V=invalid
|
|
"""
|
|
self.angle = angle
|
|
self.reference = reference
|
|
self.speed = speed
|
|
self.speed_units = speed_units
|
|
self.status = status
|
|
|
|
def format_fields(self) -> Optional[str]:
|
|
"""Format MWV fields."""
|
|
# Need at least angle or speed
|
|
if self.angle is None and self.speed is None:
|
|
return None
|
|
|
|
angle_str = f"{self.angle:.1f}" if self.angle is not None else ""
|
|
speed_str = f"{self.speed:.1f}" if self.speed is not None else ""
|
|
|
|
return (
|
|
f"{angle_str},"
|
|
f"{self.reference},"
|
|
f"{speed_str},"
|
|
f"{self.speed_units},"
|
|
f"{self.status}"
|
|
)
|
|
|
|
|
|
class MWDSentence(NMEASentence):
|
|
"""MWD - Wind Direction and Speed.
|
|
|
|
Format:
|
|
$IIMWD,D.D,T,D.D,M,S.S,N,S.S,M*CC
|
|
|
|
Fields:
|
|
1. Wind direction (true) in degrees
|
|
2. T = True
|
|
3. Wind direction (magnetic) in degrees
|
|
4. M = Magnetic
|
|
5. Wind speed in knots
|
|
6. N = Knots
|
|
7. Wind speed in m/s
|
|
8. M = Meters/second
|
|
|
|
Example:
|
|
$IIMWD,270.0,T,258.0,M,12.5,N,6.4,M*5A
|
|
|
|
Note:
|
|
MWD provides true wind direction (the direction FROM which wind blows),
|
|
expressed as a compass bearing, not relative to the vessel.
|
|
"""
|
|
|
|
talker_id = "II"
|
|
sentence_type = "MWD"
|
|
|
|
def __init__(
|
|
self,
|
|
direction_true: Optional[float] = None,
|
|
direction_mag: Optional[float] = None,
|
|
speed_kts: Optional[float] = None,
|
|
):
|
|
"""Initialize MWD sentence.
|
|
|
|
Args:
|
|
direction_true: True wind direction in degrees (from which wind blows)
|
|
direction_mag: Magnetic wind direction in degrees
|
|
speed_kts: Wind speed in knots
|
|
"""
|
|
self.direction_true = direction_true
|
|
self.direction_mag = direction_mag
|
|
self.speed_kts = speed_kts
|
|
|
|
def format_fields(self) -> Optional[str]:
|
|
"""Format MWD fields."""
|
|
# Need at least direction or speed
|
|
if self.direction_true is None and self.speed_kts is None:
|
|
return None
|
|
|
|
# Format directions
|
|
dir_t_str = f"{self.direction_true:.1f}" if self.direction_true is not None else ""
|
|
dir_m_str = f"{self.direction_mag:.1f}" if self.direction_mag is not None else ""
|
|
|
|
# Format speeds
|
|
if self.speed_kts is not None:
|
|
spd_kts_str = f"{self.speed_kts:.1f}"
|
|
spd_ms = self.speed_kts / 1.94384449
|
|
spd_ms_str = f"{spd_ms:.1f}"
|
|
else:
|
|
spd_kts_str = ""
|
|
spd_ms_str = ""
|
|
|
|
return (
|
|
f"{dir_t_str},T,"
|
|
f"{dir_m_str},M,"
|
|
f"{spd_kts_str},N,"
|
|
f"{spd_ms_str},M"
|
|
)
|