From 971a2075829b370d234fe32a4954f777ae18b441 Mon Sep 17 00:00:00 2001 From: Mark Qvist Date: Sat, 1 Jun 2024 12:08:09 +0200 Subject: [PATCH] Added tank and fuel sensor types. Added basic renderer for proximity, gravity, magnetics and angular velocity. --- sbapp/sideband/sense.py | 237 +++++++++++++++++++++++++++++++++++++- sbapp/ui/objectdetails.py | 52 ++++++++- 2 files changed, 284 insertions(+), 5 deletions(-) diff --git a/sbapp/sideband/sense.py b/sbapp/sideband/sense.py index ba76347..edbb17c 100644 --- a/sbapp/sideband/sense.py +++ b/sbapp/sideband/sense.py @@ -53,7 +53,7 @@ class Telemeter(): Sensor.SID_PROXIMITY: Proximity, Sensor.SID_POWER_CONSUMPTION: PowerConsumption, Sensor.SID_POWER_PRODUCTION: PowerProduction, Sensor.SID_PROCESSOR: Processor, Sensor.SID_RAM: RandomAccessMemory, Sensor.SID_NVM: NonVolatileMemory, - Sensor.SID_CUSTOM: Custom, + Sensor.SID_CUSTOM: Custom, Sensor.SID_TANK: Tank, Sensor.SID_FUEL: Fuel, } self.available = { "time": Sensor.SID_TIME, @@ -66,7 +66,7 @@ class Telemeter(): "acceleration": Sensor.SID_ACCELERATION, "proximity": Sensor.SID_PROXIMITY, "power_consumption": Sensor.SID_POWER_CONSUMPTION, "power_production": Sensor.SID_POWER_PRODUCTION, "processor": Sensor.SID_PROCESSOR, "ram": Sensor.SID_RAM, "nvm": Sensor.SID_NVM, - "custom": Sensor.SID_CUSTOM + "custom": Sensor.SID_CUSTOM, "tank": Sensor.SID_TANK, "fuel": Sensor.SID_FUEL } self.from_packed = from_packed self.sensors = {} @@ -193,6 +193,8 @@ class Sensor(): SID_PROCESSOR = 0x13 SID_RAM = 0x14 SID_NVM = 0x15 + SID_TANK = 0x16 + SID_FUEL = 0x17 SID_CUSTOM = 0xff def __init__(self, sid = None, stale_time = None): @@ -1080,6 +1082,17 @@ class MagneticField(Sensor): except: return None + def render(self, relative_to=None): + if self.data == None: + return None + + rendered = { + "icon": "magnet", + "name": "Magnetic Field", + "values": { "x": self.data["x"], "y": self.data["y"], "z": self.data["z"] }, + } + return rendered + class AmbientLight(Sensor): SID = Sensor.SID_AMBIENT_LIGHT STALE_TIME = 1 @@ -1192,6 +1205,17 @@ class Gravity(Sensor): except: return None + def render(self, relative_to=None): + if self.data == None: + return None + + rendered = { + "icon": "arrow-down-thin-circle-outline", + "name": "Gravity", + "values": { "x": self.data["x"], "y": self.data["y"], "z": self.data["z"] }, + } + return rendered + class AngularVelocity(Sensor): SID = Sensor.SID_ANGULAR_VELOCITY STALE_TIME = 1 @@ -1238,6 +1262,17 @@ class AngularVelocity(Sensor): except: return None + def render(self, relative_to=None): + if self.data == None: + return None + + rendered = { + "icon": "orbit", + "name": "Angular Velocity", + "values": { "x": self.data["x"], "y": self.data["y"], "z": self.data["z"] }, + } + return rendered + class Acceleration(Sensor): SID = Sensor.SID_ACCELERATION STALE_TIME = 1 @@ -1329,6 +1364,17 @@ class Proximity(Sensor): except: return None + def render(self, relative_to=None): + if self.data == None: + return None + + rendered = { + "icon": "signal-distance-variant", + "name": "Proximity", + "values": { "triggered": self.data }, + } + return rendered + class PowerConsumption(Sensor): SID = Sensor.SID_POWER_CONSUMPTION STALE_TIME = 5 @@ -1835,3 +1881,190 @@ class Custom(Sensor): } return rendered + + +class Tank(Sensor): + SID = Sensor.SID_TANK + STALE_TIME = 5 + + def __init__(self): + super().__init__(type(self).SID, type(self).STALE_TIME) + + def setup_sensor(self): + self.update_data() + + def teardown_sensor(self): + self.data = None + + def update_entry(self, capacity=0, level=0, unit=None, type_label=None, custom_icon=None): + if type_label == None: + type_label = 0x00 + elif type(type_label) != str: + return False + + if unit != None and type(unit) != str: + return False + + if self.data == None: + self.data = {} + + self.data[type_label] = [capacity, level, unit, custom_icon] + return True + + def remove_entry(self, type_label=None): + if type_label == None: + type_label = 0x00 + + if type_label in self.data: + self.data.pop(type_label) + return True + + return False + + def update_data(self): + pass + + def pack(self): + d = self.data + if d == None: + return None + else: + packed = [] + for type_label in self.data: + packed.append([type_label, self.data[type_label]]) + return packed + + def unpack(self, packed): + try: + if packed == None: + return None + else: + unpacked = {} + for entry in packed: + unpacked[entry[0]] = entry[1] + return unpacked + + except: + return None + + def render(self, relative_to=None): + if self.data == None: + return None + + entries = [] + for type_label in self.data: + if type_label == 0x00: + label = "Tank" + else: + label = type_label + set_unit = self.data[type_label][2] if self.data[type_label][2] != None else "L" + entries.append({ + "label": label, + "unit": set_unit, + "capacity": self.data[type_label][0], + "level": self.data[type_label][1], + "free": self.data[type_label][0]-self.data[type_label][1], + "percent": (self.data[type_label][1]/self.data[type_label][0])*100, + "custom_icon": self.data[type_label][3], + }) + + rendered = { + "icon": "storage-tank", + "name": "Tank", + "values": entries, + } + + return rendered + +class Fuel(Sensor): + SID = Sensor.SID_FUEL + STALE_TIME = 5 + + def __init__(self): + super().__init__(type(self).SID, type(self).STALE_TIME) + + def setup_sensor(self): + self.update_data() + + def teardown_sensor(self): + self.data = None + + def update_entry(self, capacity=0, level=0, unit=None, type_label=None, custom_icon=None): + if type_label == None: + type_label = 0x00 + elif type(type_label) != str: + return False + + if unit != None and type(unit) != str: + return False + + if self.data == None: + self.data = {} + + self.data[type_label] = [capacity, level, unit, custom_icon] + return True + + def remove_entry(self, type_label=None): + if type_label == None: + type_label = 0x00 + + if type_label in self.data: + self.data.pop(type_label) + return True + + return False + + def update_data(self): + pass + + def pack(self): + d = self.data + if d == None: + return None + else: + packed = [] + for type_label in self.data: + packed.append([type_label, self.data[type_label]]) + return packed + + def unpack(self, packed): + try: + if packed == None: + return None + else: + unpacked = {} + for entry in packed: + unpacked[entry[0]] = entry[1] + return unpacked + + except: + return None + + def render(self, relative_to=None): + if self.data == None: + return None + + entries = [] + for type_label in self.data: + if type_label == 0x00: + label = "Fuel" + else: + label = type_label + set_unit = self.data[type_label][2] if self.data[type_label][2] != None else "L" + entries.append({ + "label": label, + "unit": set_unit, + "capacity": self.data[type_label][0], + "level": self.data[type_label][1], + "free": self.data[type_label][0]-self.data[type_label][1], + "percent": (self.data[type_label][1]/self.data[type_label][0])*100, + "custom_icon": self.data[type_label][3], + }) + + rendered = { + "icon": "fuel", + "name": "Fuel", + "values": entries, + } + + return rendered \ No newline at end of file diff --git a/sbapp/ui/objectdetails.py b/sbapp/ui/objectdetails.py index 0168101..f84e901 100644 --- a/sbapp/ui/objectdetails.py +++ b/sbapp/ui/objectdetails.py @@ -312,13 +312,22 @@ class RVDetails(MDRecycleView): "Ambient Temperature": 40, "Relative Humidity": 50, "Ambient Pressure": 60, + "Magnetic Field": 61, + "Gravity": 62, + "Angular Velocity": 63, + "Acceleration": 64, + "Proximity": 65, "Battery": 70, "Processor": 72, "Random Access Memory": 74, "Non-Volatile Memory": 76, - "Timestamp": 80, - "Custom": 85, - "Received": 90, + "Power Consumption": 80, + "Power Production": 81, + "Tank": 90, + "Fuel": 91, + "Custom": 100, + "Timestamp": 190, + "Received": 200, } def pass_job(sender=None): @@ -326,6 +335,8 @@ class RVDetails(MDRecycleView): self.entries = [] rendered_telemetry.sort(key=lambda s: sort[s["name"]] if s["name"] in sort else 1000) + RNS.log("Sorted:") + RNS.log(str(rendered_telemetry)) for s in rendered_telemetry: try: extra_entries = [] @@ -532,6 +543,38 @@ class RVDetails(MDRecycleView): e_text = f"{label} [b]{value}[/b]" extra_entries.append({"icon": set_icon, "text": e_text}) + elif name == "Tank": + cs = s["values"] + if cs != None: + for c in cs: + label = c["label"] + cicon = c["custom_icon"] + unit = c["unit"] + cap = round(c["capacity"], 1) + lvl = round(c["level"], 1) + free = round(c["free"], 1) + pct = round(c["percent"], 1) + + set_icon = cicon if cicon else s["icon"] + e_text = f"{label} level is [b]{lvl} {unit}[/b] ([b]{pct}%[/b])" + extra_entries.append({"icon": set_icon, "text": e_text}) + + elif name == "Fuel": + cs = s["values"] + if cs != None: + for c in cs: + label = c["label"] + cicon = c["custom_icon"] + unit = c["unit"] + cap = round(c["capacity"], 1) + lvl = round(c["level"], 1) + free = round(c["free"], 1) + pct = round(c["percent"], 1) + + set_icon = cicon if cicon else s["icon"] + e_text = f"{label} level is [b]{lvl} {unit}[/b] ([b]{pct}%[/b])" + extra_entries.append({"icon": set_icon, "text": e_text}) + elif name == "Processor": cs = s["values"] if cs != None: @@ -711,6 +754,9 @@ class RVDetails(MDRecycleView): if "deltas" in s and dt in s["deltas"] and s["deltas"][dt] != None: d = s["deltas"][dt] formatted_values += f" (Δ = {d} {vn})" + + formatted_values += ", " + formatted_values = formatted_values[:-2] data = None if formatted_values != None: