Added a basic vehicle status UI showing mode and a few key datapoints.

This commit is contained in:
RedNicStone committed 2026-11-08 21:45:48 +01:00
1 parent f05a6148fb
commit ea6ba54666
15 files changed
+623

No files matched your search

Binary file not shown.
+43
View File
@@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c3kgbws2ejds6"
path="res://.godot/imported/rov.svg-85cd68e18cc64f6002858c870af4fd81.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/vector/status/rov.svg"
dest_files=["res://.godot/imported/rov.svg-85cd68e18cc64f6002858c870af4fd81.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false
Binary file not shown.
@@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bc2m1gknloa5i"
path="res://.godot/imported/stationkeep.svg-ba46234e5cd35725d5ce1d66d82e2fa0.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/vector/status/stationkeep.svg"
dest_files=["res://.godot/imported/stationkeep.svg-ba46234e5cd35725d5ce1d66d82e2fa0.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false
+274
View File
@@ -0,0 +1,274 @@
[gd_scene format=3 uid="uid://c6xqxnk0pqhg1"]
[ext_resource type="Script" uid="uid://d3jrypgr15n4x" path="res://scripts/vehicle_status_panel.gd" id="1"]
[ext_resource type="Script" uid="uid://rh8gwu8mfqx2" path="res://scripts/vehicle_status_art.gd" id="2"]
[ext_resource type="Script" uid="uid://bqvhrignal143" path="res://scripts/status_gauge.gd" id="3"]
[ext_resource type="Texture2D" uid="uid://bc2m1gknloa5i" path="res://assets/vector/status/stationkeep.svg" id="4"]
[node name="VehicleStatusPanel" type="PanelContainer" unique_id=489606862]
custom_minimum_size = Vector2(600, 440)
offset_right = 600.0
offset_bottom = 440.0
theme_type_variation = &"VehicleBackground"
script = ExtResource("1")
mode_icon = ExtResource("4")
[node name="Margin" type="MarginContainer" parent="." unique_id=1101194281]
layout_mode = 2
theme_override_constants/margin_left = 16
theme_override_constants/margin_top = 12
theme_override_constants/margin_right = 16
theme_override_constants/margin_bottom = 12
[node name="Layout" type="VBoxContainer" parent="Margin" unique_id=221437014]
layout_mode = 2
theme_override_constants/separation = 12
[node name="StatusArea" type="MarginContainer" parent="Margin/Layout" unique_id=1107401965]
custom_minimum_size = Vector2(0, 164)
clip_contents = true
layout_mode = 2
size_flags_vertical = 3
[node name="StatusArt" type="Control" parent="Margin/Layout/StatusArea" unique_id=649910411]
unique_name_in_owner = true
layout_mode = 2
mouse_filter = 2
script = ExtResource("2")
[node name="ModeIcon" type="TextureRect" parent="Margin/Layout/StatusArea/StatusArt" unique_id=728690011]
unique_name_in_owner = true
visible = false
self_modulate = Color(1, 0.61176467, 0.25, 0.09)
layout_mode = 1
anchors_preset = -1
anchor_left = 0.68
anchor_top = 0.5
anchor_right = 0.68
anchor_bottom = 0.5
offset_left = -105.0
offset_top = -105.0
offset_right = 105.0
offset_bottom = 105.0
rotation = -0.20943952
pivot_offset = Vector2(105, 105)
mouse_filter = 2
texture = ExtResource("4")
expand_mode = 1
stretch_mode = 5
[node name="Inset" type="MarginContainer" parent="Margin/Layout/StatusArea" unique_id=2050290664]
layout_mode = 2
theme_override_constants/margin_left = 12
theme_override_constants/margin_top = 8
theme_override_constants/margin_right = 12
theme_override_constants/margin_bottom = 8
[node name="Text" type="VBoxContainer" parent="Margin/Layout/StatusArea/Inset" unique_id=905192152]
layout_mode = 2
theme_override_constants/separation = 4
[node name="Top" type="HBoxContainer" parent="Margin/Layout/StatusArea/Inset/Text" unique_id=424687654]
layout_mode = 2
[node name="Code" type="Label" parent="Margin/Layout/StatusArea/Inset/Text/Top" unique_id=1099636858]
unique_name_in_owner = true
visible = false
layout_mode = 2
size_flags_horizontal = 3
theme_type_variation = &"Label"
theme_override_font_sizes/font_size = 18
[node name="Severity" type="Label" parent="Margin/Layout/StatusArea/Inset/Text/Top" unique_id=1356897068]
unique_name_in_owner = true
layout_mode = 2
theme_type_variation = &"Label"
theme_override_font_sizes/font_size = 18
text = "NO DATA"
horizontal_alignment = 2
[node name="StatusName" type="Label" parent="Margin/Layout/StatusArea/Inset/Text" unique_id=1189663888]
unique_name_in_owner = true
layout_mode = 2
theme_type_variation = &"Label"
theme_override_font_sizes/font_size = 30
text = "Waiting for telemetry"
autowrap_mode = 3
[node name="Detail" type="Label" parent="Margin/Layout/StatusArea/Inset/Text" unique_id=703466821]
unique_name_in_owner = true
layout_mode = 2
theme_type_variation = &"Label"
theme_override_font_sizes/font_size = 18
autowrap_mode = 3
[node name="Action" type="Label" parent="Margin/Layout/StatusArea/Inset/Text" unique_id=514634651]
unique_name_in_owner = true
layout_mode = 2
theme_type_variation = &"Label"
theme_override_font_sizes/font_size = 18
autowrap_mode = 3
[node name="Readouts" type="VBoxContainer" parent="Margin/Layout" unique_id=1999758637]
layout_mode = 2
theme_override_constants/separation = 8
[node name="Voltage" type="VBoxContainer" parent="Margin/Layout/Readouts" unique_id=1002742281]
layout_mode = 2
theme_override_constants/separation = 2
[node name="Numbers" type="HBoxContainer" parent="Margin/Layout/Readouts/Voltage" unique_id=1312021033]
layout_mode = 2
theme_override_constants/separation = 12
[node name="Title" type="Label" parent="Margin/Layout/Readouts/Voltage/Numbers" unique_id=264983620]
custom_minimum_size = Vector2(124, 0)
layout_mode = 2
theme_override_font_sizes/font_size = 18
text = "VOLTAGE"
[node name="VoltageValue" type="Label" parent="Margin/Layout/Readouts/Voltage/Numbers" unique_id=1230347145]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 26
text = "—"
horizontal_alignment = 2
[node name="VoltageReference" type="Label" parent="Margin/Layout/Readouts/Voltage/Numbers" unique_id=264381298]
unique_name_in_owner = true
custom_minimum_size = Vector2(100, 0)
layout_mode = 2
theme_override_font_sizes/font_size = 18
text = "/ 48 V"
vertical_alignment = 1
[node name="VoltageGauge" type="Control" parent="Margin/Layout/Readouts/Voltage" unique_id=446082505]
unique_name_in_owner = true
custom_minimum_size = Vector2(0, 16)
layout_mode = 2
script = ExtResource("3")
minimum = 42.0
maximum = 54.0
warning_low = 47.0
warning_high = 49.0
fault_low = 45.0
fault_high = 51.0
nominal = 48.0
[node name="Current" type="VBoxContainer" parent="Margin/Layout/Readouts" unique_id=1982270337]
layout_mode = 2
theme_override_constants/separation = 2
[node name="Numbers" type="HBoxContainer" parent="Margin/Layout/Readouts/Current" unique_id=619271939]
layout_mode = 2
theme_override_constants/separation = 12
[node name="Title" type="Label" parent="Margin/Layout/Readouts/Current/Numbers" unique_id=137700803]
custom_minimum_size = Vector2(124, 0)
layout_mode = 2
theme_override_font_sizes/font_size = 18
text = "CURRENT"
[node name="CurrentValue" type="Label" parent="Margin/Layout/Readouts/Current/Numbers" unique_id=2147417420]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 26
text = "—"
horizontal_alignment = 2
[node name="CurrentReference" type="Label" parent="Margin/Layout/Readouts/Current/Numbers" unique_id=1995980746]
unique_name_in_owner = true
custom_minimum_size = Vector2(100, 0)
layout_mode = 2
theme_override_font_sizes/font_size = 18
text = "/ 30 A"
vertical_alignment = 1
[node name="CurrentGauge" type="Control" parent="Margin/Layout/Readouts/Current" unique_id=484645650]
unique_name_in_owner = true
custom_minimum_size = Vector2(0, 16)
layout_mode = 2
script = ExtResource("3")
nominal = nan
[node name="Power" type="VBoxContainer" parent="Margin/Layout/Readouts" unique_id=1074490654]
layout_mode = 2
theme_override_constants/separation = 2
[node name="Numbers" type="HBoxContainer" parent="Margin/Layout/Readouts/Power" unique_id=111236353]
layout_mode = 2
theme_override_constants/separation = 12
[node name="Title" type="Label" parent="Margin/Layout/Readouts/Power/Numbers" unique_id=213594380]
custom_minimum_size = Vector2(124, 0)
layout_mode = 2
theme_override_font_sizes/font_size = 18
text = "POWER"
[node name="PowerValue" type="Label" parent="Margin/Layout/Readouts/Power/Numbers" unique_id=1921756191]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 26
text = "—"
horizontal_alignment = 2
[node name="PowerReference" type="Label" parent="Margin/Layout/Readouts/Power/Numbers" unique_id=1441937096]
unique_name_in_owner = true
custom_minimum_size = Vector2(100, 0)
layout_mode = 2
theme_override_font_sizes/font_size = 18
text = "/ 1440 W"
vertical_alignment = 1
[node name="PowerGauge" type="Control" parent="Margin/Layout/Readouts/Power" unique_id=82393019]
unique_name_in_owner = true
custom_minimum_size = Vector2(0, 16)
layout_mode = 2
script = ExtResource("3")
maximum = 1728.0
warning_high = 1152.0
fault_high = 1440.0
nominal = nan
[node name="Temperature" type="VBoxContainer" parent="Margin/Layout/Readouts" unique_id=658026844]
layout_mode = 2
theme_override_constants/separation = 2
[node name="Numbers" type="HBoxContainer" parent="Margin/Layout/Readouts/Temperature" unique_id=567006533]
layout_mode = 2
theme_override_constants/separation = 12
[node name="Title" type="Label" parent="Margin/Layout/Readouts/Temperature/Numbers" unique_id=1987975109]
custom_minimum_size = Vector2(124, 0)
layout_mode = 2
theme_override_font_sizes/font_size = 18
text = "INTERNAL"
[node name="TemperatureValue" type="Label" parent="Margin/Layout/Readouts/Temperature/Numbers" unique_id=1041616611]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 26
text = "—"
horizontal_alignment = 2
[node name="TemperatureReference" type="Label" parent="Margin/Layout/Readouts/Temperature/Numbers" unique_id=1032238631]
unique_name_in_owner = true
custom_minimum_size = Vector2(100, 0)
layout_mode = 2
theme_override_font_sizes/font_size = 18
text = "/ 65 °C"
vertical_alignment = 1
[node name="TemperatureGauge" type="Control" parent="Margin/Layout/Readouts/Temperature" unique_id=214013672]
unique_name_in_owner = true
custom_minimum_size = Vector2(0, 16)
layout_mode = 2
script = ExtResource("3")
maximum = 90.0
warning_high = 55.0
fault_high = 65.0
nominal = nan
+30
View File
@@ -0,0 +1,30 @@
# Vehicle status prototype
Run `scenes/vehicle_status_demo.tscn` with F6. The controls switch between normal, warning, fault, and a stopped feed, plus high contrast and alert pulsing.
Instance `components/vehicle_status_panel.tscn` for integration:
```gdscript
$VehicleStatusPanel.set_status("STATIONKEEP", 0, "", "Position hold active", "Thrusters enabled")
$VehicleStatusPanel.set_telemetry(48.0, 18.2, 874.0, 34.0)
# severity: 0 normal, 1 warning, 2 fault
$VehicleStatusPanel.set_status("Enclosure overtemperature", 2, "TMP-003",
"68 °C · trip 65 °C · thrusters inhibited", "Inspect cooling before reset")
```
All sample fault codes, responses, and thresholds are illustrative. The UI displays reported vehicle status; gauge zones do not control the ROV or generate its faults.
Configure each gauge in the scene Inspector. The numeric references use the voltage nominal or the other gauges' upper fault thresholds. Voltage marks 48 V at center; any deviation enters a yellow region.
| Gauge | Display range | Warning zone | Fault zone |
| --- | --- | --- | --- |
| Voltage | 42–54 V | Either side of 48 V | Below 45 / above 51 V |
| Current | 0–36 A | 24–30 A | Above 30 A |
| Power | 0–1728 W | 1152–1440 W | Above 1440 W |
| Internal temperature | 0–90 °C | 55–65 °C | Above 65 °C |
Only 48 V nominal and 30 A were supplied. The other thresholds need confirmation; 1440 W is the provisional 48 × 30 reference. Markers clamp to the track, but numeric readings remain unclamped.
Labels and containers own layout. `status_gauge.gd` draws tracks and markers; `vehicle_status_art.gd` draws the watermark and status background. Warning/fault backgrounds alternate shades once per second; `pulse_alerts` disables that behavior. After two seconds without telemetry, the status is marked STALE and readings are held. Colors come from the shared palette and generated themes.
`mode_icon` selects the SVG watermark (stationkeep and ROV samples are in `assets/vector/status/`). Edit `ModeIcon` anchors, rotation, and size in the scene. Readings are right-aligned beside a fixed-width, left-aligned limits column. Off-phase warning/fault shades are derived in the shared palette.
+44
View File
@@ -0,0 +1,44 @@
[gd_scene format=3]
[ext_resource type="PackedScene" path="res://components/vehicle_status_panel.tscn" id="1"]
[ext_resource type="Script" path="res://scripts/vehicle_status_demo.gd" id="2"]
[node name="VehicleStatusDemo" type="VBoxContainer"]
offset_left = 24.0
offset_top = 24.0
offset_right = 624.0
offset_bottom = 560.0
theme_override_constants/separation = 12
script = ExtResource("2")
[node name="Notice" type="Label" parent="."]
layout_mode = 2
text = "SIMULATED / gauge thresholds are provisional"
[node name="VehicleStatusPanel" parent="." instance=ExtResource("1")]
layout_mode = 2
[node name="Controls" type="HBoxContainer" parent="."]
layout_mode = 2
[node name="State" type="OptionButton" parent="Controls"]
layout_mode = 2
item_count = 4
selected = 0
popup/item_0/text = "Normal"
popup/item_0/id = 0
popup/item_1/text = "Warning"
popup/item_1/id = 1
popup/item_2/text = "Fault"
popup/item_2/id = 2
popup/item_3/text = "Stop feed / stale"
popup/item_3/id = 3
[node name="Contrast" type="CheckButton" parent="Controls"]
layout_mode = 2
text = "High contrast"
[node name="Pulse" type="CheckButton" parent="Controls"]
layout_mode = 2
text = "Pulse"
button_pressed = true
+40
View File
@@ -0,0 +1,40 @@
@tool
extends Control
@export var minimum := 0.0
@export var maximum := 36.0
@export var warning_low := 0.0
@export var warning_high := 24.0
@export var fault_low := 0.0
@export var fault_high := 30.0
@export var nominal := NAN
var value := 0.0
var available := false
func _ready() -> void:
resized.connect(queue_redraw)
theme_changed.connect(queue_redraw)
func _x(number: float) -> float:
return 4 + clampf((number - minimum) / maxf(maximum - minimum, 0.001), 0, 1) * (size.x - 8)
func _zone(low: float, high: float, role: String) -> void:
if high <= low:
return
var color := get_theme_color(role, "SurfaceSide")
color.a = 0.65
draw_rect(Rect2(_x(low), 4, _x(high) - _x(low), 6), color)
func _draw() -> void:
draw_rect(Rect2(4, 4, maxf(size.x - 8, 0), 6), get_theme_color("instrument_grid", "SurfaceSide"))
_zone(minimum, fault_low, "fault")
_zone(fault_low, warning_low, "warning")
_zone(warning_high, fault_high, "warning")
_zone(fault_high, maximum, "fault")
if is_finite(nominal):
draw_line(Vector2(_x(nominal), 0), Vector2(_x(nominal), 16), get_theme_color("instrument_accent", "SurfaceSide"), 2)
if available:
var x := _x(value)
var ink := get_theme_color("font_color", "Label")
draw_line(Vector2(x, 0), Vector2(x, 14), ink, 3)
draw_colored_polygon(PackedVector2Array([Vector2(x - 5, 0), Vector2(x + 5, 0), Vector2(x, 4)]), ink)
+1
View File
@@ -0,0 +1 @@
uid://bqvhrignal143
+29
View File
@@ -0,0 +1,29 @@
@tool
extends Control
@export_enum("Normal", "Warning", "Fault", "No data") var severity := 3
@export var pulse_alerts := true
var _phase := -1
func _ready() -> void:
resized.connect(queue_redraw)
theme_changed.connect(_update_icon)
_update_icon()
func _process(_delta: float) -> void:
var phase := int(Time.get_ticks_msec() / 1000.0) % 2 if pulse_alerts else 0
if phase != _phase:
_phase = phase
queue_redraw()
func _draw() -> void:
if severity in [1, 2]:
var role := "warning" if severity == 1 else "fault"
if _phase == 1:
role += "_alternate"
draw_rect(Rect2(Vector2.ZERO, size), get_theme_color(role, "SurfaceSide"))
func _update_icon() -> void:
var tint := get_theme_color("status_icon", "SurfaceSide")
tint.a = 0.09
$ModeIcon.self_modulate = tint
queue_redraw()
+1
View File
@@ -0,0 +1 @@
uid://rh8gwu8mfqx2
+27
View File
@@ -0,0 +1,27 @@
extends VBoxContainer
@onready var panel = $VehicleStatusPanel
var elapsed := 0.0
func _ready() -> void:
$Controls/State.item_selected.connect(_select_state)
$Controls/Contrast.toggled.connect(func(high: bool) -> void:
theme = load("res://themes/theme_highcontrast.tres" if high else "res://themes/theme.tres")
)
$Controls/Pulse.toggled.connect(func(enabled: bool) -> void: panel.pulse_alerts = enabled)
_select_state(0)
func _select_state(index: int) -> void:
match index:
0: panel.set_status("STATIONKEEP", 0, "", "Position hold active", "Thrusters enabled")
1: panel.set_status("Supply voltage low", 1, "PWR-012", "46.5 V · below 48 V nominal", "Check topside supply and tether load")
2: panel.set_status("Enclosure overtemperature", 2, "TMP-003", "68 °C · trip 65 °C · thrusters inhibited", "Inspect cooling before reset")
3: panel.set_status("Enclosure overtemperature", 2, "TMP-003", "68 °C · trip 65 °C · thrusters inhibited", "Inspect cooling before reset")
func _process(delta: float) -> void:
elapsed += delta
match $Controls/State.selected:
0: panel.set_telemetry(48.0, 18.2 + sin(elapsed) * 0.6, 874 + sin(elapsed) * 29, 34)
1: panel.set_telemetry(46.5, 25.5, 1186, 42)
2: panel.set_telemetry(48.0, 2.1, 101, 68)
3: pass
+1
View File
@@ -0,0 +1 @@
uid://qipln371l5is
+83
View File
@@ -0,0 +1,83 @@
@tool
extends PanelContainer
@export var mode_icon: Texture2D:
set(value):
mode_icon = value
if is_node_ready():
%ModeIcon.texture = value
@export var stale_after_seconds := 2.0
@export var pulse_alerts := true:
set(value):
pulse_alerts = value
if is_node_ready():
%StatusArt.pulse_alerts = value
var _received_ms := -1
var _severity := 0
var _name := ""
var _code := ""
var _detail := ""
var _action := ""
var _stale := false
func _ready() -> void:
%ModeIcon.texture = mode_icon
_refresh_status()
_refresh_references()
## Severity and fault explanations come from vehicle telemetry, not gauge zones.
func set_status(name_text: String, severity: int = 0, code: String = "", detail: String = "", action: String = "") -> void:
_name = name_text
_severity = clampi(severity, 0, 2)
_code = code
_detail = detail
_action = action
_refresh_status()
func set_telemetry(voltage: float, current: float, power: float, internal_temperature: float) -> void:
for number in [voltage, current, power, internal_temperature]:
if not is_finite(number):
return
_refresh_references()
_received_ms = Time.get_ticks_msec()
var values := [voltage, current, power, internal_temperature]
var labels := [%VoltageValue, %CurrentValue, %PowerValue, %TemperatureValue]
var gauges := [%VoltageGauge, %CurrentGauge, %PowerGauge, %TemperatureGauge]
for index in range(4):
labels[index].text = (["%.1f V", "%.1f A", "%.0f W", "%.1f °C"][index]) % values[index]
gauges[index].value = values[index]
gauges[index].available = true
gauges[index].queue_redraw()
_refresh_status()
func _process(_delta: float) -> void:
var stale := _received_ms >= 0 and Time.get_ticks_msec() - _received_ms > stale_after_seconds * 1000
if stale != _stale:
_refresh_status()
func _refresh_status() -> void:
if not is_node_ready():
return
_stale = _received_ms >= 0 and Time.get_ticks_msec() - _received_ms > stale_after_seconds * 1000
var missing := _received_ms < 0
var unavailable := missing or _stale
%StatusArt.severity = 3 if unavailable else _severity
%StatusArt.pulse_alerts = pulse_alerts
%StatusArt.queue_redraw()
%ModeIcon.visible = not unavailable and _severity == 0
%Severity.text = "NO DATA" if missing else ("STALE" if _stale else ["", "WARNING", "FAULT"][_severity])
%StatusName.text = "Waiting for telemetry" if missing else (_name if not _name.is_empty() else "Mode unavailable")
%Code.text = _code
%Code.visible = not _code.is_empty() and not missing
%Detail.text = "" if missing else _detail
%Action.text = "Values held · connection overdue" if _stale else ("" if missing else _action)
var variant := ("VehicleWarningText" if _severity == 1 else "VehicleFaultText") if _severity in [1, 2] and not unavailable else "Label"
for label in [%Severity, %StatusName, %Code, %Detail, %Action]:
label.theme_type_variation = variant
func _refresh_references() -> void:
%VoltageReference.text = "/ %.0f V" % %VoltageGauge.nominal
%CurrentReference.text = "/ %.0f A" % %CurrentGauge.fault_high
%PowerReference.text = "/ %.0f W" % %PowerGauge.fault_high
%TemperatureReference.text = "/ %.0f °C" % %TemperatureGauge.fault_high
+1
View File
@@ -0,0 +1 @@
uid://d3jrypgr15n4x