battery panel

This commit is contained in:
infiniteCable2
2025-11-16 15:14:39 +01:00
parent a61e8735ae
commit 749c106794
3 changed files with 147 additions and 1 deletions
+1 -1
View File
@@ -60,8 +60,8 @@ class SettingsLayout(Widget):
self._panels = {
PanelType.DEVICE: PanelInfo(tr_noop("Device"), DeviceLayout()),
PanelType.NETWORK: PanelInfo(tr_noop("Network"), NetworkUI(wifi_manager)),
PanelType.ICTOGGLES: PanelInfo(tr_noop("infiniteCableCustom"), ICTogglesLayout()),
PanelType.TOGGLES: PanelInfo(tr_noop("Toggles"), TogglesLayout()),
PanelType.ICTOGGLES: PanelInfo(tr_noop("infiniteCable"), ICTogglesLayout()),
PanelType.SOFTWARE: PanelInfo(tr_noop("Software"), SoftwareLayout()),
PanelType.FIREHOSE: PanelInfo(tr_noop("Firehose"), FirehoseLayout()),
PanelType.DEVELOPER: PanelInfo(tr_noop("Developer"), DeveloperLayout()),
+141
View File
@@ -0,0 +1,141 @@
import pyray as rl
from dataclasses import dataclass
from openpilot.common.params import Params
from openpilot.selfdrive.ui.ui_state import ui_state
from openpilot.system.ui.lib.application import gui_app, FontWeight
from openpilot.system.ui.widgets import Widget
@dataclass(frozen=True)
class BatteryPanelConfig:
scale_factor: float = 1.1
panel_width_ratio: float = 0.7 # 70 % der Breite von rechts
panel_margin: int = 30 # Abstand zum Rand
line_height: int = 48 # Basis-Zeilenhöhe
label_width: int = 265
text_margin: int = 25 # Abstand Label → Wert
CONFIG = BatteryPanelConfig()
class BatteryDetails(Widget):
def __init__(self, button_size: int, icon_size: int):
super().__init__()
self._params = Params()
self._capacity: float = 0.0
self._charge: float = 0.0
self._soc: float = 0.0
self._temperature: float = 0.0
self._heaterActive: bool = False
self._voltage: float = 0.0
self._current: float = 0.0
self._power: float = 0.0
self._font: rl.Font = gui_app.font(FontWeight.MEDIUM)
self._panel_bg: rl.Color = rl.Color(0, 0, 0, 128)
self._text_color: rl.Color = rl.Color(255, 255, 255, 255)
self._display_enabled: bool = False
def _update_state(self) -> None:
self._display_enabled = self._params.get_bool("BatteryDetails")
if not self._display_enabled:
return
sm = ui_state.sm
if sm.recv_frame["carState"] < ui_state.started_frame:
self._reset_values()
return
car_state = sm["carState"]
battery_data = car_state.batteryDetails
self._capacity = float(battery_data.capacity)
self._charge = float(battery_data.charge)
self._soc = float(battery_data.soc)
self._temperature = float(battery_data.temperature)
self._heater_active = bool(battery_data.heaterActive)
self._voltage = float(battery_data.voltage)
self._current = float(battery_data.current)
self._power = float(battery_data.power)
def _reset_values(self) -> None:
self._capacity = 0.0
self._charge = 0.0
self._soc = 0.0
self._temperature = 0.0
self._heater_active = False
self._voltage = 0.0
self._current = 0.0
self._power = 0.0
def _render(self, rect: rl.Rectangle) -> None:
if not self._display_enabled:
return
scale = CONFIG.scale_factor
base_line_h = CONFIG.line_height
line_h = int(base_line_h * scale)
panel_width = int(rect.width * CONFIG.panel_width_ratio)
panel_height = line_h * 4
panel_margin = CONFIG.panel_margin
x_start = int(rect.x + rect.width - panel_width - panel_margin)
y_start = int(rect.y + rect.height - panel_margin - panel_height)
panel_rect = rl.Rectangle(x_start, y_start, panel_width, panel_height)
rl.draw_rectangle_rounded(panel_rect, 0.1, 8, self._panel_bg)
label_width = CONFIG.label_width
text_margin = CONFIG.text_margin
column_spacing = panel_width // 2 - 20
value_width = column_spacing - label_width - text_margin
labels = [
"Capacity:", "Charge:", "SoC:", "Temperature:",
"Heater Active:", "Voltage:", "Current:", "Power:",
]
values = [
f"{self._capacity:.2f} Wh",
f"{self._charge:.2f} Wh",
f"{self._soc:.2f} %",
f"{self._temperature:.2f} °C",
"True" if self._heater_active else "False",
f"{self._voltage:.2f} V",
f"{self._current:.2f} A",
f"{self._power:.2f} kW",
]
rl.draw_text_ex
for i, (label, value) in enumerate(zip(labels, values)):
column = i // 4
row = i % 4
base_x = x_start + column * column_spacing
base_y = y_start + row * line_h
label_pos = rl.Vector2(float(base_x), float(base_y))
rl.draw_text_ex(
self._font,
label,
label_pos,
40 * scale,
0,
self._text_color,
)
value_x = base_x + label_width + text_margin
value_pos = rl.Vector2(float(value_x), float(base_y))
rl.draw_text_ex(
self._font,
value,
value_pos,
40 * scale,
0,
self._text_color,
)
+5
View File
@@ -2,6 +2,7 @@ import pyray as rl
from dataclasses import dataclass
from openpilot.common.constants import CV
from openpilot.selfdrive.ui.onroad.exp_button import ExpButton
from openpilot.selfdrive.ui.onroad.battery_details import BatteryDetails
from openpilot.selfdrive.ui.ui_state import ui_state, UIStatus
from openpilot.system.ui.lib.application import gui_app, FontWeight
from openpilot.system.ui.lib.multilang import tr
@@ -71,6 +72,7 @@ class HudRenderer(Widget):
self._font_medium: rl.Font = gui_app.font(FontWeight.MEDIUM)
self._exp_button: ExpButton = ExpButton(UI_CONFIG.button_size, UI_CONFIG.wheel_icon_size)
self._battery_details = BatteryDetails()
def _update_state(self) -> None:
"""Update HUD state based on car state and controls state."""
@@ -99,6 +101,8 @@ class HudRenderer(Widget):
v_ego = v_ego_cluster if self.v_ego_cluster_seen else car_state.vEgo
speed_conversion = CV.MS_TO_KPH if ui_state.is_metric else CV.MS_TO_MPH
self.speed = max(0.0, v_ego * speed_conversion)
self._battery_details.update()
def _render(self, rect: rl.Rectangle) -> None:
"""Render HUD elements to the screen."""
@@ -119,6 +123,7 @@ class HudRenderer(Widget):
button_x = rect.x + rect.width - UI_CONFIG.border_size - UI_CONFIG.button_size
button_y = rect.y + UI_CONFIG.border_size
self._battery_details.render(rect)
self._exp_button.render(rl.Rectangle(button_x, button_y, UI_CONFIG.button_size, UI_CONFIG.button_size))
def user_interacting(self) -> bool: